package main import ( "bytes" "flag" "fmt" "log" "os" "path/filepath" "syscall" ) var ( dir string mount string ) func init() { flag.StringVar(&dir, "dir", "/etc/binfmt.d", "directory with config files") flag.StringVar(&mount, "mount", "/proc/sys/fs/binfmt_misc", "binfmt_misc mount point") } func binfmt(line []byte) error { register := filepath.Join(mount, "register") file, err := os.OpenFile(register, os.O_WRONLY, 0) if err != nil { e, ok := err.(*os.PathError) if ok && e.Err == syscall.ENOENT { return fmt.Errorf("ENOENT opening %s is it mounted?", register) } if ok && e.Err == syscall.EPERM { return fmt.Errorf("EPERM opening %s check permissions?", register) } return fmt.Errorf("Cannot open %s: %s", register, err) } defer file.Close() // short writes should not occur on sysfs, cannot usefully recover _, err = file.Write(line) if err != nil { e, ok := err.(*os.PathError) if ok && e.Err == syscall.EEXIST { // clear existing entry split := bytes.SplitN(line[1:], []byte(":"), 2) if len(split) == 0 { return fmt.Errorf("Cannot determine arch from: %s", line) } arch := filepath.Join(mount, string(split[0])) clear, err := os.OpenFile(arch, os.O_WRONLY, 0) if err != nil { return fmt.Errorf("Cannot open %s: %s", arch, err) } defer clear.Close() _, err = clear.Write([]byte("-1")) if err != nil { return fmt.Errorf("Cannot write to %s: %s", arch, err) } _, err = file.Write(line) if err != nil { return fmt.Errorf("Cannot write to %s: %s", register, err) } return nil } return fmt.Errorf("Cannot write to %s: %s", register, err) } return nil } func main() { flag.Parse() if err := syscall.Mount("binfmt_misc", mount, "binfmt_misc", 0, ""); err != nil { log.Fatalf("Cannot mount binfmt_misc filesystem at %s: %v", mount, err) } defer syscall.Unmount(mount, 0) files, err := os.ReadDir(dir) if err != nil { log.Fatalf("Cannot read directory %s: %s", dir, err) } for _, file := range files { contents, err := os.ReadFile(filepath.Join(dir, file.Name())) if err != nil { log.Fatalf("Cannot read file %s: %s", file.Name(), err) } lines := bytes.Split(contents, []byte("\n")) for _, line := range lines { if len(line) == 0 { continue } // ignore comments if line[0] == '#' { continue } err = binfmt(line) if err != nil { log.Fatal(err) } } } }