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