7b0fc19e9d
Library Changes . added PROC_EDITCMDLCVT flag . added an internal (static) fill_cmdline_cvt function: - reads and "escapes" /proc/#/cmdline - returns result as a single string in a single vector - callers are guaranteed a cmdline (no more NULL) . added vectorize_this_str function, exploited by fill_cgroup_cvt, fill_cmdline_cvt . generalized read_cmdline function as read_unvectored, now exploited by fill_cgroup_cvt, fill_cmdline_cvt, read_cmdline ( cgroup and cmdline no longer need be converted to string ) ( vectors before being transformed to final representation ) . fixed bug regarding skipped group numbers (when enabled) . escape_str made responsible for all single byte translation with distinction between control chars + other unprintable . added escaped_copy function for already escaped strings . reorganized parts of proc_t to restore formatting standards ( displacement changes shouldn't matter with new version # ) . former ZAP_SUSEONLY #define now OOMEM_ENABLE . added to library.map: escaped_copy; read_cmdline Top Program Changes . exploited the new PROC_EDITCMDLCVT provision . eliminated now obsolete #include "proc/escape.h" . changed the P_WCH display format if no kernel symbol table . fixed very old bug in lflgs for out-of-view sort fields . former ZAP_SUSEONLY #define now OOMEM_ENABLE Ps Program Changes . exploited the new PROC_EDITCMDLCVT provision . exploited the new escaped_copy function . consolidated pr_args and pr_comm into pr_argcom Signed-off-by: Jan Görig <jgorig@redhat.com>
600 lines
18 KiB
C
600 lines
18 KiB
C
/*
|
|
* Copyright 1998-2003 by Albert Cahalan; all rights resered.
|
|
* This file may be used subject to the terms and conditions of the
|
|
* GNU Library General Public License Version 2, or any later version
|
|
* at your option, as published by the Free Software Foundation.
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU Library General Public License for more details.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
|
|
#if (__GNU_LIBRARY__ >= 6)
|
|
# include <locale.h>
|
|
#endif
|
|
|
|
/* username lookups */
|
|
#include <sys/types.h>
|
|
#include <pwd.h>
|
|
#include <grp.h>
|
|
|
|
/* major/minor number */
|
|
#include <sys/sysmacros.h>
|
|
|
|
#include <signal.h> /* catch signals */
|
|
|
|
#include "common.h"
|
|
#include "../proc/wchan.h"
|
|
#include "../proc/version.h"
|
|
#include "../proc/readproc.h"
|
|
#include "../proc/sysinfo.h"
|
|
#include "../proc/sig.h"
|
|
|
|
#ifndef SIGCHLD
|
|
#define SIGCHLD SIGCLD
|
|
#endif
|
|
|
|
/* just reports a crash */
|
|
static void signal_handler(int signo){
|
|
if(signo==SIGPIPE) _exit(0); /* "ps | head" will cause this */
|
|
/* fprintf() is not reentrant, but we _exit() anyway */
|
|
fprintf(stderr,
|
|
"\n\n"
|
|
"Signal %d (%s) caught by ps (%s).\n"
|
|
"Please send bug reports to <feedback@lists.sf.net> or <albert@users.sf.net>\n",
|
|
signo,
|
|
signal_number_to_name(signo),
|
|
procps_version
|
|
);
|
|
_exit(signo+128);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////////
|
|
#undef DEBUG
|
|
#ifdef DEBUG
|
|
void init_stack_trace(char *prog_name);
|
|
|
|
#include <ctype.h>
|
|
|
|
void hex_dump(void *vp){
|
|
char *charlist;
|
|
int i = 0;
|
|
int line = 45;
|
|
char *cp = (char *)vp;
|
|
|
|
while(line--){
|
|
printf("%8lx ", (unsigned long)cp);
|
|
charlist = cp;
|
|
cp += 16;
|
|
for(i=0; i<16; i++){
|
|
if((charlist[i]>31) && (charlist[i]<127)){
|
|
printf("%c", charlist[i]);
|
|
}else{
|
|
printf(".");
|
|
}
|
|
}
|
|
printf(" ");
|
|
for(i=0; i<16; i++) printf(" %2x",(unsigned int)((unsigned char)(charlist[i])));
|
|
printf("\n");
|
|
i=0;
|
|
}
|
|
}
|
|
|
|
static void show_tgid(char *s, int n, sel_union *data){
|
|
printf("%s ", s);
|
|
while(--n){
|
|
printf("%d,", data[n].tgid);
|
|
}
|
|
printf("%d\n", data[0].tgid);
|
|
}
|
|
|
|
static void show_uid(char *s, int n, sel_union *data){
|
|
struct passwd *pw_data;
|
|
printf("%s ", s);
|
|
while(--n){
|
|
pw_data = getpwuid(data[n].uid);
|
|
if(pw_data) printf("%s,", pw_data->pw_name);
|
|
else printf("%d,", data[n].uid);
|
|
}
|
|
pw_data = getpwuid(data[n].uid);
|
|
if(pw_data) printf("%s\n", pw_data->pw_name);
|
|
else printf("%d\n", data[n].uid);
|
|
}
|
|
|
|
static void show_gid(char *s, int n, sel_union *data){
|
|
struct group *gr_data;
|
|
printf("%s ", s);
|
|
while(--n){
|
|
gr_data = getgrgid(data[n].gid);
|
|
if(gr_data) printf("%s,", gr_data->gr_name);
|
|
else printf("%d,", data[n].gid);
|
|
}
|
|
gr_data = getgrgid(data[n].gid);
|
|
if(gr_data) printf("%s\n", gr_data->gr_name);
|
|
else printf("%d\n", data[n].gid);
|
|
}
|
|
|
|
static void show_tty(char *s, int n, sel_union *data){
|
|
printf("%s ", s);
|
|
while(--n){
|
|
printf("%d:%d,", (int)major(data[n].tty), (int)minor(data[n].tty));
|
|
}
|
|
printf("%d:%d\n", (int)major(data[n].tty), (int)minor(data[n].tty));
|
|
}
|
|
|
|
static void show_cmd(char *s, int n, sel_union *data){
|
|
printf("%s ", s);
|
|
while(--n){
|
|
printf("%.8s,", data[n].cmd);
|
|
}
|
|
printf("%.8s\n", data[0].cmd);
|
|
}
|
|
|
|
static void arg_show(void){
|
|
selection_node *walk = selection_list;
|
|
while(walk){
|
|
switch(walk->typecode){
|
|
case SEL_RUID: show_uid("RUID", walk->n, walk->u); break;
|
|
case SEL_EUID: show_uid("EUID", walk->n, walk->u); break;
|
|
case SEL_SUID: show_uid("SUID", walk->n, walk->u); break;
|
|
case SEL_FUID: show_uid("FUID", walk->n, walk->u); break;
|
|
case SEL_RGID: show_gid("RGID", walk->n, walk->u); break;
|
|
case SEL_EGID: show_gid("EGID", walk->n, walk->u); break;
|
|
case SEL_SGID: show_gid("SGID", walk->n, walk->u); break;
|
|
case SEL_FGID: show_gid("FGID", walk->n, walk->u); break;
|
|
case SEL_PGRP: show_pid("PGRP", walk->n, walk->u); break;
|
|
case SEL_PID : show_pid("PID ", walk->n, walk->u); break;
|
|
case SEL_PPID: show_pid("PPID", walk->n, walk->u); break;
|
|
case SEL_TTY : show_tty("TTY ", walk->n, walk->u); break;
|
|
case SEL_SESS: show_pid("SESS", walk->n, walk->u); break;
|
|
case SEL_COMM: show_cmd("COMM", walk->n, walk->u); break;
|
|
default: printf("Garbage typecode value!\n");
|
|
}
|
|
walk = walk->next;
|
|
}
|
|
}
|
|
|
|
#endif
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
/***** check the header */
|
|
/* Unix98: must not print empty header */
|
|
static void check_headers(void){
|
|
format_node *walk = format_list;
|
|
int head_normal = 0;
|
|
if(header_type==HEAD_MULTI){
|
|
header_gap = screen_rows-1; /* true BSD */
|
|
return;
|
|
}
|
|
if(header_type==HEAD_NONE){
|
|
lines_to_next_header = -1; /* old Linux */
|
|
return;
|
|
}
|
|
while(walk){
|
|
if(!*(walk->name)){
|
|
walk = walk->next;
|
|
continue;
|
|
}
|
|
if(walk->pr){
|
|
head_normal++;
|
|
walk = walk->next;
|
|
continue;
|
|
}
|
|
walk = walk->next;
|
|
}
|
|
if(!head_normal) lines_to_next_header = -1; /* how UNIX does --noheader */
|
|
}
|
|
|
|
/***** check sort needs */
|
|
/* see what files need to be read, etc. */
|
|
static unsigned check_sort_needs(sort_node *walk){
|
|
unsigned needs = 0;
|
|
while(walk){
|
|
needs |= walk->need;
|
|
walk = walk->next;
|
|
}
|
|
return needs;
|
|
}
|
|
|
|
/***** check needs */
|
|
/* see what files need to be read, etc. */
|
|
static unsigned collect_format_needs(format_node *walk){
|
|
unsigned needs = 0;
|
|
while(walk){
|
|
needs |= walk->need;
|
|
walk = walk->next;
|
|
}
|
|
return needs;
|
|
}
|
|
|
|
static format_node *proc_format_list;
|
|
static format_node *task_format_list;
|
|
|
|
static unsigned needs_for_threads;
|
|
static unsigned needs_for_sort;
|
|
static unsigned proc_format_needs;
|
|
static unsigned task_format_needs;
|
|
|
|
#define needs_for_format (proc_format_needs|task_format_needs)
|
|
|
|
#define PROC_ONLY_FLAGS (PROC_FILLENV|PROC_FILLARG|PROC_FILLCOM|PROC_FILLMEM|PROC_FILLCGROUP)
|
|
|
|
/***** munge lists and determine openproc() flags */
|
|
static void lists_and_needs(void){
|
|
check_headers();
|
|
|
|
// only care about the difference when showing both
|
|
if(thread_flags & TF_show_both){
|
|
format_node pfn, tfn; // junk, to handle special case at begin of list
|
|
format_node *walk = format_list;
|
|
format_node *p_end = &pfn;
|
|
format_node *t_end = &tfn;
|
|
while(walk){
|
|
format_node *new = malloc(sizeof(format_node));
|
|
memcpy(new,walk,sizeof(format_node));
|
|
p_end->next = walk;
|
|
t_end->next = new;
|
|
p_end = walk;
|
|
t_end = new;
|
|
switch(walk->flags & CF_PRINT_MASK){
|
|
case CF_PRINT_THREAD_ONLY:
|
|
p_end->pr = pr_nop;
|
|
p_end->need = 0;
|
|
break;
|
|
case CF_PRINT_PROCESS_ONLY:
|
|
t_end->pr = pr_nop;
|
|
t_end->need = 0;
|
|
break;
|
|
default:
|
|
fprintf(stderr, "please report this bug\n");
|
|
// FALL THROUGH
|
|
case CF_PRINT_AS_NEEDED:
|
|
case CF_PRINT_EVERY_TIME:
|
|
break;
|
|
}
|
|
walk = walk->next;
|
|
}
|
|
t_end->next = NULL;
|
|
p_end->next = NULL;
|
|
proc_format_list = pfn.next;
|
|
task_format_list = tfn.next;
|
|
}else{
|
|
proc_format_list = format_list;
|
|
task_format_list = format_list;
|
|
}
|
|
|
|
proc_format_needs = collect_format_needs(proc_format_list);
|
|
task_format_needs = collect_format_needs(task_format_list);
|
|
|
|
needs_for_sort = check_sort_needs(sort_list);
|
|
|
|
// move process-only flags to the process
|
|
proc_format_needs |= (task_format_needs &~ PROC_ONLY_FLAGS);
|
|
task_format_needs &= ~PROC_ONLY_FLAGS;
|
|
|
|
if(bsd_c_option){
|
|
proc_format_needs &= ~PROC_FILLARG;
|
|
needs_for_sort &= ~PROC_FILLARG;
|
|
}
|
|
if(!unix_f_option){
|
|
proc_format_needs &= ~PROC_FILLCOM;
|
|
proc_format_needs |= PROC_EDITCMDLCVT;
|
|
needs_for_sort &= ~PROC_FILLCOM;
|
|
}
|
|
// convert ARG to COM as a standard
|
|
if(proc_format_needs & PROC_FILLARG){
|
|
proc_format_needs |= (PROC_FILLCOM | PROC_EDITCMDLCVT);
|
|
proc_format_needs &= ~PROC_FILLARG;
|
|
}
|
|
if(bsd_e_option){
|
|
if(proc_format_needs&PROC_FILLCOM) proc_format_needs |= PROC_FILLENV;
|
|
}
|
|
|
|
/* FIXME broken filthy hack -- got to unify some stuff here */
|
|
if( ( (proc_format_needs|task_format_needs|needs_for_sort) & PROC_FILLWCHAN) && !wchan_is_number)
|
|
if (open_psdb(namelist_file)) wchan_is_number = 1;
|
|
|
|
if(thread_flags&TF_loose_tasks) needs_for_threads |= PROC_LOOSE_TASKS;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
/***** fill in %CPU; not in libproc because of include_dead_children */
|
|
/* Note: for sorting, not display, so 0..0x7fffffff would be OK */
|
|
static int want_this_proc_pcpu(proc_t *buf){
|
|
unsigned long long used_jiffies;
|
|
unsigned long pcpu = 0;
|
|
unsigned long long avail_jiffies;
|
|
|
|
if(!want_this_proc(buf)) return 0;
|
|
|
|
used_jiffies = buf->utime + buf->stime;
|
|
if(include_dead_children) used_jiffies += (buf->cutime + buf->cstime);
|
|
|
|
avail_jiffies = seconds_since_boot * Hertz - buf->start_time;
|
|
if(avail_jiffies) pcpu = (used_jiffies << 24) / avail_jiffies;
|
|
|
|
buf->pcpu = pcpu; // fits in an int, summing children on 128 CPUs
|
|
|
|
return 1;
|
|
}
|
|
|
|
/***** just display */
|
|
static void simple_spew(void){
|
|
proc_t buf;
|
|
PROCTAB* ptp;
|
|
ptp = openproc(needs_for_format | needs_for_sort | needs_for_select | needs_for_threads);
|
|
if(!ptp) {
|
|
fprintf(stderr, "Error: can not access /proc.\n");
|
|
exit(1);
|
|
}
|
|
memset(&buf, '#', sizeof(proc_t));
|
|
switch(thread_flags & (TF_show_proc|TF_loose_tasks|TF_show_task)){
|
|
case TF_show_proc: // normal non-thread output
|
|
while(readproc(ptp,&buf)){
|
|
if(want_this_proc(&buf)){
|
|
show_one_proc(&buf, proc_format_list);
|
|
}
|
|
if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse
|
|
if(buf.environ) free((void*)*buf.environ); // ought to reuse
|
|
if(buf.cgroup) free((void*)*buf.cgroup);
|
|
}
|
|
break;
|
|
case TF_show_proc|TF_loose_tasks: // H option
|
|
while(readproc(ptp,&buf)){
|
|
proc_t buf2;
|
|
// must still have the process allocated
|
|
while(readtask(ptp,&buf,&buf2)){
|
|
if(!want_this_proc(&buf)) continue;
|
|
show_one_proc(&buf2, task_format_list);
|
|
}
|
|
if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse
|
|
if(buf.environ) free((void*)*buf.environ); // ought to reuse
|
|
if(buf.cgroup) free((void*)*buf.cgroup);
|
|
}
|
|
break;
|
|
case TF_show_proc|TF_show_task: // m and -m options
|
|
while(readproc(ptp,&buf)){
|
|
if(want_this_proc(&buf)){
|
|
proc_t buf2;
|
|
show_one_proc(&buf, proc_format_list);
|
|
// must still have the process allocated
|
|
while(readtask(ptp,&buf,&buf2)) show_one_proc(&buf2, task_format_list);
|
|
}
|
|
if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse
|
|
if(buf.environ) free((void*)*buf.environ); // ought to reuse
|
|
if(buf.cgroup) free((void*)*buf.cgroup);
|
|
}
|
|
break;
|
|
case TF_show_task: // -L and -T options
|
|
while(readproc(ptp,&buf)){
|
|
if(want_this_proc(&buf)){
|
|
proc_t buf2;
|
|
// must still have the process allocated
|
|
while(readtask(ptp,&buf,&buf2)) show_one_proc(&buf2, task_format_list);
|
|
}
|
|
if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse
|
|
if(buf.environ) free((void*)*buf.environ); // ought to reuse
|
|
if(buf.cgroup) free((void*)*buf.cgroup);
|
|
}
|
|
break;
|
|
}
|
|
closeproc(ptp);
|
|
}
|
|
|
|
/***** forest output requires sorting by ppid; add start_time by default */
|
|
static void prep_forest_sort(void){
|
|
sort_node *tmp_list = sort_list;
|
|
const format_struct *incoming;
|
|
|
|
if(!sort_list) { /* assume start time order */
|
|
incoming = search_format_array("start_time");
|
|
if(!incoming) fprintf(stderr, "Could not find start_time!\n");
|
|
tmp_list = malloc(sizeof(sort_node));
|
|
tmp_list->reverse = 0;
|
|
tmp_list->typecode = '?'; /* what was this for? */
|
|
tmp_list->sr = incoming->sr;
|
|
tmp_list->need = incoming->need;
|
|
tmp_list->next = sort_list;
|
|
sort_list = tmp_list;
|
|
}
|
|
/* this is required for the forest option */
|
|
incoming = search_format_array("ppid");
|
|
if(!incoming) fprintf(stderr, "Could not find ppid!\n");
|
|
tmp_list = malloc(sizeof(sort_node));
|
|
tmp_list->reverse = 0;
|
|
tmp_list->typecode = '?'; /* what was this for? */
|
|
tmp_list->sr = incoming->sr;
|
|
tmp_list->need = incoming->need;
|
|
tmp_list->next = sort_list;
|
|
sort_list = tmp_list;
|
|
}
|
|
|
|
/* we rely on the POSIX requirement for zeroed memory */
|
|
//static proc_t *processes[98*1024]; // FIXME
|
|
static proc_t **processes;
|
|
|
|
/***** compare function for qsort */
|
|
static int compare_two_procs(const void *a, const void *b){
|
|
sort_node *tmp_list = sort_list;
|
|
while(tmp_list){
|
|
int result;
|
|
result = (*tmp_list->sr)(*(const proc_t *const*)a, *(const proc_t *const*)b);
|
|
if(result) return (tmp_list->reverse) ? -result : result;
|
|
tmp_list = tmp_list->next;
|
|
}
|
|
return 0; /* no conclusion */
|
|
}
|
|
|
|
/***** show pre-sorted array of process pointers */
|
|
static void show_proc_array(PROCTAB *restrict ptp, int n){
|
|
proc_t **p = processes;
|
|
while(n--){
|
|
if(thread_flags & TF_show_proc) show_one_proc(*p, proc_format_list);
|
|
if(thread_flags & TF_show_task){
|
|
proc_t buf2;
|
|
// must still have the process allocated
|
|
while(readtask(ptp,*p,&buf2)) show_one_proc(&buf2, task_format_list);
|
|
// must not attempt to free cmdline and environ
|
|
}
|
|
/* no point freeing any of this -- won't need more mem */
|
|
// if((*p)->cmdline) free((void*)*(*p)->cmdline);
|
|
// if((*p)->environ) free((void*)*(*p)->environ);
|
|
// memset(*p, '%', sizeof(proc_t)); /* debug */
|
|
// free(*p);
|
|
p++;
|
|
}
|
|
}
|
|
|
|
/***** show tree */
|
|
/* this needs some optimization work */
|
|
#define ADOPTED(x) 1
|
|
static void show_tree(const int self, const int n, const int level, const int have_sibling){
|
|
int i = 0;
|
|
if(level){
|
|
/* add prefix of "+" or "L" */
|
|
if(have_sibling) forest_prefix[level-1] = '+';
|
|
else forest_prefix[level-1] = 'L';
|
|
forest_prefix[level] = '\0';
|
|
}
|
|
show_one_proc(processes[self],format_list); /* first show self */
|
|
/* no point freeing any of this -- won't need more mem */
|
|
// if(processes[self]->cmdline) free((void*)*processes[self]->cmdline);
|
|
// if(processes[self]->environ) free((void*)*processes[self]->environ);
|
|
for(;;){ /* look for children */
|
|
if(i >= n) return; /* no children */
|
|
if(processes[i]->ppid == processes[self]->XXXID) break;
|
|
i++;
|
|
}
|
|
if(level){
|
|
/* change our prefix to "|" or " " for the children */
|
|
if(have_sibling) forest_prefix[level-1] = '|';
|
|
else forest_prefix[level-1] = ' ';
|
|
forest_prefix[level] = '\0';
|
|
}
|
|
for(;;){
|
|
int self_pid;
|
|
int more_children = 1;
|
|
if(i >= n) break; /* over the edge */
|
|
self_pid=processes[self]->XXXID;
|
|
if(i+1 >= n)
|
|
more_children = 0;
|
|
else
|
|
if(processes[i+1]->ppid != self_pid) more_children = 0;
|
|
if(self_pid==1 && ADOPTED(processes[i]) && forest_type!='u')
|
|
show_tree(i++, n, level, more_children);
|
|
else
|
|
show_tree(i++, n, level+1, more_children);
|
|
if(!more_children) break;
|
|
}
|
|
/* chop prefix that children added -- do we need this? */
|
|
forest_prefix[level] = '\0';
|
|
// memset(processes[self], '$', sizeof(proc_t)); /* debug */
|
|
}
|
|
|
|
/***** show forest */
|
|
static void show_forest(const int n){
|
|
int i = n;
|
|
int j;
|
|
while(i--){ /* cover whole array looking for trees */
|
|
j = n;
|
|
while(j--){ /* search for parent: if none, i is a tree! */
|
|
if(processes[j]->XXXID == processes[i]->ppid) goto not_root;
|
|
}
|
|
show_tree(i,n,0,0);
|
|
not_root:
|
|
;
|
|
}
|
|
/* don't free the array because it takes time and ps will exit anyway */
|
|
}
|
|
|
|
static int want_this_proc_nop(proc_t *dummy){
|
|
(void)dummy;
|
|
return 1;
|
|
}
|
|
|
|
/***** sorted or forest */
|
|
static void fancy_spew(void){
|
|
proc_data_t *pd = NULL;
|
|
PROCTAB *restrict ptp;
|
|
int n = 0; /* number of processes & index into array */
|
|
|
|
ptp = openproc(needs_for_format | needs_for_sort | needs_for_select | needs_for_threads);
|
|
if(!ptp) {
|
|
fprintf(stderr, "Error: can not access /proc.\n");
|
|
exit(1);
|
|
}
|
|
|
|
if(thread_flags & TF_loose_tasks){
|
|
pd = readproctab2(want_this_proc_nop, want_this_proc_pcpu, ptp);
|
|
}else{
|
|
pd = readproctab2(want_this_proc_pcpu, (void*)0xdeadbeaful, ptp);
|
|
}
|
|
n = pd->n;
|
|
processes = pd->tab;
|
|
|
|
if(!n) return; /* no processes */
|
|
if(forest_type) prep_forest_sort();
|
|
qsort(processes, n, sizeof(proc_t*), compare_two_procs);
|
|
if(forest_type) show_forest(n);
|
|
else show_proc_array(ptp,n);
|
|
closeproc(ptp);
|
|
}
|
|
|
|
|
|
/***** no comment */
|
|
int main(int argc, char *argv[]){
|
|
#if (__GNU_LIBRARY__ >= 6)
|
|
setlocale (LC_CTYPE, "");
|
|
#endif
|
|
|
|
#ifdef DEBUG
|
|
init_stack_trace(argv[0]);
|
|
#else
|
|
do {
|
|
struct sigaction sa;
|
|
int i = 32;
|
|
memset(&sa, 0, sizeof(sa));
|
|
sa.sa_handler = signal_handler;
|
|
sigfillset(&sa.sa_mask);
|
|
while(i--) switch(i){
|
|
default:
|
|
sigaction(i,&sa,NULL);
|
|
case 0:
|
|
case SIGINT: /* ^C */
|
|
case SIGTSTP: /* ^Z */
|
|
case SIGTTOU: /* see stty(1) man page */
|
|
case SIGQUIT: /* ^\ */
|
|
case SIGPROF: /* profiling */
|
|
case SIGKILL: /* can not catch */
|
|
case SIGSTOP: /* can not catch */
|
|
case SIGWINCH: /* don't care if window size changes */
|
|
;
|
|
}
|
|
} while (0);
|
|
#endif
|
|
|
|
reset_global(); /* must be before parser */
|
|
arg_parse(argc,argv);
|
|
|
|
/* arg_show(); */
|
|
trace("screen is %ux%u\n",screen_cols,screen_rows);
|
|
/* printf("sizeof(proc_t) is %d.\n", sizeof(proc_t)); */
|
|
trace("======= ps output follows =======\n");
|
|
|
|
init_output(); /* must be between parser and output */
|
|
|
|
lists_and_needs();
|
|
|
|
if(forest_type || sort_list) fancy_spew(); /* sort or forest */
|
|
else simple_spew(); /* no sort, no forest */
|
|
show_one_proc((proc_t *)-1,format_list); /* no output yet? */
|
|
return 0;
|
|
}
|