]>
git.ipfire.org Git - thirdparty/systemd.git/blob - klibc/klibc/tests/minips.c
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.
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.
17 * Maintainers: do not compile or install for normal systems.
18 * Anyone needing this will want to tweak their compiler anyway.
24 #include <sys/ioctl.h>
25 #include <sys/types.h>
31 #include <asm/param.h> /* HZ */
32 #include <asm/page.h> /* PAGE_SIZE */
36 static char P_cmd
[16];
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
, P_utime
, P_stime
;
40 static long P_cutime
, P_cstime
, P_priority
, P_nice
, P_timeout
, P_it_real_value
;
41 static unsigned long P_start_time
, P_vsize
;
43 static unsigned long P_rss_rlim
, P_start_code
, P_end_code
, P_start_stack
, P_kstk_esp
, P_kstk_eip
;
44 static unsigned P_signal
, P_blocked
, P_sigignore
, P_sigcatch
;
45 static unsigned long P_wchan
, P_nswap
, P_cnswap
;
49 static int screen_cols
= 80;
53 static int want_one_pid
;
54 static const char *want_one_command
;
55 static int select_notty
;
56 static int select_all
;
59 static int old_h_option
;
61 /* we only pretend to support this */
62 static int show_args
; /* implicit with -f and all BSD options */
63 static int bsd_c_option
; /* this option overrides the above */
65 static int ps_argc
; /* global argc */
66 static char **ps_argv
; /* global argv */
67 static int thisarg
; /* index into ps_argv */
68 static char *flagptr
; /* current location in ps_argv[thisarg] */
72 #warning PAGE_SIZE not defined, assuming it is 4096
73 #define PAGE_SIZE 4096
77 #warning HZ not defined, assuming it is 100
83 static void usage(void){
85 "-C select by command name (minimal ps only accepts one)\n"
86 "-p select by process ID (minimal ps only accepts one)\n"
87 "-e all processes (same as ax)\n"
88 "a all processes w/ tty, including other users\n"
89 "x processes w/o controlling ttys\n"
91 "-j,j job control format\n"
92 "v virtual memory format\n"
94 "u user-oriented format\n"
95 "-o user-defined format (limited support, only \"ps -o pid=\")\n"
98 "-A all processes (same as ax)\n"
99 "c true command name\n"
107 * Return the next argument, or call the usage function.
108 * This handles both: -oFOO -o FOO
110 static const char *get_opt_arg(void){
112 ret
= flagptr
+1; /* assume argument is part of ps_argv[thisarg] */
114 if(++thisarg
>= ps_argc
) usage(); /* there is nothing left */
115 /* argument is the new ps_argv[thisarg] */
116 ret
= ps_argv
[thisarg
];
117 if(!ret
|| !*ret
) usage();
122 /* return the PID, or 0 if nothing good */
123 static void parse_pid(const char *str
){
127 num
= strtol(str
, &endp
, 0);
128 if(*endp
!= '\0') goto bad
;
130 if(want_one_pid
) goto bad
;
137 /***************** parse SysV options, including Unix98 *****************/
138 static void parse_sysv_option(void){
141 /**** selection ****/
143 if(want_one_command
) usage();
144 want_one_command
= get_opt_arg();
145 return; /* can't have any more options */
147 parse_pid(get_opt_arg());
148 return; /* can't have any more options */
153 case 'w': /* here for now, since the real one is not used */
155 /**** output format ****/
161 if(ps_format
) usage();
162 ps_format
= *flagptr
;
165 /* We only support a limited form: "ps -o pid=" (yes, just "pid=") */
166 if(strcmp(get_opt_arg(),"pid=")) usage();
167 if(ps_format
) usage();
170 return; /* can't have any more options */
171 /**** other stuff ****/
183 /************************* parse BSD options **********************/
184 static void parse_bsd_option(void){
187 /**** selection ****/
195 parse_pid(get_opt_arg());
196 return; /* can't have any more options */
197 /**** output format ****/
202 if(ps_format
) usage();
203 ps_format
= 0x80 | *flagptr
; /* use 0x80 to tell BSD from SysV */
205 /**** other stuff ****/
227 static void choose_dimensions(void){
230 /* screen_cols is 80 by default */
231 if(ioctl(1, TIOCGWINSZ
, &ws
) != -1 && ws
.ws_col
>30) screen_cols
= ws
.ws_col
;
232 columns
= getenv("COLUMNS");
233 if(columns
&& *columns
){
236 t
= strtol(columns
, &endptr
, 0);
237 if(!*endptr
&& (t
>30) && (t
<(long)999999999)) screen_cols
= (int)t
;
239 if(w_count
&& (screen_cols
<132)) screen_cols
=132;
240 if(w_count
>1) screen_cols
=999999999;
244 static void arg_parse(int argc
, char *argv
[]){
245 int sel
= 0; /* to verify option sanity */
249 /**** iterate over the args ****/
250 while(++thisarg
< ps_argc
){
251 flagptr
= ps_argv
[thisarg
];
267 /**** sanity check and clean-up ****/
268 if(want_one_pid
) sel
++;
269 if(want_one_command
) sel
++;
270 if(select_notty
|| select_all
) sel
++;
271 if(sel
>1 || select_notty
>1 || select_all
>1 || bsd_c_option
>1 || old_h_option
>1) usage();
272 if(bsd_c_option
) show_args
= 0;
275 /* return 1 if it works, or 0 for failure */
276 static int stat2proc(int pid
) {
277 char buf
[800]; /* about 40 fields, 64-bit decimal is about 20 chars */
281 struct stat sb
; /* stat() used to get EUID */
282 snprintf(buf
, 32, "/proc/%d/stat", pid
);
283 if ( (fd
= open(buf
, O_RDONLY
, 0) ) == -1 ) return 0;
284 num
= read(fd
, buf
, sizeof buf
- 1);
290 tmp
= strrchr(buf
, ')'); /* split into "PID (cmd" and "<rest>" */
291 *tmp
= '\0'; /* replace trailing ')' with NUL */
292 /* parse these two strings separately, skipping the leading "(". */
293 memset(P_cmd
, 0, sizeof P_cmd
); /* clear */
294 sscanf(buf
, "%d (%15c", &P_pid
, P_cmd
); /* comm[16] in kernel */
295 num
= sscanf(tmp
+ 2, /* skip space after ')' too */
298 "%lu %lu %lu %lu %lu %lu %lu "
299 "%ld %ld %ld %ld %ld %ld "
302 "%lu %lu %lu %lu %lu %lu "
303 "%u %u %u %u " /* no use for RT signals */
306 &P_ppid
, &P_pgrp
, &P_session
, &P_tty
, &P_tpgid
,
307 &P_flags
, &P_min_flt
, &P_cmin_flt
, &P_maj_flt
, &P_cmaj_flt
, &P_utime
, &P_stime
,
308 &P_cutime
, &P_cstime
, &P_priority
, &P_nice
, &P_timeout
, &P_it_real_value
,
309 &P_start_time
, &P_vsize
,
311 &P_rss_rlim
, &P_start_code
, &P_end_code
, &P_start_stack
, &P_kstk_esp
, &P_kstk_eip
,
312 &P_signal
, &P_blocked
, &P_sigignore
, &P_sigcatch
,
313 &P_wchan
, &P_nswap
, &P_cnswap
315 /* fprintf(stderr, "stat2proc converted %d fields.\n",num); */
317 P_rss
*= (PAGE_SIZE
/1024);
318 if(num
< 30) return 0;
319 if(P_pid
!= pid
) return 0;
323 static const char *do_time(unsigned long t
){
334 if(t
) cnt
= snprintf(buf
, sizeof buf
, "%d-", (int)t
);
335 snprintf(cnt
+ buf
, sizeof(buf
)-cnt
, "%02d:%02d:%02d", hh
, mm
, ss
);
339 static void print_proc(void){
341 snprintf(tty
, sizeof tty
, "%3d,%-3d", (P_tty
>>8)&0xff, P_tty
&0xff);
344 printf("%5d %s %s", P_pid
, tty
, do_time(P_utime
+P_stime
));
347 printf("%d\n", P_pid
);
348 return; /* don't want the command */
351 "%03x %c %5d %5d %5d - %3d %3d - "
353 (unsigned)P_flags
&0x777, P_state
, P_euid
, P_pid
, P_ppid
,
354 (int)P_priority
, (int)P_nice
, P_vsize
/(PAGE_SIZE
/1024),
355 (unsigned)(P_wchan
&0xffffff), tty
, do_time(P_utime
+P_stime
)
360 "%5d %5d %5d - - %s %s",
361 P_euid
, P_pid
, P_ppid
, tty
, do_time(P_utime
+P_stime
)
367 P_pid
, P_pgrp
, P_session
, tty
, do_time(P_utime
+P_stime
)
372 "%5d %5d - - %5ld %5ld %s %c - %s",
373 P_euid
, P_pid
, P_vsize
, P_rss
, tty
, P_state
,
374 do_time(P_utime
+P_stime
)
379 "%5d %s %c %s %6d - - %5d -",
380 P_pid
, tty
, P_state
, do_time(P_utime
+P_stime
), (int)P_maj_flt
,
386 "%5d %5d %5d %5d %s %5d %c %5d %s",
387 P_ppid
, P_pid
, P_pgrp
, P_session
, tty
, P_tpgid
, P_state
, P_euid
, do_time(P_utime
+P_stime
)
392 "%03x %5d %5d %5d %3d %3d "
393 "%5ld %4ld %06x %c %s %s",
394 (unsigned)P_flags
&0x777, P_euid
, P_pid
, P_ppid
, (int)P_priority
, (int)P_nice
,
395 P_vsize
, P_rss
, (unsigned)(P_wchan
&0xffffff), P_state
, tty
, do_time(P_utime
+P_stime
)
401 if(show_args
) printf(" [%s]\n", P_cmd
);
402 else printf(" %s\n", P_cmd
);
406 int main(int argc
, char *argv
[]){
407 arg_parse(argc
, argv
);
414 default: /* can't happen */
415 case 0: head
= " PID TTY TIME CMD"; break;
416 case 'l': head
= " F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD"; break;
417 case 'f': head
= " UID PID PPID C STIME TTY TIME CMD"; break;
418 case 'j': head
= " PID PGID SID TTY TIME CMD"; break;
419 case 'u'|0x80: head
= " UID PID %CPU %MEM VSZ RSS TTY S START TIME COMMAND"; break;
420 case 'v'|0x80: head
= " PID TTY S TIME MAJFL TRS DRS RSS %MEM COMMAND"; break;
421 case 'j'|0x80: head
= " PPID PID PGID SID TTY TPGID S UID TIME COMMAND"; break;
422 case 'l'|0x80: head
= " F UID PID PPID PRI NI VSZ RSS WCHAN S TTY TIME COMMAND"; break;
427 if(stat2proc(want_one_pid
)) print_proc();
430 struct dirent
*ent
; /* dirent handle */
436 dir
= opendir("/proc");
437 while(( ent
= readdir(dir
) )){
438 if(*ent
->d_name
<'0' || *ent
->d_name
>'9') continue;
439 if(!stat2proc(atoi(ent
->d_name
))) continue;
440 if(want_one_command
){
441 if(strcmp(want_one_command
,P_cmd
)) continue;
443 if(!select_notty
&& P_tty
==-1) continue;
444 if(!select_all
&& P_euid
!=ouruid
) continue;