Files
linuxkit/pkg/mount/mountie.go
Justin Cormack 1412cf8835 Fix mode of created directories in mountie
Signed-off-by: Justin Cormack <justin.cormack@docker.com>
2017-07-31 17:31:40 +01:00

193 lines
4.4 KiB
Go

package main
import (
"bufio"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
"os"
"os/exec"
"path/filepath"
"regexp"
"sort"
"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
}
// 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)
}
}