3 |
* Mini ps implementation(s) for busybox |
* Mini ps implementation(s) for busybox |
4 |
* |
* |
5 |
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> |
* Copyright (C) 1999-2004 by Erik Andersen <andersen@codepoet.org> |
6 |
|
* Fix for SELinux Support:(c)2007 Hiroshi Shinji <shiroshi@my.email.ne.jp> |
7 |
|
* (c)2007 Yuichi Nakamura <ynakam@hitachisoft.jp> |
8 |
* |
* |
9 |
* Licensed under the GPL version 2, see the file LICENSE in this tarball. |
* Licensed under the GPL version 2, see the file LICENSE in this tarball. |
10 |
*/ |
*/ |
11 |
|
|
12 |
#include "busybox.h" |
#include "libbb.h" |
13 |
|
|
14 |
|
/* Absolute maximum on output line length */ |
15 |
|
enum { MAX_WIDTH = 2*1024 }; |
16 |
|
|
17 |
#if ENABLE_DESKTOP |
#if ENABLE_DESKTOP |
18 |
|
|
19 |
|
#include <sys/times.h> /* for times() */ |
20 |
|
//#include <sys/sysinfo.h> /* for sysinfo() */ |
21 |
|
#ifndef AT_CLKTCK |
22 |
|
#define AT_CLKTCK 17 |
23 |
|
#endif |
24 |
|
|
25 |
|
|
26 |
|
#if ENABLE_SELINUX |
27 |
|
#define SELINUX_O_PREFIX "label," |
28 |
|
#define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" USE_FEATURE_PS_TIME(",time") ",args") |
29 |
|
#else |
30 |
|
#define DEFAULT_O_STR ("pid,user" USE_FEATURE_PS_TIME(",time") ",args") |
31 |
|
#endif |
32 |
|
|
33 |
|
typedef struct { |
34 |
|
uint16_t width; |
35 |
|
char name[6]; |
36 |
|
const char *header; |
37 |
|
void (*f)(char *buf, int size, const procps_status_t *ps); |
38 |
|
int ps_flags; |
39 |
|
} ps_out_t; |
40 |
|
|
41 |
|
struct globals { |
42 |
|
ps_out_t* out; |
43 |
|
int out_cnt; |
44 |
|
int print_header; |
45 |
|
int need_flags; |
46 |
|
char *buffer; |
47 |
|
unsigned terminal_width; |
48 |
|
#if ENABLE_FEATURE_PS_TIME |
49 |
|
unsigned kernel_HZ; |
50 |
|
unsigned long long seconds_since_boot; |
51 |
|
#endif |
52 |
|
char default_o[sizeof(DEFAULT_O_STR)]; |
53 |
|
}; |
54 |
|
#define G (*(struct globals*)&bb_common_bufsiz1) |
55 |
|
#define out (G.out ) |
56 |
|
#define out_cnt (G.out_cnt ) |
57 |
|
#define print_header (G.print_header ) |
58 |
|
#define need_flags (G.need_flags ) |
59 |
|
#define buffer (G.buffer ) |
60 |
|
#define terminal_width (G.terminal_width ) |
61 |
|
#define kernel_HZ (G.kernel_HZ ) |
62 |
|
#define seconds_since_boot (G.seconds_since_boot) |
63 |
|
#define default_o (G.default_o ) |
64 |
|
|
65 |
|
#if ENABLE_FEATURE_PS_TIME |
66 |
|
/* for ELF executables, notes are pushed before environment and args */ |
67 |
|
static ptrdiff_t find_elf_note(ptrdiff_t findme) |
68 |
|
{ |
69 |
|
ptrdiff_t *ep = (ptrdiff_t *) environ; |
70 |
|
|
71 |
|
while (*ep++); |
72 |
|
while (*ep) { |
73 |
|
if (ep[0] == findme) { |
74 |
|
return ep[1]; |
75 |
|
} |
76 |
|
ep += 2; |
77 |
|
} |
78 |
|
return -1; |
79 |
|
} |
80 |
|
|
81 |
|
#if ENABLE_FEATURE_PS_UNUSUAL_SYSTEMS |
82 |
|
static unsigned get_HZ_by_waiting(void) |
83 |
|
{ |
84 |
|
struct timeval tv1, tv2; |
85 |
|
unsigned t1, t2, r, hz; |
86 |
|
unsigned cnt = cnt; /* for compiler */ |
87 |
|
int diff; |
88 |
|
|
89 |
|
r = 0; |
90 |
|
|
91 |
|
/* Wait for times() to reach new tick */ |
92 |
|
t1 = times(NULL); |
93 |
|
do { |
94 |
|
t2 = times(NULL); |
95 |
|
} while (t2 == t1); |
96 |
|
gettimeofday(&tv2, NULL); |
97 |
|
|
98 |
|
do { |
99 |
|
t1 = t2; |
100 |
|
tv1.tv_usec = tv2.tv_usec; |
101 |
|
|
102 |
|
/* Wait exactly one times() tick */ |
103 |
|
do { |
104 |
|
t2 = times(NULL); |
105 |
|
} while (t2 == t1); |
106 |
|
gettimeofday(&tv2, NULL); |
107 |
|
|
108 |
|
/* Calculate ticks per sec, rounding up to even */ |
109 |
|
diff = tv2.tv_usec - tv1.tv_usec; |
110 |
|
if (diff <= 0) diff += 1000000; |
111 |
|
hz = 1000000u / (unsigned)diff; |
112 |
|
hz = (hz+1) & ~1; |
113 |
|
|
114 |
|
/* Count how many same hz values we saw */ |
115 |
|
if (r != hz) { |
116 |
|
r = hz; |
117 |
|
cnt = 0; |
118 |
|
} |
119 |
|
cnt++; |
120 |
|
} while (cnt < 3); /* exit if saw 3 same values */ |
121 |
|
|
122 |
|
return r; |
123 |
|
} |
124 |
|
#else |
125 |
|
static inline unsigned get_HZ_by_waiting(void) |
126 |
|
{ |
127 |
|
/* Better method? */ |
128 |
|
return 100; |
129 |
|
} |
130 |
|
#endif |
131 |
|
|
132 |
|
static unsigned get_kernel_HZ(void) |
133 |
|
{ |
134 |
|
//char buf[64]; |
135 |
|
struct sysinfo info; |
136 |
|
|
137 |
|
if (kernel_HZ) |
138 |
|
return kernel_HZ; |
139 |
|
|
140 |
|
/* Works for ELF only, Linux 2.4.0+ */ |
141 |
|
kernel_HZ = find_elf_note(AT_CLKTCK); |
142 |
|
if (kernel_HZ == (unsigned)-1) |
143 |
|
kernel_HZ = get_HZ_by_waiting(); |
144 |
|
|
145 |
|
//if (open_read_close("/proc/uptime", buf, sizeof(buf) <= 0) |
146 |
|
// bb_perror_msg_and_die("cannot read %s", "/proc/uptime"); |
147 |
|
//buf[sizeof(buf)-1] = '\0'; |
148 |
|
///sscanf(buf, "%llu", &seconds_since_boot); |
149 |
|
sysinfo(&info); |
150 |
|
seconds_since_boot = info.uptime; |
151 |
|
|
152 |
|
return kernel_HZ; |
153 |
|
} |
154 |
|
#endif |
155 |
|
|
156 |
/* Print value to buf, max size+1 chars (including trailing '\0') */ |
/* Print value to buf, max size+1 chars (including trailing '\0') */ |
157 |
|
|
158 |
void func_user(char *buf, int size, const procps_status_t *ps) |
static void func_user(char *buf, int size, const procps_status_t *ps) |
159 |
{ |
{ |
160 |
|
#if 1 |
161 |
safe_strncpy(buf, get_cached_username(ps->uid), size+1); |
safe_strncpy(buf, get_cached_username(ps->uid), size+1); |
162 |
|
#else |
163 |
|
/* "compatible" version, but it's larger */ |
164 |
|
/* procps 2.18 shows numeric UID if name overflows the field */ |
165 |
|
/* TODO: get_cached_username() returns numeric string if |
166 |
|
* user has no passwd record, we will display it |
167 |
|
* left-justified here; too long usernames are shown |
168 |
|
* as _right-justified_ IDs. Is it worth fixing? */ |
169 |
|
const char *user = get_cached_username(ps->uid); |
170 |
|
if (strlen(user) <= size) |
171 |
|
safe_strncpy(buf, user, size+1); |
172 |
|
else |
173 |
|
sprintf(buf, "%*u", size, (unsigned)ps->uid); |
174 |
|
#endif |
175 |
} |
} |
176 |
|
|
177 |
void func_comm(char *buf, int size, const procps_status_t *ps) |
static void func_comm(char *buf, int size, const procps_status_t *ps) |
178 |
{ |
{ |
179 |
safe_strncpy(buf, ps->comm, size+1); |
safe_strncpy(buf, ps->comm, size+1); |
180 |
} |
} |
181 |
|
|
182 |
void func_args(char *buf, int size, const procps_status_t *ps) |
static void func_args(char *buf, int size, const procps_status_t *ps) |
183 |
{ |
{ |
184 |
buf[0] = '\0'; |
read_cmdline(buf, size, ps->pid, ps->comm); |
|
if (ps->cmd) |
|
|
safe_strncpy(buf, ps->cmd, size+1); |
|
|
else if (size >= 2) |
|
|
snprintf(buf, size+1, "[%.*s]", size-2, ps->comm); |
|
185 |
} |
} |
186 |
|
|
187 |
void func_pid(char *buf, int size, const procps_status_t *ps) |
static void func_pid(char *buf, int size, const procps_status_t *ps) |
188 |
{ |
{ |
189 |
snprintf(buf, size+1, "%*u", size, ps->pid); |
sprintf(buf, "%*u", size, ps->pid); |
190 |
} |
} |
191 |
|
|
192 |
void func_ppid(char *buf, int size, const procps_status_t *ps) |
static void func_ppid(char *buf, int size, const procps_status_t *ps) |
193 |
{ |
{ |
194 |
snprintf(buf, size+1, "%*u", size, ps->ppid); |
sprintf(buf, "%*u", size, ps->ppid); |
195 |
} |
} |
196 |
|
|
197 |
void func_pgid(char *buf, int size, const procps_status_t *ps) |
static void func_pgid(char *buf, int size, const procps_status_t *ps) |
198 |
{ |
{ |
199 |
snprintf(buf, size+1, "%*u", size, ps->pgid); |
sprintf(buf, "%*u", size, ps->pgid); |
200 |
} |
} |
201 |
|
|
202 |
void func_rss(char *buf, int size, const procps_status_t *ps) |
static void put_lu(char *buf, int size, unsigned long u) |
203 |
{ |
{ |
204 |
char buf5[5]; |
char buf4[5]; |
205 |
smart_ulltoa5( ((unsigned long long)ps->rss) << 10, buf5); |
|
206 |
snprintf(buf, size+1, "%.*s", size, buf5); |
/* see http://en.wikipedia.org/wiki/Tera */ |
207 |
|
smart_ulltoa4(u, buf4, " mgtpezy"); |
208 |
|
buf4[4] = '\0'; |
209 |
|
sprintf(buf, "%.*s", size, buf4); |
210 |
} |
} |
211 |
|
|
212 |
/* |
static void func_vsz(char *buf, int size, const procps_status_t *ps) |
|
void func_nice(char *buf, int size, const procps_status_t *ps) |
|
213 |
{ |
{ |
214 |
ps->??? |
put_lu(buf, size, ps->vsz); |
215 |
|
} |
216 |
|
|
217 |
|
static void func_rss(char *buf, int size, const procps_status_t *ps) |
218 |
|
{ |
219 |
|
put_lu(buf, size, ps->rss); |
220 |
} |
} |
221 |
|
|
222 |
void func_etime(char *buf, int size, const procps_status_t *ps) |
static void func_tty(char *buf, int size, const procps_status_t *ps) |
223 |
{ |
{ |
224 |
elapled time [[dd-]hh:]mm:ss |
buf[0] = '?'; |
225 |
|
buf[1] = '\0'; |
226 |
|
if (ps->tty_major) /* tty field of "0" means "no tty" */ |
227 |
|
snprintf(buf, size+1, "%u,%u", ps->tty_major, ps->tty_minor); |
228 |
} |
} |
229 |
|
|
230 |
void func_time(char *buf, int size, const procps_status_t *ps) |
#if ENABLE_FEATURE_PS_TIME |
231 |
|
static void func_etime(char *buf, int size, const procps_status_t *ps) |
232 |
{ |
{ |
233 |
cumulative time [[dd-]hh:]mm:ss |
/* elapsed time [[dd-]hh:]mm:ss; here only mm:ss */ |
234 |
|
unsigned long mm; |
235 |
|
unsigned ss; |
236 |
|
|
237 |
|
mm = ps->start_time / get_kernel_HZ(); |
238 |
|
/* must be after get_kernel_HZ()! */ |
239 |
|
mm = seconds_since_boot - mm; |
240 |
|
ss = mm % 60; |
241 |
|
mm /= 60; |
242 |
|
snprintf(buf, size+1, "%3lu:%02u", mm, ss); |
243 |
} |
} |
244 |
|
|
245 |
void func_pcpu(char *buf, int size, const procps_status_t *ps) |
static void func_time(char *buf, int size, const procps_status_t *ps) |
246 |
{ |
{ |
247 |
|
/* cumulative time [[dd-]hh:]mm:ss; here only mm:ss */ |
248 |
|
unsigned long mm; |
249 |
|
unsigned ss; |
250 |
|
|
251 |
|
mm = (ps->utime + ps->stime) / get_kernel_HZ(); |
252 |
|
ss = mm % 60; |
253 |
|
mm /= 60; |
254 |
|
snprintf(buf, size+1, "%3lu:%02u", mm, ss); |
255 |
} |
} |
256 |
|
#endif |
257 |
|
|
258 |
void func_tty(char *buf, int size, const procps_status_t *ps) |
#if ENABLE_SELINUX |
259 |
|
static void func_label(char *buf, int size, const procps_status_t *ps) |
260 |
{ |
{ |
261 |
|
safe_strncpy(buf, ps->context ? ps->context : "unknown", size+1); |
262 |
} |
} |
263 |
*/ |
#endif |
264 |
|
|
265 |
typedef struct { |
/* |
266 |
char name[8]; |
static void func_nice(char *buf, int size, const procps_status_t *ps) |
267 |
const char *header; |
{ |
268 |
void (*f)(char *buf, int size, const procps_status_t *ps); |
ps->??? |
269 |
int ps_flags; |
} |
270 |
int width; |
|
271 |
} ps_out_t; |
static void func_pcpu(char *buf, int size, const procps_status_t *ps) |
272 |
|
{ |
273 |
|
} |
274 |
|
*/ |
275 |
|
|
276 |
static const ps_out_t out_spec[] = { |
static const ps_out_t out_spec[] = { |
277 |
// Mandated by POSIX: |
// Mandated by POSIX: |
278 |
{ "user" ,"USER" ,func_user ,PSSCAN_UIDGID,8 }, |
{ 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, |
279 |
{ "comm" ,"COMMAND",func_comm ,PSSCAN_COMM ,16 }, |
{ 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM }, |
280 |
{ "args" ,"COMMAND",func_args ,PSSCAN_CMD|PSSCAN_COMM,256 }, |
{ 256 , "args" ,"COMMAND",func_args ,PSSCAN_COMM }, |
281 |
{ "pid" ,"PID" ,func_pid ,PSSCAN_PID ,5 }, |
{ 5 , "pid" ,"PID" ,func_pid ,PSSCAN_PID }, |
282 |
{ "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID ,5 }, |
{ 5 , "ppid" ,"PPID" ,func_ppid ,PSSCAN_PPID }, |
283 |
{ "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID ,5 }, |
{ 5 , "pgid" ,"PGID" ,func_pgid ,PSSCAN_PGID }, |
284 |
// { "etime" ,"ELAPSED",func_etime ,PSSCAN_ ,sizeof("ELAPSED")-1 }, |
#if ENABLE_FEATURE_PS_TIME |
285 |
// { "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID,sizeof("GROUP" )-1 }, |
{ sizeof("ELAPSED")-1, "etime" ,"ELAPSED",func_etime ,PSSCAN_START_TIME }, |
286 |
// { "nice" ,"NI" ,func_nice ,PSSCAN_ ,sizeof("NI" )-1 }, |
#endif |
287 |
// { "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ ,sizeof("%CPU" )-1 }, |
// { sizeof("GROUP" )-1, "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, |
288 |
// { "rgroup","RGROUP" ,func_rgroup,PSSCAN_UIDGID,sizeof("RGROUP" )-1 }, |
// { sizeof("NI" )-1, "nice" ,"NI" ,func_nice ,PSSCAN_ }, |
289 |
// { "ruser" ,"RUSER" ,func_ruser ,PSSCAN_UIDGID,sizeof("RUSER" )-1 }, |
// { sizeof("%CPU" )-1, "pcpu" ,"%CPU" ,func_pcpu ,PSSCAN_ }, |
290 |
// { "time" ,"TIME" ,func_time ,PSSCAN_ ,sizeof("TIME" )-1 }, |
// { sizeof("RGROUP" )-1, "rgroup","RGROUP" ,func_rgroup,PSSCAN_UIDGID }, |
291 |
// { "tty" ,"TT" ,func_tty ,PSSCAN_ ,sizeof("TT" )-1 }, |
// { sizeof("RUSER" )-1, "ruser" ,"RUSER" ,func_ruser ,PSSCAN_UIDGID }, |
292 |
// { "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ ,4 }, |
#if ENABLE_FEATURE_PS_TIME |
293 |
// Not mandated by POSIX: |
{ 6 , "time" ,"TIME" ,func_time ,PSSCAN_STIME | PSSCAN_UTIME }, |
294 |
{ "rss" ,"RSS" ,func_rss ,PSSCAN_RSS ,4 }, |
#endif |
295 |
|
{ 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, |
296 |
|
{ 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ }, |
297 |
|
// Not mandated by POSIX, but useful: |
298 |
|
{ 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS }, |
299 |
|
#if ENABLE_SELINUX |
300 |
|
{ 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, |
301 |
|
#endif |
302 |
}; |
}; |
303 |
|
|
|
#define VEC_SIZE(v) ( sizeof(v) / sizeof((v)[0]) ) |
|
|
|
|
|
static ps_out_t* out; |
|
|
static int out_cnt; |
|
|
static int print_header; |
|
|
static int ps_flags; |
|
|
static char *buffer; |
|
|
static unsigned terminal_width; |
|
|
|
|
|
|
|
304 |
static ps_out_t* new_out_t(void) |
static ps_out_t* new_out_t(void) |
305 |
{ |
{ |
306 |
int i = out_cnt++; |
out = xrealloc_vector(out, 2, out_cnt); |
307 |
out = xrealloc(out, out_cnt * sizeof(*out)); |
return &out[out_cnt++]; |
|
return &out[i]; |
|
308 |
} |
} |
309 |
|
|
310 |
static const ps_out_t* find_out_spec(const char *name) |
static const ps_out_t* find_out_spec(const char *name) |
311 |
{ |
{ |
312 |
int i; |
unsigned i; |
313 |
for (i = 0; i < VEC_SIZE(out_spec); i++) { |
for (i = 0; i < ARRAY_SIZE(out_spec); i++) { |
314 |
if (!strcmp(name, out_spec[i].name)) |
if (!strcmp(name, out_spec[i].name)) |
315 |
return &out_spec[i]; |
return &out_spec[i]; |
316 |
} |
} |
334 |
} |
} |
335 |
break; |
break; |
336 |
} |
} |
337 |
|
// opt points to last spec in comma separated list. |
338 |
|
// This one can have =HEADER part. |
339 |
new = new_out_t(); |
new = new_out_t(); |
340 |
if (equal) |
if (equal) |
341 |
*equal = '\0'; |
*equal = '\0'; |
361 |
int i; |
int i; |
362 |
int width = 0; |
int width = 0; |
363 |
for (i = 0; i < out_cnt; i++) { |
for (i = 0; i < out_cnt; i++) { |
364 |
ps_flags |= out[i].ps_flags; |
need_flags |= out[i].ps_flags; |
365 |
if (out[i].header[0]) { |
if (out[i].header[0]) { |
366 |
print_header = 1; |
print_header = 1; |
367 |
} |
} |
368 |
width += out[i].width + 1; /* "FIELD " */ |
width += out[i].width + 1; /* "FIELD " */ |
369 |
} |
} |
370 |
|
#if ENABLE_SELINUX |
371 |
|
if (!is_selinux_enabled()) |
372 |
|
need_flags &= ~PSSCAN_CONTEXT; |
373 |
|
#endif |
374 |
buffer = xmalloc(width + 1); /* for trailing \0 */ |
buffer = xmalloc(width + 1); /* for trailing \0 */ |
375 |
} |
} |
376 |
|
|
378 |
{ |
{ |
379 |
int i; |
int i; |
380 |
ps_out_t* op; |
ps_out_t* op; |
381 |
char *p = buffer; |
char *p; |
382 |
|
|
383 |
if (!print_header) |
if (!print_header) |
384 |
return; |
return; |
385 |
|
p = buffer; |
386 |
i = 0; |
i = 0; |
387 |
if (out_cnt) { |
if (out_cnt) { |
388 |
while (1) { |
while (1) { |
420 |
printf("%.*s\n", terminal_width, buffer); |
printf("%.*s\n", terminal_width, buffer); |
421 |
} |
} |
422 |
|
|
423 |
/* Cannot be const: parse_o() will choke */ |
int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
424 |
static char default_o[] = "pid,user" /* TODO: ,vsz,stat */ ",args"; |
int ps_main(int argc UNUSED_PARAM, char **argv) |
|
|
|
|
int ps_main(int argc, char **argv) |
|
425 |
{ |
{ |
426 |
procps_status_t *p; |
procps_status_t *p; |
427 |
llist_t* opt_o = NULL; |
llist_t* opt_o = NULL; |
428 |
|
USE_SELINUX(int opt;) |
429 |
|
|
430 |
// POSIX: |
// POSIX: |
431 |
// -a Write information for all processes associated with terminals |
// -a Write information for all processes associated with terminals |
436 |
// -f Generate a full listing |
// -f Generate a full listing |
437 |
// -l Generate a long listing |
// -l Generate a long listing |
438 |
// -o col1,col2,col3=header |
// -o col1,col2,col3=header |
439 |
// Select which columns to distplay |
// Select which columns to display |
440 |
/* We allow (and ignore) most of the above. FIXME */ |
/* We allow (and ignore) most of the above. FIXME */ |
441 |
opt_complementary = "o::"; |
opt_complementary = "o::"; |
442 |
getopt32(argc, argv, "o:aAdefl", &opt_o); |
USE_SELINUX(opt =) getopt32(argv, "Zo:aAdefl", &opt_o); |
443 |
if (opt_o) { |
if (opt_o) { |
|
opt_o = rev_llist(opt_o); |
|
444 |
do { |
do { |
445 |
parse_o(opt_o->data); |
parse_o(llist_pop(&opt_o)); |
|
opt_o = opt_o->link; |
|
446 |
} while (opt_o); |
} while (opt_o); |
447 |
} else |
} else { |
448 |
|
/* Below: parse_o() needs char*, NOT const char*... */ |
449 |
|
#if ENABLE_SELINUX |
450 |
|
if (!(opt & 1) || !is_selinux_enabled()) { |
451 |
|
/* no -Z or no SELinux: do not show LABEL */ |
452 |
|
strcpy(default_o, DEFAULT_O_STR + sizeof(SELINUX_O_PREFIX)-1); |
453 |
|
} else |
454 |
|
#endif |
455 |
|
{ |
456 |
|
strcpy(default_o, DEFAULT_O_STR); |
457 |
|
} |
458 |
parse_o(default_o); |
parse_o(default_o); |
459 |
|
} |
460 |
post_process(); |
post_process(); |
461 |
|
|
462 |
terminal_width = INT_MAX; |
/* Was INT_MAX, but some libc's go belly up with printf("%.*s") |
463 |
|
* and such large widths */ |
464 |
|
terminal_width = MAX_WIDTH; |
465 |
if (isatty(1)) { |
if (isatty(1)) { |
466 |
get_terminal_width_height(1, &terminal_width, NULL); |
get_terminal_width_height(0, &terminal_width, NULL); |
467 |
terminal_width--; |
if (--terminal_width > MAX_WIDTH) |
468 |
|
terminal_width = MAX_WIDTH; |
469 |
} |
} |
470 |
format_header(); |
format_header(); |
471 |
|
|
472 |
p = NULL; |
p = NULL; |
473 |
while ((p = procps_scan(p, ps_flags))) { |
while ((p = procps_scan(p, need_flags))) { |
474 |
format_process(p); |
format_process(p); |
475 |
} |
} |
476 |
|
|
481 |
#else /* !ENABLE_DESKTOP */ |
#else /* !ENABLE_DESKTOP */ |
482 |
|
|
483 |
|
|
484 |
int ps_main(int argc, char **argv) |
int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
485 |
|
int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) |
486 |
{ |
{ |
487 |
procps_status_t *p = NULL; |
procps_status_t *p = NULL; |
488 |
int i, len; |
int len; |
489 |
SKIP_SELINUX(const) int use_selinux = 0; |
SKIP_SELINUX(const) int use_selinux = 0; |
490 |
USE_SELINUX(security_context_t sid = NULL;) |
USE_SELINUX(int i;) |
491 |
#if !ENABLE_FEATURE_PS_WIDE |
#if !ENABLE_FEATURE_PS_WIDE |
492 |
enum { terminal_width = 79 }; |
enum { terminal_width = 79 }; |
493 |
#else |
#else |
494 |
int terminal_width; |
unsigned terminal_width; |
495 |
int w_count = 0; |
int w_count = 0; |
496 |
#endif |
#endif |
497 |
|
|
498 |
#if ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX |
#if ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX |
499 |
#if ENABLE_FEATURE_PS_WIDE |
#if ENABLE_FEATURE_PS_WIDE |
500 |
opt_complementary = "-:ww"; |
opt_complementary = "-:ww"; |
501 |
USE_SELINUX(i =) getopt32(argc, argv, USE_SELINUX("c") "w", &w_count); |
USE_SELINUX(i =) getopt32(argv, USE_SELINUX("Z") "w", &w_count); |
502 |
/* if w is given once, GNU ps sets the width to 132, |
/* if w is given once, GNU ps sets the width to 132, |
503 |
* if w is given more than once, it is "unlimited" |
* if w is given more than once, it is "unlimited" |
504 |
*/ |
*/ |
505 |
if (w_count) { |
if (w_count) { |
506 |
terminal_width = (w_count==1) ? 132 : INT_MAX; |
terminal_width = (w_count==1) ? 132 : MAX_WIDTH; |
507 |
} else { |
} else { |
508 |
get_terminal_width_height(1, &terminal_width, NULL); |
get_terminal_width_height(0, &terminal_width, NULL); |
509 |
/* Go one less... */ |
/* Go one less... */ |
510 |
terminal_width--; |
if (--terminal_width > MAX_WIDTH) |
511 |
|
terminal_width = MAX_WIDTH; |
512 |
} |
} |
513 |
#else /* only ENABLE_SELINUX */ |
#else /* only ENABLE_SELINUX */ |
514 |
i = getopt32(argc, argv, "c"); |
i = getopt32(argv, "Z"); |
515 |
#endif |
#endif |
516 |
#if ENABLE_SELINUX |
#if ENABLE_SELINUX |
517 |
if ((i & 1) && is_selinux_enabled()) |
if ((i & 1) && is_selinux_enabled()) |
518 |
use_selinux = 1; |
use_selinux = PSSCAN_CONTEXT; |
519 |
#endif |
#endif |
520 |
#endif /* ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX */ |
#endif /* ENABLE_FEATURE_PS_WIDE || ENABLE_SELINUX */ |
521 |
|
|
522 |
if (use_selinux) |
if (use_selinux) |
523 |
puts(" PID Context Stat Command"); |
puts(" PID CONTEXT STAT COMMAND"); |
524 |
else |
else |
525 |
puts(" PID Uid VmSize Stat Command"); |
puts(" PID USER VSZ STAT COMMAND"); |
526 |
|
|
527 |
while ((p = procps_scan(p, 0 |
while ((p = procps_scan(p, 0 |
528 |
| PSSCAN_PID |
| PSSCAN_PID |
529 |
| PSSCAN_UIDGID |
| PSSCAN_UIDGID |
530 |
| PSSCAN_STATE |
| PSSCAN_STATE |
531 |
| PSSCAN_RSS |
| PSSCAN_VSZ |
532 |
| PSSCAN_CMD |
| PSSCAN_COMM |
533 |
|
| use_selinux |
534 |
))) { |
))) { |
|
char *namecmd = p->cmd; |
|
535 |
#if ENABLE_SELINUX |
#if ENABLE_SELINUX |
536 |
if (use_selinux) { |
if (use_selinux) { |
537 |
char sbuf[128]; |
len = printf("%5u %-32.32s %s ", |
538 |
len = sizeof(sbuf); |
p->pid, |
539 |
|
p->context ? p->context : "unknown", |
540 |
if (is_selinux_enabled()) { |
p->state); |
|
if (getpidcon(p->pid, &sid) < 0) |
|
|
sid = NULL; |
|
|
} |
|
|
|
|
|
if (sid) { |
|
|
/* I assume sid initialized with NULL */ |
|
|
len = strlen(sid) + 1; |
|
|
safe_strncpy(sbuf, sid, len); |
|
|
freecon(sid); |
|
|
sid = NULL; |
|
|
} else { |
|
|
safe_strncpy(sbuf, "unknown", 7); |
|
|
} |
|
|
len = printf("%5u %-32s %s ", p->pid, sbuf, p->state); |
|
541 |
} else |
} else |
542 |
#endif |
#endif |
543 |
{ |
{ |
544 |
const char *user = get_cached_username(p->uid); |
const char *user = get_cached_username(p->uid); |
545 |
if (p->rss == 0) |
//if (p->vsz == 0) |
546 |
len = printf("%5u %-8s %s ", |
// len = printf("%5u %-8.8s %s ", |
547 |
p->pid, user, p->state); |
// p->pid, user, p->state); |
548 |
else |
//else |
549 |
len = printf("%5u %-8s %6ld %s ", |
{ |
550 |
p->pid, user, p->rss, p->state); |
char buf6[6]; |
551 |
|
smart_ulltoa5(p->vsz, buf6, " mgtpezy"); |
552 |
|
buf6[5] = '\0'; |
553 |
|
len = printf("%5u %-8.8s %s %s ", |
554 |
|
p->pid, user, buf6, p->state); |
555 |
|
} |
556 |
} |
} |
557 |
|
|
558 |
i = terminal_width-len; |
{ |
559 |
|
int sz = terminal_width - len; |
560 |
if (namecmd && namecmd[0]) { |
char buf[sz + 1]; |
561 |
if (i < 0) |
read_cmdline(buf, sz, p->pid, p->comm); |
562 |
i = 0; |
puts(buf); |
|
if (strlen(namecmd) > (size_t)i) |
|
|
namecmd[i] = 0; |
|
|
puts(namecmd); |
|
|
} else { |
|
|
namecmd = p->comm; |
|
|
if (i < 2) |
|
|
i = 2; |
|
|
if (strlen(namecmd) > ((size_t)i-2)) |
|
|
namecmd[i-2] = 0; |
|
|
printf("[%s]\n", namecmd); |
|
563 |
} |
} |
564 |
} |
} |
565 |
if (ENABLE_FEATURE_CLEAN_UP) |
if (ENABLE_FEATURE_CLEAN_UP) |