From 3a16c12ce38305c819cc1c904abaa85504de0643 Mon Sep 17 00:00:00 2001 From: albert <> Date: Tue, 7 Oct 2003 03:12:50 +0000 Subject: [PATCH] top on wyse60, whitespace doc, thread fixes --- NEWS | 1 + proc/readproc.h | 32 +++++++------ ps/common.h | 9 +++- ps/display.c | 22 ++++++--- ps/output.c | 6 +-- ps/parser.c | 49 ++++++++++++------- ps/ps.1 | 13 ++++- ps/sortformat.c | 124 ++++++++++++++++++++++++++++-------------------- top.c | 26 ++++++++-- 9 files changed, 181 insertions(+), 101 deletions(-) diff --git a/NEWS b/NEWS index ff87c19b..a6a1910a 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,6 @@ procps-3.1.13 --> procps-3.1.14 +top: displays on more genuine serial terminals handle 32-bit dev_t of Linux 2.6 ps: finally, m and -m satisfy the original design ps: distinct per-thread and whole-process pending signals diff --git a/proc/readproc.h b/proc/readproc.h index 0b97c385..997d6a9c 100644 --- a/proc/readproc.h +++ b/proc/readproc.h @@ -210,25 +210,27 @@ extern void freeproc(proc_t* p); // argument is the length of the list (currently only used for lists of user // id's since uid_t supports no convenient termination sentinel.) -#define PROC_FILLMEM 0x0001 // read statm -#define PROC_FILLCOM 0x0002 // alloc and fill in `cmdline' -#define PROC_FILLENV 0x0004 // alloc and fill in `environ' -#define PROC_FILLUSR 0x0008 // resolve user id number -> user name -#define PROC_FILLGRP 0x0010 // resolve group id number -> group name -#define PROC_FILLSTATUS 0x0020 // read status -- currently unconditional -#define PROC_FILLSTAT 0x0040 // read stat -- currently unconditional -#define PROC_FILLWCHAN 0x0080 // look up WCHAN name -#define PROC_FILLARG 0x0100 // alloc and fill in `cmdline' +#define PROC_FILLMEM 0x0001 // read statm +#define PROC_FILLCOM 0x0002 // alloc and fill in `cmdline' +#define PROC_FILLENV 0x0004 // alloc and fill in `environ' +#define PROC_FILLUSR 0x0008 // resolve user id number -> user name +#define PROC_FILLGRP 0x0010 // resolve group id number -> group name +#define PROC_FILLSTATUS 0x0020 // read status -- currently unconditional +#define PROC_FILLSTAT 0x0040 // read stat -- currently unconditional +#define PROC_FILLWCHAN 0x0080 // look up WCHAN name +#define PROC_FILLARG 0x0100 // alloc and fill in `cmdline' + +#define PROC_LOOSE_TASKS 0x0200 // threat threads as if they were processes // Obsolete, consider only processes with one of the passed: -#define PROC_PID 0x1000 // process id numbers ( 0 terminated) -#define PROC_UID 0x4000 // user id numbers ( length needed ) +#define PROC_PID 0x1000 // process id numbers ( 0 terminated) +#define PROC_UID 0x4000 // user id numbers ( length needed ) // it helps to give app code a few spare bits -#define PROC_SPARE_1 0x01000000 -#define PROC_SPARE_2 0x02000000 -#define PROC_SPARE_3 0x04000000 -#define PROC_SPARE_4 0x08000000 +#define PROC_SPARE_1 0x01000000 +#define PROC_SPARE_2 0x02000000 +#define PROC_SPARE_3 0x04000000 +#define PROC_SPARE_4 0x08000000 EXTERN_C_END #endif diff --git a/ps/common.h b/ps/common.h index d8f63152..580d5945 100644 --- a/ps/common.h +++ b/ps/common.h @@ -101,6 +101,11 @@ #define TF_U_L 0x0010 #define TF_show_proc 0x0100 // show the summary line #define TF_show_task 0x0200 // show the per-thread lines +#define TF_show_both 0x0400 // distinct proc/task format lists +#define TF_loose_tasks 0x0800 // let sorting break up task groups (BSDish) +#define TF_no_sort 0x1000 // don't know if thread-grouping should survive a sort +#define TF_no_forest 0x2000 // don't see how to do threads w/ forest option +#define TF_must_use 0x4000 // options only make sense if LWP/SPID column added /* personality control flags */ #define PER_BROKEN_o 0x0001 @@ -140,10 +145,10 @@ #define FM_c 0x0001 /* -c */ #define FM_j 0x0002 /* -j */ /* only set when !sysv_j_format */ #define FM_y 0x0004 /* -y */ -#define FM_L 0x0008 /* -L */ +//#define FM_L 0x0008 /* -L */ #define FM_P 0x0010 /* -P */ #define FM_M 0x0020 /* -M */ -#define FM_T 0x0040 /* -T */ +//#define FM_T 0x0040 /* -T */ #define FM_F 0x0080 /* -F */ /* -F also sets the regular -f flags */ /* sorting & formatting */ diff --git a/ps/display.c b/ps/display.c index e39f9a3b..8d5e30d8 100644 --- a/ps/display.c +++ b/ps/display.c @@ -212,6 +212,7 @@ static unsigned collect_format_needs(format_node *walk){ 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; @@ -225,7 +226,7 @@ static void lists_and_needs(void){ check_headers(); // only care about the difference when showing both - if( (thread_flags & (TF_show_proc|TF_show_task)) == (TF_show_proc|TF_show_task) ){ + 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; @@ -293,6 +294,8 @@ static void lists_and_needs(void){ /* 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; } ////////////////////////////////////////////////////////////////////////// @@ -317,12 +320,11 @@ static void fill_pcpu(proc_t *buf){ static void simple_spew(void){ proc_t buf; PROCTAB* ptp; - ptp = openproc(needs_for_format | needs_for_sort | needs_for_select); + 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) thread_flags=TF_show_proc; memset(&buf, '#', sizeof(proc_t)); while(readproc(ptp,&buf)){ if(want_this_proc(&buf)){ @@ -385,10 +387,16 @@ static int compare_two_procs(const void *a, const void *b){ } /***** show pre-sorted array of process pointers */ -static void show_proc_array(int n){ +static void show_proc_array(PROCTAB *restrict ptp, int n){ proc_t **p = processes; while(n--){ - show_one_proc(*p,format_list); + 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); @@ -469,7 +477,7 @@ static void fancy_spew(void){ fprintf(stderr, "can't have threads with sorting or forest output\n"); exit(49); } - ptp = openproc(needs_for_format | needs_for_sort | needs_for_select); + 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); @@ -487,7 +495,7 @@ static void fancy_spew(void){ 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(n); + else show_proc_array(ptp,n); } diff --git a/ps/output.c b/ps/output.c index 3ce71613..f5f45e2a 100644 --- a/ps/output.c +++ b/ps/output.c @@ -1323,11 +1323,11 @@ static const format_struct format_array[] = { {"timeout", "TMOUT", pr_timeout, sr_timeout, 5, 0, LNX, AN|RIGHT}, {"tmout", "TMOUT", pr_timeout, sr_timeout, 5, 0, LNX, AN|RIGHT}, {"tname", "TTY", pr_tty8, sr_tty, 8, 0, DEC, PO|LEFT}, -{"tpgid", "TPGID", pr_tpgid, sr_tpgid, 5, 0, XXX, AN|PIDMAX|RIGHT}, +{"tpgid", "TPGID", pr_tpgid, sr_tpgid, 5, 0, XXX, PO|PIDMAX|RIGHT}, {"trs", "TRS", pr_trs, sr_trs, 4, MEM, AIX, PO|RIGHT}, {"trss", "TRSS", pr_trs, sr_trs, 4, MEM, BSD, PO|RIGHT}, /* 4.3BSD NET/2 */ -{"tsess", "TSESS", pr_nop, sr_nop, 5, 0, BSD, AN|PIDMAX|RIGHT}, -{"tsession", "TSESS", pr_nop, sr_nop, 5, 0, DEC, AN|PIDMAX|RIGHT}, +{"tsess", "TSESS", pr_nop, sr_nop, 5, 0, BSD, PO|PIDMAX|RIGHT}, +{"tsession", "TSESS", pr_nop, sr_nop, 5, 0, DEC, PO|PIDMAX|RIGHT}, {"tsiz", "TSIZ", pr_tsiz, sr_nop, 4, 0, BSD, PO|RIGHT}, {"tt", "TT", pr_tty8, sr_tty, 8, 0, BSD, PO|LEFT}, {"tty", "TT", pr_tty8, sr_tty, 8, 0, U98, PO|LEFT}, /* Unix98 requires "TT" but has "TTY" too. :-( */ /* was 3 wide */ diff --git a/ps/parser.c b/ps/parser.c index d9a91d7d..ffb3e70d 100644 --- a/ps/parser.c +++ b/ps/parser.c @@ -265,8 +265,7 @@ static const char *parse_sysv_option(void){ */ trace("-L Print LWP (thread) info.\n"); thread_flags |= TF_U_L; - thread_flags |= TF_show_task; - format_modifiers |= FM_L; +// format_modifiers |= FM_L; break; case 'M': /* someday, maybe, we will have MAC like SGI's Irix */ trace("-M Print security label for Mandatory Access Control.\n"); @@ -301,8 +300,7 @@ static const char *parse_sysv_option(void){ */ trace("-T adds strange SPID column (old sproc() threads?)\n"); thread_flags |= TF_U_T; - thread_flags |= TF_show_task; - format_modifiers |= FM_T; +// format_modifiers |= FM_T; break; case 'U': /* end */ trace("-U select by RUID (supports names).\n"); @@ -362,7 +360,7 @@ static const char *parse_sysv_option(void){ return "List of session leaders OR effective group IDs was invalid."; case 'j': trace("-j jobs format.\n"); - /* Debian uses RD_j and Digital uses JFMT */ + /* old Debian used RD_j and Digital uses JFMT */ if(sysv_j_format) format_flags |= FF_Uj; else format_modifiers |= FM_j; break; @@ -374,8 +372,6 @@ static const char *parse_sysv_option(void){ trace("-m shows threads.\n"); /* note that AIX shows 2 lines for a normal process */ thread_flags |= TF_U_m; - thread_flags |= TF_show_proc; - thread_flags |= TF_show_task; break; case 'n': /* end */ trace("-n sets namelist file.\n"); @@ -507,7 +503,6 @@ static const char *parse_bsd_option(void){ case 'H': // The FreeBSD way (NetBSD:s OpenBSD:k FreeBSD:H -- NIH???) trace("H Print LWP (thread) info.\n"); // was: Use /vmcore as c-dumpfile\n"); thread_flags |= TF_B_H; - thread_flags |= TF_show_task; // FIXME: determine if TF_show_proc is needed //format_modifiers |= FM_L; // FIXME: determine if we need something like this break; case 'L': /* single */ @@ -606,8 +601,6 @@ static const char *parse_bsd_option(void){ #if 0 case 'k': // OpenBSD: don't hide "kernel threads" -- like the swapper? trace("k Print LWP (thread) info.\n"); // was: Use /vmcore as c-dumpfile\n"); - thread_flags |= TF_show_task; // FIXME: determine if TF_show_proc is needed - //format_modifiers |= FM_L; // FIXME: determine if we need something like this break; #endif case 'l': @@ -625,8 +618,6 @@ static const char *parse_bsd_option(void){ break; } thread_flags |= TF_B_m; - thread_flags |= TF_show_proc; - thread_flags |= TF_show_task; break; case 'n': trace("n Numeric output for WCHAN, and USER replaced by UID\n"); @@ -1101,7 +1092,15 @@ static void choose_dimensions(void){ } static const char *thread_option_check(void){ - if(!thread_flags) return NULL; + if(!thread_flags){ + thread_flags = TF_show_proc; + return NULL; + } + + if(forest_type){ + return "Thread display conflicts with forest display."; + } + //thread_flags |= TF_no_forest; if((thread_flags&TF_B_H) && (thread_flags&(TF_B_m|TF_U_m))) return "Thread flags conflict; can't use H with m or -m."; @@ -1110,6 +1109,22 @@ static const char *thread_option_check(void){ if((thread_flags&TF_U_L) && (thread_flags&TF_U_T)) return "Thread flags conflict; can't use both -L and -T."; + if(thread_flags&TF_B_H) thread_flags |= (TF_show_proc|TF_loose_tasks); + if(thread_flags&(TF_B_m|TF_U_m)) thread_flags |= (TF_show_proc|TF_show_task|TF_show_both); + + if(thread_flags&(TF_U_T|TF_U_L)){ + if(thread_flags&(TF_B_m|TF_U_m|TF_B_H)){ + // Got a thread style, so format modification is a requirement? + // Maybe -T/-L has H thread style though. (sorting interaction?) + //return "Huh? Tell procps-feedback@lists.sf.net what you expected."; + thread_flags |= TF_must_use; + }else{ + // using -L/-T thread style, so format from elsewhere is OK + thread_flags |= TF_show_task; // or like the H option? + //thread_flags |= TF_no_sort; + } + } + return NULL; } @@ -1124,10 +1139,10 @@ int arg_parse(int argc, char *argv[]){ err = parse_all_options(); if(err) goto try_bsd; - err = process_sf_options(!not_pure_unix); - if(err) goto try_bsd; err = thread_option_check(); if(err) goto try_bsd; + err = process_sf_options(!not_pure_unix); + if(err) goto try_bsd; err = select_bits_setup(); if(err) goto try_bsd; @@ -1154,10 +1169,10 @@ try_bsd: err2 = parse_all_options(); if(err2) goto total_failure; - err2 = process_sf_options(!not_pure_unix); - if(err2) goto total_failure; err2 = thread_option_check(); if(err2) goto total_failure; + err2 = process_sf_options(!not_pure_unix); + if(err2) goto total_failure; err2 = select_bits_setup(); if(err2) goto total_failure; diff --git a/ps/ps.1 b/ps/ps.1 index c99cd2d4..17facc89 100644 --- a/ps/ps.1 +++ b/ps/ps.1 @@ -102,7 +102,6 @@ v display virtual memory format OUTPUT MODIFIERS -H show process hierarchy (forest) --m show threads -n set namelist file -w wide output C use raw CPU time for %CPU instead of decaying average @@ -113,7 +112,6 @@ c true command name e show environment after the command f ASCII-art process hierarchy (forest) h no header (or, one header per screen in the BSD personality) -m all threads n numeric output for WCHAN and USER w wide output --cols set screen width @@ -127,6 +125,13 @@ w wide output --sort specify sorting order --width set screen width +THREAD DISPLAY +-L show threads, possibly with LWP and NLWP columns +-T show threads, possibly with SPID column +-m show threads after processes +H show threads as if they were processes +m show threads after processes + INFORMATION -V print version L list all format specifiers @@ -160,6 +165,10 @@ Use the $PS_FORMAT environment variable to specify a default as desired; DefSysV and DefBSD are macros that may be used to choose the default UNIX or BSD columns. +The following user-defined format specifiers may contain +spaces: comm, args, cmd, comm, command, fname, ucmd, ucomm, +lstart, bsdstart, start + The "-g" option can select by session leader OR by group name. Selection by session leader is specified by many standards, but selection by group is the logical behavior that several other diff --git a/ps/sortformat.c b/ps/sortformat.c index ff82be9e..010f70a3 100644 --- a/ps/sortformat.c +++ b/ps/sortformat.c @@ -276,7 +276,7 @@ out: if(colon_loc){ /* if width override */ *colon_loc = '\0'; colon_loc++; - if(strspn(colon_loc,"0123456789") != strlen(colon_loc) || *colon_loc=='0'){ + if(strspn(colon_loc,"0123456789") != strlen(colon_loc) || *colon_loc=='0' || !*colon_loc){ free(buf); goto badwidth; } @@ -351,7 +351,6 @@ static const char *long_sort_parse(sf_node *sfn){ char *buf; /* temp copy of arg to hack on */ char *sep_loc; /* separator location: " \t,\n" */ char *walk; - const char *err; /* error code that could or did happen */ sort_node *snode; int items; int need_item; @@ -364,7 +363,6 @@ static const char *long_sort_parse(sf_node *sfn){ need_item = 1; /* true */ items = 0; walk = buf; - err = "Improper sort specifier list."; do{ switch(*walk){ case ' ': case ',': case '\t': case '\n': case '\0': @@ -713,16 +711,16 @@ static const char *generate_sysv_list(void){ }else if(format_flags & FF_Ul){ PUSH("ni"); PUSH("opri"); } - if((format_modifiers & FM_L) && (format_flags & FF_Uf)) PUSH("nlwp"); + if((thread_flags & TF_U_L) && (format_flags & FF_Uf)) PUSH("nlwp"); if( (format_flags & (FF_Uf|FF_Ul)) && !(format_modifiers & FM_c) ) PUSH("c"); if(format_modifiers & FM_P) PUSH("psr"); - if(format_modifiers & FM_L) PUSH("lwp"); + if(thread_flags & TF_U_L) PUSH("lwp"); if(format_modifiers & FM_j){ PUSH("sid"); PUSH("pgid"); } if(format_flags & (FF_Uf|FF_Ul)) PUSH("ppid"); - if(format_modifiers & FM_T) PUSH("spid"); + if(thread_flags & TF_U_T) PUSH("spid"); PUSH("pid"); if(format_flags & FF_Uf){ if(personality & PER_SANE_USER) PUSH("user"); @@ -737,7 +735,6 @@ static const char *generate_sysv_list(void){ if(format_modifiers & FM_M){ PUSH("label"); /* Mandatory Access Control */ } - format_modifiers = 0; return NULL; } @@ -749,7 +746,6 @@ static const char *generate_sysv_list(void){ */ const char *process_sf_options(int localbroken){ sf_node *sf_walk; - int option_source; /* true if user-defined */ if(personality & PER_BROKEN_o) localbroken = 1; if(personality & PER_GOOD_o) localbroken = 0; @@ -794,10 +790,49 @@ const char *process_sf_options(int localbroken){ sf_walk = sf_walk->next; } + // Get somebody to explain how -L/-T is supposed to interact + // with sorting. Do the threads remain grouped, with sorting + // by process, or do the threads get sorted by themselves? + if(sort_list && (thread_flags&TF_no_sort)){ + return "Tell procps-feedback@lists.sf.net what you expected."; + } + + // If nothing else, try to use $PS_FORMAT before the default. + if(!format_flags && !format_modifiers && !format_list){ + char *tmp; + if(thread_flags&TF_must_use) return "Tell procps-feedback@sf.net what you want. (-L/-T, -m/m/H, and $PS_FORMAT)"; + tmp = getenv("PS_FORMAT"); /* user override kills default */ + if(tmp && *tmp){ + const char *err; + sf_node sfn; + sfn.sf = tmp; + sfn.f_cooked = NULL; + err = format_parse(&sfn); + if(!err){ + format_node *fmt_walk; + fmt_walk = sfn.f_cooked; + while(fmt_walk){ /* put any nodes onto format_list in opposite way */ + format_node *travler; + travler = fmt_walk; + fmt_walk = fmt_walk->next; + travler->next = format_list; + format_list = travler; + } + return NULL; + } + // FIXME: prove that this won't be hit on valid bogus-BSD options + fprintf(stderr, "Warning: $PS_FORMAT ignored. (%s)\n", err); + } + } + if(format_list){ if(format_flags) return "Conflicting format options."; - option_source = 1; - }else{ + if(format_modifiers) return "Can't use output modifiers with user-defined output"; + if(thread_flags&TF_must_use) return "-L/-T with H/m/-m and -o/-O/o/O is nonsense"; + return NULL; + } + + do{ const char *spec; switch(format_flags){ @@ -831,35 +866,10 @@ const char *process_sf_options(int localbroken){ } /* end switch(format_flags) */ - option_source = 0; - if(!format_flags && !format_modifiers){ /* was default */ - char *tmp; - tmp = getenv("PS_FORMAT"); /* user override kills default */ - if(tmp && *tmp){ - const char *err; - sf_node sfn; -// spec = tmp; -// option_source = 2; - sfn.sf = tmp; - sfn.f_cooked = NULL; - err = format_parse(&sfn); - if(!err){ - format_node *fmt_walk; - fmt_walk = sfn.f_cooked; - while(fmt_walk){ /* put any nodes onto format_list in opposite way */ - format_node *travler; - travler = fmt_walk; - fmt_walk = fmt_walk->next; - travler->next = format_list; - format_list = travler; - } - return NULL; - } - fprintf(stderr, "Warning: $PS_FORMAT ignored. (%s)\n", err); - } - } + // not just for case 0, since sysv_l_format and such may be NULL + if(!spec) return generate_sysv_list(); - if(spec){ + do{ format_node *fmt_walk; fmt_walk = do_one_spec(spec, NULL); /* use override "" for no headers */ while(fmt_walk){ /* put any nodes onto format_list in opposite way */ @@ -869,16 +879,11 @@ const char *process_sf_options(int localbroken){ travler->next = format_list; format_list = travler; } - }else{ - const char *err; - err = generate_sysv_list(); - if(err) return err; - option_source = 3; - } - } - if(format_modifiers){ /* generate_sysv_list() may have cleared some bits */ + }while(0); + }while(0); + + do{ format_node *fn; - if(option_source) return "Can't use output modifiers with user-defined output"; if(format_modifiers & FM_j){ fn = do_one_spec("pgid", NULL); if(!fmt_add_after("PPID", fn)) if(!fmt_add_after("PID", fn)) @@ -902,9 +907,25 @@ const char *process_sf_options(int localbroken){ fn = do_one_spec("pri", NULL); if(!fmt_add_after("CLS", fn)) return "Lost my CLS!"; } - } - if(!option_source){ /* OK to really muck with stuff */ - format_node *fn; + if(thread_flags & TF_U_T){ + fn = do_one_spec("spid", NULL); + if(!fmt_add_after("PID", fn) && (thread_flags&TF_must_use)) + return "-T with H/-m/m but no PID for SPID to follow"; + } + if(thread_flags & TF_U_L){ + fn = do_one_spec("lwp", NULL); + if(fmt_add_after("SID", fn)) goto did_lwp; + if(fmt_add_after("SESS", fn)) goto did_lwp; + if(fmt_add_after("PGID", fn)) goto did_lwp; + if(fmt_add_after("PGRP", fn)) goto did_lwp; + if(fmt_add_after("PPID", fn)) goto did_lwp; + if(fmt_add_after("PID", fn)) goto did_lwp; + if(thread_flags&TF_must_use) + return "-L with H/-m/m but no PID/PGID/SID/SESS for NLWP to follow"; +did_lwp: + fn = do_one_spec("nlwp", NULL); + fmt_add_after("%CPU", fn); + } /* Do personality-specific translations not covered by format_flags. * Generally, these only get hit when personality overrides unix output. * That (mostly?) means the Digital and Debian personalities. @@ -917,9 +938,8 @@ const char *process_sf_options(int localbroken){ fn = do_one_spec("user", NULL); if(fmt_add_after("UID", fn)) fmt_delete("UID"); } - } + }while(0); - /* Could scan for duplicates (format and sort) here. Digital does. */ return NULL; } diff --git a/top.c b/top.c index 9cd58399..6d4ebb72 100644 --- a/top.c +++ b/top.c @@ -2302,16 +2302,36 @@ static void wins_reflag (int what, int flg) static void wins_resize (int dont_care_sig) { struct winsize wz; + char *env_columns; // Unix98 environment variable COLUMNS + char *env_lines; // Unix98 environment variable LINES (void)dont_care_sig; - Screen_cols = columns; - Screen_rows = lines; - if (-1 != (ioctl(STDOUT_FILENO, TIOCGWINSZ, &wz))) { + + Screen_cols = columns; // + Screen_rows = lines; // + + if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &wz) != -1 && wz.ws_col>0 && wz.ws_row>0) { Screen_cols = wz.ws_col; Screen_rows = wz.ws_row; } + if (Batch) Screen_rows = MAXINT; + env_columns = getenv("COLUMNS"); + if(env_columns && *env_columns){ + long t; + char *endptr; + t = strtol(env_columns, &endptr, 0); + if(!*endptr && (t>0) && (t<=0x7fffffffL)) Screen_cols = (int)t; + } + env_lines = getenv("LINES"); + if(env_lines && *env_lines){ + long t; + char *endptr; + t = strtol(env_lines, &endptr, 0); + if(!*endptr && (t>0) && (t<=0x7fffffffL)) Screen_rows = (int)t; + } + // we might disappoint some folks (but they'll deserve it) if (SCREENMAX < Screen_cols) Screen_cols = SCREENMAX;