procps/ps/global.c

517 lines
15 KiB
C
Raw Normal View History

2002-02-02 04:17:29 +05:30
/*
* global.c - generic ps symbols and functions
* Copyright 1998-2002 by Albert Cahalan
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
2002-02-02 04:17:29 +05:30
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <fcntl.h>
#include <grp.h>
#include <pwd.h>
#include <stdio.h>
2002-02-02 04:17:29 +05:30
#include <stdlib.h>
#include <string.h>
#include <termios.h>
2002-02-02 04:17:29 +05:30
#include <unistd.h>
2002-02-02 04:17:29 +05:30
#include <sys/ioctl.h>
2004-08-18 07:52:13 +05:30
#include <sys/stat.h>
2002-02-02 04:17:29 +05:30
#include <sys/sysmacros.h>
#include <sys/types.h>
2002-12-09 12:30:07 +05:30
#include "../proc/wchan.h"
2002-02-02 04:17:29 +05:30
#include "../proc/version.h"
#include "../proc/sysinfo.h"
#include "../include/c.h"
#include "common.h"
2002-02-02 04:17:29 +05:30
#ifndef __GNU_LIBRARY__
#define __GNU_LIBRARY__ -1
#endif
#ifndef __GLIBC__
#define __GLIBC__ -1
#endif
#ifndef __GLIBC_MINOR__
#define __GLIBC_MINOR__ -1
#endif
2002-10-12 09:55:57 +05:30
static const char * saved_personality_text = "You found a bug!";
2002-02-02 04:17:29 +05:30
int all_processes = -1;
2002-10-12 09:55:57 +05:30
const char *bsd_j_format = (const char *)0xdeadbeef;
const char *bsd_l_format = (const char *)0xdeadbeef;
const char *bsd_s_format = (const char *)0xdeadbeef;
const char *bsd_u_format = (const char *)0xdeadbeef;
const char *bsd_v_format = (const char *)0xdeadbeef;
2002-02-02 04:17:29 +05:30
int bsd_c_option = -1;
int bsd_e_option = -1;
uid_t cached_euid = -1;
dev_t cached_tty = -1;
2002-11-27 05:54:01 +05:30
char forest_prefix[4 * 32*1024 + 100]; // FIXME
2002-02-02 04:17:29 +05:30
int forest_type = -1;
unsigned format_flags = 0xffffffff; /* -l -f l u s -j... */
format_node *format_list = (format_node *)0xdeadbeef; /* digested formatting options */
unsigned format_modifiers = 0xffffffff; /* -c -j -y -P -L... */
int header_gap = -1;
int header_type = -1;
int include_dead_children = -1;
int lines_to_next_header = -1;
int negate_selection = -1;
int running_only = -1;
2002-11-27 05:54:01 +05:30
int page_size = -1; // "int" for math reasons?
2002-02-02 04:17:29 +05:30
unsigned personality = 0xffffffff;
int prefer_bsd_defaults = -1;
int screen_cols = -1;
int screen_rows = -1;
time_t seconds_since_boot = -1;
2002-02-02 04:17:29 +05:30
selection_node *selection_list = (selection_node *)0xdeadbeef;
unsigned simple_select = 0xffffffff;
sort_node *sort_list = (sort_node *)0xdeadbeef; /* ready-to-use sort list */
2002-10-12 09:55:57 +05:30
const char *sysv_f_format = (const char *)0xdeadbeef;
const char *sysv_fl_format = (const char *)0xdeadbeef;
const char *sysv_j_format = (const char *)0xdeadbeef;
const char *sysv_l_format = (const char *)0xdeadbeef;
2003-09-20 13:59:55 +05:30
unsigned thread_flags = 0xffffffff;
2002-02-02 04:17:29 +05:30
int unix_f_option = -1;
int user_is_number = -1;
int wchan_is_number = -1;
const char *the_word_help;
2002-02-02 04:17:29 +05:30
static void reset_selection_list(void){
selection_node *old;
selection_node *walk = selection_list;
if(selection_list == (selection_node *)0xdeadbeef){
selection_list = NULL;
return;
}
while(walk){
old = walk;
walk = old->next;
free(old->u);
free(old);
}
selection_list = NULL;
}
2004-08-18 07:52:13 +05:30
// The rules:
// 1. Defaults are implementation-specific. (ioctl,termcap,guess)
// 2. COLUMNS and LINES override the defaults. (standards compliance)
// 3. Command line options override everything else.
// 4. Actual output may be more if the above is too narrow.
//
// SysV tends to spew semi-wide output in all cases. The args
// will be limited to 64 or 80 characters, without regard to
// screen size. So lines of 120 to 160 chars are normal.
// Tough luck if you want more or less than that! HP-UX has a
// new "-x" option for 1024-char args in place of comm that
// we'll implement at some point.
//
// BSD tends to make a good effort, then fall back to 80 cols.
// Use "ww" to get infinity. This is nicer for "ps | less"
// and "watch ps". It can run faster too.
2002-02-02 04:17:29 +05:30
static void set_screen_size(void){
struct winsize ws;
char *columns; /* Unix98 environment variable */
char *lines; /* Unix98 environment variable */
2004-08-18 07:52:13 +05:30
do{
int fd;
if(ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0) break;
if(ioctl(STDERR_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0) break;
if(ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != -1 && ws.ws_col>0 && ws.ws_row>0) break;
fd = open("/dev/tty", O_NOCTTY|O_NONBLOCK|O_RDONLY);
if(fd != -1){
int ret = ioctl(fd, TIOCGWINSZ, &ws);
close(fd);
if(ret != -1 && ws.ws_col>0 && ws.ws_row>0) break;
}
// TODO: ought to do tgetnum("co") and tgetnum("li") here
ws.ws_col = 80;
ws.ws_row = 24;
}while(0);
screen_cols = ws.ws_col; // hmmm, NetBSD subtracts 1
screen_rows = ws.ws_row;
// TODO: delete this line
2002-02-02 04:17:29 +05:30
if(!isatty(STDOUT_FILENO)) screen_cols = OUTBUF_SIZE;
2004-08-18 07:52:13 +05:30
2002-02-02 04:17:29 +05:30
columns = getenv("COLUMNS");
if(columns && *columns){
long t;
char *endptr;
t = strtol(columns, &endptr, 0);
if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_cols = (int)t;
}
2004-08-18 07:52:13 +05:30
2002-02-02 04:17:29 +05:30
lines = getenv("LINES");
if(lines && *lines){
long t;
char *endptr;
t = strtol(lines, &endptr, 0);
if(!*endptr && (t>0) && (t<(long)OUTBUF_SIZE)) screen_rows = (int)t;
}
2004-08-18 07:52:13 +05:30
2002-02-02 04:17:29 +05:30
if((screen_cols<9) || (screen_rows<2))
fprintf(stderr,_("your %dx%d screen size is bogus. expect trouble\n"),
2002-02-02 04:17:29 +05:30
screen_cols, screen_rows
);
}
/**************** personality control **************/
typedef struct personality_table_struct {
const char *name; /* personality name */
const void *jump; /* See gcc extension info. :-) */
} personality_table_struct;
static int compare_personality_table_structs(const void *a, const void *b){
2002-10-12 09:55:57 +05:30
return strcasecmp(((const personality_table_struct*)a)->name,((const personality_table_struct*)b)->name);
2002-02-02 04:17:29 +05:30
}
static const char *set_personality(void){
2002-10-12 09:55:57 +05:30
const char *s;
2002-02-02 04:17:29 +05:30
size_t sl;
char buf[16];
personality_table_struct findme = { buf, NULL};
personality_table_struct *found;
static const personality_table_struct personality_table[] = {
{"390", &&case_390},
{"aix", &&case_aix},
{"bsd", &&case_bsd},
{"compaq", &&case_compaq},
{"debian", &&case_debian},
{"default", &&case_default},
{"digital", &&case_digital},
{"gnu", &&case_gnu},
{"hp", &&case_hp},
{"hpux", &&case_hpux},
{"irix", &&case_irix},
{"linux", &&case_linux},
{"old", &&case_old},
{"os390", &&case_os390},
{"posix", &&case_posix},
{"s390", &&case_s390},
{"sco", &&case_sco},
{"sgi", &&case_sgi},
{"solaris2", &&case_solaris2},
{"sunos4", &&case_sunos4},
2004-04-26 06:17:31 +05:30
{"svr4", &&case_svr4},
2002-02-02 04:17:29 +05:30
{"sysv", &&case_sysv},
{"tru64", &&case_tru64},
{"unix", &&case_unix},
{"unix95", &&case_unix95},
{"unix98", &&case_unix98},
{"unknown", &&case_unknown}
};
const int personality_table_count = sizeof(personality_table)/sizeof(personality_table_struct);
personality = 0;
prefer_bsd_defaults = 0;
bsd_j_format = "OL_j";
bsd_l_format = "OL_l";
bsd_s_format = "OL_s";
bsd_u_format = "OL_u";
bsd_v_format = "OL_v";
/* When these are NULL, the code does SysV output modifier logic */
sysv_f_format = NULL;
sysv_fl_format = NULL;
sysv_j_format = NULL;
sysv_l_format = NULL;
s = getenv("PS_PERSONALITY");
if(!s || !*s) s = getenv("CMD_ENV");
if(!s || !*s) s="unknown"; /* "Do The Right Thing[tm]" */
if(getenv("I_WANT_A_BROKEN_PS")) s="old";
sl = strlen(s);
if(sl > 15) return _("environment specified an unknown personality");
2002-02-02 04:17:29 +05:30
strncpy(buf, s, sl);
buf[sl] = '\0';
if ((saved_personality_text = strdup(buf))==NULL) {
fprintf(stderr, _("cannot strdup() personality text\n"));
exit(EXIT_FAILURE);
}
2002-02-02 04:17:29 +05:30
found = bsearch(&findme, personality_table, personality_table_count,
sizeof(personality_table_struct), compare_personality_table_structs
);
if(!found) return _("environment specified an unknown personality");
2002-02-02 04:17:29 +05:30
goto *(found->jump); /* See gcc extension info. :-) */
case_bsd:
personality = PER_FORCE_BSD | PER_BSD_h | PER_BSD_m;
prefer_bsd_defaults = 1;
bsd_j_format = "FB_j";
bsd_l_format = "FB_l";
/* bsd_s_format not used */
bsd_u_format = "FB_u";
bsd_v_format = "FB_v";
return NULL;
case_old:
personality = PER_FORCE_BSD | PER_OLD_m;
prefer_bsd_defaults = 1;
return NULL;
case_debian: /* Toss this? They don't seem to care much. */
case_gnu:
personality = PER_GOOD_o | PER_OLD_m;
2002-02-02 04:17:29 +05:30
prefer_bsd_defaults = 1;
sysv_f_format = "RD_f";
/* sysv_fl_format = "RD_fl"; */ /* old Debian ps can't do this! */
2002-02-02 04:17:29 +05:30
sysv_j_format = "RD_j";
sysv_l_format = "RD_l";
return NULL;
case_linux:
personality = PER_GOOD_o | PER_ZAP_ADDR | PER_SANE_USER;
return NULL;
case_default: /* use defaults for ps, ignoring other environment variables */
case_unknown: /* defaults, but also check inferior environment variables */
return NULL;
case_aix:
bsd_j_format = "FB_j";
bsd_l_format = "FB_l";
/* bsd_s_format not used */
bsd_u_format = "FB_u";
bsd_v_format = "FB_v";
return NULL;
case_tru64:
case_compaq:
case_digital:
2004-03-27 09:25:52 +05:30
// no PER_NO_DEFAULT_g even though man page claims it
// Reality: the g is a NOP
2002-02-02 04:17:29 +05:30
personality = PER_GOOD_o | PER_BSD_h;
prefer_bsd_defaults = 1;
sysv_f_format = "F5FMT";
sysv_fl_format = "FL5FMT";
sysv_j_format = "JFMT";
sysv_l_format = "L5FMT";
bsd_j_format = "JFMT";
bsd_l_format = "LFMT";
bsd_s_format = "SFMT";
bsd_u_format = "UFMT";
bsd_v_format = "VFMT";
return NULL;
case_sunos4:
personality = PER_NO_DEFAULT_g;
prefer_bsd_defaults = 1;
bsd_j_format = "FB_j";
bsd_l_format = "FB_l";
/* bsd_s_format not used */
bsd_u_format = "FB_u";
bsd_v_format = "FB_v";
return NULL;
case_irix:
case_sgi:
s = getenv("_XPG");
if(s && s[0]>'0' && s[0]<='9')
return NULL;
personality = PER_IRIX_l;
2002-02-02 04:17:29 +05:30
return NULL;
case_os390: /* IBM's OS/390 OpenEdition on the S/390 mainframe */
case_s390:
case_390:
sysv_j_format = "J390"; /* don't know what -jl and -jf do */
return NULL;
case_hp:
case_hpux:
personality = PER_HPUX_x;
2004-04-26 06:17:31 +05:30
return NULL;
case_svr4:
case_sysv:
2002-02-02 04:17:29 +05:30
case_sco:
personality = PER_SVR4_x;
2004-04-26 06:17:31 +05:30
return NULL;
case_posix:
2002-02-02 04:17:29 +05:30
case_solaris2:
case_unix95:
case_unix98:
case_unix:
return NULL;
}
/************ Call this to reinitialize everything ***************/
void reset_global(void){
static proc_t p;
reset_selection_list();
look_up_our_self(&p);
set_screen_size();
set_personality();
2002-02-02 04:17:29 +05:30
all_processes = 0;
bsd_c_option = 0;
bsd_e_option = 0;
cached_euid = geteuid();
cached_tty = p.tty;
/* forest_prefix must be all zero because of POSIX */
forest_type = 0;
format_flags = 0; /* -l -f l u s -j... */
format_list = NULL; /* digested formatting options */
format_modifiers = 0; /* -c -j -y -P -L... */
header_gap = -1; /* send lines_to_next_header to -infinity */
header_type = HEAD_SINGLE;
include_dead_children = 0;
lines_to_next_header = 1;
negate_selection = 0;
2002-11-27 05:54:01 +05:30
page_size = getpagesize();
2002-02-02 04:17:29 +05:30
running_only = 0;
seconds_since_boot = uptime(0,0);
selection_list = NULL;
simple_select = 0;
sort_list = NULL;
2003-09-20 13:59:55 +05:30
thread_flags = 0;
2002-02-02 04:17:29 +05:30
unix_f_option = 0;
user_is_number = 0;
wchan_is_number = 0;
/* Translation Note:
. The following translatable word will be used to recognize the
. user's request for help text. In other words, the translation
. you provide will alter program behavior.
.
. It must be limited to 15 characters or less.
*/
the_word_help = _("help");
2002-02-02 04:17:29 +05:30
}
2003-01-22 14:01:50 +05:30
static const char archdefs[] =
#ifdef __alpha__
" alpha"
#endif
#ifdef __arm__
" arm"
#endif
#ifdef __hppa__
" hppa"
#endif
#ifdef __i386__
" i386"
#endif
#ifdef __ia64__
" ia64"
#endif
#ifdef __mc68000__
" mc68000"
#endif
#ifdef __mips64__
" mips64"
#endif
#ifdef __mips__
" mips"
#endif
#ifdef __powerpc__
" powerpc"
#endif
#ifdef __sh3__
" sh3"
#endif
#ifdef __sh__
" sh"
#endif
#ifdef __sparc__
" sparc"
#endif
#ifdef __sparc_v9__
" sparc_v9"
#endif
#ifdef __x86_64__
" x86_64"
#endif
"";
2002-02-02 04:17:29 +05:30
/*********** spew variables ***********/
void self_info(void){
int linux_version_code = procps_linux_version();
2002-02-02 04:17:29 +05:30
fprintf(stderr,
"BSD j %s\n"
"BSD l %s\n"
"BSD s %s\n"
"BSD u %s\n"
"BSD v %s\n"
"SysV -f %s\n"
"SysV -fl %s\n"
"SysV -j %s\n"
"SysV -l %s\n"
"\n",
bsd_j_format ? bsd_j_format : "(none)",
bsd_l_format ? bsd_l_format : "(none)",
bsd_s_format ? bsd_s_format : "(none)",
bsd_u_format ? bsd_u_format : "(none)",
bsd_v_format ? bsd_v_format : "(none)",
sysv_f_format ? sysv_f_format : "(none)",
sysv_fl_format ? sysv_fl_format : "(none)",
sysv_j_format ? sysv_j_format : "(none)",
sysv_l_format ? sysv_l_format : "(none)"
);
fprintf(stderr, "%s version %s\n", PACKAGE_NAME, PACKAGE_VERSION);
fprintf(stderr, "Linux version %d.%d.%d\n",
2002-02-02 04:17:29 +05:30
LINUX_VERSION_MAJOR(linux_version_code),
LINUX_VERSION_MINOR(linux_version_code),
LINUX_VERSION_PATCH(linux_version_code)
);
/* __libc_print_version(); */ /* how can we get the run-time version? */
fprintf(stderr, "Compiled with: glibc %d.%d, gcc %d.%d\n\n",
2003-01-22 14:01:50 +05:30
__GLIBC__, __GLIBC_MINOR__, __GNUC__, __GNUC_MINOR__
2002-02-02 04:17:29 +05:30
);
fprintf(stderr,
"header_gap=%d lines_to_next_header=%d\n"
"screen_cols=%d screen_rows=%d\n"
"\n",
2002-02-02 04:17:29 +05:30
header_gap, lines_to_next_header,
screen_cols, screen_rows
);
fprintf(stderr,
"personality=0x%08x (from \"%s\")\n"
"EUID=%d TTY=%d,%d Hertz=%lld page_size=%d\n",
2002-02-02 04:17:29 +05:30
personality, saved_personality_text,
2002-11-27 05:54:01 +05:30
cached_euid, (int)major(cached_tty), (int)minor(cached_tty), Hertz,
(int)(page_size)
2002-02-02 04:17:29 +05:30
);
2002-11-27 05:54:01 +05:30
2003-01-22 14:01:50 +05:30
fprintf(stderr,
"sizeof(proc_t)=%d sizeof(long)=%d sizeof(KLONG)=%d\n",
2003-01-22 14:01:50 +05:30
(int)sizeof(proc_t), (int)sizeof(long), (int)sizeof(KLONG)
);
fprintf(stderr, "archdefs:%s\n", archdefs);
2002-02-02 04:17:29 +05:30
}
void __attribute__ ((__noreturn__))
catastrophic_failure(const char *filename,
unsigned int linenum,
const char *message)
{
error_at_line(0, 0, filename, linenum, "%s", message);
exit(EXIT_FAILURE);
}