github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/cmds/core/mount/mount.go (about)

     1  // Copyright 2012-2017 the u-root Authors. All rights reserved
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  //go:build !plan9
     6  // +build !plan9
     7  
     8  // mount mounts a filesystem at the specified path.
     9  //
    10  // Synopsis:
    11  //
    12  //	mount [-r] [-o options] [-t FSTYPE] DEV PATH
    13  //
    14  // Options:
    15  //
    16  //	-r: read only
    17  package main
    18  
    19  import (
    20  	"flag"
    21  	"fmt"
    22  	"log"
    23  	"os"
    24  	"strings"
    25  
    26  	"github.com/mvdan/u-root-coreutils/pkg/mount"
    27  	"github.com/mvdan/u-root-coreutils/pkg/mount/loop"
    28  	"golang.org/x/sys/unix"
    29  )
    30  
    31  type mountOptions []string
    32  
    33  func (o *mountOptions) String() string {
    34  	return strings.Join(*o, ",")
    35  }
    36  
    37  func (o *mountOptions) Set(value string) error {
    38  	for _, option := range strings.Split(value, ",") {
    39  		*o = append(*o, option)
    40  	}
    41  	return nil
    42  }
    43  
    44  var (
    45  	ro      = flag.Bool("r", false, "Read only mount")
    46  	fsType  = flag.String("t", "", "File system type")
    47  	options mountOptions
    48  )
    49  
    50  func init() {
    51  	flag.Var(&options, "o", "Comma separated list of mount options")
    52  }
    53  
    54  func loopSetup(filename string) (loopDevice string, err error) {
    55  	loopDevice, err = loop.FindDevice()
    56  	if err != nil {
    57  		return "", err
    58  	}
    59  	if err := loop.SetFile(loopDevice, filename); err != nil {
    60  		return "", err
    61  	}
    62  	return loopDevice, nil
    63  }
    64  
    65  // extended from boot.go
    66  func getSupportedFilesystem(originFS string) ([]string, bool, error) {
    67  	var known bool
    68  	var err error
    69  	fs, err := os.ReadFile("/proc/filesystems")
    70  	if err != nil {
    71  		return nil, known, err
    72  	}
    73  	var returnValue []string
    74  	for _, f := range strings.Split(string(fs), "\n") {
    75  		n := strings.Fields(f)
    76  		last := len(n) - 1
    77  		if last < 0 {
    78  			continue
    79  		}
    80  		if n[last] == originFS {
    81  			known = true
    82  		}
    83  		returnValue = append(returnValue, n[last])
    84  	}
    85  	return returnValue, known, err
    86  }
    87  
    88  func informIfUnknownFS(originFS string) {
    89  	knownFS, known, err := getSupportedFilesystem(originFS)
    90  	if err != nil {
    91  		// just don't make things even worse...
    92  		return
    93  	}
    94  	if !known {
    95  		log.Printf("Hint: unknown filesystem %s. Known are: %v", originFS, knownFS)
    96  	}
    97  }
    98  
    99  func main() {
   100  	if len(os.Args) == 1 {
   101  		n := []string{"/proc/self/mounts", "/proc/mounts", "/etc/mtab"}
   102  		for _, p := range n {
   103  			if b, err := os.ReadFile(p); err == nil {
   104  				fmt.Print(string(b))
   105  				os.Exit(0)
   106  			}
   107  		}
   108  		log.Fatalf("Could not read %s to get namespace", n)
   109  	}
   110  	flag.Parse()
   111  	if len(flag.Args()) < 2 {
   112  		flag.Usage()
   113  		os.Exit(1)
   114  	}
   115  	a := flag.Args()
   116  	dev := a[0]
   117  	path := a[1]
   118  	var flags uintptr
   119  	var data []string
   120  	var err error
   121  	for _, option := range options {
   122  		switch option {
   123  		case "loop":
   124  			dev, err = loopSetup(dev)
   125  			if err != nil {
   126  				log.Fatal("Error setting loop device:", err)
   127  			}
   128  		default:
   129  			if f, ok := opts[option]; ok {
   130  				flags |= f
   131  			} else {
   132  				data = append(data, option)
   133  			}
   134  		}
   135  	}
   136  	if *ro {
   137  		flags |= unix.MS_RDONLY
   138  	}
   139  	if *fsType == "" {
   140  		if _, err := mount.TryMount(dev, path, strings.Join(data, ","), flags); err != nil {
   141  			log.Fatalf("%v", err)
   142  		}
   143  	} else {
   144  		if _, err := mount.Mount(dev, path, *fsType, strings.Join(data, ","), flags); err != nil {
   145  			log.Printf("%v", err)
   146  			informIfUnknownFS(*fsType)
   147  			os.Exit(1)
   148  		}
   149  	}
   150  }