github.com/u-root/u-root@v7.0.1-0.20200915234505-ad7babab0a8e+incompatible/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 plan9.
    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  //
    25  func Parse(r io.Reader) (File, error) {
    26  	scanner := bufio.NewScanner(r)
    27  
    28  	cmds := []Modifier{}
    29  	for scanner.Scan() {
    30  		buf := scanner.Bytes()
    31  		if len(buf) <= 0 {
    32  			continue
    33  		}
    34  		r := buf[0]
    35  		// Blank lines and lines with # as the first non–space character are ignored.
    36  		if r == '#' || r == ' ' {
    37  			continue
    38  		}
    39  		cmd, err := ParseLine(scanner.Text())
    40  
    41  		if err != nil {
    42  			return nil, err
    43  		}
    44  		cmds = append(cmds, cmd)
    45  	}
    46  	if err := scanner.Err(); err != nil {
    47  		fmt.Fprintln(os.Stderr, "reading standard input:", err)
    48  	}
    49  	return cmds, nil
    50  }
    51  
    52  // ParseFlags parses flags as mount, bind would.
    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 could be used to parse os.Args
    84  // to unify all commangs under a namespace.Main()
    85  // it isn't.
    86  func ParseArgs(args []string) (Modifier, error) {
    87  	arg := args[0]
    88  	args = args[1:]
    89  	trap := syzcall(0)
    90  
    91  	c := cmd{
    92  		syscall: trap,
    93  		flag:    REPL,
    94  		args:    args,
    95  	}
    96  	switch arg {
    97  	case "bind":
    98  		c.syscall = BIND
    99  	case "mount":
   100  		c.syscall = MOUNT
   101  	case "unmount":
   102  		c.syscall = UNMOUNT
   103  	case "clear":
   104  		c.syscall = RFORK
   105  	case "cd":
   106  		c.syscall = CHDIR
   107  	case ".":
   108  		c.syscall = INCLUDE
   109  	case "import":
   110  		c.syscall = IMPORT
   111  	default:
   112  		panic(arg)
   113  	}
   114  
   115  	c.flag, c.args = ParseFlags(args)
   116  
   117  	return c, nil
   118  }
   119  
   120  // ParseLine could be used to parse os.Args
   121  // to unify all commangs under a namespace.Main()
   122  // it isn't.
   123  func ParseLine(line string) (Modifier, error) {
   124  	return ParseArgs(strings.Fields(line))
   125  }