Browse Source

Added tested losetup functions

Toby Chui 1 year ago
parent
commit
daf445cfd1
3 changed files with 176 additions and 14 deletions
  1. 99 0
      mod/disk/raid/losetup.go
  2. 77 0
      mod/disk/raid/raid.go
  3. 0 14
      web/SystemAO/disk/RAID/raid.go

+ 99 - 0
mod/disk/raid/losetup.go

@@ -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
+}

+ 77 - 0
mod/disk/raid/raid.go

@@ -0,0 +1,77 @@
+package raid
+
+import (
+	"errors"
+	"fmt"
+	"os"
+	"os/exec"
+	"path/filepath"
+
+	"imuslab.com/arozos/mod/apt"
+	"imuslab.com/arozos/mod/utils"
+)
+
+/*
+	RAID management package for handling RAID and Virtual Image Creation
+	for Linux with mdadm installed
+*/
+
+type Options struct {
+}
+
+type Manager struct {
+	Usable  bool //If Manager can be used. Return false if package missing or not found
+	Options *Options
+}
+
+// Create a new raid manager
+func NewRaidManager(options *Options) (*Manager, error) {
+	//Check if mdadm exists
+	mdadmExists, err := apt.PackageExists("mdadm")
+	if err != nil {
+		mdadmExists = false
+	}
+	return &Manager{
+		Usable:  mdadmExists,
+		Options: options,
+	}, nil
+}
+
+// Create a virtual image partition at given path with given size
+func CreateVirtualPartition(imagePath string, totalSize int64) error {
+	cmd := exec.Command("sudo", "dd", "if=/dev/zero", "of="+imagePath, "bs=4M", "count="+fmt.Sprintf("%dM", totalSize/(4*1024*1024)))
+
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+
+	err := cmd.Run()
+	if err != nil {
+		return fmt.Errorf("dd error: %v", err)
+	}
+
+	return nil
+}
+
+// Format the given image file
+func FormatVirtualPartition(imagePath string) error {
+	//Check if image actually exists
+	if !utils.FileExists(imagePath) {
+		return errors.New("image file not exists")
+	}
+
+	if filepath.Ext(imagePath) != ".img" {
+		return errors.New("given file is not an image path")
+	}
+
+	cmd := exec.Command("sudo", "mkfs.ext4", imagePath)
+
+	cmd.Stdout = os.Stdout
+	cmd.Stderr = os.Stderr
+
+	err := cmd.Run()
+	if err != nil {
+		return fmt.Errorf("error running mkfs.ext4 command: %v", err)
+	}
+
+	return nil
+}

+ 0 - 14
web/SystemAO/disk/RAID/raid.go

@@ -1,14 +0,0 @@
-package raid
-
-type Options struct {
-}
-type Manager struct {
-	Options *Options
-}
-
-// Create a new raid manager
-func NewRaidManager(options *Options) (*Manager, error) {
-	return &Manager{
-		Options: options,
-	}, nil
-}