|
@@ -0,0 +1,99 @@
|
|
|
+package raid
|
|
|
+
|
|
|
+import (
|
|
|
+ "fmt"
|
|
|
+ "os"
|
|
|
+ "os/exec"
|
|
|
+ "path/filepath"
|
|
|
+ "strings"
|
|
|
+)
|
|
|
+
|
|
|
+/*
|
|
|
+ losetup.go
|
|
|
+
|
|
|
+ This script handle losetup loopback interface setup and listing
|
|
|
+*/
|
|
|
+
|
|
|
+type LoopDevice struct {
|
|
|
+ Device string
|
|
|
+ PartitionRange string
|
|
|
+ ImageFile string
|
|
|
+}
|
|
|
+
|
|
|
+// List all the loop devices
|
|
|
+func ListAllLoopDevices() ([]*LoopDevice, error) {
|
|
|
+ cmd := exec.Command("sudo", "losetup", "-a")
|
|
|
+
|
|
|
+ output, err := cmd.CombinedOutput()
|
|
|
+ if err != nil {
|
|
|
+ return nil, fmt.Errorf("error running losetup -a command: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ //Example of returned values
|
|
|
+ // /dev/loop0: [2049]:265955 (/home/aroz/test/sdX.img)
|
|
|
+
|
|
|
+ // Split the output into lines and extract device names
|
|
|
+ lines := strings.Split(string(output), "\n")
|
|
|
+ var devices []*LoopDevice = []*LoopDevice{}
|
|
|
+ for _, line := range lines {
|
|
|
+ fields := strings.Fields(line)
|
|
|
+ if len(fields) >= 3 {
|
|
|
+ //As the image name contains a bracket, that needs to be trimmed off
|
|
|
+ imageName := strings.TrimPrefix(strings.TrimSpace(fields[2]), "(")
|
|
|
+ imageName = strings.TrimSuffix(imageName, ")")
|
|
|
+ devices = append(devices, &LoopDevice{
|
|
|
+ Device: fields[0],
|
|
|
+ PartitionRange: fields[1],
|
|
|
+ ImageFile: imageName,
|
|
|
+ })
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return devices, nil
|
|
|
+}
|
|
|
+
|
|
|
+// Mount an given image path as loopback device
|
|
|
+func MountImageAsLoopDevice(imagePath string) error {
|
|
|
+ cmd := exec.Command("sudo", "losetup", "-f", imagePath)
|
|
|
+
|
|
|
+ cmd.Stdout = os.Stdout
|
|
|
+ cmd.Stderr = os.Stderr
|
|
|
+
|
|
|
+ err := cmd.Run()
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("creating loopback device failed: %v", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+// Get loopdrive ID (/dev/loop1) by the image path, return empty string if not found error if load failed
|
|
|
+func GetLoopDriveIDFromImagePath(imagePath string) (string, error) {
|
|
|
+ absPath, err := filepath.Abs(imagePath)
|
|
|
+ if err != nil {
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+
|
|
|
+ devs, err := ListAllLoopDevices()
|
|
|
+ if err != nil {
|
|
|
+ return "", err
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, dev := range devs {
|
|
|
+ if filepath.ToSlash(dev.ImageFile) == filepath.ToSlash(absPath) {
|
|
|
+ //Found. already mounted
|
|
|
+ return dev.Device, nil
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return "", nil
|
|
|
+}
|
|
|
+
|
|
|
+// Check if an image file is already mounted as loop drive
|
|
|
+func ImageAlreadyMounted(imagePath string) (bool, error) {
|
|
|
+ loopDriveId, err := GetLoopDriveIDFromImagePath(imagePath)
|
|
|
+ if err != nil {
|
|
|
+ return false, err
|
|
|
+ }
|
|
|
+ return loopDriveId != "", nil
|
|
|
+}
|