package platform import ( "fmt" "os" "os/exec" "path/filepath" "sort" "strings" ) func (s *System) ListRemovableTargets() ([]RemovableTarget, error) { raw, err := exec.Command("lsblk", "-P", "-o", "NAME,TYPE,PKNAME,RM,FSTYPE,MOUNTPOINT,SIZE,LABEL,MODEL").Output() if err != nil { return nil, err } var out []RemovableTarget for _, line := range strings.Split(strings.TrimSpace(string(raw)), "\n") { if strings.TrimSpace(line) == "" { continue } fields := parseLSBLKPairs(line) deviceType := fields["TYPE"] if deviceType == "rom" || deviceType == "loop" { continue } removable := fields["RM"] == "1" if !removable { if parent := fields["PKNAME"]; parent != "" { if data, err := os.ReadFile(filepath.Join("/sys/class/block", parent, "removable")); err == nil { removable = strings.TrimSpace(string(data)) == "1" } } } if !removable || fields["FSTYPE"] == "" { continue } out = append(out, RemovableTarget{ Device: "/dev/" + fields["NAME"], FSType: fields["FSTYPE"], Size: fields["SIZE"], Label: fields["LABEL"], Model: fields["MODEL"], Mountpoint: fields["MOUNTPOINT"], }) } sort.Slice(out, func(i, j int) bool { return out[i].Device < out[j].Device }) return out, nil } func (s *System) ExportFileToTarget(src string, target RemovableTarget) (string, error) { if src == "" || target.Device == "" { return "", fmt.Errorf("source and target are required") } if _, err := os.Stat(src); err != nil { return "", err } mountpoint := strings.TrimSpace(target.Mountpoint) mountedHere := false if mountpoint == "" { mountpoint = filepath.Join("/tmp", "bee-export-"+filepath.Base(target.Device)) if err := os.MkdirAll(mountpoint, 0755); err != nil { return "", err } if raw, err := exec.Command("mount", target.Device, mountpoint).CombinedOutput(); err != nil { _ = os.Remove(mountpoint) return string(raw), err } mountedHere = true } filename := filepath.Base(src) dst := filepath.Join(mountpoint, filename) data, err := os.ReadFile(src) if err != nil { return "", err } if err := os.WriteFile(dst, data, 0644); err != nil { return "", err } _ = exec.Command("sync").Run() if mountedHere { _ = exec.Command("umount", mountpoint).Run() _ = os.Remove(mountpoint) } return dst, nil }