github.com/sdibtacm/sandbox@v0.0.0-20200320120712-60470cf803dc/units/pstree/pstree.go (about) 1 // Code copy from github.com/sbinet/pstree 2 //+build linux 3 4 // package pstree provides an API to retrieve the process tree from procfs. 5 package pstree 6 7 import ( 8 "fmt" 9 "log" 10 "os" 11 "path/filepath" 12 "sort" 13 "strings" 14 ) 15 16 // New returns the whole system process tree. 17 func New() (*Tree, error) { 18 files, err := filepath.Glob("/proc/[0-9]*") 19 if err != nil { 20 return nil, err 21 } 22 23 procs := make(map[int]Process, len(files)) 24 for _, dir := range files { 25 proc, err := scan(dir) 26 if err != nil { 27 return nil, err 28 } 29 if proc.Stat.Pid == 0 { 30 // process vanished since Glob. 31 continue 32 } 33 procs[proc.Stat.Pid] = proc 34 } 35 36 for pid, proc := range procs { 37 if proc.Stat.Ppid == 0 { 38 continue 39 } 40 parent, ok := procs[proc.Stat.Ppid] 41 if !ok { 42 log.Panicf( 43 "internal logic error. parent of [%d] does not exist!", 44 pid, 45 ) 46 } 47 parent.Children = append(parent.Children, pid) 48 procs[parent.Stat.Pid] = parent 49 } 50 51 for pid, proc := range procs { 52 if len(proc.Children) > 0 { 53 sort.Ints(proc.Children) 54 } 55 procs[pid] = proc 56 } 57 58 tree := &Tree{ 59 Procs: procs, 60 } 61 return tree, err 62 } 63 64 const ( 65 statfmt = "%c %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d %d" 66 ) 67 68 // ProcessStat contains process information. 69 // see: http://man7.org/linux/man-pages/man5/proc.5.html 70 type ProcessStat struct { 71 Pid int // process ID 72 Comm string // filename of the executable in parentheses 73 State byte // process state 74 Ppid int // pid of the parent process 75 Pgrp int // process group ID of the process 76 Session int // session ID of the process 77 Tty int // controlling terminal of the process 78 Tpgid int // ID of foreground process group 79 Flags uint32 // kernel flags word of the process 80 Minflt uint64 // number of minor faults the process has made which have not required loading a memory page from disk 81 Cminflt uint64 // number of minor faults the process's waited-for children have made 82 Majflt uint64 // number of major faults the process has made which have required loading a memory page from disk 83 Cmajflt uint64 // number of major faults the process's waited-for children have made 84 Utime uint64 // user time in clock ticks 85 Stime uint64 // system time in clock ticks 86 Cutime uint64 // children user time in clock ticks 87 Cstime uint64 // children system time in clock ticks 88 Priority int64 // priority 89 Nice int64 // the nice value 90 Nthreads int64 // number of threads in this process 91 Itrealval int64 // time in jiffies before next SIGALRM is sent to the process due to an interval timer 92 Starttime int64 // time the process started after system boot in clock ticks 93 Vsize uint64 // virtual memory size in bytes 94 Rss int64 // resident set size: number of pages the process has in real memory 95 } 96 97 func scan(dir string) (Process, error) { 98 f, err := os.Open(filepath.Join(dir, "stat")) 99 if err != nil { 100 // process vanished since Glob. 101 return Process{}, nil 102 } 103 defer f.Close() 104 105 var proc Process 106 107 _, err = fmt.Fscanf(f, "%d %s", &proc.Stat.Pid, &proc.Stat.Comm) 108 if err != nil { 109 return proc, err 110 } 111 112 // some of command will have space, we should get all 113 for !strings.HasSuffix(proc.Stat.Comm, ")") { 114 var str string 115 _, err = fmt.Fscanf(f, "%s", &str) 116 if err != nil { 117 return proc, err 118 } 119 proc.Stat.Comm += str 120 } 121 122 _, err = fmt.Fscanf( 123 f, statfmt, 124 &proc.Stat.State, 125 &proc.Stat.Ppid, &proc.Stat.Pgrp, &proc.Stat.Session, 126 &proc.Stat.Tty, &proc.Stat.Tpgid, &proc.Stat.Flags, 127 &proc.Stat.Minflt, &proc.Stat.Cminflt, &proc.Stat.Majflt, &proc.Stat.Cmajflt, 128 &proc.Stat.Utime, &proc.Stat.Stime, 129 &proc.Stat.Cutime, &proc.Stat.Cstime, 130 &proc.Stat.Priority, 131 &proc.Stat.Nice, 132 &proc.Stat.Nthreads, 133 &proc.Stat.Itrealval, &proc.Stat.Starttime, 134 &proc.Stat.Vsize, &proc.Stat.Rss, 135 ) 136 if err != nil { 137 return proc, err 138 } 139 140 proc.Name = proc.Stat.Comm 141 if strings.HasPrefix(proc.Name, "(") && strings.HasSuffix(proc.Name, ")") { 142 proc.Name = proc.Name[1 : len(proc.Name)-1] 143 } 144 return proc, nil 145 } 146 147 // Tree is a tree of processes. 148 type Tree struct { 149 Procs map[int]Process 150 } 151 152 // Process stores information about a UNIX process. 153 type Process struct { 154 Name string 155 Stat ProcessStat 156 Children []int 157 }