diff --git a/FAQ b/FAQ new file mode 100644 index 00000000..c68bf7bc --- /dev/null +++ b/FAQ @@ -0,0 +1,99 @@ +Why does "ps -aux" complain about a bogus '-'? + +According to the POSIX and UNIX standards, the above command asks to display +all processes with a TTY (generally the commands users are running) plus all +processes owned by a user named "x". If that user doesn't exist, then ps will +assume you really meant "ps aux". The warning is given to gently break you of a +habit that will cause you trouble if a user named "x" were created. + + +Why don't I see SMP (per-CPU) stats in top? + +You didn't enable it. Press '?' for built-in help or read the man page. Per-CPU +stats are disabled by default because they take up too much space. Some Linux +systems have hundreds of CPUs. + + +Why do long usernames get printed as numbers? + +The UNIX and POSIX standards require that user names and group names be printed +as decimal integers when there is not enough room in the column. Truncating the +names, besides being a violation of the standard, would lead to confusion +between names like MichelleRichards and MichelleRichardson. The UNIX and POSIX +way to change column width is to rename the column: + + ps -o pid,user=CumbersomeUserNames -o comm + +The easy way is to directly specify the desired width: + + ps -o pid,user:19,comm + + +Why is %CPU underreported for multi-threaded (Java, etc.) apps? + +You need to upgrade to the 2.6.10 kernel at least. Older kernels do not provide +a reasonable way to get this information. + + +Why do ps and top show threads individually? + +The 2.4.xx kernel does not provide proper support for grouping threads by +process. Hacks exist to group them anyway, but such hacks will falsely group +similar tasks and will fail to group tasks due to race conditions. The hacks +are also slow. As none of this is acceptable in a critical system tool, task +grouping is not currently available for the 2.4.xx kernel. The 2.6.xx kernel +allows for proper thread grouping and reporting. To take advantage of this, +your programs must use a threading library that features the CLONE_THREAD flag. +The NPTL pthreads provided by recent glibc releases use CLONE_THREAD. + + +What systems are supported? + +Linux 2.4.xx and 2.6.xx are commonly tested and expected to work well. SMP is +well supported. Multi-node cluster views require a multi-node /proc filesystem; +without that you will see a single-node view. + + +Where to I send bug reports? + +You may use the Debian bug tracking system or send your report to +procps@freelists.org (no subscription required) instead. + + +Why are there so many procps projects? + +The original maintainer seems to have had little time for procps. Whatever his +reasons, the project didn't get maintained. Starting in 1997, Albert Cahalan +wrote a new ps program for the package. For the next few years, Albert quietly +helped the Debian package maintainer fix bugs. In 2001, Rik van Riel decided to +do something about what appeared to be the lack of a maintainer. He picked up +the buggy old code in Red Hat's CVS and started adding patches. Meanwhile, +other people have patched procps in a great many ways. + +In 2002, Albert moved procps to http://procps.sourceforge.net. This was done to +ensure that years of testing and bug fixes would not be lost. The major version +number was changed to 3, partly to avoid confusing users and partly because the +top program had been redone. + +After development essentially stopped on sourceforge.net, in 2011 the project +found a new home at http://gitorious.org/procps. This represents the Debian, +Fedora and openSUSE fork of procps. To avoid confusion and potential name +clashes the package is now known as procps-ng (next generation), the version +number was raised to 3.3.0 and the library soname changed to libproc-ng-3.3.0. + + +What is being done to procps-ng at its new home? + +All programs are in the process of being modernized, both in terms of coding +style and supporting documentation. Autotools have been integrated and the +library API has been expanded with many new fields supported such as control +groups, supplementary groups, etc. The top program has been rewritten offering +many new capabilities while providing performance improvements up to 300%. + + +Why does ps get signal 17? + +No ps release has ever had this problem. Most likely your system has been +broken into. You might want to install a more recent version of the OS. If +you'd rather take your chances, simply upgrade procps. + diff --git a/Makefile.am b/Makefile.am index 890f71bc..9ca3c53b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -9,9 +9,6 @@ AM_LDFLAGS = ./proc/libproc-ng.la sbin_PROGRAMS = \ sysctl -bin_PROGRAMS = \ - kill - usrbin_exec_PROGRAMS = \ free \ pgrep \ @@ -27,7 +24,6 @@ usrbin_exec_PROGRAMS = \ dist_man_MANS = \ free.1 \ - kill.1 \ pgrep.1 \ pkill.1 \ pmap.1 \ @@ -41,6 +37,11 @@ dist_man_MANS = \ vmstat.8 \ w.1 +if BUILD_KILL +bin_PROGRAMS = kill +dist_man_MANS += kill.1 +endif + if HAVE_NCURSES usrbin_exec_PROGRAMS += \ slabtop \ @@ -64,12 +65,13 @@ sysconf_DATA = sysctl.conf EXTRA_DIST = \ autogen.sh \ - BUGS \ CodingStyle \ - contrib/dummy.c \ - contrib/minimal.c \ - contrib/tmp-junk.c \ - contrib/utmp.c \ + contrib/ \ COPYING.LIB \ - README.top \ $(sysconf_DATA) + +procpsngdir = $(docdir) +dist_procpsng_DATA = \ + BUGS \ + FAQ \ + README.top diff --git a/configure.ac b/configure.ac index aa124050..183e24a9 100644 --- a/configure.ac +++ b/configure.ac @@ -142,6 +142,12 @@ if test "x$with_ncurses" != xno; then fi AC_SUBST([NCURSES_LIBS]) +AC_ARG_ENABLE([kill], + AS_HELP_STRING([--disable-kill], [do not build kill]), + [], enable_kill=yes +) +AM_CONDITIONAL(BUILD_KILL, test "x$enable_kill" = xyes) + AC_ARG_ENABLE([oomem], AS_HELP_STRING([--enable-oomem], [add out-of-memory fields to the library and top]), [], enable_oomem=no @@ -150,6 +156,14 @@ if test "x$enable_oomem" = xyes; then AC_DEFINE(OOMEM_ENABLE, 1, [add out-of-memory fields to the library and top]) fi +AC_ARG_ENABLE([w-from], + AS_HELP_STRING([--enable-w-from], [enable w from field by default]), + [], enable_w_from=no +) +if test "x$enable_w_from" = xyes; then + AC_DEFINE(W_SHOWFROM, 1, [enable w from field by default]) +fi + AC_CONFIG_FILES([ Makefile proc/Makefile diff --git a/contrib/response.filtered-with-patches.err b/contrib/response.filtered-with-patches.err new file mode 100644 index 00000000..ae6cda01 --- /dev/null +++ b/contrib/response.filtered-with-patches.err @@ -0,0 +1,312 @@ +See http://www.freelists.org/post/procps/Scan-results,5 + + + based on: +filtered-with-patches.err + + these are the categories i've assigned: +defect_was_fixed + EVALUATION_ORDER + pmap + TAINTED_STRING + tload + +possibly_filter_out_? + MISSING_BREAK + slabtop + ps/output + +avoidable_false_positive + DEADCODE + proc/readproc + FORWARD_NULL + top + vmstat + RESOURCE_LEAK + ps/parser (3) + STRING_NULL + pwdx + proc/readproc + TAINTED_SCALAR + pgrep + slabtop + top (3) + TAINTED_STRING + watch (2) + TOCTOU + sysctl (2) + UNINIT + ps/output (2) + +unavoidable_false_positive_? + UNREACHABLE + ps/sortformat + +unavoidable_false_positive_but_patched_anyway + OVERRUN_STATIC + top (no defect, but i yield) + + + + pgrep ------------------------------------------------------------------------ +Error: TAINTED_SCALAR: + agree that argv might be tainted + but the (int)argv[1][1] index is being passed to isdigit() function (and glibc safely indexes into array sized at 384 bytes) + my_category: avoidable_false_positive (out of step with current glibc implementation) +pgrep.c:720: tainted_data: Passing tainted variable "argv" to a tainted sink. +pgrep.c:558: data_index: Using tainted variable "(int)argv[1][1]" as an index to pointer "*__ctype_b_loc()". + + + pmap ------------------------------------------------------------------------- +Error: EVALUATION_ORDER: + agree that there is a problem. + moreover, it deals with an undocumented command line argument (but sami has documentation addition pending) + a deference was added in line with intent, hopefully avoids this warning + my_category: defect_was_fixed +pmap.c:314: write_write_order: In "arg2 = (arg2 ? arg2++ : arg1)", "arg2" is written in "arg2" (the assignment left-hand side) and written in "arg2 ? arg2++ : arg1" but the order in which the side effects take place is undefined because there is no intervening sequence point. + + + + pwdx ------------------------------------------------------------------------- +Error: STRING_NULL: + static buffer is initialized to 0 + it is +1 larger than size passed to readlink + was fixed in previous analysis + my_category: avoidable_false_positive +pwdx.c:86: string_null_argument: Function "readlink" does not terminate string "*buf". +pwdx.c:73: var_assign_var: Assigning: "s" = "buf". Both now point to the same unterminated string. +pwdx.c:73: var_assign_var: Assigning: "s" = "buf". Both now point to the same unterminated string. +pwdx.c:73: var_assign_var: Assigning: "s" = "buf". Both now point to the same unterminated string. +pwdx.c:92: string_null: Passing unterminated string "s" to "printf". + + + + slabtop ---------------------------------------------------------------------- +Error: MISSING_BREAK: + intentional fall through after setting return code + no change made + my_category: possibly_filter_out_? +slabtop.c:314: unterminated_case: This case (value 104) is not terminated by a 'break' statement. +slabtop.c:316: fallthrough: The above case falls through to this one. + +Error: TAINTED_SCALAR: + read limited to single byte signed 'char' + ultimately passed to toupper() function (and glibc safely indexes into array sized at 384 bytes) + my_category: avoidable_false_positive (out of step with current glibc implementation) +slabtop.c:387: tainted_data_argument: Calling function "read" taints argument "c". +slabtop.c:389: tainted_data: Passing tainted variable "c" to a tainted sink. +slabtop.c:233: data_index: Using tainted variable "(int)c" as an index to pointer "*__ctype_toupper_loc()". + + + + sysctl ----------------------------------------------------------------------- +Error: TOCTOU: + the pathlength between these two events cannot be reduced further + instead of assessing intervening lines of code, perhaps tool should assess 'if' statements (2) + my_category: avoidable_false_positive +sysctl.c:149: fs_check_call: Calling function "stat" to perform check on "tmpname". +sysctl.c:168: toctou: Calling function "fopen" that uses "tmpname" after a check function. This can cause a time-of-check, time-of-use race condition. + +Error: TOCTOU: + the pathlength between these two events cannot be reduced further + instead of assessing intervening lines of code, perhaps tool should assess 'if' statements (2) + my_category: avoidable_false_positive +sysctl.c:327: fs_check_call: Calling function "stat" to perform check on "tmpname". +sysctl.c:345: toctou: Calling function "fopen" that uses "tmpname" after a check function. This can cause a time-of-check, time-of-use race condition. + + + + tload ------------------------------------------------------------------------ +Error: TAINTED_STRING: + altered perror call to provide an untainted string + my_category: defect_was_fixed +tload.c:89: tainted_string: Passing tainted string "argv[optind]" to a function that cannot accept tainted data. + + + + top -------------------------------------------------------------------------- +Error: FORWARD_NULL: + cpus cannot be NULL without fp also being NULL + the very next 'if (!fp)' ensures cpus will be allocated + my_category: avoidable_false_positive +top.c:1790: assign_zero: Assigning: "cpus" = 0. +top.c:1807: var_deref_op: Dereferencing null variable "cpus". + +Error: OVERRUN_STATIC: + This "error" is centered around the following code: + f = w->pflgsall[i + w->begpflg]; + w->procflgs[i] = f; + #ifndef USE_X_COLHDR + if (P_MAXPFLGS < f) continue; + #endif + h = Fieldstab[f].head; + + The enum P_MAXPFLGS is strictly a fencepost and can *never* appear in the arrays pflgsall or procflgs. + Thus it (39th element) cannot be used in referencing Fieldstab. + However, two enums of higher value (X_XON=40 and X_XOF=41) *can* appear in those arrays. + But the test against the fencepost ensures that those two enums are *never* used in referencing Fieldstab. + + When the analyzer sees the conditional using '<' and not '<=' it reports a false positive. + + i'm tired of explaining this so the program was changed to accommodate the tool's deficiency + my_category: unavoidable_false_positive_but_patched_anyway +top.c:1417: overrun-local: Overrunning static array "Fieldstab", with 39 elements, at position 39 with index variable "f". + +Error: TAINTED_SCALAR: + the index is used subordinate to a case statement ensuring a value between '1' and '4' + my_category: avoidable_false_positive +top.c:2442: tainted_data_argument: Calling function "chin" taints argument "ch". +top.c:848: tainted_data_argument: Calling function "read" taints parameter "*buf". +top.c:2452: tainted_data: Using tainted variable "ch - 49" as an index into an array "Winstk". + +Error: TAINTED_SCALAR: + the index is used subordinate to as case statement ensuring a value between '1' and '4' + my_category: avoidable_false_positive +top.c:2719: tainted_data_argument: Calling function "chin" taints argument "ch". +top.c:848: tainted_data_argument: Calling function "read" taints parameter "*buf". +top.c:2720: tainted_data: Passing tainted variable "ch" to a tainted sink. +top.c:2452: data_index: Using tainted variable "ch - 49" as an index to array "Winstk". + +Error: TAINTED_SCALAR: + buf tainted by chin is zero terminated + single char is ultimately passed to isprintf() function (and glibc safely indexes into array sized at 384 bytes) + my_category: avoidable_false_positive (out of step with current glibc implementation) +top.c:972: tainted_data_return: Function "keyin" returns tainted data. +top.c:912: tainted_data_argument: Function "chin" taints argument "buf". +top.c:848: tainted_data_argument: Calling function "read" taints parameter "*buf". +top.c:926: return_tainted_data: Returning tainted variable "buf[0]". +top.c:972: var_assign: Assigning: "key" = "keyin", which taints "key". +top.c:1001: tainted_data: Using tainted variable "(int)key" as an index to pointer "*__ctype_b_loc()". + + + + vmstat ----------------------------------------------------------------------- +Error: FORWARD_NULL: + partition made non-null with optarg for -p where statMode |= PARTITIONSTAT + if no optarg then program exits with usage + thus call to diskpartition_format will be with non-null pointer + my_category: avoidable_false_positive +vmstat.c:593: assign_zero: Assigning: "partition" = 0. +vmstat.c:669: var_deref_model: Passing null variable "partition" to function "diskpartition_format", which dereferences it. +vmstat.c:301: deref_parm_in_call: Function "strcmp" dereferences parameter "partition_name". (The dereference is assumed on the basis of the 'nonnull' parameter attribute.) + + + + watch ------------------------------------------------------------------------ +Error: TAINTED_STRING: + even though the environment variable COLUMNS might begin tainted, from my analysis, the tool is totally mistaken + strtol actually untaints data in the form of 't' and 'endptr' then the environment variable COLUMNS is potentially purified with -1 + my_category: avoidable_false_positive +watch.c:95: tainted_string_return_content: "getenv" returns tainted string content. +watch.c:95: var_assign: Assigning: "s" = "getenv("COLUMNS")", which taints "s". +watch.c:100: tainted_data_transitive: Call to function "strtol" with tainted argument "s" returns tainted data. +watch.c:100: var_assign: Assigning: "t" = "strtol(s, &endptr, 0)", which taints "t". +watch.c:101: var_assign_var: Assigning: "incoming_cols" = "(int)t". Both are now tainted. +watch.c:102: var_assign_var: Assigning: "width" = "incoming_cols". Both are now tainted. +watch.c:103: vararg_transitive: Call to "snprintf" with tainted argument "width" taints "env_col_buf". +watch.c:104: tainted_string: Passing tainted string "env_col_buf" to a function that cannot accept tainted data. + +Error: TAINTED_STRING: + even though the environment variable LINES might begin tainted, from my analysis, the tool is totally mistaken + strtol actually untaints data in the form of 't' and 'endptr' then the environment variable LINES is potentially purified with -1 + my_category: avoidable_false_positive +watch.c:108: tainted_string_return_content: "getenv" returns tainted string content. +watch.c:108: var_assign: Assigning: "s" = "getenv("LINES")", which taints "s". +watch.c:113: tainted_data_transitive: Call to function "strtol" with tainted argument "s" returns tainted data. +watch.c:113: var_assign: Assigning: "t" = "strtol(s, &endptr, 0)", which taints "t". +watch.c:114: var_assign_var: Assigning: "incoming_rows" = "(int)t". Both are now tainted. +watch.c:115: var_assign_var: Assigning: "height" = "incoming_rows". Both are now tainted. +watch.c:116: vararg_transitive: Call to "snprintf" with tainted argument "height" taints "env_row_buf". +watch.c:117: tainted_string: Passing tainted string "env_row_buf" to a function that cannot accept tainted data. + + + + proc/readproc ---------------------------------------------------------------- +Error: DEADCODE: + the tool does not understand gperf and the pseudo case labels preceded by goto + the following code snippets illustrate the deficiency: + goto *(&&base + entry.offset); + ... + case_Threads: + Threads = strtol(S,&S,10); + continue; + my_category: avoidable_false_positive +proc/readproc.c:387: dead_error_condition: On this path, the condition "Threads" cannot be true. +proc/readproc.c:115: const: After this line, the value of "Threads" is equal to 0. +proc/readproc.c:115: assignment: Assigning: "Threads" = "0L". +proc/readproc.c:388: dead_error_begin: Execution cannot reach this statement "P->nlwp = Threads;". + +Error: STRING_NULL: + read is asked to retrieve -1 bytes than passed capacity: num_read = read(fd, ret, cap - 1); + file2str does indeed null terminate sbuf: ret[num_read] = '\0'; + my_category: avoidable_false_positive +proc/readproc.c:1193: string_null_argument: Function "file2str" does not terminate string "*sbuf". +proc/readproc.c:514: string_null_argument: Function "read" fills array "*ret" with a non-terminated string. +proc/readproc.c:1197: string_null: Passing unterminated string "sbuf" to a function expecting a null-terminated string. +proc/readproc.c:447: string_null_sink_parm_call: Passing parameter "S" to "strchr" which expects a null-terminated string. + + + + ps/output -------------------------------------------------------------------- +Error: MISSING_BREAK: + intentional fall through + my_category: possibly_filter_out_? +ps/output.c:1983: unterminated_default: The default case is not terminated by a 'break' statement. +ps/output.c:1984: fallthrough: The above case falls through to this one. + +Error: UNINIT: + the first member is initialized in the very next statement, sufficient for bsearch callback + key.spec = findme; + my_category: avoidable_false_positive +ps/output.c:1737: var_decl: Declaring variable "key" without initializer. +ps/output.c:1739: uninit_use_in_call: Using uninitialized value "key": field "key".flags is uninitialized when calling "bsearch". + +Error: UNINIT: + the first member is initialized in the very next statement, sufficient for bsearch callback + key.spec = findme; + my_category: avoidable_false_positive +ps/output.c:1745: var_decl: Declaring variable "key" without initializer. +ps/output.c:1747: uninit_use_in_call: Using uninitialized value "key": field "key".head is uninitialized when calling "bsearch". + + + + ps/parser -------------------------------------------------------------------- +Error: RESOURCE_LEAK: + intentional omission + abexit shortly + my_category: avoidable_false_positive +ps/parser.c:1021: alloc_fn: Calling allocation function "malloc". +ps/parser.c:1021: var_assign: Assigning: "pidnode" = storage returned from "malloc(sizeof (selection_node) /*24*/)". +ps/parser.c:1041: leaked_storage: Variable "pidnode" going out of scope leaks the storage it points to. +ps/parser.c:1062: leaked_storage: Variable "pidnode" going out of scope leaks the storage it points to. + +Error: RESOURCE_LEAK: + intentional omission + abexit shortly + my_category: avoidable_false_positive +ps/parser.c:1025: alloc_fn: Calling allocation function "malloc". +ps/parser.c:1025: var_assign: Assigning: "grpnode" = storage returned from "malloc(sizeof (selection_node) /*24*/)". +ps/parser.c:1041: leaked_storage: Variable "grpnode" going out of scope leaks the storage it points to. +ps/parser.c:1062: leaked_storage: Variable "grpnode" going out of scope leaks the storage it points to. + +Error: RESOURCE_LEAK: + intentional omission + abexit shortly + my_category: avoidable_false_positive +ps/parser.c:1029: alloc_fn: Calling allocation function "malloc". +ps/parser.c:1029: var_assign: Assigning: "sidnode" = storage returned from "malloc(sizeof (selection_node) /*24*/)". +ps/parser.c:1041: leaked_storage: Variable "sidnode" going out of scope leaks the storage it points to. +ps/parser.c:1062: leaked_storage: Variable "sidnode" going out of scope leaks the storage it points to. + + + + ps/sortformat ---------------------------------------------------------------- +Error: UNREACHABLE: + the tool does not understand the following 'label' usage (nor do i - perhaps some obscure compiler/platform warning/quirk) + goto unknown; + ... + if(0) unknown: err=errbuf; + my_category: unavoidable_false_positive_? +ps/sortformat.c:312: unreachable: This code cannot be reached: "if (0){ + unknown: + err = ...". diff --git a/pgrep.c b/pgrep.c index bbb7cd11..5492fa72 100644 --- a/pgrep.c +++ b/pgrep.c @@ -193,19 +193,22 @@ static union el *read_pidfile(void) int fd; struct stat sbuf; char *endp; - int pid; + int n, pid; union el *list = NULL; fd = open(opt_pidfile, O_RDONLY|O_NOCTTY|O_NONBLOCK); if(fd<0) - goto out; + goto just_ret; if(fstat(fd,&sbuf) || !S_ISREG(sbuf.st_mode) || sbuf.st_size<1) goto out; // type of lock, if any, is not standardized on Linux if(opt_lock && !has_flock(fd) && !has_fcntl(fd)) - goto out; + goto out; memset(buf,'\0',sizeof buf); - buf[read(fd,buf+1,sizeof buf-2)] = '\0'; + n = read(fd,buf+1,sizeof buf-2); + if (n<1) + goto out; + buf[n] = '\0'; pid = strtoul(buf+1,&endp,10); if(endp<=buf+1 || pid<1 || pid>0x7fffffff) goto out; @@ -216,6 +219,7 @@ static union el *read_pidfile(void) list[1].num = pid; out: close(fd); +just_ret: return list; } @@ -376,6 +380,7 @@ static PROCTAB *do_openproc (void) } flags |= PROC_UID; ptp = openproc (flags, uids, num); + free(uids); } else { ptp = openproc (flags); } @@ -404,6 +409,7 @@ static regex_t * do_regcomp (void) } re_err = regcomp (preg, re, REG_EXTENDED | REG_NOSUB | opt_case); + free(re); if (re_err) { regerror (re_err, preg, errbuf, sizeof(errbuf)); fputs(errbuf,stderr); @@ -530,8 +536,8 @@ static union el * select_procs (int *num) memset (&task, 0, sizeof (task)); } closeproc (ptp); - *num = matches; + free(preg); return list; } diff --git a/pmap.c b/pmap.c index 24a4e427..9fcaa2af 100644 --- a/pmap.c +++ b/pmap.c @@ -311,7 +311,7 @@ int main(int argc, char *argv[]){ char *arg2 = strchr(arg1,','); if(arg2) *arg2 = '\0'; - arg2 = arg2 ? arg2++ : arg1; + arg2 = *arg2 ? arg2++ : arg1; if(*arg1) range_low = STRTOUKL(arg1,&arg1,16); diff --git a/proc/readproc.c b/proc/readproc.c index 4949704e..45ec4150 100644 --- a/proc/readproc.c +++ b/proc/readproc.c @@ -1112,15 +1112,13 @@ next_proc: } next_task: - for (;;) { - // fills in our path, plus x->tid and x->tgid - if ((!(PT->taskfinder(PT,&skel_p,x,path))) // simple_nexttid - || (!(ret = PT->taskreader(PT,new_p,x,path)))) { // simple_readtask - goto next_proc; - } - if (!new_p) new_p = ret; - return ret; + // fills in our path, plus x->tid and x->tgid + if ((!(PT->taskfinder(PT,&skel_p,x,path))) // simple_nexttid + || (!(ret = PT->taskreader(PT,new_p,x,path)))) { // simple_readtask + goto next_proc; } + if (!new_p) new_p = ret; + return ret; end_procs: if (!saved_x) free(x); @@ -1152,7 +1150,7 @@ PROCTAB* openproc(int flags, ...) { PT->finder = listed_nextpid; }else{ PT->procfs = opendir("/proc"); - if(!PT->procfs) return NULL; + if(!PT->procfs) { free(PT); return NULL; } PT->finder = simple_nextpid; } PT->flags = flags; diff --git a/proc/sig.c b/proc/sig.c index ea633973..3d6e0584 100644 --- a/proc/sig.c +++ b/proc/sig.c @@ -214,7 +214,7 @@ void pretty_print_signals(void){ while(++i <= number_of_signals){ int n; n = printf("%2d %s", i, signal_number_to_name(i)); - if(i%7) printf(" \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + n); + if(n>0 && i%7) printf(" \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + n); else printf("\n"); } if((i-1)%7) printf("\n"); diff --git a/proc/slab.c b/proc/slab.c index 60c56960..d53b327d 100644 --- a/proc/slab.c +++ b/proc/slab.c @@ -312,11 +312,13 @@ int get_slabinfo(struct slab_info **list, struct slab_stat *stats) if (!fgets(buffer, SLABINFO_VER_LEN, slabfile)) { fprintf(stderr, "cannot read from slabinfo\n"); + free(slabfile); return 1; } if (sscanf(buffer, "slabinfo - version: %d.%d", &major, &minor) != 2) { fprintf(stderr, "not the good old slabinfo we know\n"); + free(slabfile); return 1; } @@ -328,6 +330,7 @@ int get_slabinfo(struct slab_info **list, struct slab_stat *stats) ret = parse_slabinfo10(list, stats, slabfile); else { fprintf(stderr, "unrecognizable slabinfo version\n"); + free(slabfile); return 1; } diff --git a/proc/sysinfo.c b/proc/sysinfo.c index 6396db58..3fe70da0 100644 --- a/proc/sysinfo.c +++ b/proc/sysinfo.c @@ -856,8 +856,8 @@ unsigned int getdiskstat(struct disk_stat **disks, struct partition_stat **parti break; } fields = sscanf(buff, " %*d %*d %*s %*u %*u %*u %*u %*u %*u %*u %*u %*u %*u %u", &dummy); + (*disks) = realloc(*disks, (cDisk+1)*sizeof(struct disk_stat)); if (fields == 1){ - (*disks) = realloc(*disks, (cDisk+1)*sizeof(struct disk_stat)); sscanf(buff, " %*d %*d %15s %u %u %llu %u %u %u %llu %u %u %u %u", //&disk_major, //&disk_minor, diff --git a/ps/display.c b/ps/display.c index 0c5e6753..74d1119b 100644 --- a/ps/display.c +++ b/ps/display.c @@ -379,7 +379,7 @@ static void prep_forest_sort(void){ if(!sort_list) { /* assume start time order */ incoming = search_format_array("start_time"); - if(!incoming) fprintf(stderr, "Could not find start_time!\n"); + if(!incoming) { fprintf(stderr, "Could not find start_time!\n"); exit(1); } tmp_list = malloc(sizeof(sort_node)); tmp_list->reverse = 0; tmp_list->typecode = '?'; /* what was this for? */ @@ -390,7 +390,7 @@ static void prep_forest_sort(void){ } /* this is required for the forest option */ incoming = search_format_array("ppid"); - if(!incoming) fprintf(stderr, "Could not find ppid!\n"); + if(!incoming) { fprintf(stderr, "Could not find ppid!\n"); exit(1); } tmp_list = malloc(sizeof(sort_node)); tmp_list->reverse = 0; tmp_list->typecode = '?'; /* what was this for? */ diff --git a/ps/parser.c b/ps/parser.c index 3e8f8875..70d94fe1 100644 --- a/ps/parser.c +++ b/ps/parser.c @@ -119,6 +119,7 @@ static const char *parse_gid(char *str, sel_union *ret){ static const char *parse_cmd(char *str, sel_union *ret){ strncpy(ret->cmd, str, sizeof ret->cmd); // strncpy pads to end + ret->cmd[sizeof(ret->cmd)-1] = '\0'; // but let's be safe return 0; } diff --git a/ps/sortformat.c b/ps/sortformat.c index 36d5d435..dec351e8 100644 --- a/ps/sortformat.c +++ b/ps/sortformat.c @@ -103,7 +103,7 @@ static void O_wrap(sf_node *sfn, int otype){ endp->next = fnode; fnode = do_one_spec(trailer,NULL); - if(!fnode)fprintf(stderr,"Seriously crashing. Goodbye cruel world.\n"); + if(!fnode) { fprintf(stderr,"Seriously crashing. Goodbye cruel world.\n"); exit(1); } endp = fnode; while(endp->next) endp = endp->next; /* find end */ endp->next = sfn->f_cooked; sfn->f_cooked = fnode; diff --git a/pwdx.c b/pwdx.c index bda1bf11..ac42736b 100644 --- a/pwdx.c +++ b/pwdx.c @@ -35,7 +35,7 @@ static void version(void) int main(int argc, char* argv[]) { - char buf[PATH_MAX+1]; + static char buf[PATH_MAX+1]; // null terminate string via static regex_t re; int i; diff --git a/skill.c b/skill.c index 96cc386e..1aa1a54d 100644 --- a/skill.c +++ b/skill.c @@ -46,8 +46,7 @@ static int saved_argc; static int sig_or_pri; -static int program; -#define PROG_GARBAGE 0 /* keep this 0 */ +static int program = -1; #define PROG_KILL 1 #define PROG_SKILL 2 /* #define PROG_NICE 3 */ /* easy, but the old one isn't broken */ @@ -558,17 +557,13 @@ int main(int argc, const char *argv[]){ tmpstr=strrchr(*argv,'/'); if(tmpstr) tmpstr++; if(!tmpstr) tmpstr=*argv; - program = PROG_GARBAGE; - if(*tmpstr=='s'){ - setpriority(PRIO_PROCESS,my_pid,-20); - if(!strcmp(tmpstr,"snice")) program = PROG_SNICE; - if(!strcmp(tmpstr,"skill")) program = PROG_SKILL; - }else{ - if(!strcmp(tmpstr,"kill")) program = PROG_KILL; - } + if(strstr(tmpstr,"kill")) program = PROG_KILL; + if(strstr(tmpstr,"skill")) program = PROG_SKILL; + if(strstr(tmpstr,"snice")) program = PROG_SNICE; switch(program){ case PROG_SNICE: case PROG_SKILL: + setpriority(PRIO_PROCESS,my_pid,-20); skillsnice_parse(argc, argv); /* show_lists(); */ iterate(); /* this is it, go get them */ diff --git a/tload.c b/tload.c index 1d346bbe..14c02166 100644 --- a/tload.c +++ b/tload.c @@ -87,7 +87,7 @@ int main(int argc, char **argv) if (argc > optind) { if ((fd = open(argv[optind], 1)) == -1) { - perror(argv[optind]); + perror("tty"); exit(1); } } diff --git a/top.c b/top.c index b7beb4da..235f215e 100644 --- a/top.c +++ b/top.c @@ -714,10 +714,13 @@ static inline void show_scroll (void) { * what will fit within the current screen width. * Our special formatting consists of: * "some text <_delimiter_> some more text <_delimiter_>...\n" - * Where <_delimiter_> is a single byte in the range of: - * \01 through \10 (in decimalizee, 1 - 8) - * and is used to select an 'attribute' from a capabilities table - * which is then applied to the *preceding* substring. + * Where <_delimiter_> is a two bye combination consisting of a + * tilde followed by an ascii digit in the the range of 1 - 8. + * examples: ~1, ~5, ~8, etc. + * The tilde is effectively stripped and the next digit + * converted to an index which is then used to select an + * 'attribute' from a capabilities table. That attribute + * is then applied to the *preceding* substring. * Once recognized, the delimiter is replaced with a null character * and viola, we've got a substring ready to output! Strings or * substrings without delimiters will receive the Cap_norm attribute. @@ -732,24 +735,23 @@ static inline void show_scroll (void) { * Tabs must always be avoided or our efforts are wasted and * lines will wrap. To lessen but not eliminate the risk of * terminfo string truncation, such non-display stuff should - * be placed at the beginning of a "short" line. - * (and as for tabs, gimme 1 more color then no worries, mate) */ + * be placed at the beginning of a "short" line. */ static void show_special (int interact, const char *glob) { /* note: the following is for documentation only, the real captab is now found in a group's WIN_t ! +------------------------------------------------------+ | char *captab[] = { : Cap's/Delim's | - | Cap_norm, Cap_norm, = \00, \01, | - | cap_bold, capclr_sum, = \02, \03, | - | capclr_msg, capclr_pmt, = \04, \05, | - | capclr_hdr, = \06, | - | capclr_rowhigh, = \07, | - | capclr_rownorm }; = \10 [octal!] | + | Cap_norm, Cap_norm, = \000, \001, | + | cap_bold, capclr_sum, = \002, \003, | + | capclr_msg, capclr_pmt, = \004, \005, | + | capclr_hdr, = \006, | + | capclr_rowhigh, = \007, | + | capclr_rownorm }; = \010 [octal!] | +------------------------------------------------------+ */ /* ( pssst, after adding the termcap transitions, row may ) ( exceed 300+ bytes, even in an 80x24 terminal window! ) */ char tmp[SMLBUFSIZ], lin[MEDBUFSIZ], row[LRGBUFSIZ]; - char *rp, *cap, *lin_end, *sub_beg, *sub_end; + char *rp, *lin_end, *sub_beg, *sub_end; int room; // handle multiple lines passed in a bunch @@ -763,16 +765,17 @@ static void show_special (int interact, const char *glob) { *(rp = row) = '\0'; while (*sub_beg) { - switch (*sub_end) { + int ch = *sub_end; + if ('~' == ch) ch = *(sub_end + 1) - '0'; + switch (ch) { case 0: // no end delim, captab makes normal *(sub_end + 1) = '\0'; // extend str end, then fall through case 1 ... 8: - cap = Curwin->captab[(int)*sub_end]; *sub_end = '\0'; - snprintf(tmp, sizeof(tmp), "%s%.*s%s", cap, room, sub_beg, Caps_off); + snprintf(tmp, sizeof(tmp), "%s%.*s%s", Curwin->captab[ch], room, sub_beg, Caps_off); rp = scat(rp, tmp); room -= (sub_end - sub_beg); - sub_beg = ++sub_end; + sub_beg = (sub_end += (ch ? 2 : 1)); break; default: // nothin' special, just text ++sub_end; @@ -1412,7 +1415,7 @@ static void calibrate_fields (void) { f = w->pflgsall[i + w->begpflg]; w->procflgs[i] = f; #ifndef USE_X_COLHDR - if (P_MAXPFLGS < f) continue; + if (P_MAXPFLGS <= f) continue; #endif h = Fieldstab[f].head; // oops, won't fit -- we're outta here... @@ -1463,7 +1466,7 @@ static void calibrate_fields (void) { w->hdrcaplen += strlen(Caps_off) + strlen(w->capclr_msg); } #else - if (P_MAXPFLGS < f) continue; + if (P_MAXPFLGS <= f) continue; #endif h = Fieldstab[f].head; if (P_WCH == f) needpsdb = 1; @@ -3334,8 +3337,8 @@ static void summary_show (void) { int shift = 0; /*** hotplug_acclimated ***/ - if (kb_main_total > 9999999) { which = "Mb"; shift = 10; } - if (kb_main_total > 9999999999) { which = "Gb"; shift = 20; } + if (kb_main_total > 9999999) { which = "Mb"; shift = 10; } + if (kb_main_total > 9999999999ull) { which = "Gb"; shift = 20; } show_special(0, fmtmk(MEMORY_twolines , which, mkM(total), mkM(used), mkM(free), mkM(buffers) diff --git a/top.h b/top.h index 5dd0733b..e071bba3 100644 --- a/top.h +++ b/top.h @@ -476,63 +476,63 @@ typedef struct WIN_t { /* Summary Lines specially formatted string(s) -- see 'show_special' for syntax details + other cautions. */ #define LOADAV_line "%s -%s\n" -#define LOADAV_line_alt "%s\06 -%s\n" -#define STATES_line1 "%s:\03" \ - " %3u \02total,\03 %3u \02running,\03 %3u \02sleeping,\03 %3u \02stopped,\03 %3u \02zombie\03\n" -#define STATES_line2x4 "%%%s\03" \ - " %#5.1f \02user,\03 %#5.1f \02system,\03 %#5.1f \02nice,\03 %#5.1f \02idle\03\n" +#define LOADAV_line_alt "%s~6 -%s\n" +#define STATES_line1 "%s:~3" \ + " %3u ~2total,~3 %3u ~2running,~3 %3u ~2sleeping,~3 %3u ~2stopped,~3 %3u ~2zombie~3\n" +#define STATES_line2x4 "%%%s~3" \ + " %#5.1f ~2user,~3 %#5.1f ~2system,~3 %#5.1f ~2nice,~3 %#5.1f ~2idle~3\n" /* These are the STATES_line evolutions lnx 2.5.x, procps-3.0.5 : IO-wait = i/o wait time lnx 2.6.x, procps-3.1.12 : IO-wait now wa, hi = hard irq, si = soft irq lnx 2.7.x, procps-3.2.7 : st = steal time */ -#define STATES_line2x5 "%%%s\03" \ - " %#5.1f \02user,\03 %#5.1f \02system,\03 %#5.1f \02nice,\03 %#5.1f \02idle,\03 %#5.1f \02IO-wait\03\n" -#define STATES_line2x6 "%%%s\03" \ - " %#5.1f \02us,\03 %#5.1f \02sy,\03 %#5.1f \02ni,\03 %#5.1f \02id,\03 %#5.1f \02wa,\03 %#5.1f \02hi,\03 %#5.1f \02si\03\n" -#define STATES_line2x7 "%%%s\03" \ - "%#5.1f \02us,\03%#5.1f \02sy,\03%#5.1f \02ni,\03%#5.1f \02id,\03%#5.1f \02wa,\03%#5.1f \02hi,\03%#5.1f \02si,\03%#5.1f \02st\03\n" +#define STATES_line2x5 "%%%s~3" \ + " %#5.1f ~2user,~3 %#5.1f ~2system,~3 %#5.1f ~2nice,~3 %#5.1f ~2idle,~3 %#5.1f ~2IO-wait~3\n" +#define STATES_line2x6 "%%%s~3" \ + " %#5.1f ~2us,~3 %#5.1f ~2sy,~3 %#5.1f ~2ni,~3 %#5.1f ~2id,~3 %#5.1f ~2wa,~3 %#5.1f ~2hi,~3 %#5.1f ~2si~3\n" +#define STATES_line2x7 "%%%s~3" \ + "%#5.1f ~2us,~3%#5.1f ~2sy,~3%#5.1f ~2ni,~3%#5.1f ~2id,~3%#5.1f ~2wa,~3%#5.1f ~2hi,~3%#5.1f ~2si,~3%#5.1f ~2st~3\n" #define MEMORY_twolines \ - "%s Mem: \03 %8lu \02total,\03 %8lu \02used,\03 %8lu \02free,\03 %8lu \02buffers\03\n" \ - "%s Swap:\03 %8lu \02total,\03 %8lu \02used,\03 %8lu \02free,\03 %8lu \02cached\03\n" + "%s Mem: ~3 %8lu ~2total,~3 %8lu ~2used,~3 %8lu ~2free,~3 %8lu ~2buffers~3\n" \ + "%s Swap:~3 %8lu ~2total,~3 %8lu ~2used,~3 %8lu ~2free,~3 %8lu ~2cached~3\n" /* Keyboard Help specially formatted string(s) -- see 'show_special' for syntax details + other cautions. */ #define KEYS_help \ - "Help for Interactive Commands\02 - %s\n" \ - "Window \01%s\06: \01Cumulative mode \03%s\02. \01System\06: \01Delay \03%.1f secs\02; \01Secure mode \03%s\02.\n" \ + "Help for Interactive Commands~2 - %s\n" \ + "Window ~1%s~6: ~1Cumulative mode ~3%s~2. ~1System~6: ~1Delay ~3%.1f secs~2; ~1Secure mode ~3%s~2.\n" \ "\n" \ - " Z\05,\01B\05 Global: '\01Z\02' change color mappings; '\01B\02' disable/enable bold\n" \ - " l,t,m Toggle Summaries: '\01l\02' load avg; '\01t\02' task/cpu stats; '\01m\02' mem info\n" \ - " 1,I Toggle SMP view: '\0011\02' single/separate states; '\01I\02' Irix/Solaris mode\n" \ + " Z~5,~1B~5 Global: '~1Z~2' change color mappings; '~1B~2' disable/enable bold\n" \ + " l,t,m Toggle Summaries: '~1l~2' load avg; '~1t~2' task/cpu stats; '~1m~2' mem info\n" \ + " 1,I Toggle SMP view: '~11~2' single/separate states; '~1I~2' Irix/Solaris mode\n" \ " f,F Manage Fields: add/remove; change order; select sort field\n" \ "\n" \ - " <,> . Move sort field: '\01<\02' next col left; '\01>\02' next col right\n" \ - " R,H,V . Toggle: '\01R\02' norm/rev sort; '\01H\02' show threads; '\01V\02' forest view\n" \ - " c,i,S . Toggle: '\01c\02' cmd name/line; '\01i\02' idle tasks; '\01S\02' cumulative time\n" \ - " x\05,\01y\05 . Toggle highlights: '\01x\02' sort field; '\01y\02' running tasks\n" \ - " z\05,\01b\05 . Toggle: '\01z\02' color/mono; '\01b\02' bold/reverse (only if 'x' or 'y')\n" \ - " u,U . Show: '\01u\02' effective user; '\01U\02' real, saved, file or effective user\n" \ + " <,> . Move sort field: '~1<~2' next col left; '~1>~2' next col right\n" \ + " R,H,V . Toggle: '~1R~2' norm/rev sort; '~1H~2' show threads; '~1V~2' forest view\n" \ + " c,i,S . Toggle: '~1c~2' cmd name/line; '~1i~2' idle tasks; '~1S~2' cumulative time\n" \ + " x~5,~1y~5 . Toggle highlights: '~1x~2' sort field; '~1y~2' running tasks\n" \ + " z~5,~1b~5 . Toggle: '~1z~2' color/mono; '~1b~2' bold/reverse (only if 'x' or 'y')\n" \ + " u,U . Show: '~1u~2' effective user; '~1U~2' real, saved, file or effective user\n" \ " n or # . Set maximum tasks displayed\n" \ - " C,... . Toggle scroll coordinates msg for: \01up\02,\01down\02,\01left\02,right\02,\01home\02,\01end\02\n" \ + " C,... . Toggle scroll coordinates msg for: ~1up~2,~1down~2,~1left~2,right~2,~1home~2,~1end~2\n" \ "\n" \ "%s" \ " W Write configuration file\n" \ " q Quit\n" \ - " ( commands shown with '.' require a \01visible\02 task display \01window\02 ) \n" \ - "Press '\01h\02' or '\01?\02' for help with \01Windows\02,\n" \ + " ( commands shown with '.' require a ~1visible~2 task display ~1window~2 ) \n" \ + "Press '~1h~2' or '~1?~2' for help with ~1Windows~2,\n" \ "any other key to continue " \ "" /* This guy goes into the help text (maybe) */ #define KEYS_help_unsecured \ - " k,r Manipulate tasks: '\01k\02' kill; '\01r\02' renice\n" \ + " k,r Manipulate tasks: '~1k~2' kill; '~1r~2' renice\n" \ " d or s Set update interval\n" \ "" /* Fields Management specially formatted string(s) -- see 'show_special' for syntax details + other cautions */ #define FIELDS_heading \ - "Fields Management\02 for window \01%s\06, whose current sort field is \01%s\02\n" \ + "Fields Management~2 for window ~1%s~6, whose current sort field is ~1%s~2\n" \ " Navigate with Up/Dn, Right selects for move then or Left commits,\n" \ " 'd' or toggles display, 's' sets sort. Use 'q' or to end! " \ "" @@ -540,58 +540,58 @@ typedef struct WIN_t { /* Colors Help specially formatted string(s) -- see 'show_special' for syntax details + other cautions. */ #define COLOR_help \ - "Help for color mapping\02 - %s\n" \ - "current window: \01%s\06\n" \ + "Help for color mapping~2 - %s\n" \ + "current window: ~1%s~6\n" \ "\n" \ " color - 04:25:44 up 8 days, 50 min, 7 users, load average:\n" \ - " Tasks:\03 64 \02total,\03 2 \03running,\03 62 \02sleeping,\03 0 \02stopped,\03\n" \ - " %%Cpu(s):\03 76.5 \02user,\03 11.2 \02system,\03 0.0 \02nice,\03 12.3 \02idle\03\n" \ - " \01 Nasty Message! \04 -or- \01Input Prompt\05\n" \ - " \01 PID TTY PR NI %%CPU TIME+ VIRT SWAP S COMMAND \06\n" \ - " 17284 \10pts/2 \07 8 0 0.0 0:00.75 1380 0 S /bin/bash \10\n" \ - " \01 8601 pts/1 7 -10 0.4 0:00.03 916 0 R color -b -z\07\n" \ - " 11005 \10? \07 9 0 0.0 0:02.50 2852 1008 S amor -sessi\10\n" \ - " available toggles: \01B\02 =disable bold globally (\01%s\02),\n" \ - " \01z\02 =color/mono (\01%s\02), \01b\02 =tasks \"bold\"/reverse (\01%s\02)\n" \ + " Tasks:~3 64 ~2total,~3 2 ~3running,~3 62 ~2sleeping,~3 0 ~2stopped,~3\n" \ + " %%Cpu(s):~3 76.5 ~2user,~3 11.2 ~2system,~3 0.0 ~2nice,~3 12.3 ~2idle~3\n" \ + " ~1 Nasty Message! ~4 -or- ~1Input Prompt~5\n" \ + " ~1 PID TTY PR NI %%CPU TIME+ VIRT SWAP S COMMAND ~6\n" \ + " 17284 ~8pts/2 ~7 8 0 0.0 0:00.75 1380 0 S /bin/bash ~8\n" \ + " ~1 8601 pts/1 7 -10 0.4 0:00.03 916 0 R color -b -z~7\n" \ + " 11005 ~8? ~7 9 0 0.0 0:02.50 2852 1008 S amor -sessi~8\n" \ + " available toggles: ~1B~2 =disable bold globally (~1%s~2),\n" \ + " ~1z~2 =color/mono (~1%s~2), ~1b~2 =tasks \"bold\"/reverse (~1%s~2)\n" \ "\n" \ - "Select \01target\02 as upper case letter:\n" \ - " S\02 = Summary Data,\01 M\02 = Messages/Prompts,\n" \ - " H\02 = Column Heads,\01 T\02 = Task Information\n" \ - "Select \01color\02 as number:\n" \ - " 0\02 = black,\01 1\02 = red, \01 2\02 = green,\01 3\02 = yellow,\n" \ - " 4\02 = blue, \01 5\02 = magenta,\01 6\02 = cyan, \01 7\02 = white\n" \ + "Select ~1target~2 as upper case letter:\n" \ + " S~2 = Summary Data,~1 M~2 = Messages/Prompts,\n" \ + " H~2 = Column Heads,~1 T~2 = Task Information\n" \ + "Select ~1color~2 as number:\n" \ + " 0~2 = black,~1 1~2 = red, ~1 2~2 = green,~1 3~2 = yellow,\n" \ + " 4~2 = blue, ~1 5~2 = magenta,~1 6~2 = cyan, ~1 7~2 = white\n" \ "\n" \ - "Selected: \01target\02 \01 %c \04; \01color\02 \01 %d \04\n" \ - " press 'q' to abort changes to window '\01%s\02'\n" \ + "Selected: ~1target~2 ~1 %c ~4; ~1color~2 ~1 %d ~4\n" \ + " press 'q' to abort changes to window '~1%s~2'\n" \ " press 'a' or 'w' to commit & change another, to commit and end " \ "" /* Windows/Field Group Help specially formatted string(s) -- see 'show_special' for syntax details + other cautions. */ #define WINDOWS_help \ - "Help for Windows / Field Groups\02 - \"Current Window\" = \01 %s \06\n" \ + "Help for Windows / Field Groups~2 - \"Current Window\" = ~1 %s ~6\n" \ "\n" \ - ". Use multiple \01windows\02, each with separate config opts (color,fields,sort,etc)\n" \ - ". The 'current' window controls the \01Summary Area\02 and responds to your \01Commands\02\n" \ - " . that window's \01task display\02 can be turned \01Off\02 & \01On\02, growing/shrinking others\n" \ - " . with \01NO\02 task display, some commands will be \01disabled\02 ('i','R','n','c', etc)\n" \ - " until a \01different window\02 has been activated, making it the 'current' window\n" \ - ". You \01change\02 the 'current' window by: \01 1\02) cycling forward/backward;\01 2\02) choosing\n" \ - " a specific field group; or\01 3\02) exiting the color mapping or fields screens\n" \ - ". Commands \01available anytime -------------\02\n" \ - " A . Alternate display mode toggle, show \01Single\02 / \01Multiple\02 windows\n" \ + ". Use multiple ~1windows~2, each with separate config opts (color,fields,sort,etc)\n" \ + ". The 'current' window controls the ~1Summary Area~2 and responds to your ~1Commands~2\n" \ + " . that window's ~1task display~2 can be turned ~1Off~2 & ~1On~2, growing/shrinking others\n" \ + " . with ~1NO~2 task display, some commands will be ~1disabled~2 ('i','R','n','c', etc)\n" \ + " until a ~1different window~2 has been activated, making it the 'current' window\n" \ + ". You ~1change~2 the 'current' window by: ~1 1~2) cycling forward/backward;~1 2~2) choosing\n" \ + " a specific field group; or~1 3~2) exiting the color mapping or fields screens\n" \ + ". Commands ~1available anytime -------------~2\n" \ + " A . Alternate display mode toggle, show ~1Single~2 / ~1Multiple~2 windows\n" \ " g . Choose another field group and make it 'current', or change now\n" \ - " by selecting a number from: \01 1\02 =%s;\01 2\02 =%s;\01 3\02 =%s; or\01 4\02 =%s\n" \ - ". Commands \01requiring\02 '\01A\02' mode\01 -------------\02\n" \ - " G . Change the \01Name\05 of the 'current' window/field group\n" \ - " \01*\04 a , w . Cycle through all four windows: '\01a\05' Forward; '\01w\05' Backward\n" \ - " \01*\04 - , _ . Show/Hide: '\01-\05' \01Current\02 window; '\01_\05' all \01Visible\02/\01Invisible\02\n" \ + " by selecting a number from: ~1 1~2 =%s;~1 2~2 =%s;~1 3~2 =%s; or~1 4~2 =%s\n" \ + ". Commands ~1requiring~2 '~1A~2' mode~1 -------------~2\n" \ + " G . Change the ~1Name~5 of the 'current' window/field group\n" \ + " ~1*~4 a , w . Cycle through all four windows: '~1a~5' Forward; '~1w~5' Backward\n" \ + " ~1*~4 - , _ . Show/Hide: '~1-~5' ~1Current~2 window; '~1_~5' all ~1Visible~2/~1Invisible~2\n" \ " The screen will be divided evenly between task displays. But you can make\n" \ - " some \01larger\02 or \01smaller\02, using '\01n\02' and '\01i\02' commands. Then later you could:\n" \ - " \01*\04 = , + . Rebalance tasks: '\01=\05' \01Current\02 window; '\01+\05' \01Every\02 window\n" \ - " (this also forces the \01current\02 or \01every\02 window to become visible)\n" \ + " some ~1larger~2 or ~1smaller~2, using '~1n~2' and '~1i~2' commands. Then later you could:\n" \ + " ~1*~4 = , + . Rebalance tasks: '~1=~5' ~1Current~2 window; '~1+~5' ~1Every~2 window\n" \ + " (this also forces the ~1current~2 or ~1every~2 window to become visible)\n" \ "\n" \ - "In '\01A\02' mode, '\01*\04' keys are your \01essential\02 commands. Please try the '\01a\02' and '\01w\02'\n" \ + "In '~1A~2' mode, '~1*~4' keys are your ~1essential~2 commands. Please try the '~1a~2' and '~1w~2'\n" \ "commands plus the 'g' sub-commands NOW. Press to make 'Current' " \ "" diff --git a/vmstat.c b/vmstat.c index e0d3c23f..756ec4f9 100644 --- a/vmstat.c +++ b/vmstat.c @@ -303,6 +303,8 @@ static int diskpartition_format(const char* partition_name){ } } if(!current_partition){ + free(disks); + free(partitions); return -1; } diskpartition_header(partition_name); @@ -323,6 +325,8 @@ static int diskpartition_format(const char* partition_name){ } } if(!current_partition){ + free(disks); + free(partitions); return -1; } printf (format, @@ -422,7 +426,7 @@ static void slabformat (void){ fSlab=fopen("/proc/slabinfo", "rb"); if(!fSlab){ - fprintf(stderr, "Your kernel doesn't support slabinfo.\n"); + fprintf(stderr, "Your kernel doesn't support slabinfo or your permissions are insufficient.\n"); return; } @@ -454,6 +458,7 @@ static void slabformat (void){ } free(slabs); } + free(fSlab); } ////////////////////////////////////////////////////////////////////////////