ps.c - ubase - suckless linux base utils
(HTM) git clone git://git.suckless.org/ubase
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) 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", 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 }