mirror of
				https://github.com/linuxkit/linuxkit.git
				synced 2025-11-04 13:36:56 +00:00 
			
		
		
		
	go_vet (via https://goreportcard.com/report/github.com/linuxkit/linuxkit) reported: error: missing argument for Printf("%v"): format reads arg 2, have only 1 args (vet) error: wrong number of args for format in Printf call: 2 needed but 3 args (vet) Signed-off-by: Ian Campbell <ijc@docker.com>
		
			
				
	
	
		
			277 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			277 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package main
 | 
						|
 | 
						|
import (
 | 
						|
	"bufio"
 | 
						|
	"encoding/json"
 | 
						|
	"flag"
 | 
						|
	"fmt"
 | 
						|
	"io/ioutil"
 | 
						|
	"log"
 | 
						|
	"os"
 | 
						|
	"os/exec"
 | 
						|
	"path/filepath"
 | 
						|
	"regexp"
 | 
						|
	"sort"
 | 
						|
	"strconv"
 | 
						|
	"strings"
 | 
						|
	"syscall"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	deviceVar, labelVar, uuidVar string
 | 
						|
)
 | 
						|
 | 
						|
// Fdisk is the JSON output from libfdisk
 | 
						|
type Fdisk struct {
 | 
						|
	PartitionTable struct {
 | 
						|
		Label      string `json:"label"`
 | 
						|
		ID         string `json:"id"`
 | 
						|
		Device     string `json:"device"`
 | 
						|
		Unit       string `json:"unit"`
 | 
						|
		FirstLBA   int    `json:"firstlba"`
 | 
						|
		LastLBA    int    `json:"lastlba"`
 | 
						|
		Partitions []struct {
 | 
						|
			Node  string `json:"node"`
 | 
						|
			Start int    `json:"start"`
 | 
						|
			Size  int    `json:"size"`
 | 
						|
			Type  string `json:"type"`
 | 
						|
			UUID  string `json:"uuid"`
 | 
						|
			Name  string `json:"name"`
 | 
						|
		}
 | 
						|
	} `json:"partitionTable"`
 | 
						|
}
 | 
						|
 | 
						|
// mount drive/partition to mountpoint
 | 
						|
func mount(device, mountpoint string) error {
 | 
						|
	if out, err := exec.Command("mount", device, mountpoint).CombinedOutput(); err != nil {
 | 
						|
		return fmt.Errorf("Error mounting %s to %s: %v\n%s", device, mountpoint, err, string(out))
 | 
						|
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func findDevice(pattern string) (string, error) {
 | 
						|
	out, err := exec.Command("findfs", pattern).Output()
 | 
						|
	if err != nil {
 | 
						|
		return "", fmt.Errorf("Error finding device with %s: %v", pattern, err)
 | 
						|
	}
 | 
						|
	device := strings.TrimSpace(string(out))
 | 
						|
	return device, nil
 | 
						|
}
 | 
						|
 | 
						|
func findFirst(drives []string) (string, error) {
 | 
						|
	var first string
 | 
						|
 | 
						|
	out, err := exec.Command("mount").Output()
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	mounted := make(map[string]bool)
 | 
						|
	scanner := bufio.NewScanner(strings.NewReader(string(out)))
 | 
						|
	for scanner.Scan() {
 | 
						|
		parts := strings.Split(scanner.Text(), " ")
 | 
						|
		if _, err := os.Stat(parts[0]); os.IsNotExist(err) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		if _, ok := mounted[parts[0]]; !ok {
 | 
						|
			mounted[parts[0]] = true
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	for _, d := range drives {
 | 
						|
		err := exec.Command("sfdisk", "-d", d).Run()
 | 
						|
		if err != nil {
 | 
						|
			log.Printf("No partition table found on device %s. Skipping.", d)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
 | 
						|
		data, err := exec.Command("sfdisk", "-J", d).Output()
 | 
						|
		if err != nil {
 | 
						|
			log.Fatalf("Unable to get drive data for %s from sfdisk: %v", d, err)
 | 
						|
		}
 | 
						|
 | 
						|
		f := Fdisk{}
 | 
						|
		if err := json.Unmarshal(data, &f); err != nil {
 | 
						|
			return "", fmt.Errorf("Unable to unmarshal partition table from sfdisk: %v", err)
 | 
						|
		}
 | 
						|
 | 
						|
		for _, partition := range f.PartitionTable.Partitions {
 | 
						|
			// ignore anything that isn't a Linux partition
 | 
						|
			if partition.Type != "83" {
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			if _, ok := mounted[partition.Node]; ok {
 | 
						|
				log.Printf("%s already mounted. Skipping", partition.Node)
 | 
						|
				continue
 | 
						|
			}
 | 
						|
			first = partition.Node
 | 
						|
			break
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if first == "" {
 | 
						|
		return "", fmt.Errorf("No eligible disks found")
 | 
						|
	}
 | 
						|
	return first, nil
 | 
						|
}
 | 
						|
 | 
						|
func makeDevLinks() error {
 | 
						|
	rex := regexp.MustCompile(`([A-Z]+)=("(?:\\.|[^"])*") ?`)
 | 
						|
 | 
						|
	byLabel := "/dev/disk/by-label"
 | 
						|
	byUUID := "/dev/disk/by-uuid"
 | 
						|
	for _, p := range []string{byLabel, byUUID} {
 | 
						|
		err := os.MkdirAll(p, 0755)
 | 
						|
		if err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	devs, err := ioutil.ReadDir("/sys/class/block")
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
	for _, dev := range devs {
 | 
						|
		name := dev.Name()
 | 
						|
		devpath := filepath.Join("/dev", name)
 | 
						|
		outb, err := exec.Command("blkid", devpath).CombinedOutput()
 | 
						|
		if err != nil {
 | 
						|
			log.Printf("Unable to get blkid for %s: %v", devpath, err)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		out := string(outb)
 | 
						|
		if out == "" {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		prefix := devpath + ": "
 | 
						|
		if !strings.HasPrefix(out, prefix) {
 | 
						|
			log.Printf("Malformed blkid for %s: %s", name, out)
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		out = strings.TrimPrefix(out, prefix)
 | 
						|
 | 
						|
		for _, match := range rex.FindAllStringSubmatch(out, -1) {
 | 
						|
			key := match[1]
 | 
						|
 | 
						|
			val, err := strconv.Unquote(match[2])
 | 
						|
			if err != nil {
 | 
						|
				log.Printf("Failed to parse: %s\n", match[0])
 | 
						|
				continue
 | 
						|
			}
 | 
						|
 | 
						|
			switch key {
 | 
						|
			case "LABEL":
 | 
						|
				// This is not currently handled
 | 
						|
				// because for compatibility we would
 | 
						|
				// need to encode val according to
 | 
						|
				// blkid_encode_string which hex
 | 
						|
				// escapes certain chacters as \xXX.
 | 
						|
				//
 | 
						|
				// See:
 | 
						|
				// https://github.com/systemd/systemd/blob/8d8ce9e2cd066e90c17e2d1eb1882defabb1fa63/src/udev/udev-builtin-blkid.c#L61..L66
 | 
						|
				// https://www.kernel.org/pub/linux/utils/util-linux/v2.21/libblkid-docs/libblkid-Encoding-utils.html
 | 
						|
			case "UUID":
 | 
						|
				// Strictly the value should be
 | 
						|
				// encoded here as with "LABEL" but we
 | 
						|
				// take the chance that a string UUID
 | 
						|
				// is unlikely to contain any unsafe
 | 
						|
				// characters.
 | 
						|
				sympath := filepath.Join(byUUID, val)
 | 
						|
				// udev makes these relative links, copy that behaviour.
 | 
						|
				tgtpath := filepath.Join("..", "..", name)
 | 
						|
				if err := os.Symlink(tgtpath, sympath); err != nil {
 | 
						|
					log.Printf("Failed to create %q: %v", sympath, err)
 | 
						|
					continue
 | 
						|
				}
 | 
						|
			case "TYPE":
 | 
						|
				// uninteresting
 | 
						|
			default:
 | 
						|
				log.Printf("unused %q blkid property %q in %q", name, key, match[0])
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// return a list of all available drives
 | 
						|
func findDrives() []string {
 | 
						|
	driveKeys := []string{}
 | 
						|
	ignoreExp := regexp.MustCompile(`^loop.*$|^nbd.*$|^[a-z]+[0-9]+$`)
 | 
						|
	devs, _ := ioutil.ReadDir("/dev")
 | 
						|
	for _, d := range devs {
 | 
						|
		// this probably shouldn't be so hard
 | 
						|
		// but d.Mode()&os.ModeDevice == 0 doesn't work as expected
 | 
						|
		mode := d.Sys().(*syscall.Stat_t).Mode
 | 
						|
		if (mode & syscall.S_IFMT) != syscall.S_IFBLK {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		// ignore if it matches regexp
 | 
						|
		if ignoreExp.MatchString(d.Name()) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		driveKeys = append(driveKeys, filepath.Join("/dev", d.Name()))
 | 
						|
	}
 | 
						|
	sort.Strings(driveKeys)
 | 
						|
	return driveKeys
 | 
						|
}
 | 
						|
 | 
						|
func init() {
 | 
						|
	flag.StringVar(&deviceVar, "device", "", "Name of the device to mount")
 | 
						|
	flag.StringVar(&labelVar, "label", "", "Label of the device to mount")
 | 
						|
	flag.StringVar(&uuidVar, "uuid", "", "UUID of the device to mount")
 | 
						|
}
 | 
						|
 | 
						|
func main() {
 | 
						|
	flag.Parse()
 | 
						|
 | 
						|
	var mountpoint string
 | 
						|
 | 
						|
	switch flag.NArg() {
 | 
						|
	case 0:
 | 
						|
		log.Fatal("No mountpoints provided")
 | 
						|
	case 1:
 | 
						|
		mountpoint = flag.Args()[0]
 | 
						|
	case 2:
 | 
						|
		deviceVar = flag.Args()[0]
 | 
						|
		mountpoint = flag.Args()[1]
 | 
						|
	default:
 | 
						|
		log.Fatalf("Too many arguments")
 | 
						|
	}
 | 
						|
 | 
						|
	err := os.MkdirAll(mountpoint, 0755)
 | 
						|
	if err != nil {
 | 
						|
		log.Fatalf("Unable to create mountpoint %s: %v", mountpoint, err)
 | 
						|
	}
 | 
						|
	if deviceVar == "" && labelVar != "" {
 | 
						|
		deviceVar, err = findDevice(fmt.Sprintf("LABEL=%s", labelVar))
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if deviceVar == "" && uuidVar != "" {
 | 
						|
		deviceVar, err = findDevice(fmt.Sprintf("UUID=%s", uuidVar))
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	if deviceVar == "" {
 | 
						|
		// find first device
 | 
						|
		drives := findDrives()
 | 
						|
		first, err := findFirst(drives)
 | 
						|
		if err != nil {
 | 
						|
			log.Fatal(err)
 | 
						|
		}
 | 
						|
		deviceVar = first
 | 
						|
	}
 | 
						|
 | 
						|
	if err := mount(deviceVar, mountpoint); err != nil {
 | 
						|
		log.Fatal(err)
 | 
						|
	}
 | 
						|
 | 
						|
	if err := makeDevLinks(); err != nil {
 | 
						|
		log.Printf("Failed to make /dev/ links for: %v", err)
 | 
						|
	}
 | 
						|
 | 
						|
}
 |