//go:build linux package client import ( "fmt" "log" "os" "path/filepath" "strings" "time" "golang.org/x/sys/unix" ) // createSocketPair creates a Unix domain socket pair func createSocketPair() ([2]int, error) { fds, err := unix.Socketpair(unix.AF_UNIX, unix.SOCK_STREAM, 0) if err != nil { return [2]int{}, fmt.Errorf("socketpair: %w", err) } return fds, nil } func closeFDs(fds [2]int) { unix.Close(fds[0]) unix.Close(fds[1]) } func fdToFile(fd int, name string) *os.File { return os.NewFile(uintptr(fd), name) } // fixVHCIDevicePermissions waits for the VHCI-attached device to create // device nodes (e.g. /dev/video*) and sets them to world-accessible. // VHCI-created devices don't get normal udev rules applied, so they // default to root-only access. func fixVHCIDevicePermissions(port int) { // Wait for the device to finish enumerating and create device nodes. // The kernel needs time to enumerate descriptors and bind drivers. for attempt := 0; attempt < 15; attempt++ { time.Sleep(500 * time.Millisecond) found := false // Walk the VHCI sysfs tree to find device nodes at any depth. // Paths look like: vhci_hcd.0/usb3/3-1/3-1:1.0/video4linux/video0 filepath.WalkDir("/sys/devices/platform/vhci_hcd.0", func(path string, d os.DirEntry, err error) error { if err != nil { return nil } dir := filepath.Dir(path) parent := filepath.Base(dir) // video4linux devices → /dev/videoN if parent == "video4linux" && strings.HasPrefix(d.Name(), "video") { devPath := "/dev/" + d.Name() if err := os.Chmod(devPath, 0666); err == nil { log.Printf("[use] set permissions 0666 on %s", devPath) found = true } } // sound devices → /dev/snd/* if parent == "sound" && strings.HasPrefix(d.Name(), "card") { // For sound cards, chmod all related device nodes sndDir := filepath.Join(path, "device") if _, err := os.Stat(sndDir); err == nil { filepath.WalkDir("/dev/snd", func(sndPath string, sd os.DirEntry, err error) error { if err == nil && !sd.IsDir() { os.Chmod(sndPath, 0666) } return nil }) } } // input devices → /dev/input/eventN if strings.HasPrefix(d.Name(), "event") && strings.Contains(path, "/input/input") { devPath := "/dev/input/" + d.Name() if err := os.Chmod(devPath, 0666); err == nil { log.Printf("[use] set permissions 0666 on %s", devPath) } } return nil }) if attempt >= 2 && found { return } } }