package main

import (
	"bytes"
	"log"
	"os"
	"path/filepath"
	"strconv"
	"strings"
	"syscall"

	"golang.org/x/sys/unix"
)

// Simulate a udev run for our needs
func syncSysToDev() {
	// loop devices
	sysPaths, _ := filepath.Glob("/sys/devices/virtual/block/loop*/**/dev")
	for _, sysPath := range sysPaths {
		mknodBlk(sysPath)
	}
}

func mknodBlk(sysPath string) {
	devPath := "/dev/" + filepath.Base(filepath.Dir(sysPath))
	if _, err := os.Stat(devPath); os.IsNotExist(err) {
		// ok
	} else if err != nil {
		log.Printf("stat %s failed: %v", devPath, err)
		return
	} else {
		return // exists
	}

	devBytes, err := os.ReadFile(sysPath)
	if err != nil {
		log.Printf("read %s failed: %v", sysPath, err)
		return
	}
	devBytes = bytes.TrimSpace(devBytes)

	// rust: let Some(dev) = devBytes.split_once(':').filter_map(|a,b| Some(mkdev(a.parse().ok()?, b.parse().ok()?)));
	majorStr, minorStr, ok := strings.Cut(string(devBytes), ":")
	if !ok {
		log.Printf("%s: invalid dev string: %s", sysPath, string(devBytes))
		return
	}
	major, err := strconv.ParseUint(majorStr, 10, 32)
	if err != nil {
		log.Printf("%s: invalid major: %q", sysPath, majorStr)
		return
	}
	minor, err := strconv.ParseUint(minorStr, 10, 32)
	if err != nil {
		log.Printf("%s: invalid minor: %q", sysPath, minorStr)
		return
	}

	devMajMin := int(unix.Mkdev(uint32(major), uint32(minor)))

	log.Printf("mknod %s b %d %d", devPath, major, minor)
	unix.Mknod(devPath, syscall.S_IFBLK|0o0600, devMajMin)
}
