github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/namespace/parser.go (about) 1 // Copyright 2020 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 // Package namespace parses name space description files 6 // https://plan9.io/magic/man2html/6/namespace 7 package namespace 8 9 import ( 10 "bufio" 11 "fmt" 12 "io" 13 "os" 14 "strings" 15 ) 16 17 // Parse takes a namespace file and returns a collection 18 // of operations that build a name space in Plan 9. 19 // 20 // Think oci runtime spec, but don't think too much cause the JSON 21 // will make your head hurt. 22 // 23 // http://man.cat-v.org/plan_9/1/ns 24 func Parse(r io.Reader) (File, error) { 25 scanner := bufio.NewScanner(r) 26 27 cmds := []Modifier{} 28 for scanner.Scan() { 29 buf := scanner.Bytes() 30 if len(buf) <= 0 { 31 continue 32 } 33 r := buf[0] 34 // Blank lines and lines with # as the first non–space character are ignored. 35 if r == '#' || r == ' ' { 36 continue 37 } 38 cmd, err := ParseLine(scanner.Text()) 39 if err != nil { 40 return nil, err 41 } 42 cmds = append(cmds, cmd) 43 } 44 if err := scanner.Err(); err != nil { 45 fmt.Fprintln(os.Stderr, "reading standard input:", err) 46 } 47 return cmds, nil 48 } 49 50 // ParseFlags parses flags as mount, bind would. Supports -a, -b, -c, 51 // -q, and -C, although the -q flag is not yet implemented. Other flags 52 // are silently ignored. 53 // Not using the os.Flag package here as that would break the 54 // name space description files. 55 // https://9p.io/magic/man2html/6/namespace 56 func ParseFlags(args []string) (mountflag, []string) { 57 flag := REPL 58 for i, arg := range args { 59 // these args are passed trough strings.Fields which doesn't return empty strings 60 // so this is ok. 61 if arg[0] == '-' { 62 args = append(args[:i], args[i+1:]...) 63 for _, r := range arg { 64 switch r { 65 case 'a': 66 flag |= AFTER 67 case 'b': 68 flag |= BEFORE 69 case 'c': 70 flag |= CREATE 71 case 'q': 72 // todo(sevki): support quiet flag 73 case 'C': 74 flag |= CACHE 75 default: 76 } 77 } 78 } 79 } 80 return flag, args 81 } 82 83 // ParseArgs parses os.Args (not flag.Args()!) to return a 84 // namespace.Modifier which is appropriate for the given 85 // command. The command is taken from args[0]; the following 86 // commands are supported: bind, mount, unmount, clear, cd, ., import. 87 // 88 // After extracting the command, ParseArgs will call ParseFlags to extract 89 // appropriate bind/mount flags, if any. 90 func ParseArgs(args []string) (Modifier, error) { 91 arg := args[0] 92 args = args[1:] 93 trap := syzcall(0) 94 95 c := cmd{ 96 syscall: trap, 97 flag: REPL, 98 args: args, 99 } 100 switch arg { 101 case "bind": 102 c.syscall = BIND 103 case "mount": 104 c.syscall = MOUNT 105 case "unmount": 106 c.syscall = UNMOUNT 107 case "clear": 108 c.syscall = RFORK 109 case "cd": 110 c.syscall = CHDIR 111 case ".": 112 c.syscall = INCLUDE 113 case "import": 114 c.syscall = IMPORT 115 default: 116 return nil, fmt.Errorf("%q is an unknown operation", arg) 117 } 118 119 c.flag, c.args = ParseFlags(args) 120 121 return c, nil 122 } 123 124 // ParseLine breaks a string into arguments and passes them to ParseArgs. 125 func ParseLine(line string) (Modifier, error) { 126 return ParseArgs(strings.Fields(line)) 127 }