ps.c - ubase - suckless linux base utils | |
git clone git://git.suckless.org/ubase | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
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… | |
87 sutime / 3600, (sutime % 3600) / 60, sutime % 6… | |
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 … | |
115 pw->pw_name, ps->pid, | |
116 ps->ppid, stimestr, ttystr, | |
117 sutime / 3600, (sutime % 3600) / 60, sutime % 6… | |
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 … | |
178 recurse("/proc", psr); | |
179 return 0; | |
180 } |