2 * global.c - generic ps symbols and functions
3 * Copyright 1998-2002 by Albert Cahalan
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
29 #include <sys/ioctl.h>
31 #include <sys/sysmacros.h>
32 #include <sys/types.h>
39 #ifndef __GNU_LIBRARY__
40 #define __GNU_LIBRARY__ -1
45 #ifndef __GLIBC_MINOR__
46 #define __GLIBC_MINOR__ -1
49 // --- <pids> interface begin ||||||||||||||||||||||||||||||||||||||||||||
50 // -----------------------------------------------------------------------
51 struct pids_info *Pids_info = NULL; // our required <pids> context
52 enum pids_item *Pids_items; // allocated as PIDSITEMS
53 int Pids_index; // actual number of active enums
55 // most of these could be defined as static in the output.c module
56 // (but for future flexibility, the easiest route has been chosen)
58 makREL(ADDR_CODE_START)
61 makREL(ADDR_STACK_START)
101 makREL(IO_WRITE_BYTES)
102 makREL(IO_WRITE_CBYTES)
103 makREL(IO_WRITE_CHARS)
121 makREL(PROCESSOR_NODE)
137 makREL(SMAP_PRV_TOTAL)
151 makREL(UTILIZATION_C)
153 makREL(VM_RSS_LOCKED)
161 // -----------------------------------------------------------------------
162 // --- <pids> interface end ||||||||||||||||||||||||||||||||||||||||||||||
165 static const char * saved_personality_text = "You found a bug!";
167 int all_processes = -1;
168 const char *bsd_j_format = (const char *)0xdeadbeef;
169 const char *bsd_l_format = (const char *)0xdeadbeef;
170 const char *bsd_s_format = (const char *)0xdeadbeef;
171 const char *bsd_u_format = (const char *)0xdeadbeef;
172 const char *bsd_v_format = (const char *)0xdeadbeef;
173 int bsd_c_option = -1;
174 int bsd_e_option = -1;
175 unsigned cached_euid = 0xffffffff;
177 char forest_prefix[4 * 32*1024 + 100]; // FIXME
178 int forest_type = -1;
179 unsigned format_flags = 0xffffffff; /* -l -f l u s -j... */
180 format_node *format_list = (format_node *)0xdeadbeef; /* digested formatting options */
181 unsigned format_modifiers = 0xffffffff; /* -c -j -y -P -L... */
183 int header_type = -1;
184 int include_dead_children = -1;
185 int lines_to_next_header = -1;
186 char *lstart_format = NULL;
187 int negate_selection = -1;
188 int running_only = -1;
189 int page_size = -1; // "int" for math reasons?
190 unsigned personality = 0xffffffff;
191 int prefer_bsd_defaults = -1;
192 int screen_cols = -1;
193 int screen_rows = -1;
194 selection_node *selection_list = (selection_node *)0xdeadbeef;
195 unsigned simple_select = 0xffffffff;
196 sort_node *sort_list = (sort_node *)0xdeadbeef; /* ready-to-use sort list */
197 const char *sysv_f_format = (const char *)0xdeadbeef;
198 const char *sysv_fl_format = (const char *)0xdeadbeef;
199 const char *sysv_j_format = (const char *)0xdeadbeef;
200 const char *sysv_l_format = (const char *)0xdeadbeef;
201 unsigned thread_flags = 0xffffffff;
202 int unix_f_option = -1;
203 int user_is_number = -1;
204 int wchan_is_number = -1;
205 const char *the_word_help;
207 static void reset_selection_list(void){
209 selection_node *walk = selection_list;
210 if(selection_list == (selection_node *)0xdeadbeef){
211 selection_list = NULL;
220 selection_list = NULL;
224 // 1. Defaults are implementation-specific. (ioctl,termcap,guess)
225 // 2. COLUMNS and LINES override the defaults. (standards compliance)
226 // 3. Command line options override everything else.
227 // 4. Actual output may be more if the above is too narrow.
229 // SysV tends to spew semi-wide output in all cases. The args
230 // will be limited to 64 or 80 characters, without regard to
231 // screen size. So lines of 120 to 160 chars are normal.
232 // Tough luck if you want more or less than that! HP-UX has a
233 // new "-x" option for 1024-char args in place of comm that
234 // we'll implement at some point.
236 // BSD tends to make a good effort, then fall back to 80 cols.
237 // Use "ww" to get infinity. This is nicer for "ps | less"
238 // and "watch ps". It can run faster too.
239 static void set_screen_size(void){
241 char *columns; /* Unix98 environment variable */
242 char *lines; /* Unix98 environment variable */
246 if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0) break;
247 if(ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0) break;
248 if(ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0) break;
249 fd = open("/dev/tty", O_NOCTTY|O_NONBLOCK|O_RDONLY);
251 int ret = ioctl(fd, TIOCGWINSZ, &ws);
253 if(ret != -1 && ws.ws_col>0 && ws.ws_row>0) break;
255 // TODO: ought to do tgetnum("co") and tgetnum("li") here
259 screen_cols = ws.ws_col; // hmmm, NetBSD subtracts 1
260 screen_rows = ws.ws_row;
262 // TODO: delete this line
263 if(!isatty(STDOUT_FILENO)) screen_cols = OUTBUF_SIZE;
265 columns = getenv("COLUMNS");
266 if(columns && *columns){
269 t = strtol(columns, &endptr, 0);
270 if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_cols = (int)t;
273 lines = getenv("LINES");
277 t = strtol(lines, &endptr, 0);
278 if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_rows = (int)t;
281 if((screen_cols<9) || (screen_rows<2))
282 fprintf(stderr,_("your %dx%d screen size is bogus. expect trouble\n"),
283 screen_cols, screen_rows
287 /**************** personality control **************/
289 typedef struct personality_table_struct {
290 const char *name; /* personality name */
291 const void *jump; /* See gcc extension info. :-) */
292 } personality_table_struct;
294 static int compare_personality_table_structs(const void *a, const void *b){
295 return strcasecmp(((const personality_table_struct*)a)->name,((const personality_table_struct*)b)->name);
298 static const char *set_personality(void){
302 personality_table_struct findme = { buf, NULL};
303 personality_table_struct *found;
304 static const personality_table_struct personality_table[] = {
308 {"compaq", &&case_compaq},
309 {"debian", &&case_debian},
310 {"default", &&case_default},
311 {"digital", &&case_digital},
314 {"hpux", &&case_hpux},
315 {"irix", &&case_irix},
316 {"linux", &&case_linux},
318 {"os390", &&case_os390},
319 {"posix", &&case_posix},
320 {"s390", &&case_s390},
323 {"solaris2", &&case_solaris2},
324 {"sunos4", &&case_sunos4},
325 {"svr4", &&case_svr4},
326 {"sysv", &&case_sysv},
327 {"tru64", &&case_tru64},
328 {"unix", &&case_unix},
329 {"unix95", &&case_unix95},
330 {"unix98", &&case_unix98},
331 {"unknown", &&case_unknown}
333 const int personality_table_count = sizeof(personality_table)/sizeof(personality_table_struct);
336 prefer_bsd_defaults = 0;
338 bsd_j_format = "OL_j";
339 bsd_l_format = "OL_l";
340 bsd_s_format = "OL_s";
341 bsd_u_format = "OL_u";
342 bsd_v_format = "OL_v";
344 /* When these are NULL, the code does SysV output modifier logic */
345 sysv_f_format = NULL;
346 sysv_fl_format = NULL;
347 sysv_j_format = NULL;
348 sysv_l_format = NULL;
350 s = getenv("PS_PERSONALITY");
351 if(!s || !*s) s = getenv("CMD_ENV");
352 if(!s || !*s) s="unknown"; /* "Do The Right Thing[tm]" */
353 if(getenv("I_WANT_A_BROKEN_PS")) s="old";
355 if(sl > 15) return _("environment specified an unknown personality");
358 if ((saved_personality_text = strdup(buf))==NULL) {
359 fprintf(stderr, _("cannot strdup() personality text\n"));
363 found = bsearch(&findme, personality_table, personality_table_count,
364 sizeof(personality_table_struct), compare_personality_table_structs
367 if(!found) return _("environment specified an unknown personality");
369 goto *(found->jump); /* See gcc extension info. :-) */
372 personality = PER_FORCE_BSD | PER_BSD_h | PER_BSD_m;
373 prefer_bsd_defaults = 1;
374 bsd_j_format = "FB_j";
375 bsd_l_format = "FB_l";
376 /* bsd_s_format not used */
377 bsd_u_format = "FB_u";
378 bsd_v_format = "FB_v";
382 personality = PER_FORCE_BSD | PER_OLD_m;
383 prefer_bsd_defaults = 1;
386 case_debian: /* Toss this? They don't seem to care much. */
388 personality = PER_GOOD_o | PER_OLD_m;
389 prefer_bsd_defaults = 1;
390 sysv_f_format = "RD_f";
391 /* sysv_fl_format = "RD_fl"; */ /* old Debian ps can't do this! */
392 sysv_j_format = "RD_j";
393 sysv_l_format = "RD_l";
397 personality = PER_GOOD_o | PER_ZAP_ADDR | PER_SANE_USER;
400 case_default: /* use defaults for ps, ignoring other environment variables */
401 case_unknown: /* defaults, but also check inferior environment variables */
405 bsd_j_format = "FB_j";
406 bsd_l_format = "FB_l";
407 /* bsd_s_format not used */
408 bsd_u_format = "FB_u";
409 bsd_v_format = "FB_v";
415 // no PER_NO_DEFAULT_g even though man page claims it
416 // Reality: the g is a NOP
417 personality = PER_GOOD_o | PER_BSD_h;
418 prefer_bsd_defaults = 1;
419 sysv_f_format = "F5FMT";
420 sysv_fl_format = "FL5FMT";
421 sysv_j_format = "JFMT";
422 sysv_l_format = "L5FMT";
423 bsd_j_format = "JFMT";
424 bsd_l_format = "LFMT";
425 bsd_s_format = "SFMT";
426 bsd_u_format = "UFMT";
427 bsd_v_format = "VFMT";
431 personality = PER_NO_DEFAULT_g;
432 prefer_bsd_defaults = 1;
433 bsd_j_format = "FB_j";
434 bsd_l_format = "FB_l";
435 /* bsd_s_format not used */
436 bsd_u_format = "FB_u";
437 bsd_v_format = "FB_v";
443 if(s && s[0]>'0' && s[0]<='9')
445 personality = PER_IRIX_l;
448 case_os390: /* IBM's OS/390 OpenEdition on the S/390 mainframe */
451 sysv_j_format = "J390"; /* don't know what -jl and -jf do */
456 personality = PER_HPUX_x;
462 personality = PER_SVR4_x;
474 /************ Call this to reinitialize everything ***************/
475 void reset_global(void){
479 reset_selection_list();
481 // --- <pids> interface --------------------------------------------------
483 Pids_items = xcalloc(PIDSITEMS, sizeof(enum pids_item));
485 for (i = 0; i < PIDSITEMS; i++)
486 Pids_items[i] = PIDS_noop;
489 if (procps_pids_new(&Pids_info, Pids_items, i)) {
490 fprintf(stderr, _("fatal library error, context\n"));
495 Pids_items[0] = PIDS_TTY;
496 procps_pids_reset(Pids_info, Pids_items, 1);
497 if (!(p = fatal_proc_unmounted(Pids_info, 1))) {
498 fprintf(stderr, _("fatal library error, lookup self\n"));
501 // --- <pids> interface --------------------------------------------------
509 cached_euid = geteuid();
510 cached_tty = PIDS_VAL(0, s_int, p, Pids_info);
511 /* forest_prefix must be all zero because of POSIX */
513 format_flags = 0; /* -l -f l u s -j... */
514 format_list = NULL; /* digested formatting options */
515 format_modifiers = 0; /* -c -j -y -P -L... */
516 header_gap = -1; /* send lines_to_next_header to -infinity */
517 header_type = HEAD_SINGLE;
518 include_dead_children = 0;
519 lines_to_next_header = 1;
520 negate_selection = 0;
521 page_size = getpagesize();
523 selection_list = NULL;
531 . The following translatable word will be used to recognize the
532 . user's request for help text. In other words, the translation
533 . you provide will alter program behavior.
535 . It must be limited to 15 characters or less.
537 the_word_help = _("help");
540 static const char archdefs[] =
585 /*********** spew variables ***********/
586 void self_info(void){
598 bsd_j_format ? bsd_j_format : "(none)",
599 bsd_l_format ? bsd_l_format : "(none)",
600 bsd_s_format ? bsd_s_format : "(none)",
601 bsd_u_format ? bsd_u_format : "(none)",
602 bsd_v_format ? bsd_v_format : "(none)",
603 sysv_f_format ? sysv_f_format : "(none)",
604 sysv_fl_format ? sysv_fl_format : "(none)",
605 sysv_j_format ? sysv_j_format : "(none)",
606 sysv_l_format ? sysv_l_format : "(none)"
609 fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
610 /* __libc_print_version(); */ /* how can we get the run-time version? */
611 fprintf(stderr, "Compiled with: glibc %d.%d, gcc %d.%d\n\n",
612 __GLIBC__, __GLIBC_MINOR__, __GNUC__, __GNUC_MINOR__
616 "header_gap=%d lines_to_next_header=%d\n"
617 "screen_cols=%d screen_rows=%d\n"
619 header_gap, lines_to_next_header,
620 screen_cols, screen_rows
624 "personality=0x%08x (from \"%s\")\n"
625 "EUID=%d TTY=%d,%d page_size=%d\n",
626 personality, saved_personality_text,
627 cached_euid, (int)major(cached_tty), (int)minor(cached_tty),
632 "sizeof(proc_t)=%d sizeof(long)=%d sizeof(long)=%d\n",
633 (int)sizeof(proc_t), (int)sizeof(long), (int)sizeof(long)
636 fprintf(stderr, "archdefs:%s\n", archdefs);
639 void __attribute__ ((__noreturn__))
640 catastrophic_failure(const char *filename,
641 unsigned int linenum,
644 error_at_line(0, 0, filename, linenum, "%s", message);