Magellan Linux

Contents of /trunk/mkinitrd-magellan/klibc/usr/utils/minips.c

Parent Directory Parent Directory | Revision Log 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)
-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 }