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.
15 #include <sys/ioctl.h>
16 #include <sys/types.h>
26 #include <sys/sysmacros.h>
27 #include "../proc/wchan.h"
28 #include "../proc/version.h"
29 #include "../proc/sysinfo.h"
32 #ifndef __GNU_LIBRARY__
33 #define __GNU_LIBRARY__ -1
38 #ifndef __GLIBC_MINOR__
39 #define __GLIBC_MINOR__ -1
43 static const char * saved_personality_text = "You found a bug!";
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
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... */
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;
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;
86 static void reset_selection_list(void){
88 selection_node *walk = selection_list;
89 if(selection_list == (selection_node *)0xdeadbeef){
90 selection_list = NULL;
99 selection_list = NULL;
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.
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.
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){
120 char *columns; /* Unix98 environment variable */
121 char *lines; /* Unix98 environment variable */
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);
130 int ret = ioctl(fd, TIOCGWINSZ, &ws);
132 if(ret != -1 && ws.ws_col>0 && ws.ws_row>0) break;
134 // TODO: ought to do tgetnum("co") and tgetnum("li") here
138 screen_cols = ws.ws_col; // hmmm, NetBSD subtracts 1
139 screen_rows = ws.ws_row;
141 // TODO: delete this line
142 if(!isatty(STDOUT_FILENO)) screen_cols = OUTBUF_SIZE;
144 columns = getenv("COLUMNS");
145 if(columns && *columns){
148 t = strtol(columns, &endptr, 0);
149 if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_cols = (int)t;
152 lines = getenv("LINES");
156 t = strtol(lines, &endptr, 0);
157 if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_rows = (int)t;
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
166 /**************** personality control **************/
168 typedef struct personality_table_struct {
169 const char *name; /* personality name */
170 const void *jump; /* See gcc extension info. :-) */
171 } personality_table_struct;
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);
177 static const char *set_personality(void){
181 personality_table_struct findme = { buf, NULL};
182 personality_table_struct *found;
183 static const personality_table_struct personality_table[] = {
187 {"compaq", &&case_compaq},
188 {"debian", &&case_debian},
189 {"default", &&case_default},
190 {"digital", &&case_digital},
193 {"hpux", &&case_hpux},
194 {"irix", &&case_irix},
195 {"linux", &&case_linux},
197 {"os390", &&case_os390},
198 {"posix", &&case_posix},
199 {"s390", &&case_s390},
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}
212 const int personality_table_count = sizeof(personality_table)/sizeof(personality_table_struct);
215 prefer_bsd_defaults = 0;
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";
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;
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";
234 if(sl > 15) return "Environment specified an unknown personality.";
237 saved_personality_text = strdup(buf);
239 found = bsearch(&findme, personality_table, personality_table_count,
240 sizeof(personality_table_struct), compare_personality_table_structs
243 if(!found) return "Environment specified an unknown personality.";
245 goto *(found->jump); /* See gcc extension info. :-) */
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";
258 personality = PER_FORCE_BSD | PER_OLD_m;
259 prefer_bsd_defaults = 1;
262 case_debian: /* Toss this? They don't seem to care much. */
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";
273 personality = PER_GOOD_o | PER_ZAP_ADDR | PER_SANE_USER;
276 case_default: /* use defaults for ps, ignoring other environment variables */
279 case_unknown: /* defaults, but also check inferior environment variables */
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;
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";
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";
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";
326 if(s && s[0]>'0' && s[0]<='9') personality = PER_BROKEN_o;
327 else personality = PER_IRIX_l;
330 case_os390: /* IBM's OS/390 OpenEdition on the S/390 mainframe */
333 sysv_j_format = "J390"; /* don't know what -jl and -jf do */
338 personality = PER_BROKEN_o | PER_HPUX_x;
344 personality = PER_BROKEN_o | PER_SVR4_x;
352 personality = PER_BROKEN_o;
357 /************ Call this to reinitialize everything ***************/
358 void reset_global(void){
360 reset_selection_list();
361 look_up_our_self(&p);
368 cached_euid = geteuid();
370 /* forest_prefix must be all zero because of POSIX */
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();
383 seconds_since_boot = uptime(0,0);
384 selection_list = NULL;
393 static const char archdefs[] =
438 /*********** spew variables ***********/
439 void self_info(void){
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)"
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)
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__
474 "header_gap=%d lines_to_next_header=%d\n"
475 "screen_cols=%d screen_rows=%d\n"
477 header_gap, lines_to_next_header,
478 screen_cols, screen_rows
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,
490 "sizeof(proc_t)=%d sizeof(long)=%d sizeof(KLONG)=%d\n",
491 (int)sizeof(proc_t), (int)sizeof(long), (int)sizeof(KLONG)
494 fprintf(stderr, "archdefs:%s\n", archdefs);
496 open_psdb(namelist_file);
497 fprintf(stderr,"namelist_file=\"%s\"\n",namelist_file?namelist_file:"<no System.map file>");