ps.c (3915B)
1 /* See LICENSE file for copyright and license details. */ 2 #include <sys/ioctl.h> 3 #include <sys/sysinfo.h> 4 5 #include <errno.h> 6 #include <libgen.h> 7 #include <limits.h> 8 #include <pwd.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 #include <time.h> 13 #include <unistd.h> 14 15 #include "proc.h" 16 #include "util.h" 17 18 static void psout(struct procstat *ps); 19 static void psr(const char *file); 20 21 enum { 22 PS_aflag = 1 << 0, 23 PS_Aflag = 1 << 1, 24 PS_dflag = 1 << 2, 25 PS_fflag = 1 << 3 26 }; 27 28 static void 29 usage(void) 30 { 31 eprintf("usage: [-aAdef] %s\n", argv0); 32 } 33 34 static int flags; 35 36 int 37 main(int argc, char *argv[]) 38 { 39 ARGBEGIN { 40 case 'a': 41 flags |= PS_aflag; 42 break; 43 case 'A': 44 flags |= PS_Aflag; 45 break; 46 case 'd': 47 flags |= PS_dflag; 48 break; 49 case 'e': 50 flags |= PS_Aflag; 51 break; 52 case 'f': 53 flags |= PS_fflag; 54 break; 55 default: 56 usage(); 57 } ARGEND; 58 59 if (!(flags & PS_fflag)) 60 printf(" PID TTY TIME CMD\n"); 61 else 62 printf("UID PID PPID C STIME TTY TIME CMD\n"); 63 recurse("/proc", psr); 64 return 0; 65 } 66 67 static void 68 psout(struct procstat *ps) 69 { 70 struct procstatus pstatus; 71 char cmdline[BUFSIZ], *cmd; 72 char buf[BUFSIZ]; 73 char *ttystr, *myttystr; 74 int tty_maj, tty_min; 75 uid_t myeuid; 76 unsigned sutime; 77 time_t start; 78 char stimestr[sizeof("%H:%M")]; 79 struct sysinfo info; 80 struct passwd *pw; 81 struct winsize w; 82 83 /* Ignore session leaders */ 84 if (flags & PS_dflag) 85 if (ps->pid == ps->sid) 86 return; 87 88 devtotty(ps->tty_nr, &tty_maj, &tty_min); 89 ttystr = ttytostr(tty_maj, tty_min); 90 91 /* Only print processes that are associated with 92 * a terminal and they are not session leaders */ 93 if (flags & PS_aflag) { 94 if (ps->pid == ps->sid || ttystr[0] == '?') { 95 free(ttystr); 96 return; 97 } 98 } 99 100 if (parsestatus(ps->pid, &pstatus) < 0) 101 return; 102 103 /* This is the default case, only print processes that have 104 * the same controlling terminal as the invoker and the same 105 * euid as the current user */ 106 if (!(flags & (PS_aflag | PS_Aflag | PS_dflag))) { 107 myttystr = ttyname(0); 108 if (myttystr) { 109 if (strcmp(myttystr + strlen("/dev/"), ttystr)) { 110 free(ttystr); 111 return; 112 } 113 } else { 114 /* The invoker has no controlling terminal - just 115 * go ahead and print the processes anyway */ 116 ttystr[0] = '?'; 117 ttystr[1] = '\0'; 118 } 119 myeuid = geteuid(); 120 if (myeuid != pstatus.euid) { 121 free(ttystr); 122 return; 123 } 124 } 125 126 sutime = (ps->stime + ps->utime) / sysconf(_SC_CLK_TCK); 127 128 ioctl(1, TIOCGWINSZ, &w); 129 if (!(flags & PS_fflag)) { 130 snprintf(buf, sizeof(buf), "%5d %-6s %02u:%02u:%02u %s", ps->pid, ttystr, 131 sutime / 3600, (sutime % 3600) / 60, sutime % 60, 132 ps->comm); 133 if (w.ws_col) 134 printf("%.*s\n", w.ws_col, buf); 135 else 136 printf("%s\n", buf); 137 } else { 138 errno = 0; 139 pw = getpwuid(pstatus.uid); 140 if (!pw) 141 eprintf("getpwuid %d:", pstatus.uid); 142 143 if (sysinfo(&info) < 0) 144 eprintf("sysinfo:"); 145 146 start = time(NULL) - info.uptime; 147 start += (ps->starttime / sysconf(_SC_CLK_TCK)); 148 strftime(stimestr, sizeof(stimestr), 149 "%H:%M", localtime(&start)); 150 151 /* For kthreads/zombies /proc/<pid>/cmdline will be 152 * empty so use ps->comm in that case */ 153 if (parsecmdline(ps->pid, cmdline, sizeof(cmdline)) < 0) 154 cmd = ps->comm; 155 else 156 cmd = cmdline; 157 158 snprintf(buf, sizeof(buf), "%-8s %5d %5d ? %5s %-5s %02u:%02u:%02u %s%s%s", 159 pw->pw_name, ps->pid, 160 ps->ppid, stimestr, ttystr, 161 sutime / 3600, (sutime % 3600) / 60, sutime % 60, 162 (cmd == ps->comm) ? "[" : "", cmd, 163 (cmd == ps->comm) ? "]" : ""); 164 if (w.ws_col) 165 printf("%.*s\n", w.ws_col, buf); 166 else 167 printf("%s\n", buf); 168 } 169 free(ttystr); 170 } 171 172 static void 173 psr(const char *file) 174 { 175 char path[PATH_MAX], *p; 176 struct procstat ps; 177 pid_t pid; 178 179 if (strlcpy(path, file, sizeof(path)) >= sizeof(path)) 180 eprintf("path too long\n"); 181 p = basename(path); 182 if (pidfile(p) == 0) 183 return; 184 pid = estrtol(p, 10); 185 if (parsestat(pid, &ps) < 0) 186 return; 187 psout(&ps); 188 }