Updated with Tizen:Base source codes
[external/procps.git] / ps / global.c
1 /*
2  * Copyright 1998-2002 by Albert Cahalan; all rights resered.         
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 #include <stdlib.h>
12 #include <termios.h>
13 #include <stdio.h>
14 #include <unistd.h>
15 #include <sys/ioctl.h>
16 #include <sys/types.h>
17 #include <pwd.h>
18 #include <grp.h>
19 #include <string.h>
20 #include <sys/stat.h>
21 #include <fcntl.h>
22                      
23
24 #include "common.h"
25
26 #include <sys/sysmacros.h>
27 #include "../proc/wchan.h"
28 #include "../proc/version.h"
29 #include "../proc/sysinfo.h"
30
31
32 #ifndef __GNU_LIBRARY__
33 #define __GNU_LIBRARY__ -1
34 #endif
35 #ifndef __GLIBC__
36 #define __GLIBC__ -1
37 #endif
38 #ifndef __GLIBC_MINOR__
39 #define __GLIBC_MINOR__ -1
40 #endif
41
42
43 static const char * saved_personality_text = "You found a bug!";
44
45 int             all_processes = -1;
46 const char     *bsd_j_format = (const char *)0xdeadbeef;
47 const char     *bsd_l_format = (const char *)0xdeadbeef;
48 const char     *bsd_s_format = (const char *)0xdeadbeef;
49 const char     *bsd_u_format = (const char *)0xdeadbeef;
50 const char     *bsd_v_format = (const char *)0xdeadbeef;
51 int             bsd_c_option = -1;
52 int             bsd_e_option = -1;
53 uid_t           cached_euid = -1;
54 dev_t           cached_tty = -1;
55 char            forest_prefix[4 * 32*1024 + 100];     // FIXME
56 int             forest_type = -1;
57 unsigned        format_flags = 0xffffffff;   /* -l -f l u s -j... */
58 format_node    *format_list = (format_node *)0xdeadbeef; /* digested formatting options */
59 unsigned        format_modifiers = 0xffffffff;   /* -c -j -y -P -L... */
60 int             header_gap = -1;
61 int             header_type = -1;
62 int             include_dead_children = -1;
63 int             lines_to_next_header = -1;
64 const char     *namelist_file = (const char *)0xdeadbeef;
65 int             negate_selection = -1;
66 int             running_only = -1;
67 int             page_size = -1;  // "int" for math reasons?
68 unsigned        personality = 0xffffffff;
69 int             prefer_bsd_defaults = -1;
70 int             screen_cols = -1;
71 int             screen_rows = -1;
72 unsigned long   seconds_since_boot = -1;
73 selection_node *selection_list = (selection_node *)0xdeadbeef;
74 unsigned        simple_select = 0xffffffff;
75 sort_node      *sort_list = (sort_node *)0xdeadbeef; /* ready-to-use sort list */
76 const char     *sysv_f_format = (const char *)0xdeadbeef;
77 const char     *sysv_fl_format = (const char *)0xdeadbeef;
78 const char     *sysv_j_format = (const char *)0xdeadbeef;
79 const char     *sysv_l_format = (const char *)0xdeadbeef;
80 unsigned        thread_flags = 0xffffffff;
81 int             unix_f_option = -1;
82 int             user_is_number = -1;
83 int             wchan_is_number = -1;
84
85
86 static void reset_selection_list(void){
87   selection_node *old;
88   selection_node *walk = selection_list;
89   if(selection_list == (selection_node *)0xdeadbeef){
90     selection_list = NULL;
91     return;
92   }
93   while(walk){
94     old = walk;
95     walk = old->next;
96     free(old->u);
97     free(old);
98   }
99   selection_list = NULL;
100 }
101
102 // The rules:
103 // 1. Defaults are implementation-specific. (ioctl,termcap,guess)
104 // 2. COLUMNS and LINES override the defaults. (standards compliance)
105 // 3. Command line options override everything else.
106 // 4. Actual output may be more if the above is too narrow.
107 //
108 // SysV tends to spew semi-wide output in all cases. The args
109 // will be limited to 64 or 80 characters, without regard to
110 // screen size. So lines of 120 to 160 chars are normal.
111 // Tough luck if you want more or less than that! HP-UX has a
112 // new "-x" option for 1024-char args in place of comm that
113 // we'll implement at some point.
114 //
115 // BSD tends to make a good effort, then fall back to 80 cols.
116 // Use "ww" to get infinity. This is nicer for "ps | less"
117 // and "watch ps". It can run faster too.
118 static void set_screen_size(void){
119   struct winsize ws;
120   char *columns; /* Unix98 environment variable */
121   char *lines;   /* Unix98 environment variable */
122
123   do{
124     int fd;
125     if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0) break;
126     if(ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0) break;
127     if(ioctl(STDIN_FILENO,  TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0) break;
128     fd = open("/dev/tty", O_NOCTTY|O_NONBLOCK|O_RDONLY);
129     if(fd != -1){
130       int ret = ioctl(fd, TIOCGWINSZ, &ws);
131       close(fd);
132       if(ret != -1 && ws.ws_col>0 && ws.ws_row>0) break;
133     }
134     // TODO: ought to do tgetnum("co") and tgetnum("li") here
135     ws.ws_col = 80;
136     ws.ws_row = 24;
137   }while(0);
138   screen_cols = ws.ws_col;  // hmmm, NetBSD subtracts 1
139   screen_rows = ws.ws_row;
140
141   // TODO: delete this line
142   if(!isatty(STDOUT_FILENO)) screen_cols = OUTBUF_SIZE;
143
144   columns = getenv("COLUMNS");
145   if(columns && *columns){
146     long t;
147     char *endptr;
148     t = strtol(columns, &endptr, 0);
149     if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_cols = (int)t;
150   }
151
152   lines   = getenv("LINES");
153   if(lines && *lines){
154     long t;
155     char *endptr;
156     t = strtol(lines, &endptr, 0);
157     if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_rows = (int)t;
158   }
159
160   if((screen_cols<9) || (screen_rows<2))
161     fprintf(stderr,"Your %dx%d screen size is bogus. Expect trouble.\n",
162       screen_cols, screen_rows
163     );
164 }
165
166 /**************** personality control **************/
167
168 typedef struct personality_table_struct {
169   const char *name; /* personality name */
170   const void *jump; /* See gcc extension info.   :-)   */
171 } personality_table_struct;
172
173 static int compare_personality_table_structs(const void *a, const void *b){
174   return strcasecmp(((const personality_table_struct*)a)->name,((const personality_table_struct*)b)->name);
175 }
176
177 static const char *set_personality(void){
178   const char *s;
179   size_t sl;
180   char buf[16];
181   personality_table_struct findme = { buf, NULL};
182   personality_table_struct *found;
183   static const personality_table_struct personality_table[] = {
184   {"390",      &&case_390},
185   {"aix",      &&case_aix},
186   {"bsd",      &&case_bsd},
187   {"compaq",   &&case_compaq},
188   {"debian",   &&case_debian},
189   {"default",  &&case_default},
190   {"digital",  &&case_digital},
191   {"gnu",      &&case_gnu},
192   {"hp",       &&case_hp},
193   {"hpux",     &&case_hpux},
194   {"irix",     &&case_irix},
195   {"linux",    &&case_linux},
196   {"old",      &&case_old},
197   {"os390",    &&case_os390},
198   {"posix",    &&case_posix},
199   {"s390",     &&case_s390},
200   {"sco",      &&case_sco},
201   {"sgi",      &&case_sgi},
202   {"solaris2", &&case_solaris2},
203   {"sunos4",   &&case_sunos4},
204   {"svr4",     &&case_svr4},
205   {"sysv",     &&case_sysv},
206   {"tru64",    &&case_tru64},
207   {"unix",     &&case_unix},
208   {"unix95",   &&case_unix95},
209   {"unix98",   &&case_unix98},
210   {"unknown",  &&case_unknown}
211   };
212   const int personality_table_count = sizeof(personality_table)/sizeof(personality_table_struct);
213
214   personality = 0;
215   prefer_bsd_defaults = 0;
216
217   bsd_j_format = "OL_j";
218   bsd_l_format = "OL_l";
219   bsd_s_format = "OL_s";
220   bsd_u_format = "OL_u";
221   bsd_v_format = "OL_v";
222
223   /* When these are NULL, the code does SysV output modifier logic */
224   sysv_f_format  = NULL;
225   sysv_fl_format = NULL;
226   sysv_j_format  = NULL;
227   sysv_l_format  = NULL;
228
229   s = getenv("PS_PERSONALITY");
230   if(!s || !*s) s = getenv("CMD_ENV");
231   if(!s || !*s) s="unknown";   /* "Do The Right Thing[tm]" */
232   if(getenv("I_WANT_A_BROKEN_PS")) s="old";
233   sl = strlen(s);
234   if(sl > 15) return "Environment specified an unknown personality.";
235   strncpy(buf, s, sl);
236   buf[sl] = '\0';
237   saved_personality_text = strdup(buf);
238
239   found = bsearch(&findme, personality_table, personality_table_count,
240       sizeof(personality_table_struct), compare_personality_table_structs
241   );
242
243   if(!found) return "Environment specified an unknown personality.";
244
245   goto *(found->jump);    /* See gcc extension info.  :-)   */
246
247   case_bsd:
248     personality = PER_FORCE_BSD | PER_BSD_h | PER_BSD_m;
249     prefer_bsd_defaults = 1;
250     bsd_j_format = "FB_j";
251     bsd_l_format = "FB_l";
252     /* bsd_s_format not used */
253     bsd_u_format = "FB_u";
254     bsd_v_format = "FB_v";
255     return NULL;
256
257   case_old:
258     personality = PER_FORCE_BSD | PER_OLD_m;
259     prefer_bsd_defaults = 1;
260     return NULL;
261
262   case_debian:  /* Toss this? They don't seem to care much. */
263   case_gnu:
264     personality = PER_GOOD_o | PER_OLD_m;
265     prefer_bsd_defaults = 1;
266     sysv_f_format  = "RD_f";
267     /* sysv_fl_format = "RD_fl"; */   /* old Debian ps can't do this! */
268     sysv_j_format  = "RD_j";
269     sysv_l_format  = "RD_l";
270     return NULL;
271
272   case_linux:
273     personality = PER_GOOD_o | PER_ZAP_ADDR | PER_SANE_USER;
274     return NULL;
275
276   case_default: /* use defaults for ps, ignoring other environment variables */
277     return NULL;
278
279   case_unknown: /* defaults, but also check inferior environment variables */
280     if(
281       getenv("UNIX95")     /* Irix */
282       || getenv("POSIXLY_CORRECT")  /* most gnu stuff */
283       || (getenv("POSIX2") && !strcmp(getenv("POSIX2"), "on")) /* Unixware 7 */
284     ) personality = PER_BROKEN_o;
285     return NULL;
286
287   case_aix:
288     bsd_j_format = "FB_j";
289     bsd_l_format = "FB_l";
290     /* bsd_s_format not used */
291     bsd_u_format = "FB_u";
292     bsd_v_format = "FB_v";
293     return NULL;
294
295   case_tru64:
296   case_compaq:
297   case_digital:
298     // no PER_NO_DEFAULT_g even though man page claims it
299     // Reality: the g is a NOP
300     personality = PER_GOOD_o | PER_BSD_h;
301     prefer_bsd_defaults = 1;
302     sysv_f_format  = "F5FMT";
303     sysv_fl_format = "FL5FMT";
304     sysv_j_format  = "JFMT";
305     sysv_l_format  = "L5FMT";
306     bsd_j_format = "JFMT";
307     bsd_l_format = "LFMT";
308     bsd_s_format = "SFMT";
309     bsd_u_format = "UFMT";
310     bsd_v_format = "VFMT";
311     return NULL;
312
313   case_sunos4:
314     personality = PER_NO_DEFAULT_g;
315     prefer_bsd_defaults = 1;
316     bsd_j_format = "FB_j";
317     bsd_l_format = "FB_l";
318     /* bsd_s_format not used */
319     bsd_u_format = "FB_u";
320     bsd_v_format = "FB_v";
321     return NULL;
322
323   case_irix:
324   case_sgi:
325     s = getenv("_XPG");
326     if(s && s[0]>'0' && s[0]<='9') personality = PER_BROKEN_o;
327     else personality = PER_IRIX_l;
328     return NULL;
329
330   case_os390:  /* IBM's OS/390 OpenEdition on the S/390 mainframe */
331   case_s390:
332   case_390:
333     sysv_j_format  = "J390";  /* don't know what -jl and -jf do */
334     return NULL;
335
336   case_hp:
337   case_hpux:
338     personality = PER_BROKEN_o | PER_HPUX_x;
339     return NULL;
340
341   case_svr4:
342   case_sysv:
343   case_sco:
344     personality = PER_BROKEN_o | PER_SVR4_x;
345     return NULL;
346
347   case_posix:
348   case_solaris2:
349   case_unix95:
350   case_unix98:
351   case_unix:
352     personality = PER_BROKEN_o;
353     return NULL;
354 }
355
356
357 /************ Call this to reinitialize everything ***************/
358 void reset_global(void){
359   static proc_t p;
360   reset_selection_list();
361   look_up_our_self(&p);
362   set_screen_size();
363   set_personality();
364   
365   all_processes         = 0;
366   bsd_c_option          = 0;
367   bsd_e_option          = 0;
368   cached_euid           = geteuid();
369   cached_tty            = p.tty;
370 /* forest_prefix must be all zero because of POSIX */
371   forest_type           = 0;
372   format_flags          = 0;   /* -l -f l u s -j... */
373   format_list           = NULL; /* digested formatting options */
374   format_modifiers      = 0;   /* -c -j -y -P -L... */
375   header_gap            = -1;  /* send lines_to_next_header to -infinity */
376   header_type           = HEAD_SINGLE;
377   include_dead_children = 0;
378   lines_to_next_header  = 1;
379   namelist_file         = NULL;
380   negate_selection      = 0;
381   page_size             = getpagesize();
382   running_only          = 0;
383   seconds_since_boot    = uptime(0,0);
384   selection_list        = NULL;
385   simple_select         = 0;
386   sort_list             = NULL;
387   thread_flags          = 0;
388   unix_f_option         = 0;
389   user_is_number        = 0;
390   wchan_is_number       = 0;
391 }
392
393 static const char archdefs[] =
394 #ifdef __alpha__
395 " alpha"
396 #endif
397 #ifdef __arm__
398 " arm"
399 #endif
400 #ifdef __hppa__
401 " hppa"
402 #endif
403 #ifdef __i386__
404 " i386"
405 #endif
406 #ifdef __ia64__
407 " ia64"
408 #endif
409 #ifdef __mc68000__
410 " mc68000"
411 #endif
412 #ifdef __mips64__
413 " mips64"
414 #endif
415 #ifdef __mips__
416 " mips"
417 #endif
418 #ifdef __powerpc__
419 " powerpc"
420 #endif
421 #ifdef __sh3__
422 " sh3"
423 #endif
424 #ifdef __sh__
425 " sh"
426 #endif
427 #ifdef __sparc__
428 " sparc"
429 #endif
430 #ifdef __sparc_v9__
431 " sparc_v9"
432 #endif
433 #ifdef __x86_64__
434 " x86_64"
435 #endif
436 "";
437
438 /*********** spew variables ***********/
439 void self_info(void){
440   fprintf(stderr,
441     "BSD j    %s\n"
442     "BSD l    %s\n"
443     "BSD s    %s\n"
444     "BSD u    %s\n"
445     "BSD v    %s\n"
446     "SysV -f  %s\n"
447     "SysV -fl %s\n"
448     "SysV -j  %s\n"
449     "SysV -l  %s\n"
450     "\n",
451     bsd_j_format   ? bsd_j_format   : "(none)",
452     bsd_l_format   ? bsd_l_format   : "(none)",
453     bsd_s_format   ? bsd_s_format   : "(none)",
454     bsd_u_format   ? bsd_u_format   : "(none)",
455     bsd_v_format   ? bsd_v_format   : "(none)",
456     sysv_f_format  ? sysv_f_format  : "(none)",
457     sysv_fl_format ? sysv_fl_format : "(none)",
458     sysv_j_format  ? sysv_j_format  : "(none)",
459     sysv_l_format  ? sysv_l_format  : "(none)"
460   );
461
462   display_version();
463   fprintf(stderr, "Linux version %d.%d.%d\n",
464     LINUX_VERSION_MAJOR(linux_version_code),
465     LINUX_VERSION_MINOR(linux_version_code),
466     LINUX_VERSION_PATCH(linux_version_code)
467   );
468   /* __libc_print_version(); */  /* how can we get the run-time version? */
469   fprintf(stderr, "Compiled with: glibc %d.%d, gcc %d.%d\n\n",
470     __GLIBC__, __GLIBC_MINOR__, __GNUC__, __GNUC_MINOR__
471   );
472
473   fprintf(stderr,
474     "header_gap=%d lines_to_next_header=%d\n"
475     "screen_cols=%d screen_rows=%d\n"
476     "\n",
477     header_gap, lines_to_next_header,
478     screen_cols, screen_rows
479   );
480
481   fprintf(stderr,
482     "personality=0x%08x (from \"%s\")\n"
483     "EUID=%d TTY=%d,%d Hertz=%Ld page_size=%d\n",
484     personality, saved_personality_text,
485     cached_euid, (int)major(cached_tty), (int)minor(cached_tty), Hertz,
486     (int)(page_size)
487   );
488
489   fprintf(stderr,
490     "sizeof(proc_t)=%d sizeof(long)=%d sizeof(KLONG)=%d\n",
491     (int)sizeof(proc_t), (int)sizeof(long), (int)sizeof(KLONG)
492   );
493
494   fprintf(stderr, "archdefs:%s\n", archdefs);
495
496   open_psdb(namelist_file);
497   fprintf(stderr,"namelist_file=\"%s\"\n",namelist_file?namelist_file:"<no System.map file>");
498 }