github.com/opencontainers/runc@v1.2.0-rc.1.0.20240520010911-492dc558cdd6/ps.go (about) 1 package main 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "os" 8 "os/exec" 9 "strconv" 10 "strings" 11 12 "github.com/sirupsen/logrus" 13 "github.com/urfave/cli" 14 ) 15 16 var psCommand = cli.Command{ 17 Name: "ps", 18 Usage: "ps displays the processes running inside a container", 19 ArgsUsage: `<container-id> [ps options]`, 20 Flags: []cli.Flag{ 21 cli.StringFlag{ 22 Name: "format, f", 23 Value: "table", 24 Usage: `select one of: ` + formatOptions, 25 }, 26 }, 27 Action: func(context *cli.Context) error { 28 if err := checkArgs(context, 1, minArgs); err != nil { 29 return err 30 } 31 rootlessCg, err := shouldUseRootlessCgroupManager(context) 32 if err != nil { 33 return err 34 } 35 if rootlessCg { 36 logrus.Warn("runc ps may fail if you don't have the full access to cgroups") 37 } 38 39 container, err := getContainer(context) 40 if err != nil { 41 return err 42 } 43 44 pids, err := container.Processes() 45 if err != nil { 46 return err 47 } 48 49 switch context.String("format") { 50 case "table": 51 case "json": 52 return json.NewEncoder(os.Stdout).Encode(pids) 53 default: 54 return errors.New("invalid format option") 55 } 56 57 // [1:] is to remove command name, ex: 58 // context.Args(): [container_id ps_arg1 ps_arg2 ...] 59 // psArgs: [ps_arg1 ps_arg2 ...] 60 // 61 psArgs := context.Args()[1:] 62 if len(psArgs) == 0 { 63 psArgs = []string{"-ef"} 64 } 65 66 cmd := exec.Command("ps", psArgs...) 67 output, err := cmd.CombinedOutput() 68 if err != nil { 69 return fmt.Errorf("%w: %s", err, output) 70 } 71 72 lines := strings.Split(string(output), "\n") 73 pidIndex, err := getPidIndex(lines[0]) 74 if err != nil { 75 return err 76 } 77 78 fmt.Println(lines[0]) 79 for _, line := range lines[1:] { 80 if len(line) == 0 { 81 continue 82 } 83 fields := strings.Fields(line) 84 p, err := strconv.Atoi(fields[pidIndex]) 85 if err != nil { 86 return fmt.Errorf("unable to parse pid: %w", err) 87 } 88 89 for _, pid := range pids { 90 if pid == p { 91 fmt.Println(line) 92 break 93 } 94 } 95 } 96 return nil 97 }, 98 SkipArgReorder: true, 99 } 100 101 func getPidIndex(title string) (int, error) { 102 titles := strings.Fields(title) 103 104 pidIndex := -1 105 for i, name := range titles { 106 if name == "PID" { 107 return i, nil 108 } 109 } 110 111 return pidIndex, errors.New("couldn't find PID field in ps output") 112 }