github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/utils.go (about) 1 package main 2 3 import ( 4 "errors" 5 "fmt" 6 "os" 7 "path/filepath" 8 "strconv" 9 "strings" 10 11 "github.com/opencontainers/runtime-spec/specs-go" 12 13 "github.com/sirupsen/logrus" 14 "github.com/urfave/cli" 15 ) 16 17 const ( 18 exactArgs = iota 19 minArgs 20 maxArgs 21 ) 22 23 func checkArgs(context *cli.Context, expected, checkType int) error { 24 var err error 25 cmdName := context.Command.Name 26 switch checkType { 27 case exactArgs: 28 if context.NArg() != expected { 29 err = fmt.Errorf("%s: %q requires exactly %d argument(s)", os.Args[0], cmdName, expected) 30 } 31 case minArgs: 32 if context.NArg() < expected { 33 err = fmt.Errorf("%s: %q requires a minimum of %d argument(s)", os.Args[0], cmdName, expected) 34 } 35 case maxArgs: 36 if context.NArg() > expected { 37 err = fmt.Errorf("%s: %q requires a maximum of %d argument(s)", os.Args[0], cmdName, expected) 38 } 39 } 40 41 if err != nil { 42 fmt.Printf("Incorrect Usage.\n\n") 43 _ = cli.ShowCommandHelp(context, cmdName) 44 return err 45 } 46 return nil 47 } 48 49 func logrusToStderr() bool { 50 l, ok := logrus.StandardLogger().Out.(*os.File) 51 return ok && l.Fd() == os.Stderr.Fd() 52 } 53 54 // fatal prints the error's details if it is a libcontainer specific error type 55 // then exits the program with an exit status of 1. 56 func fatal(err error) { 57 fatalWithCode(err, 1) 58 } 59 60 func fatalWithCode(err error, ret int) { 61 // Make sure the error is written to the logger. 62 logrus.Error(err) 63 if !logrusToStderr() { 64 fmt.Fprintln(os.Stderr, err) 65 } 66 67 os.Exit(ret) 68 } 69 70 // setupSpec performs initial setup based on the cli.Context for the container 71 func setupSpec(context *cli.Context) (*specs.Spec, error) { 72 bundle := context.String("bundle") 73 if bundle != "" { 74 if err := os.Chdir(bundle); err != nil { 75 return nil, err 76 } 77 } 78 spec, err := loadSpec(specConfig) 79 if err != nil { 80 return nil, err 81 } 82 return spec, nil 83 } 84 85 func revisePidFile(context *cli.Context) error { 86 pidFile := context.String("pid-file") 87 if pidFile == "" { 88 return nil 89 } 90 91 // convert pid-file to an absolute path so we can write to the right 92 // file after chdir to bundle 93 pidFile, err := filepath.Abs(pidFile) 94 if err != nil { 95 return err 96 } 97 return context.Set("pid-file", pidFile) 98 } 99 100 // reviseRootDir ensures that the --root option argument, 101 // if specified, is converted to an absolute and cleaned path, 102 // and that this path is sane. 103 func reviseRootDir(context *cli.Context) error { 104 if !context.IsSet("root") { 105 return nil 106 } 107 root, err := filepath.Abs(context.GlobalString("root")) 108 if err != nil { 109 return err 110 } 111 if root == "/" { 112 // This can happen if --root argument is 113 // - "" (i.e. empty); 114 // - "." (and the CWD is /); 115 // - "../../.." (enough to get to /); 116 // - "/" (the actual /). 117 return errors.New("Option --root argument should not be set to /") 118 } 119 120 return context.GlobalSet("root", root) 121 } 122 123 // parseBoolOrAuto returns (nil, nil) if s is empty or "auto" 124 func parseBoolOrAuto(s string) (*bool, error) { 125 if s == "" || strings.ToLower(s) == "auto" { 126 return nil, nil 127 } 128 b, err := strconv.ParseBool(s) 129 return &b, err 130 }