Contents of /trunk/mkinitrd-magellan/klibc/usr/utils/minips.c
Parent Directory | Revision Log
Revision 532 -
(show annotations)
(download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 12638 byte(s)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 12638 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd
1 | /* |
2 | * Copyright 1998 by Albert Cahalan; all rights reserved. |
3 | * This file may be used subject to the terms and conditions of the |
4 | * GNU Library General Public License Version 2, or any later version |
5 | * at your option, as published by the Free Software Foundation. |
6 | * This program is distributed in the hope that it will be useful, |
7 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
8 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
9 | * GNU Library General Public License for more details. |
10 | */ |
11 | |
12 | /* This is a minimal /bin/ps, designed to be smaller than the old ps |
13 | * while still supporting some of the more important features of the |
14 | * new ps. (for total size, note that this ps does not need libproc) |
15 | * It is suitable for Linux-on-a-floppy systems only. |
16 | * |
17 | * Maintainers: do not compile or install for normal systems. |
18 | * Anyone needing this will want to tweak their compiler anyway. |
19 | */ |
20 | |
21 | #include <stdio.h> |
22 | #include <stdlib.h> |
23 | #include <string.h> |
24 | #include <sys/ioctl.h> |
25 | #include <sys/types.h> |
26 | #include <unistd.h> |
27 | #include <sys/stat.h> |
28 | #include <fcntl.h> |
29 | #include <dirent.h> |
30 | #include <unistd.h> |
31 | |
32 | #include <asm/param.h> /* HZ */ |
33 | |
34 | static int P_euid; |
35 | static int P_pid; |
36 | static char P_cmd[16]; |
37 | static char P_state; |
38 | static int P_ppid, P_pgrp, P_session, P_tty, P_tpgid; |
39 | static unsigned long P_flags, P_min_flt, P_cmin_flt, P_maj_flt, P_cmaj_flt, |
40 | P_utime, P_stime; |
41 | static long P_cutime, P_cstime, P_priority, P_nice, P_timeout, P_it_real_value; |
42 | static unsigned long P_start_time, P_vsize; |
43 | static long P_rss; |
44 | static unsigned long P_rss_rlim, P_start_code, P_end_code, P_start_stack, |
45 | P_kstk_esp, P_kstk_eip; |
46 | static unsigned P_signal, P_blocked, P_sigignore, P_sigcatch; |
47 | static unsigned long P_wchan, P_nswap, P_cnswap; |
48 | |
49 | #if 0 |
50 | static int screen_cols = 80; |
51 | static int w_count; |
52 | #endif |
53 | |
54 | static int want_one_pid; |
55 | static const char *want_one_command; |
56 | static int select_notty; |
57 | static int select_all; |
58 | |
59 | static int ps_format; |
60 | static int old_h_option; |
61 | |
62 | /* we only pretend to support this */ |
63 | static int show_args; /* implicit with -f and all BSD options */ |
64 | static int bsd_c_option; /* this option overrides the above */ |
65 | |
66 | static int ps_argc; /* global argc */ |
67 | static char **ps_argv; /* global argv */ |
68 | static int thisarg; /* index into ps_argv */ |
69 | static char *flagptr; /* current location in ps_argv[thisarg] */ |
70 | |
71 | #ifndef HZ |
72 | #warning HZ not defined, assuming it is 100 |
73 | #define HZ 100 |
74 | #endif |
75 | |
76 | int page_shift; /* Page size as shift count */ |
77 | |
78 | static void usage(void) |
79 | { |
80 | fprintf(stderr, |
81 | "-C select by command name (minimal ps only accepts one)\n" |
82 | "-p select by process ID (minimal ps only accepts one)\n" |
83 | "-e all processes (same as ax)\n" |
84 | "a all processes w/ tty, including other users\n" |
85 | "x processes w/o controlling ttys\n" |
86 | "-f full format\n" |
87 | "-j,j job control format\n" |
88 | "v virtual memory format\n" |
89 | "-l,l long format\n" |
90 | "u user-oriented format\n" |
91 | "-o user-defined format (limited support, only \"ps -o pid=\")\n" |
92 | "h no header\n" |
93 | /* |
94 | "-A all processes (same as ax)\n" |
95 | "c true command name\n" |
96 | "-w,w wide output\n" |
97 | */ |
98 | ); |
99 | exit(1); |
100 | } |
101 | |
102 | /* |
103 | * Return the next argument, or call the usage function. |
104 | * This handles both: -oFOO -o FOO |
105 | */ |
106 | static const char *get_opt_arg(void) |
107 | { |
108 | const char *ret; |
109 | ret = flagptr + 1; /* assume argument is part of ps_argv[thisarg] */ |
110 | if (*ret) |
111 | return ret; |
112 | if (++thisarg >= ps_argc) |
113 | usage(); /* there is nothing left */ |
114 | /* argument is the new ps_argv[thisarg] */ |
115 | ret = ps_argv[thisarg]; |
116 | if (!ret || !*ret) |
117 | usage(); |
118 | return ret; |
119 | } |
120 | |
121 | /* return the PID, or 0 if nothing good */ |
122 | static void parse_pid(const char *str) |
123 | { |
124 | char *endp; |
125 | int num; |
126 | if (!str) |
127 | goto bad; |
128 | num = strtol(str, &endp, 0); |
129 | if (*endp != '\0') |
130 | goto bad; |
131 | if (num < 1) |
132 | goto bad; |
133 | if (want_one_pid) |
134 | goto bad; |
135 | want_one_pid = num; |
136 | return; |
137 | bad: |
138 | usage(); |
139 | } |
140 | |
141 | /***************** parse SysV options, including Unix98 *****************/ |
142 | static void parse_sysv_option(void) |
143 | { |
144 | do { |
145 | switch (*flagptr) { |
146 | /**** selection ****/ |
147 | case 'C': /* end */ |
148 | if (want_one_command) |
149 | usage(); |
150 | want_one_command = get_opt_arg(); |
151 | return; /* can't have any more options */ |
152 | case 'p': /* end */ |
153 | parse_pid(get_opt_arg()); |
154 | return; /* can't have any more options */ |
155 | case 'A': |
156 | case 'e': |
157 | select_all++; |
158 | select_notty++; |
159 | case 'w': /* here for now, since the real one is not used */ |
160 | break; |
161 | /**** output format ****/ |
162 | case 'f': |
163 | show_args = 1; |
164 | /* FALL THROUGH */ |
165 | case 'j': |
166 | case 'l': |
167 | if (ps_format) |
168 | usage(); |
169 | ps_format = *flagptr; |
170 | break; |
171 | case 'o': /* end */ |
172 | /* We only support a limited form: "ps -o pid=" (yes, just "pid=") */ |
173 | if (strcmp(get_opt_arg(), "pid=")) |
174 | usage(); |
175 | if (ps_format) |
176 | usage(); |
177 | ps_format = 'o'; |
178 | old_h_option++; |
179 | return; /* can't have any more options */ |
180 | /**** other stuff ****/ |
181 | #if 0 |
182 | case 'w': |
183 | w_count++; |
184 | break; |
185 | #endif |
186 | default: |
187 | usage(); |
188 | } /* switch */ |
189 | } while (*++flagptr); |
190 | } |
191 | |
192 | /************************* parse BSD options **********************/ |
193 | static void parse_bsd_option(void) |
194 | { |
195 | do { |
196 | switch (*flagptr) { |
197 | /**** selection ****/ |
198 | case 'a': |
199 | select_all++; |
200 | break; |
201 | case 'x': |
202 | select_notty++; |
203 | break; |
204 | case 'p': /* end */ |
205 | parse_pid(get_opt_arg()); |
206 | return; /* can't have any more options */ |
207 | /**** output format ****/ |
208 | case 'j': |
209 | case 'l': |
210 | case 'u': |
211 | case 'v': |
212 | if (ps_format) |
213 | usage(); |
214 | ps_format = 0x80 | *flagptr; /* use 0x80 to tell BSD from SysV */ |
215 | break; |
216 | /**** other stuff ****/ |
217 | case 'c': |
218 | bsd_c_option++; |
219 | #if 0 |
220 | break; |
221 | #endif |
222 | case 'w': |
223 | #if 0 |
224 | w_count++; |
225 | #endif |
226 | break; |
227 | case 'h': |
228 | old_h_option++; |
229 | break; |
230 | default: |
231 | usage(); |
232 | } /* switch */ |
233 | } while (*++flagptr); |
234 | } |
235 | |
236 | #if 0 |
237 | /* not used yet */ |
238 | static void choose_dimensions(void) |
239 | { |
240 | struct winsize ws; |
241 | char *columns; |
242 | /* screen_cols is 80 by default */ |
243 | if (ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col > 30) |
244 | screen_cols = ws.ws_col; |
245 | columns = getenv("COLUMNS"); |
246 | if (columns && *columns) { |
247 | long t; |
248 | char *endptr; |
249 | t = strtol(columns, &endptr, 0); |
250 | if (!*endptr && (t > 30) && (t < (long)999999999)) |
251 | screen_cols = (int)t; |
252 | } |
253 | if (w_count && (screen_cols < 132)) |
254 | screen_cols = 132; |
255 | if (w_count > 1) |
256 | screen_cols = 999999999; |
257 | } |
258 | #endif |
259 | |
260 | static void arg_parse(int argc, char *argv[]) |
261 | { |
262 | int sel = 0; /* to verify option sanity */ |
263 | ps_argc = argc; |
264 | ps_argv = argv; |
265 | thisarg = 0; |
266 | /**** iterate over the args ****/ |
267 | while (++thisarg < ps_argc) { |
268 | flagptr = ps_argv[thisarg]; |
269 | switch (*flagptr) { |
270 | case '0'...'9': |
271 | show_args = 1; |
272 | parse_pid(flagptr); |
273 | break; |
274 | case '-': |
275 | flagptr++; |
276 | parse_sysv_option(); |
277 | break; |
278 | default: |
279 | show_args = 1; |
280 | parse_bsd_option(); |
281 | break; |
282 | } |
283 | } |
284 | /**** sanity check and clean-up ****/ |
285 | if (want_one_pid) |
286 | sel++; |
287 | if (want_one_command) |
288 | sel++; |
289 | if (select_notty || select_all) |
290 | sel++; |
291 | if (sel > 1 || select_notty > 1 || select_all > 1 || bsd_c_option > 1 |
292 | || old_h_option > 1) |
293 | usage(); |
294 | if (bsd_c_option) |
295 | show_args = 0; |
296 | } |
297 | |
298 | /* return 1 if it works, or 0 for failure */ |
299 | static int stat2proc(int pid) |
300 | { |
301 | char buf[800]; /* about 40 fields, 64-bit decimal is about 20 chars */ |
302 | int num; |
303 | int fd; |
304 | char *tmp; |
305 | struct stat sb; /* stat() used to get EUID */ |
306 | snprintf(buf, 32, "/proc/%d/stat", pid); |
307 | if ((fd = open(buf, O_RDONLY, 0)) == -1) |
308 | return 0; |
309 | num = read(fd, buf, sizeof buf - 1); |
310 | fstat(fd, &sb); |
311 | P_euid = sb.st_uid; |
312 | close(fd); |
313 | if (num < 80) |
314 | return 0; |
315 | buf[num] = '\0'; |
316 | tmp = strrchr(buf, ')'); /* split into "PID (cmd" and "<rest>" */ |
317 | *tmp = '\0'; /* replace trailing ')' with NUL */ |
318 | /* parse these two strings separately, skipping the leading "(". */ |
319 | memset(P_cmd, 0, sizeof P_cmd); /* clear */ |
320 | sscanf(buf, "%d (%15c", &P_pid, P_cmd); /* comm[16] in kernel */ |
321 | num = sscanf(tmp + 2, /* skip space after ')' too */ |
322 | "%c " "%d %d %d %d %d " "%lu %lu %lu %lu %lu %lu %lu " "%ld %ld %ld %ld %ld %ld " "%lu %lu " "%ld " "%lu %lu %lu %lu %lu %lu " "%u %u %u %u " /* no use for RT signals */ |
323 | "%lu %lu %lu", |
324 | &P_state, |
325 | &P_ppid, &P_pgrp, &P_session, &P_tty, &P_tpgid, |
326 | &P_flags, &P_min_flt, &P_cmin_flt, &P_maj_flt, &P_cmaj_flt, |
327 | &P_utime, &P_stime, &P_cutime, &P_cstime, &P_priority, |
328 | &P_nice, &P_timeout, &P_it_real_value, &P_start_time, |
329 | &P_vsize, &P_rss, &P_rss_rlim, &P_start_code, &P_end_code, |
330 | &P_start_stack, &P_kstk_esp, &P_kstk_eip, &P_signal, |
331 | &P_blocked, &P_sigignore, &P_sigcatch, &P_wchan, &P_nswap, |
332 | &P_cnswap); |
333 | /* fprintf(stderr, "stat2proc converted %d fields.\n",num); */ |
334 | P_vsize /= 1024; |
335 | P_rss <<= page_shift - 10; |
336 | if (num < 30) |
337 | return 0; |
338 | if (P_pid != pid) |
339 | return 0; |
340 | return 1; |
341 | } |
342 | |
343 | static const char *do_time(unsigned long t) |
344 | { |
345 | int hh, mm, ss; |
346 | static char buf[32]; |
347 | int cnt = 0; |
348 | t /= HZ; |
349 | ss = t % 60; |
350 | t /= 60; |
351 | mm = t % 60; |
352 | t /= 60; |
353 | hh = t % 24; |
354 | t /= 24; |
355 | if (t) |
356 | cnt = snprintf(buf, sizeof buf, "%d-", (int)t); |
357 | snprintf(cnt + buf, sizeof(buf) - cnt, "%02d:%02d:%02d", hh, mm, ss); |
358 | return buf; |
359 | } |
360 | |
361 | static void print_proc(void) |
362 | { |
363 | char tty[16]; |
364 | snprintf(tty, sizeof tty, "%3d,%-3d", (P_tty >> 8) & 0xff, |
365 | P_tty & 0xff); |
366 | switch (ps_format) { |
367 | case 0: |
368 | printf("%5d %s %s", P_pid, tty, do_time(P_utime + P_stime)); |
369 | break; |
370 | case 'o': |
371 | printf("%d\n", P_pid); |
372 | return; /* don't want the command */ |
373 | case 'l': |
374 | printf("%03x %c %5d %5d %5d - %3d %3d - " |
375 | "%5ld %06x %s %s", |
376 | (unsigned)P_flags & 0x777, P_state, P_euid, P_pid, |
377 | P_ppid, (int)P_priority, (int)P_nice, |
378 | P_vsize >> (page_shift - 10), |
379 | (unsigned)(P_wchan & 0xffffff), tty, |
380 | do_time(P_utime + P_stime) |
381 | ); |
382 | break; |
383 | case 'f': |
384 | printf("%5d %5d %5d - - %s %s", |
385 | P_euid, P_pid, P_ppid, tty, do_time(P_utime + P_stime) |
386 | ); |
387 | break; |
388 | case 'j': |
389 | printf("%5d %5d %5d %s %s", |
390 | P_pid, P_pgrp, P_session, tty, do_time(P_utime + P_stime) |
391 | ); |
392 | break; |
393 | case 'u' | 0x80: |
394 | printf("%5d %5d - - %5ld %5ld %s %c - %s", |
395 | P_euid, P_pid, P_vsize, P_rss, tty, P_state, |
396 | do_time(P_utime + P_stime) |
397 | ); |
398 | break; |
399 | case 'v' | 0x80: |
400 | printf("%5d %s %c %s %6d - - %5d -", |
401 | P_pid, tty, P_state, do_time(P_utime + P_stime), |
402 | (int)P_maj_flt, (int)P_rss); |
403 | break; |
404 | case 'j' | 0x80: |
405 | printf("%5d %5d %5d %5d %s %5d %c %5d %s", |
406 | P_ppid, P_pid, P_pgrp, P_session, tty, P_tpgid, P_state, |
407 | P_euid, do_time(P_utime + P_stime) |
408 | ); |
409 | break; |
410 | case 'l' | 0x80: |
411 | printf("%03x %5d %5d %5d %3d %3d " |
412 | "%5ld %4ld %06x %c %s %s", |
413 | (unsigned)P_flags & 0x777, P_euid, P_pid, P_ppid, |
414 | (int)P_priority, (int)P_nice, P_vsize, P_rss, |
415 | (unsigned)(P_wchan & 0xffffff), P_state, tty, |
416 | do_time(P_utime + P_stime) |
417 | ); |
418 | break; |
419 | default: |
420 | break; |
421 | } |
422 | if (show_args) |
423 | printf(" [%s]\n", P_cmd); |
424 | else |
425 | printf(" %s\n", P_cmd); |
426 | } |
427 | |
428 | int main(int argc, char *argv[]) |
429 | { |
430 | arg_parse(argc, argv); |
431 | |
432 | page_shift = __getpageshift(); |
433 | |
434 | #if 0 |
435 | choose_dimensions(); |
436 | #endif |
437 | if (!old_h_option) { |
438 | const char *head; |
439 | switch (ps_format) { |
440 | default: /* can't happen */ |
441 | case 0: |
442 | head = " PID TTY TIME CMD"; |
443 | break; |
444 | case 'l': |
445 | head = |
446 | " F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD"; |
447 | break; |
448 | case 'f': |
449 | head = |
450 | " UID PID PPID C STIME TTY TIME CMD"; |
451 | break; |
452 | case 'j': |
453 | head = " PID PGID SID TTY TIME CMD"; |
454 | break; |
455 | case 'u' | 0x80: |
456 | head = |
457 | " UID PID %CPU %MEM VSZ RSS TTY S START TIME COMMAND"; |
458 | break; |
459 | case 'v' | 0x80: |
460 | head = |
461 | " PID TTY S TIME MAJFL TRS DRS RSS %MEM COMMAND"; |
462 | break; |
463 | case 'j' | 0x80: |
464 | head = |
465 | " PPID PID PGID SID TTY TPGID S UID TIME COMMAND"; |
466 | break; |
467 | case 'l' | 0x80: |
468 | head = |
469 | " F UID PID PPID PRI NI VSZ RSS WCHAN S TTY TIME COMMAND"; |
470 | break; |
471 | } |
472 | printf("%s\n", head); |
473 | } |
474 | if (want_one_pid) { |
475 | if (stat2proc(want_one_pid)) |
476 | print_proc(); |
477 | else |
478 | exit(1); |
479 | } else { |
480 | struct dirent *ent; /* dirent handle */ |
481 | DIR *dir; |
482 | int ouruid; |
483 | int found_a_proc; |
484 | found_a_proc = 0; |
485 | ouruid = getuid(); |
486 | dir = opendir("/proc"); |
487 | if (!dir) |
488 | exit(1); |
489 | while ((ent = readdir(dir))) { |
490 | if (*ent->d_name < '0' || *ent->d_name > '9') |
491 | continue; |
492 | if (!stat2proc(atoi(ent->d_name))) |
493 | continue; |
494 | if (want_one_command) { |
495 | if (strcmp(want_one_command, P_cmd)) |
496 | continue; |
497 | } else { |
498 | if (!select_notty && P_tty == -1) |
499 | continue; |
500 | if (!select_all && P_euid != ouruid) |
501 | continue; |
502 | } |
503 | found_a_proc++; |
504 | print_proc(); |
505 | } |
506 | closedir(dir); |
507 | exit(!found_a_proc); |
508 | } |
509 | return 0; |
510 | } |