Annotation of /trunk/mkinitrd-magellan/klibc/usr/utils/minips.c
Parent Directory | Revision Log
Revision 532 -
(hide 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 | niro | 532 | /* |
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 | } |