Updated with Tizen:Base source codes
[external/procps.git] / minimal.c
1 /*
2  * Copyright 1998,2004 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 <pwd.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/ioctl.h>
26 #include <sys/types.h>
27 #include <unistd.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <dirent.h>
31
32
33 #define DEV_ENCODE(M,m) ( \
34   ( (M&0xfff) << 8)   |   ( (m&0xfff00) << 12)   |   (m&0xff)   \
35 )
36
37 ///////////////////////////////////////////////////////
38 #ifdef __sun__
39 #include <sys/mkdev.h>
40 #define _STRUCTURED_PROC 1
41 #include <sys/procfs.h>
42 #define NO_TTY_VALUE DEV_ENCODE(-1,-1)
43 #define HZ 1    // only bother with seconds
44 #endif
45
46 ///////////////////////////////////////////////////////
47 #ifdef __FreeBSD__
48 #include <sys/param.h>
49 #include <sys/sysctl.h>
50 #include <sys/stat.h>
51 #include <sys/proc.h>
52 #include <sys/user.h>
53 #define NO_TTY_VALUE DEV_ENCODE(-1,-1)
54 #define HZ 1    // only bother with seconds
55 #endif
56
57 ///////////////////////////////////////////////////////
58 #ifdef __linux__
59 #include <asm/param.h>  /* HZ */
60 #include <asm/page.h>   /* PAGE_SIZE */
61 #define NO_TTY_VALUE DEV_ENCODE(0,0)
62 #ifndef HZ
63 #warning HZ not defined, assuming it is 100
64 #define HZ 100
65 #endif
66 #endif
67
68 ///////////////////////////////////////////////////////////
69
70 #ifndef PAGE_SIZE
71 #warning PAGE_SIZE not defined, assuming it is 4096
72 #define PAGE_SIZE 4096
73 #endif
74
75
76
77 static char P_tty_text[16];
78 static char P_cmd[16];
79 static char P_state;
80 static int P_euid;
81 static int P_pid;
82 static int P_ppid, P_pgrp, P_session, P_tty_num, P_tpgid;
83 static unsigned long P_flags, P_min_flt, P_cmin_flt, P_maj_flt, P_cmaj_flt, P_utime, P_stime;
84 static long P_cutime, P_cstime, P_priority, P_nice, P_timeout, P_alarm;
85 static unsigned long P_start_time, P_vsize;
86 static long P_rss;
87 static unsigned long P_rss_rlim, P_start_code, P_end_code, P_start_stack, P_kstk_esp, P_kstk_eip;
88 static unsigned P_signal, P_blocked, P_sigignore, P_sigcatch;
89 static unsigned long P_wchan, P_nswap, P_cnswap;
90
91
92
93 #if 0
94 static int screen_cols = 80;
95 static int w_count;
96 #endif
97
98 static int want_one_pid;
99 static const char *want_one_command;
100 static int select_notty;
101 static int select_all;
102
103 static int ps_format;
104 static int old_h_option;
105
106 /* we only pretend to support this */
107 static int show_args;    /* implicit with -f and all BSD options */
108 static int bsd_c_option; /* this option overrides the above */
109
110 static int ps_argc;    /* global argc */
111 static char **ps_argv; /* global argv */
112 static int thisarg;    /* index into ps_argv */
113 static char *flagptr;  /* current location in ps_argv[thisarg] */
114
115
116
117
118 static void usage(void){
119   fprintf(stderr,
120     "-C   select by command name (minimal ps only accepts one)\n"
121     "-p   select by process ID (minimal ps only accepts one)\n"
122     "-e   all processes (same as ax)\n"
123     "a    all processes w/ tty, including other users\n"
124     "x    processes w/o controlling ttys\n"
125     "-f   full format\n"
126     "-j,j job control format\n"
127     "v    virtual memory format\n"
128     "-l,l long format\n"
129     "u    user-oriented format\n"
130     "-o   user-defined format (limited support, only \"ps -o pid=\")\n"
131     "h    no header\n"
132 /*
133     "-A   all processes (same as ax)\n"
134     "c    true command name\n"
135     "-w,w wide output\n"
136 */
137   );
138   exit(1);
139 }
140
141 /*
142  * Return the next argument, or call the usage function.
143  * This handles both:   -oFOO   -o FOO
144  */
145 static const char *get_opt_arg(void){
146   const char *ret;
147   ret = flagptr+1;    /* assume argument is part of ps_argv[thisarg] */
148   if(*ret) return ret;
149   if(++thisarg >= ps_argc) usage();   /* there is nothing left */
150   /* argument is the new ps_argv[thisarg] */
151   ret = ps_argv[thisarg];
152   if(!ret || !*ret) usage();
153   return ret;
154 }
155
156
157 /* return the PID, or 0 if nothing good */
158 static void parse_pid(const char *str){
159   char *endp;
160   int num;
161   if(!str)            goto bad;
162   num = strtol(str, &endp, 0);
163   if(*endp != '\0')   goto bad;
164   if(num<1)           goto bad;
165   if(want_one_pid)    goto bad;
166   want_one_pid = num;
167   return;
168 bad:
169   usage();
170 }
171
172 /***************** parse SysV options, including Unix98  *****************/
173 static void parse_sysv_option(void){
174   do{
175     switch(*flagptr){
176     /**** selection ****/
177     case 'C': /* end */
178       if(want_one_command) usage();
179       want_one_command = get_opt_arg();
180       return; /* can't have any more options */
181     case 'p': /* end */
182       parse_pid(get_opt_arg());
183       return; /* can't have any more options */
184     case 'A':
185     case 'e':
186       select_all++;
187       select_notty++;
188 case 'w':    /* here for now, since the real one is not used */
189       break;
190     /**** output format ****/
191     case 'f':
192       show_args = 1;
193       /* FALL THROUGH */
194     case 'j':
195     case 'l':
196       if(ps_format) usage();
197       ps_format = *flagptr;
198       break;
199     case 'o': /* end */
200       /* We only support a limited form: "ps -o pid="  (yes, just "pid=") */
201       if(strcmp(get_opt_arg(),"pid=")) usage();
202       if(ps_format) usage();
203       ps_format = 'o';
204       old_h_option++;
205       return; /* can't have any more options */
206     /**** other stuff ****/
207 #if 0
208     case 'w':
209       w_count++;
210       break;
211 #endif
212     default:
213       usage();
214     } /* switch */
215   }while(*++flagptr);
216 }
217
218 /************************* parse BSD options **********************/
219 static void parse_bsd_option(void){
220   do{
221     switch(*flagptr){
222     /**** selection ****/
223     case 'a':
224       select_all++;
225       break;
226     case 'x':
227       select_notty++;
228       break;
229     case 'p': /* end */
230       parse_pid(get_opt_arg());
231       return; /* can't have any more options */
232     /**** output format ****/
233     case 'j':
234     case 'l':
235     case 'u':
236     case 'v':
237       if(ps_format) usage();
238       ps_format = 0x80 | *flagptr;  /* use 0x80 to tell BSD from SysV */
239       break;
240     /**** other stuff ****/
241     case 'c':
242       bsd_c_option++;
243 #if 0
244       break;
245 #endif
246     case 'w':
247 #if 0
248       w_count++;
249 #endif
250       break;
251     case 'h':
252       old_h_option++;
253       break;
254     default:
255       usage();
256     } /* switch */
257   }while(*++flagptr);
258 }
259
260 #if 0
261 #include <termios.h>
262 /* not used yet */
263 static void choose_dimensions(void){
264   struct winsize ws;
265   char *columns;
266   /* screen_cols is 80 by default */
267   if(ioctl(1, TIOCGWINSZ, &ws) != -1 && ws.ws_col>30) screen_cols = ws.ws_col;
268   columns = getenv("COLUMNS");
269   if(columns && *columns){
270     long t;
271     char *endptr;
272     t = strtol(columns, &endptr, 0);
273     if(!*endptr && (t>30) && (t<(long)999999999)) screen_cols = (int)t;
274   }
275   if(w_count && (screen_cols<132)) screen_cols=132;
276   if(w_count>1) screen_cols=999999999;
277 }
278 #endif
279
280 static void arg_parse(int argc, char *argv[]){
281   int sel = 0;  /* to verify option sanity */
282   ps_argc = argc;
283   ps_argv = argv;
284   thisarg = 0;
285   /**** iterate over the args ****/
286   while(++thisarg < ps_argc){
287     flagptr = ps_argv[thisarg];
288     switch(*flagptr){
289     case '0' ... '9':
290       show_args = 1;
291       parse_pid(flagptr);
292       break;
293     case '-':
294       flagptr++;
295       parse_sysv_option();
296       break;
297     default:
298       show_args = 1;
299       parse_bsd_option();
300       break;
301     }
302   }
303   /**** sanity check and clean-up ****/
304   if(want_one_pid) sel++;
305   if(want_one_command) sel++;
306   if(select_notty || select_all) sel++;
307   if(sel>1 || select_notty>1 || select_all>1 || bsd_c_option>1 || old_h_option>1) usage();
308   if(bsd_c_option) show_args = 0;
309 }
310
311 #ifdef __sun__
312 /* return 1 if it works, or 0 for failure */
313 static int stat2proc(int pid) {
314     struct psinfo p;  //   /proc/*/psinfo, struct psinfo, psinfo_t
315     char buf[32];
316     int num;
317     int fd;
318     int tty_maj, tty_min;
319     snprintf(buf, sizeof buf, "/proc/%d/psinfo", pid);
320     if ( (fd = open(buf, O_RDONLY, 0) ) == -1 ) return 0;
321     num = read(fd, &p, sizeof p);
322     close(fd);
323     if(num != sizeof p) return 0;
324
325     num = PRFNSZ;
326     if (num >= sizeof P_cmd) num = sizeof P_cmd - 1;
327     memcpy(P_cmd, p.pr_fname, num);  // p.pr_fname or p.pr_lwp.pr_name
328     P_cmd[num] = '\0';
329
330     P_pid     = p.pr_pid;
331     P_ppid    = p.pr_ppid;
332     P_pgrp    = p.pr_pgid;
333     P_session = p.pr_sid;
334     P_euid    = p.pr_euid;
335     P_rss     = p.pr_rssize;
336     P_vsize   = p.pr_size;
337     P_start_time = p.pr_start.tv_sec;
338     P_wchan   = p.pr_lwp.pr_wchan;
339     P_state   = p.pr_lwp.pr_sname;
340     P_nice    = p.pr_lwp.pr_nice;
341     P_priority = p.pr_lwp.pr_pri;  // or pr_oldpri
342 //    P_ruid    = p.pr_uid;
343 //    P_rgid    = p.pr_gid;
344 //    P_egid    = p.pr_egid;
345
346 #if 0
347     // don't support these
348     P_tpgid; P_flags,
349     P_min_flt, P_cmin_flt, P_maj_flt, P_cmaj_flt, P_utime, P_stime;
350     P_cutime, P_cstime, P_timeout, P_alarm;
351     P_rss_rlim, P_start_code, P_end_code, P_start_stack, P_kstk_esp, P_kstk_eip;
352     P_signal, P_blocked, P_sigignore, P_sigcatch;
353     P_nswap, P_cnswap;
354 #endif
355
356     // we like it Linux-encoded :-)
357     tty_maj = major(p.pr_ttydev);
358     tty_min = minor(p.pr_ttydev);
359     P_tty_num = DEV_ENCODE(tty_maj,tty_min);
360
361     snprintf(P_tty_text, sizeof P_tty_text, "%3d,%-3d", tty_maj, tty_min);
362 #if 1
363     if (tty_maj == 24) snprintf(P_tty_text, sizeof P_tty_text, "pts/%-3u", tty_min);
364     if (P_tty_num == NO_TTY_VALUE)    memcpy(P_tty_text, "   ?   ", 8);
365     if (P_tty_num == DEV_ENCODE(0,0)) memcpy(P_tty_text, "console", 8);
366 #endif
367
368     if(P_pid != pid) return 0;
369     return 1;
370 }
371 #endif
372
373 #ifdef __FreeBSD__
374 /* return 1 if it works, or 0 for failure */
375 static int stat2proc(int pid) {
376     char buf[400];
377     int num;
378     int fd;
379     char* tmp;
380     int tty_maj, tty_min;
381     snprintf(buf, 32, "/proc/%d/status", pid);
382     if ( (fd = open(buf, O_RDONLY, 0) ) == -1 ) return 0;
383     num = read(fd, buf, sizeof buf - 1);
384     close(fd);
385     if(num<43) return 0;
386     buf[num] = '\0';
387
388     P_state = '-';
389
390     // FreeBSD /proc/*/status is seriously fucked. Unlike the Linux
391     // files, we can't use strrchr to find the end of a command name.
392     // Spaces in command names do not get escaped. To avoid spoofing,
393     // one may skip 20 characters and then look _forward_ only to
394     // find a pattern of entries that are {with,with,without} a comma.
395     // The entry without a comma is wchan. Then count backwards!
396     //
397     // Don't bother for now. FreeBSD isn't worth the trouble.
398
399     tmp = strchr(buf,' ');
400     num = tmp - buf;
401     if (num >= sizeof P_cmd) num = sizeof P_cmd - 1;
402     memcpy(P_cmd,buf,num);
403     P_cmd[num] = '\0';
404
405     num = sscanf(tmp+1,
406        "%d %d %d %d "
407        "%d,%d "
408        "%*s "
409        "%ld,%*d "
410        "%ld,%*d "
411        "%ld,%*d "
412        "%*s "
413        "%d %d ",
414        &P_pid, &P_ppid, &P_pgrp, &P_session,
415        &tty_maj, &tty_min,
416        /* SKIP funny flags thing */
417        &P_start_time, /* SKIP microseconds */
418        &P_utime, /* SKIP microseconds */
419        &P_stime, /* SKIP microseconds */
420        /* SKIP &P_wchan, for now -- it is a string */
421        &P_euid, &P_euid   // don't know which is which
422     );
423 /*    fprintf(stderr, "stat2proc converted %d fields.\n",num); */
424
425     snprintf(P_tty_text, sizeof P_tty_text, "%3d,%-3d", tty_maj, tty_min);
426     P_tty_num = DEV_ENCODE(tty_maj,tty_min);
427 // tty decode is 224 to 256 bytes on i386
428 #if 1
429     tmp = NULL;
430     if (tty_maj ==  5) tmp = " ttyp%c ";
431     if (tty_maj == 12) tmp = " ttyv%c ";
432     if (tty_maj == 28) tmp = " ttyd%c ";
433     if (P_tty_num == NO_TTY_VALUE) tmp = "   ?   ";
434     if (P_tty_num == DEV_ENCODE(0,0)) tmp = "console";
435     if (P_tty_num == DEV_ENCODE(12,255)) tmp = "consolectl";
436     if (tmp) {
437       snprintf(
438         P_tty_text,
439         sizeof P_tty_text,
440         tmp,
441         "0123456789abcdefghijklmnopqrstuvwxyz"[tty_min&31]
442       );
443     }
444 #endif
445
446     if(num < 9) return 0;
447     if(P_pid != pid) return 0;
448     return 1;
449 }
450 #endif
451
452 #ifdef __linux__
453 /* return 1 if it works, or 0 for failure */
454 static int stat2proc(int pid) {
455     char buf[800]; /* about 40 fields, 64-bit decimal is about 20 chars */
456     int num;
457     int fd;
458     char* tmp;
459     struct stat sb; /* stat() used to get EUID */
460     snprintf(buf, 32, "/proc/%d/stat", pid);
461     if ( (fd = open(buf, O_RDONLY, 0) ) == -1 ) return 0;
462     num = read(fd, buf, sizeof buf - 1);
463     fstat(fd, &sb);
464     P_euid = sb.st_uid;
465     close(fd);
466     if(num<80) return 0;
467     buf[num] = '\0';
468     tmp = strrchr(buf, ')');      /* split into "PID (cmd" and "<rest>" */
469     *tmp = '\0';                  /* replace trailing ')' with NUL */
470     /* parse these two strings separately, skipping the leading "(". */
471     memset(P_cmd, 0, sizeof P_cmd);          /* clear */
472     sscanf(buf, "%d (%15c", &P_pid, P_cmd);  /* comm[16] in kernel */
473     num = sscanf(tmp + 2,                    /* skip space after ')' too */
474        "%c "
475        "%d %d %d %d %d "
476        "%lu %lu %lu %lu %lu %lu %lu "
477        "%ld %ld %ld %ld %ld %ld "
478        "%lu %lu "
479        "%ld "
480        "%lu %lu %lu %lu %lu %lu "
481        "%u %u %u %u " /* no use for RT signals */
482        "%lu %lu %lu",
483        &P_state,
484        &P_ppid, &P_pgrp, &P_session, &P_tty_num, &P_tpgid,
485        &P_flags, &P_min_flt, &P_cmin_flt, &P_maj_flt, &P_cmaj_flt, &P_utime, &P_stime,
486        &P_cutime, &P_cstime, &P_priority, &P_nice, &P_timeout, &P_alarm,
487        &P_start_time, &P_vsize,
488        &P_rss,
489        &P_rss_rlim, &P_start_code, &P_end_code, &P_start_stack, &P_kstk_esp, &P_kstk_eip,
490        &P_signal, &P_blocked, &P_sigignore, &P_sigcatch,
491        &P_wchan, &P_nswap, &P_cnswap
492     );
493 /*    fprintf(stderr, "stat2proc converted %d fields.\n",num); */
494     P_vsize /= 1024;
495     P_rss *= (PAGE_SIZE/1024);
496
497     memcpy(P_tty_text, "   ?   ", 8);
498     if (P_tty_num != NO_TTY_VALUE) {
499       int tty_maj = (P_tty_num>>8)&0xfff;
500       int tty_min = (P_tty_num&0xff) | ((P_tty_num>>12)&0xfff00);
501       snprintf(P_tty_text, sizeof P_tty_text, "%3d,%-3d", tty_maj, tty_min);
502     }
503
504     if(num < 30) return 0;
505     if(P_pid != pid) return 0;
506     return 1;
507 }
508 #endif
509
510 static const char *do_time(unsigned long t){
511   int hh,mm,ss;
512   static char buf[32];
513   int cnt = 0;
514   t /= HZ;
515   ss = t%60;
516   t /= 60;
517   mm = t%60;
518   t /= 60;
519   hh = t%24;
520   t /= 24;
521   if(t) cnt = snprintf(buf, sizeof buf, "%d-", (int)t);
522   snprintf(cnt + buf, sizeof(buf)-cnt, "%02d:%02d:%02d", hh, mm, ss);
523   return buf;
524 }
525
526 static const char *do_user(void){
527   static char buf[32];
528   static struct passwd *p;
529   static int lastuid = -1;
530   if(P_euid != lastuid){
531     p = getpwuid(P_euid);
532     if(p) snprintf(buf, sizeof buf, "%-8.8s", p->pw_name);
533     else  snprintf(buf, sizeof buf, "%5d   ", P_euid);
534   }
535   return buf;
536 }
537
538 static const char *do_cpu(int longform){
539   static char buf[8];
540   strcpy(buf," -  ");
541   if(!longform) buf[2] = '\0';
542   return buf;
543 }
544
545 static const char *do_mem(int longform){
546   static char buf[8];
547   strcpy(buf," -  ");
548   if(!longform) buf[2] = '\0';
549   return buf;
550 }
551
552 static const char *do_stime(void){
553   static char buf[32];
554   strcpy(buf,"  -  ");
555   return buf;
556 }
557
558 static void print_proc(void){
559   switch(ps_format){
560   case 0:
561     printf("%5d %s %s", P_pid, P_tty_text, do_time(P_utime+P_stime));
562     break;
563   case 'o':
564     printf("%d\n", P_pid);
565     return; /* don't want the command */
566   case 'l':
567     printf(
568       "0 %c %5d %5d %5d %s %3d %3d - "
569       "%5ld %06x %s %s",
570       P_state, P_euid, P_pid, P_ppid, do_cpu(0),
571       (int)P_priority, (int)P_nice, P_vsize/(PAGE_SIZE/1024),
572       (unsigned)(P_wchan&0xffffff), P_tty_text, do_time(P_utime+P_stime)
573     );
574     break;
575   case 'f':
576     printf(
577       "%8s %5d %5d %s %s %s %s",
578       do_user(), P_pid, P_ppid, do_cpu(0), do_stime(), P_tty_text, do_time(P_utime+P_stime)
579     );
580     break;
581   case 'j':
582     printf(
583       "%5d %5d %5d %s %s",
584       P_pid, P_pgrp, P_session, P_tty_text, do_time(P_utime+P_stime)
585     );
586     break;
587   case 'u'|0x80:
588     printf(
589       "%8s %5d %s %s %5ld %4ld %s %c %s %s",
590       do_user(), P_pid, do_cpu(1), do_mem(1), P_vsize, P_rss, P_tty_text, P_state,
591       do_stime(), do_time(P_utime+P_stime)
592     );
593     break;
594   case 'v'|0x80:
595     printf(
596       "%5d %s %c %s %6d   -   - %5d %s",
597       P_pid, P_tty_text, P_state, do_time(P_utime+P_stime), (int)P_maj_flt,
598       (int)P_rss, do_mem(1)
599     );
600     break;
601   case 'j'|0x80:
602     printf(
603       "%5d %5d %5d %5d %s %5d %c %5d %s",
604       P_ppid, P_pid, P_pgrp, P_session, P_tty_text, P_tpgid, P_state, P_euid, do_time(P_utime+P_stime)
605     );
606     break;
607   case 'l'|0x80:
608     printf(
609       "0 %5d %5d %5d %3d %3d "
610       "%5ld %4ld %06x %c %s %s",
611       P_euid, P_pid, P_ppid, (int)P_priority, (int)P_nice,
612       P_vsize, P_rss, (unsigned)(P_wchan&0xffffff), P_state, P_tty_text, do_time(P_utime+P_stime)
613     );
614     break;
615   default:
616     ;
617   }
618   if(show_args) printf(" [%s]\n", P_cmd);
619   else          printf(" %s\n", P_cmd);
620 }
621
622
623 int main(int argc, char *argv[]){
624   arg_parse(argc, argv);
625 #if 0
626   choose_dimensions();
627 #endif
628   if(!old_h_option){
629     const char *head;
630     switch(ps_format){
631     default: /* can't happen */
632     case 0:        head = "  PID TTY         TIME CMD"; break;
633     case 'l':      head = "F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN    TTY       TIME CMD"; break;
634     case 'f':      head = "USER       PID  PPID  C STIME   TTY       TIME CMD"; break;
635     case 'j':      head = "  PID  PGID   SID TTY         TIME CMD"; break;
636     case 'u'|0x80: head = "USER       PID %CPU %MEM   VSZ  RSS   TTY   S START     TIME COMMAND"; break;
637     case 'v'|0x80: head = "  PID   TTY   S     TIME  MAJFL TRS DRS   RSS %MEM COMMAND"; break;
638     case 'j'|0x80: head = " PPID   PID  PGID   SID   TTY   TPGID S   UID     TIME COMMAND"; break;
639     case 'l'|0x80: head = "F   UID   PID  PPID PRI  NI   VSZ  RSS WCHAN  S   TTY       TIME COMMAND"; break;
640     }
641     printf("%s\n",head);
642   }
643   if(want_one_pid){
644     if(stat2proc(want_one_pid)) print_proc();
645     else exit(1);
646   }else{
647     struct dirent *ent;          /* dirent handle */
648     DIR *dir;
649     int ouruid;
650     int found_a_proc;
651     found_a_proc = 0;
652     ouruid = getuid();
653     dir = opendir("/proc");
654     while(( ent = readdir(dir) )){
655       if(*ent->d_name<'0' || *ent->d_name>'9') continue;
656       if(!stat2proc(atoi(ent->d_name))) continue;
657       if(want_one_command){
658         if(strcmp(want_one_command,P_cmd)) continue;
659       }else{
660         if(!select_notty && P_tty_num==NO_TTY_VALUE) continue;
661         if(!select_all && P_euid!=ouruid) continue;
662       }
663       found_a_proc++;
664       print_proc();
665     }
666     closedir(dir);
667     exit(!found_a_proc);
668   }
669   return 0;
670 }