Magellan Linux

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

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