X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=procps%2Fnmeter.c;h=6a3b3274382feee6d67b8e0dc7ba07816f1c6fe5;hb=b79a0fef99627c457548e804fcd6e162b116cbe8;hp=573052921eb44b76a06b5b94b1a8575eea787b0d;hpb=574f2f43948bb21d6e4187936ba5a5afccba25f6;p=oweals%2Fbusybox.git diff --git a/procps/nmeter.c b/procps/nmeter.c index 573052921..6a3b32743 100644 --- a/procps/nmeter.c +++ b/procps/nmeter.c @@ -1,9 +1,44 @@ /* -** Licensed under the GPL v2, see the file LICENSE in this tarball -** -** Based on nanotop.c from floppyfw project -** -** Contact me: vda.linux@googlemail.com */ + * Licensed under GPLv2, see file LICENSE in this source tree. + * + * Based on nanotop.c from floppyfw project + * + * Contact me: vda.linux@googlemail.com + */ + +//config:config NMETER +//config: bool "nmeter" +//config: default y +//config: help +//config: Prints selected system stats continuously, one line per update. + +//applet:IF_NMETER(APPLET(nmeter, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_NMETER) += nmeter.o + +//usage:#define nmeter_trivial_usage +//usage: "[-d MSEC] FORMAT_STRING" +//usage:#define nmeter_full_usage "\n\n" +//usage: "Monitor system in real time" +//usage: "\n" +//usage: "\n -d MSEC Milliseconds between updates (default:1000)" +//usage: "\n" +//usage: "\nFormat specifiers:" +//usage: "\n %Nc or %[cN] CPU. N - bar size (default:10)" +//usage: "\n (displays: S:system U:user N:niced D:iowait I:irq i:softirq)" +//usage: "\n %[nINTERFACE] Network INTERFACE" +//usage: "\n %m Allocated memory" +//usage: "\n %[mf] Free memory" +//usage: "\n %[mt] Total memory" +//usage: "\n %s Allocated swap" +//usage: "\n %f Number of used file descriptors" +//usage: "\n %Ni Total/specific IRQ rate" +//usage: "\n %x Context switch rate" +//usage: "\n %p Forks" +//usage: "\n %[pn] # of processes" +//usage: "\n %b Block io" +//usage: "\n %Nt Time (with N decimal points)" +//usage: "\n %r Print instead of at EOL" //TODO: // simplify code @@ -17,16 +52,18 @@ // totalram=2107416576, freeram=211525632, sharedram=0, bufferram=157204480} // totalswap=134209536, freeswap=134209536, procs=157}) -#include #include "libbb.h" typedef unsigned long long ullong; -enum { PROC_FILE_SIZE = 4096 }; +enum { /* Preferably use powers of 2 */ + PROC_MIN_FILE_SIZE = 256, + PROC_MAX_FILE_SIZE = 16 * 1024, +}; typedef struct proc_file { char *file; - //const char *name; + int file_sz; smallint last_gen; } proc_file; @@ -98,7 +135,7 @@ static void print_outbuf(void) { int sz = cur_outbuf - outbuf; if (sz > 0) { - xwrite(1, outbuf, sz); + xwrite(STDOUT_FILENO, outbuf, sz); cur_outbuf = outbuf; } } @@ -124,36 +161,47 @@ static void put_question_marks(int count) put_c('?'); } -static void readfile_z(char *buf, int sz, const char* fname) +static void readfile_z(proc_file *pf, const char* fname) { // open_read_close() will do two reads in order to be sure we are at EOF, // and we don't need/want that. -// sz = open_read_close(fname, buf, sz-1); - - int fd = xopen(fname, O_RDONLY); + int fd; + int sz, rdsz; + char *buf; + + sz = pf->file_sz; + buf = pf->file; + if (!buf) { + buf = xmalloc(PROC_MIN_FILE_SIZE); + sz = PROC_MIN_FILE_SIZE; + } + again: + fd = xopen(fname, O_RDONLY); buf[0] = '\0'; - if (fd >= 0) { - sz = read(fd, buf, sz-1); - if (sz > 0) buf[sz] = '\0'; - close(fd); + rdsz = read(fd, buf, sz-1); + close(fd); + if (rdsz > 0) { + if (rdsz == sz-1 && sz < PROC_MAX_FILE_SIZE) { + sz *= 2; + buf = xrealloc(buf, sz); + goto again; + } + buf[rdsz] = '\0'; } + pf->file_sz = sz; + pf->file = buf; } static const char* get_file(proc_file *pf) { if (pf->last_gen != gen) { pf->last_gen = gen; - // We allocate PROC_FILE_SIZE bytes. This wastes memory, - // but allows us to allocate only once (at first sample) - // per proc file, and reuse buffer for each sample - if (!pf->file) - pf->file = xmalloc(PROC_FILE_SIZE); - readfile_z(pf->file, PROC_FILE_SIZE, proc_name[pf - &first_proc_file]); + readfile_z(pf, proc_name[pf - &first_proc_file]); } return pf->file; } -static inline ullong read_after_slash(const char *p) +static ullong read_after_slash(const char *p) { p = strchr(p, '/'); if (!p) return 0; @@ -223,33 +271,59 @@ static int rdval_loadavg(const char* p, ullong *vec, ...) } // Parses /proc/diskstats -// 1 2 3 4 5 6(rd) 7 8 9 10(wr) 11 12 13 14 +// 1 2 3 4 5 6(rd) 7 8 9 10(wr) 11 12 13 14 // 3 0 hda 51292 14441 841783 926052 25717 79650 843256 3029804 0 148459 3956933 // 3 1 hda1 0 0 0 0 <- ignore if only 4 fields +// Linux 3.0 (maybe earlier) started printing full stats for hda1 too. +// Had to add code which skips such devices. static int rdval_diskstats(const char* p, ullong *vec) { - ullong rd = 0; // to avoid "warning: 'rd' might be used uninitialized" - int indexline = 0; + char devname[32]; + unsigned devname_len = 0; + int value_idx = 0; + vec[0] = 0; vec[1] = 0; while (1) { - indexline++; - while (*p == ' ' || *p == '\t') p++; - if (*p == '\0') break; + value_idx++; + while (*p == ' ' || *p == '\t') + p++; + if (*p == '\0') + break; if (*p == '\n') { - indexline = 0; + value_idx = 0; p++; continue; } - if (indexline == 6) { - rd = strtoull(p, NULL, 10); - } else if (indexline == 10) { - vec[0] += rd; // TODO: *sectorsize (don't know how to find out sectorsize) + if (value_idx == 3) { + char *end = strchrnul(p, ' '); + /* If this a hda1-like device (same prefix as last one + digit)? */ + if (devname_len && strncmp(devname, p, devname_len) == 0 && isdigit(p[devname_len])) { + p = end; + goto skip_line; /* skip entire line */ + } + /* It is not. Remember the name for future checks */ + devname_len = end - p; + if (devname_len > sizeof(devname)-1) + devname_len = sizeof(devname)-1; + strncpy(devname, p, devname_len); + /* devname[devname_len] = '\0'; - not really needed */ + p = end; + } else + if (value_idx == 6) { + // TODO: *sectorsize (don't know how to find out sectorsize) + vec[0] += strtoull(p, NULL, 10); + } else + if (value_idx == 10) { + // TODO: *sectorsize (don't know how to find out sectorsize) vec[1] += strtoull(p, NULL, 10); - while (*p != '\n' && *p != '\0') p++; + skip_line: + while (*p != '\n' && *p != '\0') + p++; continue; } - while (*p > ' ') p++; // skip over value + while ((unsigned char)(*p) > ' ') // skip over value + p++; } return 0; } @@ -268,33 +342,33 @@ static void scale(ullong ul) #define S_STAT(a) \ typedef struct a { \ struct s_stat *next; \ - void (*collect)(struct a *s); \ + void (*collect)(struct a *s) FAST_FUNC; \ const char *label; #define S_STAT_END(a) } a; S_STAT(s_stat) S_STAT_END(s_stat) -static void collect_literal(s_stat *s) +static void FAST_FUNC collect_literal(s_stat *s UNUSED_PARAM) { } static s_stat* init_literal(void) { - s_stat *s = xmalloc(sizeof(s_stat)); + s_stat *s = xzalloc(sizeof(*s)); s->collect = collect_literal; return (s_stat*)s; } static s_stat* init_delay(const char *param) { - delta = bb_strtoi(param, NULL, 0) * 1000; + delta = strtoul(param, NULL, 0) * 1000; /* param can be "" */ deltanz = delta > 0 ? delta : 1; need_seconds = (1000000%deltanz) != 0; return NULL; } -static s_stat* init_cr(const char *param) +static s_stat* init_cr(const char *param UNUSED_PARAM) { final_str = "\r"; return (s_stat*)0; @@ -312,7 +386,7 @@ S_STAT(cpu_stat) S_STAT_END(cpu_stat) -static void collect_cpu(cpu_stat *s) +static void FAST_FUNC collect_cpu(cpu_stat *s) { ullong data[CPU_FIELDCNT] = { 0, 0, 0, 0, 0, 0, 0 }; unsigned frac[CPU_FIELDCNT] = { 0, 0, 0, 0, 0, 0, 0 }; @@ -369,13 +443,13 @@ static void collect_cpu(cpu_stat *s) static s_stat* init_cpu(const char *param) { int sz; - cpu_stat *s = xmalloc(sizeof(cpu_stat)); + cpu_stat *s = xzalloc(sizeof(*s)); s->collect = collect_cpu; - sz = strtol(param, NULL, 0); + sz = strtoul(param, NULL, 0); /* param can be "" */ if (sz < 10) sz = 10; if (sz > 1000) sz = 1000; - s->bar = xmalloc(sz+1); - s->bar[sz] = '\0'; + s->bar = xzalloc(sz+1); + /*s->bar[sz] = '\0'; - xzalloc did it */ s->bar_sz = sz; return (s_stat*)s; } @@ -386,7 +460,7 @@ S_STAT(int_stat) int no; S_STAT_END(int_stat) -static void collect_int(int_stat *s) +static void FAST_FUNC collect_int(int_stat *s) { ullong data[1]; ullong old; @@ -404,13 +478,13 @@ static void collect_int(int_stat *s) static s_stat* init_int(const char *param) { - int_stat *s = xmalloc(sizeof(int_stat)); + int_stat *s = xzalloc(sizeof(*s)); s->collect = collect_int; - if (param[0]=='\0') { + if (param[0] == '\0') { s->no = 1; } else { - int n = strtoul(param, NULL, 0); - s->no = n+2; + int n = xatoi_positive(param); + s->no = n + 2; } return (s_stat*)s; } @@ -420,7 +494,7 @@ S_STAT(ctx_stat) ullong old; S_STAT_END(ctx_stat) -static void collect_ctx(ctx_stat *s) +static void FAST_FUNC collect_ctx(ctx_stat *s) { ullong data[1]; ullong old; @@ -436,9 +510,9 @@ static void collect_ctx(ctx_stat *s) scale(data[0] - old); } -static s_stat* init_ctx(const char *param) +static s_stat* init_ctx(const char *param UNUSED_PARAM) { - ctx_stat *s = xmalloc(sizeof(ctx_stat)); + ctx_stat *s = xzalloc(sizeof(*s)); s->collect = collect_ctx; return (s_stat*)s; } @@ -449,7 +523,7 @@ S_STAT(blk_stat) ullong old[2]; S_STAT_END(blk_stat) -static void collect_blk(blk_stat *s) +static void FAST_FUNC collect_blk(blk_stat *s) { ullong data[2]; int i; @@ -478,9 +552,9 @@ static void collect_blk(blk_stat *s) scale(data[1]*512); } -static s_stat* init_blk(const char *param) +static s_stat* init_blk(const char *param UNUSED_PARAM) { - blk_stat *s = xmalloc(sizeof(blk_stat)); + blk_stat *s = xzalloc(sizeof(*s)); s->collect = collect_blk; s->lookfor = "page"; return (s_stat*)s; @@ -491,7 +565,7 @@ S_STAT(fork_stat) ullong old; S_STAT_END(fork_stat) -static void collect_thread_nr(fork_stat *s) +static void FAST_FUNC collect_thread_nr(fork_stat *s UNUSED_PARAM) { ullong data[1]; @@ -502,7 +576,7 @@ static void collect_thread_nr(fork_stat *s) scale(data[0]); } -static void collect_fork(fork_stat *s) +static void FAST_FUNC collect_fork(fork_stat *s) { ullong data[1]; ullong old; @@ -520,7 +594,7 @@ static void collect_fork(fork_stat *s) static s_stat* init_fork(const char *param) { - fork_stat *s = xmalloc(sizeof(fork_stat)); + fork_stat *s = xzalloc(sizeof(*s)); if (*param == 'n') { s->collect = collect_thread_nr; } else { @@ -536,7 +610,7 @@ S_STAT(if_stat) char *device_colon; S_STAT_END(if_stat) -static void collect_if(if_stat *s) +static void FAST_FUNC collect_if(if_stat *s) { ullong data[4]; int i; @@ -560,16 +634,14 @@ static void collect_if(if_stat *s) static s_stat* init_if(const char *device) { - if_stat *s = xmalloc(sizeof(if_stat)); + if_stat *s = xzalloc(sizeof(*s)); if (!device || !device[0]) bb_show_usage(); s->collect = collect_if; s->device = device; - s->device_colon = xmalloc(strlen(device)+2); - strcpy(s->device_colon, device); - strcat(s->device_colon, ":"); + s->device_colon = xasprintf("%s:", device); return (s_stat*)s; } @@ -613,7 +685,7 @@ S_STAT_END(mem_stat) //HugePages_Total: 0 //HugePages_Free: 0 //Hugepagesize: 4096 kB -static void collect_mem(mem_stat *s) +static void FAST_FUNC collect_mem(mem_stat *s) { ullong m_total = 0; ullong m_free = 0; @@ -625,7 +697,7 @@ static void collect_mem(mem_stat *s) put_question_marks(4); return; } - if (s->opt == 'f') { + if (s->opt == 't') { scale(m_total << 10); return; } @@ -650,7 +722,7 @@ static void collect_mem(mem_stat *s) static s_stat* init_mem(const char *param) { - mem_stat *s = xmalloc(sizeof(mem_stat)); + mem_stat *s = xzalloc(sizeof(*s)); s->collect = collect_mem; s->opt = param[0]; return (s_stat*)s; @@ -660,7 +732,7 @@ static s_stat* init_mem(const char *param) S_STAT(swp_stat) S_STAT_END(swp_stat) -static void collect_swp(swp_stat *s) +static void FAST_FUNC collect_swp(swp_stat *s UNUSED_PARAM) { ullong s_total[1]; ullong s_free[1]; @@ -673,9 +745,9 @@ static void collect_swp(swp_stat *s) scale((s_total[0]-s_free[0]) << 10); } -static s_stat* init_swp(const char *param) +static s_stat* init_swp(const char *param UNUSED_PARAM) { - swp_stat *s = xmalloc(sizeof(swp_stat)); + swp_stat *s = xzalloc(sizeof(*s)); s->collect = collect_swp; return (s_stat*)s; } @@ -684,7 +756,7 @@ static s_stat* init_swp(const char *param) S_STAT(fd_stat) S_STAT_END(fd_stat) -static void collect_fd(fd_stat *s) +static void FAST_FUNC collect_fd(fd_stat *s UNUSED_PARAM) { ullong data[2]; @@ -696,9 +768,9 @@ static void collect_fd(fd_stat *s) scale(data[0] - data[1]); } -static s_stat* init_fd(const char *param) +static s_stat* init_fd(const char *param UNUSED_PARAM) { - fd_stat *s = xmalloc(sizeof(fd_stat)); + fd_stat *s = xzalloc(sizeof(*s)); s->collect = collect_fd; return (s_stat*)s; } @@ -709,7 +781,7 @@ S_STAT(time_stat) int scale; S_STAT_END(time_stat) -static void collect_time(time_stat *s) +static void FAST_FUNC collect_time(time_stat *s) { char buf[sizeof("12:34:56.123456")]; struct tm* tm; @@ -731,10 +803,10 @@ static void collect_time(time_stat *s) static s_stat* init_time(const char *param) { int prec; - time_stat *s = xmalloc(sizeof(time_stat)); + time_stat *s = xzalloc(sizeof(*s)); s->collect = collect_time; - prec = param[0]-'0'; + prec = param[0] - '0'; if (prec < 0) prec = 0; else if (prec > 6) prec = 6; s->prec = prec; @@ -744,7 +816,7 @@ static s_stat* init_time(const char *param) return (s_stat*)s; } -static void collect_info(s_stat *s) +static void FAST_FUNC collect_info(s_stat *s) { gen ^= 1; while (s) { @@ -757,6 +829,7 @@ static void collect_info(s_stat *s) typedef s_stat* init_func(const char *param); +// Deprecated %NNNd is to be removed, -d MSEC supersedes it static const char options[] ALIGN1 = "ncmsfixptbdr"; static init_func *const init_functions[] = { init_if, @@ -774,27 +847,34 @@ static init_func *const init_functions[] = { }; int nmeter_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int nmeter_main(int argc, char **argv) +int nmeter_main(int argc UNUSED_PARAM, char **argv) { char buf[32]; s_stat *first = NULL; s_stat *last = NULL; s_stat *s; + char *opt_d; char *cur, *prev; INIT_G(); xchdir("/proc"); - if (argc != 2) - bb_show_usage(); + if (open_read_close("version", buf, sizeof(buf)-1) > 0) { + buf[sizeof(buf)-1] = '\0'; + is26 = (strstr(buf, " 2.4.") == NULL); + } - if (open_read_close("version", buf, sizeof(buf)) > 0) - is26 = (strstr(buf, " 2.4.")==NULL); + if (getopt32(argv, "d:", &opt_d)) + init_delay(opt_d); + argv += optind; + + if (!argv[0]) + bb_show_usage(); - // Can use argv[1] directly, but this will mess up + // Can use argv[0] directly, but this will mess up // parameters as seen by e.g. ps. Making a copy... - cur = xstrdup(argv[1]); + cur = xstrdup(argv[0]); while (1) { char *param, *p; prev = cur; @@ -803,7 +883,7 @@ int nmeter_main(int argc, char **argv) if (!cur) break; if (cur[1] == '%') { // %% - strcpy(cur, cur+1); + overlapping_strcpy(cur, cur + 1); cur++; goto again; } @@ -834,7 +914,7 @@ int nmeter_main(int argc, char **argv) s = init_functions[p-options](param); if (s) { s->label = prev; - s->next = 0; + /*s->next = NULL; - all initXXX funcs use xzalloc */ if (!first) first = s; else @@ -849,7 +929,7 @@ int nmeter_main(int argc, char **argv) if (prev[0]) { s = init_literal(); s->label = prev; - s->next = 0; + /*s->next = NULL; - all initXXX funcs use xzalloc */ if (!first) first = s; else