From 54779a47e9fa7f85b2a2ff744b9121f31a7758a9 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Fri, 22 Oct 2010 13:35:47 +0200 Subject: mount: code shrink (-81 bytes) Signed-off-by: Alexander Shishkin Signed-off-by: Denys Vlasenko --- util-linux/mount.c | 56 +++++++++++++++--------------------------------------- 1 file changed, 15 insertions(+), 41 deletions(-) diff --git a/util-linux/mount.c b/util-linux/mount.c index 5e85f9986..3ac8ce093 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -775,78 +775,52 @@ static char *nfs_strerror(int status) static bool_t xdr_fhandle(XDR *xdrs, fhandle objp) { - if (!xdr_opaque(xdrs, objp, FHSIZE)) - return FALSE; - return TRUE; + return xdr_opaque(xdrs, objp, FHSIZE); } static bool_t xdr_fhstatus(XDR *xdrs, fhstatus *objp) { if (!xdr_u_int(xdrs, &objp->fhs_status)) return FALSE; - switch (objp->fhs_status) { - case 0: - if (!xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle)) - return FALSE; - break; - default: - break; - } + if (objp->fhs_status == 0) + return xdr_fhandle(xdrs, objp->fhstatus_u.fhs_fhandle); return TRUE; } static bool_t xdr_dirpath(XDR *xdrs, dirpath *objp) { - if (!xdr_string(xdrs, objp, MNTPATHLEN)) - return FALSE; - return TRUE; + return xdr_string(xdrs, objp, MNTPATHLEN); } static bool_t xdr_fhandle3(XDR *xdrs, fhandle3 *objp) { - if (!xdr_bytes(xdrs, (char **)&objp->fhandle3_val, - (unsigned int *) &objp->fhandle3_len, - FHSIZE3) - ) { - return FALSE; - } - return TRUE; + return xdr_bytes(xdrs, (char **)&objp->fhandle3_val, + (unsigned int *) &objp->fhandle3_len, + FHSIZE3); } static bool_t xdr_mountres3_ok(XDR *xdrs, mountres3_ok *objp) { if (!xdr_fhandle3(xdrs, &objp->fhandle)) return FALSE; - if (!xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), - &(objp->auth_flavours.auth_flavours_len), - ~0, - sizeof(int), - (xdrproc_t) xdr_int) - ) { - return FALSE; - } - return TRUE; + return xdr_array(xdrs, &(objp->auth_flavours.auth_flavours_val), + &(objp->auth_flavours.auth_flavours_len), + ~0, + sizeof(int), + (xdrproc_t) xdr_int); } static bool_t xdr_mountstat3(XDR *xdrs, mountstat3 *objp) { - if (!xdr_enum(xdrs, (enum_t *) objp)) - return FALSE; - return TRUE; + return xdr_enum(xdrs, (enum_t *) objp); } static bool_t xdr_mountres3(XDR *xdrs, mountres3 *objp) { if (!xdr_mountstat3(xdrs, &objp->fhs_status)) return FALSE; - switch (objp->fhs_status) { - case MNT_OK: - if (!xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo)) - return FALSE; - break; - default: - break; - } + if (objp->fhs_status == MNT_OK) + return xdr_mountres3_ok(xdrs, &objp->mountres3_u.mountinfo); return TRUE; } -- cgit v1.2.3-55-g6feb From 6a0d7490ea6ad97aeafb9da04acab13bd3c38e4d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 23 Oct 2010 21:02:15 +0200 Subject: awk: fix segfault on closing non-opened file Signed-off-by: Denys Vlasenko --- editors/awk.c | 182 +++++++++++++++++++++++++++------------------------- testsuite/awk.tests | 6 ++ 2 files changed, 102 insertions(+), 86 deletions(-) diff --git a/editors/awk.c b/editors/awk.c index 2245cad03..fb3bf6b47 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -283,88 +283,80 @@ enum { #define OC_B OC_BUILTIN static const char tokenlist[] ALIGN1 = - "\1(" NTC - "\1)" NTC - "\1/" NTC /* REGEXP */ - "\2>>" "\1>" "\1|" NTC /* OUTRDR */ - "\2++" "\2--" NTC /* UOPPOST */ - "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ - "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ - "\2*=" "\2/=" "\2%=" "\2^=" - "\1+" "\1-" "\3**=" "\2**" - "\1/" "\1%" "\1^" "\1*" - "\2!=" "\2>=" "\2<=" "\1>" - "\1<" "\2!~" "\1~" "\2&&" - "\2||" "\1?" "\1:" NTC - "\2in" NTC - "\1," NTC - "\1|" NTC - "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ - "\1]" NTC - "\1{" NTC - "\1}" NTC - "\1;" NTC - "\1\n" NTC - "\2if" "\2do" "\3for" "\5break" /* STATX */ - "\10continue" "\6delete" "\5print" - "\6printf" "\4next" "\10nextfile" - "\6return" "\4exit" NTC - "\5while" NTC - "\4else" NTC - - "\3and" "\5compl" "\6lshift" "\2or" - "\6rshift" "\3xor" - "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ - "\3cos" "\3exp" "\3int" "\3log" - "\4rand" "\3sin" "\4sqrt" "\5srand" - "\6gensub" "\4gsub" "\5index" "\6length" - "\5match" "\5split" "\7sprintf" "\3sub" - "\6substr" "\7systime" "\10strftime" "\6mktime" - "\7tolower" "\7toupper" NTC - "\7getline" NTC - "\4func" "\10function" NTC - "\5BEGIN" NTC - "\3END" "\0" + "\1(" NTC + "\1)" NTC + "\1/" NTC /* REGEXP */ + "\2>>" "\1>" "\1|" NTC /* OUTRDR */ + "\2++" "\2--" NTC /* UOPPOST */ + "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ + "\2==" "\1=" "\2+=" "\2-=" /* BINOPX */ + "\2*=" "\2/=" "\2%=" "\2^=" + "\1+" "\1-" "\3**=" "\2**" + "\1/" "\1%" "\1^" "\1*" + "\2!=" "\2>=" "\2<=" "\1>" + "\1<" "\2!~" "\1~" "\2&&" + "\2||" "\1?" "\1:" NTC + "\2in" NTC + "\1," NTC + "\1|" NTC + "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ + "\1]" NTC + "\1{" NTC + "\1}" NTC + "\1;" NTC + "\1\n" NTC + "\2if" "\2do" "\3for" "\5break" /* STATX */ + "\10continue" "\6delete" "\5print" + "\6printf" "\4next" "\10nextfile" + "\6return" "\4exit" NTC + "\5while" NTC + "\4else" NTC + + "\3and" "\5compl" "\6lshift" "\2or" + "\6rshift" "\3xor" + "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ + "\3cos" "\3exp" "\3int" "\3log" + "\4rand" "\3sin" "\4sqrt" "\5srand" + "\6gensub" "\4gsub" "\5index" "\6length" + "\5match" "\5split" "\7sprintf" "\3sub" + "\6substr" "\7systime" "\10strftime" "\6mktime" + "\7tolower" "\7toupper" NTC + "\7getline" NTC + "\4func" "\10function" NTC + "\5BEGIN" NTC + "\3END" + /* compiler adds trailing "\0" */ ; static const uint32_t tokeninfo[] = { 0, 0, OC_REGEXP, - xS|'a', xS|'w', xS|'|', - OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', - OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', - OC_FIELD|xV|P(5), - OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), - OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', - OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', - OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', - OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', - OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', - OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', - OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', - OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, - OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, - OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', - OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), - OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', - OC_COLON|xx|P(67)|':', - OC_IN|SV|P(49), + xS|'a', xS|'w', xS|'|', + OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', + OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', OC_FIELD|xV|P(5), + OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', + OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', + OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', + OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', + OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, + OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), + OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':', + OC_IN|SV|P(49), /* in */ OC_COMMA|SS|P(80), OC_PGETLINE|SV|P(37), - OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', - OC_UNARY|xV|P(19)|'!', + OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!', + 0, /* ] */ 0, 0, 0, - 0, - 0, - ST_IF, ST_DO, ST_FOR, OC_BREAK, - OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, - OC_PRINTF, OC_NEXT, OC_NEXTFILE, - OC_RETURN|Vx, OC_EXIT|Nx, + 0, /* \n */ + ST_IF, ST_DO, ST_FOR, OC_BREAK, + OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, + OC_PRINTF, OC_NEXT, OC_NEXTFILE, + OC_RETURN|Vx, OC_EXIT|Nx, ST_WHILE, - 0, + 0, /* else */ OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83), OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83), @@ -376,9 +368,9 @@ static const uint32_t tokeninfo[] = { OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), OC_GETLINE|SV|P(0), - 0, 0, + 0, 0, 0, - 0 + 0 /* END */ }; /* internal variable names and their initial values */ @@ -1836,6 +1828,8 @@ static int awk_getline(rstream *rsm, var *v) int fd, so, eo, r, rp; char c, *m, *s; + debug_printf_eval("entered %s()\n", __func__); + /* we're using our own buffer since we need access to accumulating * characters */ @@ -1922,6 +1916,8 @@ static int awk_getline(rstream *rsm, var *v) rsm->pos = p - eo; rsm->size = size; + debug_printf_eval("returning from %s(): %d\n", __func__, r); + return r; } @@ -2347,6 +2343,8 @@ static var *evaluate(node *op, var *res) if (!op) return setvar_s(res, NULL); + debug_printf_eval("entered %s()\n", __func__); + v1 = nvalloc(2); while (op) { @@ -2367,7 +2365,7 @@ static var *evaluate(node *op, var *res) opn = (opinfo & OPNMASK); g_lineno = op->lineno; op1 = op->l.n; - debug_printf_eval("opinfo:%08x opn:%08x XC:%x\n", opinfo, opn, XC(opinfo & OPCLSMASK)); + debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); /* execute inevitable things */ if (opinfo & OF_RES1) @@ -2387,6 +2385,7 @@ static var *evaluate(node *op, var *res) debug_printf_eval("L_d:%f\n", L_d); } + debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); switch (XC(opinfo & OPCLSMASK)) { /* -- iterative node type -- */ @@ -2642,8 +2641,6 @@ static var *evaluate(node *op, var *res) /* simple builtins */ case XC( OC_FBLTIN ): { - int i; - rstream *rsm; double R_d = R_d; /* for compiler */ switch (opn) { @@ -2709,26 +2706,37 @@ static var *evaluate(node *op, var *res) if (!op1) { fflush(stdout); } else if (L.s && *L.s) { - rsm = newfile(L.s); + rstream *rsm = newfile(L.s); fflush(rsm->F); } else { fflush_all(); } break; - case F_cl: - i = 0; + case F_cl: { + rstream *rsm; + int err = 0; rsm = (rstream *)hash_search(fdhash, L.s); + debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm); if (rsm) { - i = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); + debug_printf_eval("OC_FBLTIN F_cl " + "rsm->is_pipe:%d, ->F:%p\n", + rsm->is_pipe, rsm->F); + /* Can be NULL if open failed. Example: + * getline line <"doesnt_exist"; + * close("doesnt_exist"); <--- here rsm->F is NULL + */ + if (rsm->F) + err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); free(rsm->buffer); hash_remove(fdhash, L.s); } - if (i != 0) + if (err) setvar_i(intvar[ERRNO], errno); - R_d = (double)i; + R_d = (double)err; break; } + } /* switch */ setvar_i(res, R_d); break; } @@ -2877,6 +2885,7 @@ static var *evaluate(node *op, var *res) } /* while (op) */ nvfree(v1); + debug_printf_eval("returning from %s(): %p\n", __func__, res); return res; #undef fnargs #undef seed @@ -2919,18 +2928,19 @@ static int is_assignment(const char *expr) { char *exprc, *s, *s0, *s1; - exprc = xstrdup(expr); - if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) { - free(exprc); + if (!isalnum_(*expr) || (s0 = strchr(expr, '=')) == NULL) { return FALSE; } + exprc = xstrdup(expr); + s0 = exprc + (s0 - expr); *s++ = '\0'; - s0 = s1 = s; + + s = s1 = s0; while (*s) *s1++ = nextchar(&s); - *s1 = '\0'; + setvar_u(newvar(exprc), s0); free(exprc); return TRUE; diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 56b11ca46..0afe9b9e7 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -77,6 +77,12 @@ testing "awk string cast (bug 725)" \ testing "awk handles whitespace before array subscript" \ "awk 'BEGIN { arr [3] = 1; print arr [3] }'" "1\n" "" "" +# GNU awk 3.1.5's "print ERRNO" prints "No such file or directory" instead of "2", +# do we need to emulate that as well? +testing "awk handles non-existing file correctly" \ + "awk 'BEGIN { getline line <\"doesnt_exist\"; print ERRNO; ERRNO=0; close(\"doesnt_exist\"); print ERRNO; print \"Ok\" }'" \ + "2\n0\nOk\n" "" "" + prg=' BEGIN { u["a"]=1 -- cgit v1.2.3-55-g6feb From 53600591311a129717abd2e3bcaa302622a6ce67 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 23 Oct 2010 21:06:06 +0200 Subject: libbb: introduce and use strcpy_and_process_escape_sequences function old new delta strcpy_and_process_escape_sequences - 50 +50 bb_process_escape_sequence 148 138 -10 printf_main 789 776 -13 getty_main 1897 1831 -66 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/3 up/down: 50/-89) Total: -39 bytes Signed-off-by: Denys Vlasenko --- coreutils/printf.c | 18 ++++++++--------- e2fsprogs/old_e2fsprogs/fsck.c | 10 +--------- include/libbb.h | 1 + libbb/parse_config.c | 14 +------------ libbb/process_escape_sequence.c | 44 ++++++++++++++++++++++++++++------------- loginutils/getty.c | 18 +++-------------- 6 files changed, 44 insertions(+), 61 deletions(-) diff --git a/coreutils/printf.c b/coreutils/printf.c index 2cc238439..c8395fa89 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c @@ -122,16 +122,14 @@ static double my_xstrtod(const char *arg) return result; } -static void print_esc_string(char *str) +static void print_esc_string(const char *str) { - while (*str) { - if (*str == '\\') { - str++; - bb_putchar(bb_process_escape_sequence((const char **)&str)); - } else { - bb_putchar(*str); - str++; - } + char c; + while ((c = *str) != '\0') { + str++; + if (c == '\\') + c = bb_process_escape_sequence(&str); + putchar(c); } } @@ -344,7 +342,7 @@ static char **print_formatted(char *f, char **argv, int *conv_err) f--; break; default: - bb_putchar(*f); + putchar(*f); } } diff --git a/e2fsprogs/old_e2fsprogs/fsck.c b/e2fsprogs/old_e2fsprogs/fsck.c index 524b84652..3a0743bb1 100644 --- a/e2fsprogs/old_e2fsprogs/fsck.c +++ b/e2fsprogs/old_e2fsprogs/fsck.c @@ -349,15 +349,7 @@ static void parse_escape(char *word) if (!word) return; - for (p = q = word; *p; q++) { - c = *p++; - if (c != '\\') { - *q = c; - } else { - *q = bb_process_escape_sequence(&p); - } - } - *q = 0; + strcpy_and_process_escape_sequences(word, word); } static void free_instance(struct fsck_instance *i) diff --git a/include/libbb.h b/include/libbb.h index 409c434cb..c85dab282 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -324,6 +324,7 @@ extern void bb_copyfd_exact_size(int fd1, int fd2, off_t size) FAST_FUNC; /* this helper yells "short read!" if param is not -1 */ extern void complain_copyfd_and_die(off_t sz) NORETURN FAST_FUNC; extern char bb_process_escape_sequence(const char **ptr) FAST_FUNC; +char* strcpy_and_process_escape_sequences(char *dst, const char *src) FAST_FUNC; /* xxxx_strip version can modify its parameter: * "/" -> "/" * "abc" -> "abc" diff --git a/libbb/parse_config.c b/libbb/parse_config.c index 3fff9f212..9dbfaf5d7 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c @@ -187,19 +187,7 @@ again: #if 0 /* unused so far */ if (flags & PARSE_ESCAPE) { - const char *from; - char *to; - - from = to = tokens[t]; - while (*from) { - if (*from == '\\') { - from++; - *to++ = bb_process_escape_sequence(&from); - } else { - *to++ = *from++; - } - } - *to = '\0'; + strcpy_and_process_escape_sequences(tokens[t], tokens[t]); } #endif /* Skip possible delimiters */ diff --git a/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c index 82cbe10dc..dd6e076b0 100644 --- a/libbb/process_escape_sequence.c +++ b/libbb/process_escape_sequence.c @@ -31,14 +31,13 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) unsigned num_digits; unsigned r; unsigned n; - unsigned d; unsigned base; num_digits = n = 0; base = 8; q = *ptr; -#ifdef WANT_HEX_ESCAPES +#if WANT_HEX_ESCAPES if (*q == 'x') { ++q; base = 16; @@ -50,20 +49,21 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) * \02 works, \2 does not (prints \ and 2). * We treat \2 as a valid octal escape sequence. */ do { - d = (unsigned char)(*q) - '0'; -#ifdef WANT_HEX_ESCAPES - if (d >= 10) { - d = (unsigned char)(_tolower(*q)) - 'a' + 10; - } +#if !WANT_HEX_ESCAPES + unsigned d = (unsigned char)(*q) - '0'; +#else + unsigned d = (unsigned char)_tolower(*q) - '0'; + if (d >= 10) + d += ('0' - 'a' + 10); #endif - if (d >= base) { -#ifdef WANT_HEX_ESCAPES - if ((base == 16) && (!--num_digits)) { -/* return '\\'; */ - --q; + if (WANT_HEX_ESCAPES && base == 16) { + --num_digits; + if (num_digits == 0) { + /* \x */ + --q; /* go back to x */ + } } -#endif break; } @@ -85,7 +85,9 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) } } while (*++p); /* p points to found escape char or NUL, - * advance it and find what it translates to */ + * advance it and find what it translates to. + * Note that unrecognized sequence \z returns '\' + * and leaves ptr pointing to z. */ p += sizeof(charmap) / 2; n = *p; } @@ -94,3 +96,17 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) return (char) n; } + +char* FAST_FUNC strcpy_and_process_escape_sequences(char *dst, const char *src) +{ + while (1) { + char c, c1; + c = c1 = *src++; + if (c1 == '\\') + c1 = bb_process_escape_sequence(&src); + *dst = c1; + if (c == '\0') + return dst; + dst++; + } +} diff --git a/loginutils/getty.c b/loginutils/getty.c index b1cd235fb..ab55ea4b0 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -188,21 +188,9 @@ static void parse_args(char **argv, struct options *op, char **fakehost_p) &(op->login), &op->timeout); argv += optind; if (op->flags & F_INITSTRING) { - const char *p = op->initstring; - char *q; - - op->initstring = q = xstrdup(p); - /* copy optarg into op->initstring decoding \ddd - octal codes into chars */ - while (*p) { - if (*p == '\\') { - p++; - *q++ = bb_process_escape_sequence(&p); - } else { - *q++ = *p++; - } - } - *q = '\0'; + op->initstring = xstrdup(op->initstring); + /* decode \ddd octal codes into chars */ + strcpy_and_process_escape_sequences((char*)op->initstring, op->initstring); } op->flags ^= F_ISSUE; /* invert flag "show /etc/issue" */ debug("after getopt\n"); -- cgit v1.2.3-55-g6feb From 2b299fed6a77d3aaf7e4e768fb519f2536c2eff0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 01:58:04 +0200 Subject: awk: fix breakage in last commit While at it, made bb_process_escape_sequence faster (same size) function old new delta nextchar 49 53 +4 bb_process_escape_sequence 138 140 +2 next_token 838 839 +1 static.charmap 20 18 -2 is_assignment 143 135 -8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/2 up/down: 7/-10) Total: -3 bytes Signed-off-by: Denys Vlasenko --- editors/awk.c | 27 +++++++++++++----------- libbb/process_escape_sequence.c | 46 ++++++++++++++++++++--------------------- 2 files changed, 38 insertions(+), 35 deletions(-) diff --git a/editors/awk.c b/editors/awk.c index fb3bf6b47..9646cedd6 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -684,8 +684,11 @@ static char nextchar(char **s) pps = *s; if (c == '\\') c = bb_process_escape_sequence((const char**)s); - if (c == '\\' && *s == pps) - c = *(*s)++; + if (c == '\\' && *s == pps) { /* unrecognized \z? */ + c = *(*s); /* yes, fetch z */ + if (c) + (*s)++; /* advance unless z = NUL */ + } return c; } @@ -1007,9 +1010,10 @@ static uint32_t next_token(uint32_t expected) /* it's a string */ t_string = s = ++p; while (*p != '\"') { - char *pp = p; + char *pp; if (*p == '\0' || *p == '\n') syntax_error(EMSG_UNEXP_EOS); + pp = p; *s++ = nextchar(&pp); p = pp; } @@ -2926,22 +2930,21 @@ static int awk_exit(int r) * otherwise return 0 */ static int is_assignment(const char *expr) { - char *exprc, *s, *s0, *s1; + char *exprc, *val, *s, *s1; - if (!isalnum_(*expr) || (s0 = strchr(expr, '=')) == NULL) { + if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) { return FALSE; } exprc = xstrdup(expr); - s0 = exprc + (s0 - expr); - *s++ = '\0'; + val = exprc + (val - expr); + *val++ = '\0'; - s = s1 = s0; - while (*s) - *s1++ = nextchar(&s); - *s1 = '\0'; + s = s1 = val; + while ((*s1 = nextchar(&s)) != '\0') + s1++; - setvar_u(newvar(exprc), s0); + setvar_u(newvar(exprc), val); free(exprc); return TRUE; } diff --git a/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c index dd6e076b0..7b1d97f9c 100644 --- a/libbb/process_escape_sequence.c +++ b/libbb/process_escape_sequence.c @@ -18,18 +18,8 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) { - /* bash builtin "echo -e '\ec'" interprets \e as ESC, - * but coreutils "/bin/echo -e '\ec'" does not. - * manpages tend to support coreutils way. - * Update: coreutils added support for \e on 28 Oct 2009. */ - static const char charmap[] ALIGN1 = { - 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', 0, - '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\' }; - - const char *p; const char *q; unsigned num_digits; - unsigned r; unsigned n; unsigned base; @@ -37,18 +27,17 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) base = 8; q = *ptr; -#if WANT_HEX_ESCAPES - if (*q == 'x') { + if (WANT_HEX_ESCAPES && *q == 'x') { ++q; base = 16; ++num_digits; } -#endif /* bash requires leading 0 in octal escapes: * \02 works, \2 does not (prints \ and 2). * We treat \2 as a valid octal escape sequence. */ do { + unsigned r; #if !WANT_HEX_ESCAPES unsigned d = (unsigned char)(*q) - '0'; #else @@ -60,8 +49,9 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) if (WANT_HEX_ESCAPES && base == 16) { --num_digits; if (num_digits == 0) { - /* \x */ - --q; /* go back to x */ + /* \x: return '\', + * leave ptr pointing to x */ + return '\\'; } } break; @@ -76,20 +66,30 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) ++q; } while (++num_digits < 3); - if (num_digits == 0) { /* mnemonic escape sequence? */ - p = charmap; + if (num_digits == 0) { + /* Not octal or hex escape sequence. + * Is it one-letter one? */ + + /* bash builtin "echo -e '\ec'" interprets \e as ESC, + * but coreutils "/bin/echo -e '\ec'" does not. + * Manpages tend to support coreutils way. + * Update: coreutils added support for \e on 28 Oct 2009. */ + static const char charmap[] ALIGN1 = { + 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', + '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', + }; + const char *p = charmap; do { if (*p == *q) { q++; break; } - } while (*++p); - /* p points to found escape char or NUL, + } while (*++p != '\\'); + /* p points to found escape char or '\', * advance it and find what it translates to. - * Note that unrecognized sequence \z returns '\' - * and leaves ptr pointing to z. */ - p += sizeof(charmap) / 2; - n = *p; + * Note that \NUL and unrecognized sequence \z return '\' + * and leave ptr pointing to NUL or z. */ + n = p[sizeof(charmap) / 2]; } *ptr = q; -- cgit v1.2.3-55-g6feb From f2657a9968d2f5282f9a7f2e8b93a8d5a57e04fd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 02:04:10 +0200 Subject: init: do not clear CRTSCTS (fix from Debian bug 528560) Signed-off-by: Denys Vlasenko --- init/init.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/init/init.c b/init/init.c index 340731b8b..12348078d 100644 --- a/init/init.c +++ b/init/init.c @@ -463,7 +463,11 @@ static void set_sane_term(void) #endif /* Make it be sane */ - tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD; +#ifndef CRTSCTS +# define CRTSCTS 0 +#endif + /* added CRTSCTS to fix Debian bug 528560 */ + tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD | CRTSCTS; tty.c_cflag |= CREAD | HUPCL | CLOCAL; /* input modes */ @@ -473,8 +477,7 @@ static void set_sane_term(void) tty.c_oflag = OPOST | ONLCR; /* local modes */ - tty.c_lflag = - ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; + tty.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; tcsetattr_stdin_TCSANOW(&tty); } -- cgit v1.2.3-55-g6feb From 57b68331e402cdb050074d652948740524c8d389 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 02:09:32 +0200 Subject: correct manpage name Signed-off-by: Denys Vlasenko --- Makefile.custom | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile.custom b/Makefile.custom index c6577a568..6da79e6e4 100644 --- a/Makefile.custom +++ b/Makefile.custom @@ -107,7 +107,7 @@ bigdata: busybox_unstripped # Documentation Targets .PHONY: doc -doc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html +doc: docs/busybox.pod docs/BusyBox.txt docs/busybox.1 docs/BusyBox.html # FIXME: Doesn't belong here cmd_doc = @@ -135,10 +135,10 @@ docs/BusyBox.txt: docs/busybox.pod $(Q)-mkdir -p docs $(Q)-pod2text $< > $@ -docs/BusyBox.1: docs/busybox.pod +docs/busybox.1: docs/busybox.pod $(disp_doc) $(Q)-mkdir -p docs - $(Q)-pod2man --center=BusyBox --release="version $(KERNELVERSION)" $< > $@ + $(Q)-pod2man --center=busybox --release="version $(KERNELVERSION)" $< > $@ docs/BusyBox.html: docs/busybox.net/BusyBox.html $(disp_doc) -- cgit v1.2.3-55-g6feb From 1c26e05f300fbf76cf8d06e742fc571e5365fda3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 02:35:17 +0200 Subject: remove unused SC_x (serial port names) defines Signed-off-by: Denys Vlasenko --- include/libbb.h | 25 +++---------------------- 1 file changed, 3 insertions(+), 22 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index c85dab282..bd1d586c7 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1668,46 +1668,27 @@ extern const char bb_default_login_shell[]; # define VC_4 "/dev/tty4" # define VC_5 "/dev/tty5" # define VC_FORMAT "/dev/tty%d" -#elif ENABLE_FEATURE_DEVFS /* from now on, assume Linux naming */ +#elif ENABLE_FEATURE_DEVFS +/*Linux, obsolete devfs names */ # define CURRENT_VC "/dev/vc/0" # define VC_1 "/dev/vc/1" # define VC_2 "/dev/vc/2" # define VC_3 "/dev/vc/3" # define VC_4 "/dev/vc/4" # define VC_5 "/dev/vc/5" -# if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) -/* Yes, this sucks, but both SH (including sh64) and H8 have a SCI(F) for their - respective serial ports .. as such, we can't use the common device paths for - these. -- PFM */ -# define SC_0 "/dev/ttsc/0" -# define SC_1 "/dev/ttsc/1" -# define SC_FORMAT "/dev/ttsc/%d" -# else -# define SC_0 "/dev/tts/0" -# define SC_1 "/dev/tts/1" -# define SC_FORMAT "/dev/tts/%d" -# endif # define VC_FORMAT "/dev/vc/%d" # define LOOP_FORMAT "/dev/loop/%d" # define LOOP_NAMESIZE (sizeof("/dev/loop/") + sizeof(int)*3 + 1) # define LOOP_NAME "/dev/loop/" # define FB_0 "/dev/fb/0" #else +/*Linux, normal names */ # define CURRENT_VC "/dev/tty0" # define VC_1 "/dev/tty1" # define VC_2 "/dev/tty2" # define VC_3 "/dev/tty3" # define VC_4 "/dev/tty4" # define VC_5 "/dev/tty5" -# if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) -# define SC_0 "/dev/ttySC0" -# define SC_1 "/dev/ttySC1" -# define SC_FORMAT "/dev/ttySC%d" -# else -# define SC_0 "/dev/ttyS0" -# define SC_1 "/dev/ttyS1" -# define SC_FORMAT "/dev/ttyS%d" -# endif # define VC_FORMAT "/dev/tty%d" # define LOOP_FORMAT "/dev/loop%d" # define LOOP_NAMESIZE (sizeof("/dev/loop") + sizeof(int)*3 + 1) -- cgit v1.2.3-55-g6feb From 07b1c6ecc035c5b4d68db6b676610327bb897418 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 03:00:57 +0200 Subject: umount: do not (ab)use PATH_MAX as mntent buffer size Signed-off-by: Denys Vlasenko --- util-linux/umount.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/util-linux/umount.c b/util-linux/umount.c index 7ba46eeb0..1b489ba56 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c @@ -39,9 +39,6 @@ # define MS_RELATIME (1 << 21) #endif #include "libbb.h" -#ifndef PATH_MAX -# define PATH_MAX (4*1024) -#endif #if defined(__dietlibc__) @@ -73,7 +70,7 @@ int umount_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int umount_main(int argc UNUSED_PARAM, char **argv) { int doForce; - char *const buf = xmalloc(PATH_MAX * 2 + 128); /* to save stack */ + char *const buf = xmalloc(4096); /* reducing stack usage */ struct mntent me; FILE *fp; char *fstype = NULL; -- cgit v1.2.3-55-g6feb From 58647e8f851e9639d1b386c67c44ca070d1c9a49 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 03:02:57 +0200 Subject: Remove check for supported libc. If it is not supported, it won't work. No need to break working ones which happen to this over this check. Signed-off-by: Denys Vlasenko --- include/platform.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/include/platform.h b/include/platform.h index b5c668517..656327641 100644 --- a/include/platform.h +++ b/include/platform.h @@ -264,15 +264,6 @@ typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; /* ---- Miscellaneous --------------------------------------- */ -#if defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ < 5 && \ - !defined(__dietlibc__) && \ - !defined(_NEWLIB_VERSION) && \ - !(defined __digital__ && defined __unix__) -# error "Sorry, this libc version is not supported :(" -#endif - -/* Don't perpetuate e2fsck crap into the headers. Clean up e2fsck instead. */ - #if defined __GLIBC__ || defined __UCLIBC__ \ || defined __dietlibc__ || defined _NEWLIB_VERSION # include -- cgit v1.2.3-55-g6feb From 8f8ee534a7799cba8c953fffabe3b9c5571b3eb7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 03:07:18 +0200 Subject: adding docs/smallint.txt Signed-off-by: Denys Vlasenko --- docs/smallint.txt | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 docs/smallint.txt diff --git a/docs/smallint.txt b/docs/smallint.txt new file mode 100644 index 000000000..df6796447 --- /dev/null +++ b/docs/smallint.txt @@ -0,0 +1,37 @@ + smalluint i = index_in_str_array(params, name) + 1; + if (i == 0) + return 0; + if (!(i == 4 || i == 5)) + i |= 0x80; + + return i; + +I think that this optimization is wrong. +index_in_str_array returns int. At best, compiler will use it as-is. +At worst, compiler will try to make sure that it is properly casted +into a byte, which probably results in "n = n & 0xff" on many architectures. + +You save nothing on space here because i is not stored on-stack, +gcc will keep it in register. And even it is *is* stored, +it is *stack* storage, which is cheap (unlike data/bss). + +small[u]ints are useful _mostly_ for: +(a) flag variables + (a1) global flag variables - make data/bss smaller + (a2) local flag variables - "a = 5", "a |= 0x40" are smaller + for bytes than for full integers. + Example: + on i386, there is no widening constant store instruction + for some types of address modes, thus + movl $0x0,(%eax) is "c7 00 00 00 00 00" + movb $0x0,(%eax) is "c6 00 00" +(b) small integer structure members, when you have many such +structures allocated, + or when these are global objects of this structure type + +small[u]ints are *NOT* useful for: +(a) function parameters and return values - + they are pushed on-stack or stored in registers, bytes here are *harder* + to deal with than ints +(b) "computational" variables - "a++", "a = b*3 + 7" may take more code to do + on bytes than on ints on some architectires. -- cgit v1.2.3-55-g6feb From 738e4de01332a10edd30149aa998f8ed403c12ed Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 03:23:59 +0200 Subject: English fixes to docs/smallint.txt Signed-off-by: Denys Vlasenko --- docs/smallint.txt | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/smallint.txt b/docs/smallint.txt index df6796447..b57dfd775 100644 --- a/docs/smallint.txt +++ b/docs/smallint.txt @@ -8,14 +8,15 @@ I think that this optimization is wrong. index_in_str_array returns int. At best, compiler will use it as-is. -At worst, compiler will try to make sure that it is properly casted +At worst, compiler will try to make sure that it is properly cast into a byte, which probably results in "n = n & 0xff" on many architectures. You save nothing on space here because i is not stored on-stack, -gcc will keep it in register. And even it is *is* stored, +gcc will keep it in register. And even if it *is* stored, it is *stack* storage, which is cheap (unlike data/bss). small[u]ints are useful _mostly_ for: + (a) flag variables (a1) global flag variables - make data/bss smaller (a2) local flag variables - "a = 5", "a |= 0x40" are smaller @@ -26,10 +27,11 @@ small[u]ints are useful _mostly_ for: movl $0x0,(%eax) is "c7 00 00 00 00 00" movb $0x0,(%eax) is "c6 00 00" (b) small integer structure members, when you have many such -structures allocated, + structures allocated, or when these are global objects of this structure type small[u]ints are *NOT* useful for: + (a) function parameters and return values - they are pushed on-stack or stored in registers, bytes here are *harder* to deal with than ints -- cgit v1.2.3-55-g6feb From d8205b39abb9971bc6aeff4a21c22b3f5f575e49 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Sun, 24 Oct 2010 03:27:22 +0200 Subject: awk: reduce ifdef forest Signed-off-by: Rob Landley Signed-off-by: Denys Vlasenko --- editors/awk.c | 65 +++++++++++++++++++++++++++++------------------------------ 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/editors/awk.c b/editors/awk.c index 9646cedd6..8bc56756c 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -524,9 +524,7 @@ static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; -#if !ENABLE_FEATURE_AWK_LIBM static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; -#endif static void zero_out_var(var *vp) { @@ -700,8 +698,7 @@ static ALWAYS_INLINE int isalnum_(int c) static double my_strtod(char **pp) { char *cp = *pp; -#if ENABLE_DESKTOP - if (cp[0] == '0') { + if (ENABLE_DESKTOP && cp[0] == '0') { /* Might be hex or octal integer: 0x123abc or 07777 */ char c = (cp[1] | 0x20); if (c == 'x' || isdigit(cp[1])) { @@ -718,7 +715,6 @@ static double my_strtod(char **pp) */ } } -#endif return strtod(cp, pp); } @@ -2168,11 +2164,10 @@ static NOINLINE var *exec_builtin(node *op, var *res) switch (info) { case B_a2: -#if ENABLE_FEATURE_AWK_LIBM - setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1]))); -#else - syntax_error(EMSG_NO_MATH); -#endif + if (ENABLE_FEATURE_AWK_LIBM) + setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1]))); + else + syntax_error(EMSG_NO_MATH); break; case B_sp: { @@ -2655,35 +2650,40 @@ static var *evaluate(node *op, var *res) case F_rn: R_d = (double)rand() / (double)RAND_MAX; break; -#if ENABLE_FEATURE_AWK_LIBM + case F_co: - R_d = cos(L_d); - break; + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = cos(L_d); + break; + } case F_ex: - R_d = exp(L_d); - break; + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = exp(L_d); + break; + } case F_lg: - R_d = log(L_d); - break; + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = log(L_d); + break; + } case F_si: - R_d = sin(L_d); - break; + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = sin(L_d); + break; + } case F_sq: - R_d = sqrt(L_d); - break; -#else - case F_co: - case F_ex: - case F_lg: - case F_si: - case F_sq: + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = sqrt(L_d); + break; + } + syntax_error(EMSG_NO_MATH); break; -#endif + case F_sr: R_d = (double)seed; seed = op1 ? (unsigned)L_d : (unsigned)time(NULL); @@ -2834,11 +2834,10 @@ static var *evaluate(node *op, var *res) L_d /= R_d; break; case '&': -#if ENABLE_FEATURE_AWK_LIBM - L_d = pow(L_d, R_d); -#else - syntax_error(EMSG_NO_MATH); -#endif + if (ENABLE_FEATURE_AWK_LIBM) + L_d = pow(L_d, R_d); + else + syntax_error(EMSG_NO_MATH); break; case '%': if (R_d == 0) -- cgit v1.2.3-55-g6feb From 17fc33dfbdf98eb51a5cbf3345337cb4e21d60ac Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 03:46:16 +0200 Subject: finish busybox.1 renaming Signed-off-by: Denys Vlasenko --- Makefile | 2 +- docs/.gitignore | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index b7afaa9e7..c41643d8b 100644 --- a/Makefile +++ b/Makefile @@ -991,7 +991,7 @@ clean: archclean $(clean-dirs) PHONY += doc-clean doc-clean: rm-files := docs/busybox.pod \ - docs/BusyBox.html docs/BusyBox.1 docs/BusyBox.txt + docs/BusyBox.html docs/busybox.1 docs/BusyBox.txt doc-clean: $(call cmd,rmfiles) diff --git a/docs/.gitignore b/docs/.gitignore index 9d1b7c227..11d616360 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,4 +1,4 @@ -/BusyBox.1 +/busybox.1 /BusyBox.html /BusyBox.txt /busybox.pod -- cgit v1.2.3-55-g6feb From ba04337e1f2d7ff2731959a59b64bc63953e77f4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 13:28:45 +0200 Subject: umount: I forgot to change another PATH_MAX to 4096 Signed-off-by: Denys Vlasenko --- util-linux/umount.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util-linux/umount.c b/util-linux/umount.c index 1b489ba56..78c603856 100644 --- a/util-linux/umount.c +++ b/util-linux/umount.c @@ -101,7 +101,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_ALL) bb_error_msg_and_die("can't open '%s'", bb_path_mtab_file); } else { - while (getmntent_r(fp, &me, buf, PATH_MAX * 2 + 128)) { + while (getmntent_r(fp, &me, buf, 4096)) { /* Match fstype if passed */ if (!match_fstype(&me, fstype)) continue; -- cgit v1.2.3-55-g6feb From 4b63e16d20f2c89b39e26a10cb1cdbcbf079df89 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 14:54:53 +0200 Subject: md5/sha1sum: code shrink function old new delta hash_file 357 279 -78 Signed-off-by: Denys Vlasenko --- coreutils/md5_sha1_sum.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c index e79210c0d..d3d294de9 100644 --- a/coreutils/md5_sha1_sum.c +++ b/coreutils/md5_sha1_sum.c @@ -10,13 +10,13 @@ /* This is a NOEXEC applet. Be very careful! */ -typedef enum { +enum { /* 4th letter of applet_name is... */ HASH_MD5 = 's', /* "md5>s 0) { update(&context, in_buf, count); } @@ -99,27 +101,26 @@ int md5_sha1_sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) { int return_value = EXIT_SUCCESS; - uint8_t *hash_value; unsigned flags; - /*hash_algo_t hash_algo = applet_name[3];*/ if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK) { /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ flags = getopt32(argv, "scwbt"); + argv += optind; + //argc -= optind; + } else { + argv += 1; + //argc -= 1; } - else optind = 1; - argv += optind; - //argc -= optind; if (!*argv) *--argv = (char*)"-"; if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && !(flags & FLAG_CHECK)) { if (flags & FLAG_SILENT) { - bb_error_msg_and_die - ("-%c is meaningful only when verifying checksums", 's'); - } else if (flags & FLAG_WARN) { - bb_error_msg_and_die - ("-%c is meaningful only when verifying checksums", 'w'); + bb_error_msg_and_die("-%c is meaningful only with -c", 's'); + } + if (flags & FLAG_WARN) { + bb_error_msg_and_die("-%c is meaningful only with -c", 'w'); } } @@ -130,13 +131,13 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) char *line; if (argv[1]) { - bb_error_msg_and_die - ("only one argument may be specified when using -c"); + bb_error_msg_and_die("only one argument may be specified with -c"); } pre_computed_stream = xfopen_stdin(argv[0]); while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) { + uint8_t *hash_value; char *filename_ptr; count_total++; @@ -157,7 +158,7 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) *filename_ptr = '\0'; filename_ptr += 2; - hash_value = hash_file(filename_ptr /*, hash_algo*/); + hash_value = hash_file(filename_ptr); if (hash_value && (strcmp((char*)hash_value, line) == 0)) { if (!(flags & FLAG_SILENT)) @@ -183,7 +184,7 @@ int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) */ } else { do { - hash_value = hash_file(*argv/*, hash_algo*/); + uint8_t *hash_value = hash_file(*argv); if (hash_value == NULL) { return_value = EXIT_FAILURE; } else { -- cgit v1.2.3-55-g6feb From f4c93ab30460667cb3506a89a5419508a7bcfa0e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 19:27:30 +0200 Subject: sha1: use Rob's code, it's smaller and faster function old new delta static.rconsts - 16 +16 sha1_process_block64 460 298 -162 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/1 up/down: 16/-162) Total: -146 bytes Signed-off-by: Denys Vlasenko --- libbb/hash_md5_sha.c | 105 +++++++++++++++++++++++++-------------------------- 1 file changed, 51 insertions(+), 54 deletions(-) diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index aeacddef8..5e4078ae6 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c @@ -473,20 +473,13 @@ void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf) /* - * Based on shasum from http://www.netsw.org/crypto/hash/ - * Majorly hacked up to use Dr Brian Gladman's sha1 code + * SHA1 part is: + * Copyright 2007 Rob Landley * - * Copyright (C) 2002 Dr Brian Gladman , Worcester, UK. - * Copyright (C) 2003 Glenn L. McGrath - * Copyright (C) 2003 Erik Andersen - * - * Licensed under GPLv2 or later, see file LICENSE in this source tree. - * - * --------------------------------------------------------------------------- - * Issue Date: 10/11/2002 + * Based on the public domain SHA-1 in C by Steve Reid + * from http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/ * - * This is a byte oriented version of SHA1 that operates on arrays of bytes - * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor + * Licensed under GPLv2, see file LICENSE in this source tree. * * --------------------------------------------------------------------------- * @@ -503,16 +496,18 @@ void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf) static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) { - unsigned t; - uint32_t W[80], a, b, c, d, e; - const uint32_t *words = (uint32_t*) ctx->wbuffer; + static const uint32_t rconsts[] = { + 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 + }; + int i, j; + int cnt; + uint32_t W[16+16]; + uint32_t a, b, c, d, e; - for (t = 0; t < 16; ++t) - W[t] = SWAP_BE32(words[t]); - for (/*t = 16*/; t < 80; ++t) { - uint32_t T = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; - W[t] = rotl32(T, 1); - } + /* On-stack work buffer frees up one register in the main loop + * which otherwise will be needed to hold ctx pointer */ + for (i = 0; i < 16; i++) + W[i] = W[i+16] = SWAP_BE32(((uint32_t*)ctx->wbuffer)[i]); a = ctx->hash[0]; b = ctx->hash[1]; @@ -520,39 +515,41 @@ static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) d = ctx->hash[3]; e = ctx->hash[4]; -#undef ch -#undef parity -#undef maj -#undef rnd -#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) -#define parity(x,y,z) ((x) ^ (y) ^ (z)) -#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) -/* A normal version as set out in the FIPS. */ -#define rnd(f,k) \ - do { \ - uint32_t T = a; \ - a = rotl32(a, 5) + f(b, c, d) + e + k + W[t]; \ - e = d; \ - d = c; \ - c = rotl32(b, 30); \ - b = T; \ - } while (0) - - for (t = 0; t < 20; ++t) - rnd(ch, 0x5a827999); - - for (/*t = 20*/; t < 40; ++t) - rnd(parity, 0x6ed9eba1); - - for (/*t = 40*/; t < 60; ++t) - rnd(maj, 0x8f1bbcdc); - - for (/*t = 60*/; t < 80; ++t) - rnd(parity, 0xca62c1d6); -#undef ch -#undef parity -#undef maj -#undef rnd + /* 4 rounds of 20 operations each */ + cnt = 0; + for (i = 0; i < 4; i++) { + j = 19; + do { + uint32_t work; + + work = c ^ d; + if (i == 0) { + work = (work & b) ^ d; + if (j <= 3) + goto ge16; + /* Used to do SWAP_BE32 here, but this + * requires ctx (see comment above) */ + work += W[cnt]; + } else { + if (i == 2) + work = ((b | c) & d) | (b & c); + else /* i = 1 or 3 */ + work ^= b; + ge16: + W[cnt] = W[cnt+16] = rotl32(W[cnt+13] ^ W[cnt+8] ^ W[cnt+2] ^ W[cnt], 1); + work += W[cnt]; + } + work = e + work + rotl32(a, 5) + rconsts[i]; + + /* Rotate by one for next time */ + e = d; + d = c; + c = /* b = */ rotl32(b, 30); + b = a; + a = work; + cnt = (cnt + 1) & 15; + } while (--j >= 0); + } ctx->hash[0] += a; ctx->hash[1] += b; -- cgit v1.2.3-55-g6feb From 03a5fe378e50cb7a43c4c367c6c0e18e6f156597 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 24 Oct 2010 20:51:28 +0200 Subject: sha1: small tweak for clearer code, no logic changes Signed-off-by: Denys Vlasenko --- libbb/hash_md5_sha.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c index 5e4078ae6..e427f6080 100644 --- a/libbb/hash_md5_sha.c +++ b/libbb/hash_md5_sha.c @@ -539,7 +539,7 @@ static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) W[cnt] = W[cnt+16] = rotl32(W[cnt+13] ^ W[cnt+8] ^ W[cnt+2] ^ W[cnt], 1); work += W[cnt]; } - work = e + work + rotl32(a, 5) + rconsts[i]; + work += e + rotl32(a, 5) + rconsts[i]; /* Rotate by one for next time */ e = d; -- cgit v1.2.3-55-g6feb From 3b060528a26830ee26aab4e9829ac3a310f06218 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 25 Oct 2010 00:40:32 +0200 Subject: init: do not sleep forever on usage errors Signed-off-by: Denys Vlasenko --- init/init.c | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/init/init.c b/init/init.c index 12348078d..a7bbd5e64 100644 --- a/init/init.c +++ b/init/init.c @@ -660,7 +660,9 @@ static struct init_action *mark_terminated(pid_t pid) return a; } } - update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL); + update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, + /*username:*/ NULL, + /*hostname:*/ NULL); } return NULL; } @@ -1086,8 +1088,6 @@ static int check_delayed_sigs(void) int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int init_main(int argc UNUSED_PARAM, char **argv) { - die_sleep = 30 * 24*60*60; /* if xmalloc would ever die... */ - if (argv[1] && strcmp(argv[1], "-q") == 0) { return kill(1, SIGHUP); } @@ -1106,6 +1106,15 @@ int init_main(int argc UNUSED_PARAM, char **argv) #endif } + /* If, say, xmalloc would ever die, we don't want to oops kernel + * by exiting. + * NB: we set die_sleep *after* PID 1 check and bb_show_usage. + * Otherwise, for example, "init u" ("please rexec yourself" + * command for sysvinit) will show help text (which isn't too bad), + * *and sleep forever* (which is bad!) + */ + die_sleep = 30 * 24*60*60; + /* Figure out where the default console should be */ console_init(); set_sane_term(); @@ -1173,7 +1182,7 @@ int init_main(int argc UNUSED_PARAM, char **argv) /* SELinux in enforcing mode but load_policy failed */ message(L_CONSOLE, "can't load SELinux Policy. " "Machine is in enforcing mode. Halting now."); - exit(EXIT_FAILURE); + return EXIT_FAILURE; } } #endif -- cgit v1.2.3-55-g6feb From ccb070450e79c33fb3f755dbea2fdd979f09d3fb Mon Sep 17 00:00:00 2001 From: Kevin Cernekee Date: Mon, 25 Oct 2010 02:00:24 +0200 Subject: fdisk: initial stab at GPT partition support Signed-off-by: Kevin Cernekee Signed-off-by: Denys Vlasenko --- include/libbb.h | 7 +- libbb/human_readable.c | 4 +- util-linux/Config.src | 8 ++ util-linux/fdisk.c | 79 +++++++++++++------ util-linux/fdisk_gpt.c | 203 +++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 275 insertions(+), 26 deletions(-) create mode 100644 util-linux/fdisk_gpt.c diff --git a/include/libbb.h b/include/libbb.h index bd1d586c7..d14728ed0 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -746,7 +746,7 @@ char *itoa(int n) FAST_FUNC; char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC; /* Intelligent formatters of bignums */ -void smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; +void smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) FAST_FUNC; void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; /* If block_size == 0, display size without fractional part, * else display (size * block_size) with one decimal digit. @@ -1543,7 +1543,10 @@ void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; - +/* TODO: add global crc32_table pointer and create + * LE and BE functions to calculate crc32 over given bytes. + * Currently we have about five reimplementations... + */ uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; typedef struct masks_labels_t { diff --git a/libbb/human_readable.c b/libbb/human_readable.c index 22dc5d23f..50cbe41bb 100644 --- a/libbb/human_readable.c +++ b/libbb/human_readable.c @@ -94,7 +94,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val, /* Convert unsigned long long value into compact 5-char representation. * String is not terminated (buf[5] is untouched) */ -void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *scale) +void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) { const char *fmt; char c; @@ -150,7 +150,7 @@ void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *sca /* Convert unsigned long long value into compact 4-char * representation. Examples: "1234", "1.2k", " 27M", "123T" * String is not terminated (buf[4] is untouched) */ -void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) +void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) { const char *fmt; char c; diff --git a/util-linux/Config.src b/util-linux/Config.src index afa30923b..19b309e57 100644 --- a/util-linux/Config.src +++ b/util-linux/Config.src @@ -181,6 +181,14 @@ config FEATURE_OSF_LABEL Enabling this option allows you to create or change BSD disklabels and define and edit BSD disk slices. +config FEATURE_GPT_LABEL + bool "Support GPT disklabels" + default n + depends on FDISK && FEATURE_FDISK_WRITABLE + help + Enabling this option allows you to view GUID Partition Table + disklabels. + config FEATURE_FDISK_ADVANCED bool "Support expert mode" default y diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index b6417a355..3f2e0d3ae 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -107,12 +107,30 @@ struct partition { unsigned char size4[4]; /* nr of sectors in partition */ } PACKED; +/* + * per partition table entry data + * + * The four primary partitions have the same sectorbuffer (MBRbuffer) + * and have NULL ext_pointer. + * Each logical partition table entry has two pointers, one for the + * partition and one link to the next one. + */ +struct pte { + struct partition *part_table; /* points into sectorbuffer */ + struct partition *ext_pointer; /* points into sectorbuffer */ + sector_t offset_from_dev_start; /* disk sector number */ + char *sectorbuffer; /* disk sector contents */ +#if ENABLE_FEATURE_FDISK_WRITABLE + char changed; /* boolean */ +#endif +}; + #define unable_to_open "can't open '%s'" #define unable_to_read "can't read from %s" #define unable_to_seek "can't seek on %s" enum label_type { - LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF + LABEL_DOS, LABEL_SUN, LABEL_SGI, LABEL_AIX, LABEL_OSF, LABEL_GPT }; #define LABEL_IS_DOS (LABEL_DOS == current_label_type) @@ -149,6 +167,14 @@ enum label_type { #define STATIC_OSF extern #endif +#if ENABLE_FEATURE_GPT_LABEL +#define LABEL_IS_GPT (LABEL_GPT == current_label_type) +#define STATIC_GPT static +#else +#define LABEL_IS_GPT 0 +#define STATIC_GPT extern +#endif + enum action { OPEN_MAIN, TRY_ONLY, CREATE_EMPTY_DOS, CREATE_EMPTY_SUN }; static void update_units(void); @@ -162,6 +188,7 @@ static sector_t read_int(sector_t low, sector_t dflt, sector_t high, sector_t ba #endif static const char *partition_type(unsigned char type); static void get_geometry(void); +static void read_pte(struct pte *pe, sector_t offset); #if ENABLE_FEATURE_SUN_LABEL || ENABLE_FEATURE_FDISK_WRITABLE static int get_boot(enum action what); #else @@ -174,24 +201,6 @@ static int get_boot(void); static sector_t get_start_sect(const struct partition *p); static sector_t get_nr_sects(const struct partition *p); -/* - * per partition table entry data - * - * The four primary partitions have the same sectorbuffer (MBRbuffer) - * and have NULL ext_pointer. - * Each logical partition table entry has two pointers, one for the - * partition and one link to the next one. - */ -struct pte { - struct partition *part_table; /* points into sectorbuffer */ - struct partition *ext_pointer; /* points into sectorbuffer */ - sector_t offset_from_dev_start; /* disk sector number */ - char *sectorbuffer; /* disk sector contents */ -#if ENABLE_FEATURE_FDISK_WRITABLE - char changed; /* boolean */ -#endif -}; - /* DOS partition types */ static const char *const i386_sys_types[] = { @@ -653,6 +662,8 @@ STATIC_OSF void bsd_select(void); STATIC_OSF void xbsd_print_disklabel(int); #include "fdisk_osf.c" +#include "fdisk_gpt.c" + #if ENABLE_FEATURE_SGI_LABEL || ENABLE_FEATURE_SUN_LABEL static uint16_t fdisk_swap16(uint16_t x) @@ -833,6 +844,11 @@ menu(void) puts("o\tcreate a new empty DOS partition table"); puts("q\tquit without saving changes"); puts("s\tcreate a new empty Sun disklabel"); /* sun */ + } else if (LABEL_IS_GPT) { + puts("o\tcreate a new empty DOS partition table"); + puts("p\tprint the partition table"); + puts("q\tquit without saving changes"); + puts("s\tcreate a new empty Sun disklabel"); /* sun */ } else { puts("a\ttoggle a bootable flag"); puts("b\tedit bsd disklabel"); @@ -1308,7 +1324,18 @@ get_geometry(void) /* * Opens disk_device and optionally reads MBR. - * FIXME: document what each 'what' value will do! + * If what == OPEN_MAIN: + * Open device, read MBR. Abort program on short read. Create empty + * disklabel if the on-disk structure is invalid (WRITABLE mode). + * If what == TRY_ONLY: + * Open device, read MBR. Return an error if anything is out of place. + * Do not create an empty disklabel. This is used for the "list" + * operations: "fdisk -l /dev/sda" and "fdisk -l" (all devices). + * If what == CREATE_EMPTY_*: + * This means that get_boot() was called recursively from create_*label(). + * Do not re-open the device; just set up the ptes array and print + * geometry warnings. + * * Returns: * -1: no 0xaa55 flag present (possibly entire disk BSD) * 0: found or created label @@ -1390,6 +1417,10 @@ static int get_boot(void) if (check_aix_label()) return 0; #endif +#if ENABLE_FEATURE_GPT_LABEL + if (check_gpt_label()) + return 0; +#endif #if ENABLE_FEATURE_OSF_LABEL if (check_osf_label()) { possibly_osf_label = 1; @@ -1409,7 +1440,7 @@ static int get_boot(void) if (!valid_part_table_flag(MBRbuffer)) { if (what == OPEN_MAIN) { printf("Device contains neither a valid DOS " - "partition table, nor Sun, SGI or OSF " + "partition table, nor Sun, SGI, OSF or GPT " "disklabel\n"); #ifdef __sparc__ IF_FEATURE_SUN_LABEL(create_sunlabel();) @@ -2056,10 +2087,14 @@ list_table(int xtra) sun_list_table(xtra); return; } - if (LABEL_IS_SUN) { + if (LABEL_IS_SGI) { sgi_list_table(xtra); return; } + if (LABEL_IS_GPT) { + gpt_list_table(xtra); + return; + } list_disk_geometry(); diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c new file mode 100644 index 000000000..98803ec88 --- /dev/null +++ b/util-linux/fdisk_gpt.c @@ -0,0 +1,203 @@ +#if ENABLE_FEATURE_GPT_LABEL +/* + * Copyright (C) 2010 Kevin Cernekee + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +#define GPT_MAGIC 0x5452415020494645ULL +enum { + LEGACY_GPT_TYPE = 0xee, + GPT_MAX_PARTS = 256, + GPT_MAX_PART_ENTRY_LEN = 4096, + GUID_LEN = 16, +}; + +typedef struct { + uint64_t magic; + uint32_t revision; + uint32_t hdr_size; + uint32_t hdr_crc32; + uint32_t reserved; + uint64_t current_lba; + uint64_t backup_lba; + uint64_t first_usable_lba; + uint64_t last_usable_lba; + uint8_t disk_guid[GUID_LEN]; + uint64_t first_part_lba; + uint32_t n_parts; + uint32_t part_entry_len; + uint32_t part_array_crc32; +} gpt_header; + +typedef struct { + uint8_t type_guid[GUID_LEN]; + uint8_t part_guid[GUID_LEN]; + uint64_t lba_start; + uint64_t lba_end; + uint64_t flags; + uint16_t name[36]; +} gpt_partition; + +static gpt_header *gpt_hdr; + +static char *part_array; +static unsigned int n_parts; +static unsigned int part_array_len; +static unsigned int part_entry_len; + +static uint32_t *crc32_table; + +static inline gpt_partition * +gpt_part(int i) +{ + if (i >= n_parts) { + return NULL; + } + return (gpt_partition *)&part_array[i * part_entry_len]; +} + +/* TODO: move to libbb */ +static uint32_t +gpt_crc32(void *buf, int len) +{ + uint32_t crc = 0xffffffff; + + for (; len > 0; len--, buf++) { + crc = crc32_table[(crc ^ *((char *)buf)) & 0xff] ^ (crc >> 8); + } + return crc ^ 0xffffffff; +} + +static void +gpt_print_guid(uint8_t *buf) +{ + printf( + "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x", + buf[3], buf[2], buf[1], buf[0], + buf[5], buf[4], + buf[7], buf[6], + buf[8], buf[9], + buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]); +} + +/* TODO: real unicode support */ +static void +gpt_print_wide(uint16_t *s, int max_len) +{ + int i = 0; + + while (i < max_len) { + if (*s == 0) + return; + fputc(*s, stdout); + s++; + } +} + +static void +gpt_list_table(int xtra UNUSED_PARAM) +{ + int i; + char numstr6[6]; + + numstr6[5] = '\0'; + + smart_ulltoa5(total_number_of_sectors, numstr6, " KMGTPEZY"); + printf("Disk %s: %llu sectors, %s\n", disk_device, + (unsigned long long)total_number_of_sectors, + numstr6); + printf("Logical sector size: %u\n", sector_size); + printf("Disk identifier (GUID): "); + gpt_print_guid(gpt_hdr->disk_guid); + printf("\nPartition table holds up to %u entries\n", + (int)SWAP_LE32(gpt_hdr->n_parts)); + printf("First usable sector is %llu, last usable sector is %llu\n\n", + (unsigned long long)SWAP_LE64(gpt_hdr->first_usable_lba), + (unsigned long long)SWAP_LE64(gpt_hdr->last_usable_lba)); + + printf("Number Start (sector) End (sector) Size Code Name\n"); + for (i = 0; i < n_parts; i++) { + gpt_partition *p = gpt_part(i); + if (p->lba_start) { + smart_ulltoa5(1 + SWAP_LE64(p->lba_end) - SWAP_LE64(p->lba_start), + numstr6, " KMGTPEZY"); + printf("%4u %15llu %15llu %11s %04x ", + i + 1, + (unsigned long long)SWAP_LE64(p->lba_start), + (unsigned long long)SWAP_LE64(p->lba_end), + numstr6, + 0x0700 /* FIXME */); + gpt_print_wide(p->name, 18); + printf("\n"); + } + } +} + +static int +check_gpt_label(void) +{ + struct partition *first = pt_offset(MBRbuffer, 0); + struct pte pe; + uint32_t crc; + + /* LBA 0 contains the legacy MBR */ + + if (!valid_part_table_flag(MBRbuffer) + || first->sys_ind != LEGACY_GPT_TYPE + ) { + current_label_type = 0; + return 0; + } + + /* LBA 1 contains the GPT header */ + + read_pte(&pe, 1); + gpt_hdr = (void *)pe.sectorbuffer; + + if (gpt_hdr->magic != SWAP_LE64(GPT_MAGIC)) { + current_label_type = 0; + return 0; + } + + if (!crc32_table) { + crc32_table = crc32_filltable(NULL, 0); + } + + crc = SWAP_LE32(gpt_hdr->hdr_crc32); + gpt_hdr->hdr_crc32 = 0; + if (gpt_crc32(gpt_hdr, SWAP_LE32(gpt_hdr->hdr_size)) != crc) { + /* FIXME: read the backup table */ + puts("\nwarning: GPT header CRC is invalid\n"); + } + + n_parts = SWAP_LE32(gpt_hdr->n_parts); + part_entry_len = SWAP_LE32(gpt_hdr->part_entry_len); + if (n_parts > GPT_MAX_PARTS + || part_entry_len > GPT_MAX_PART_ENTRY_LEN + || SWAP_LE32(gpt_hdr->hdr_size) > sector_size + ) { + puts("\nwarning: unable to parse GPT disklabel\n"); + current_label_type = 0; + return 0; + } + + part_array_len = n_parts * part_entry_len; + part_array = xmalloc(part_array_len); + seek_sector(SWAP_LE64(gpt_hdr->first_part_lba)); + if (full_read(dev_fd, part_array, part_array_len) != part_array_len) { + fdisk_fatal(unable_to_read); + } + + if (gpt_crc32(part_array, part_array_len) != gpt_hdr->part_array_crc32) { + /* FIXME: read the backup table */ + puts("\nwarning: GPT array CRC is invalid\n"); + } + + puts("Found valid GPT with protective MBR; using GPT\n"); + + current_label_type = LABEL_GPT; + return 1; +} + +#endif /* GPT_LABEL */ -- cgit v1.2.3-55-g6feb From b507cc3aceda26eff851230223a62c6fb471573c Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Mon, 25 Oct 2010 03:44:34 +0200 Subject: powertop: new applet Signed-off-by: Marek Polacek Signed-off-by: Denys Vlasenko --- libbb/Config.src | 11 + procps/powertop.c | 886 ++++++++++++++++++++++++++++++++++++++++++++++++++ util-linux/Config.src | 11 - 3 files changed, 897 insertions(+), 11 deletions(-) create mode 100644 procps/powertop.c diff --git a/libbb/Config.src b/libbb/Config.src index 74dc9c549..f6c7a11ea 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -43,6 +43,17 @@ config FEATURE_ETC_NETWORKS a rarely used feature which allows you to use names instead of IP/mask pairs in route command. +config FEATURE_USE_TERMIOS + bool "Use termios to manipulate the screen" + default y + depends on MORE || TOP || POWERTOP + help + This option allows utilities such as 'more' and 'top' to determine + the size of the screen. If you leave this disabled, your utilities + that display things on the screen will be especially primitive and + will be unable to determine the current screen size, and will be + unable to move the cursor. + config FEATURE_EDITING bool "Command line editing" default y diff --git a/procps/powertop.c b/procps/powertop.c new file mode 100644 index 000000000..f35aa5c0a --- /dev/null +++ b/procps/powertop.c @@ -0,0 +1,886 @@ +/* vi: set sw=4 ts=4: */ +/* + * A mini 'powertop' utility: + * Analyze power consumption on Intel-based laptops. + * Based on powertop 1.11. + * + * Copyright (C) 2010 Marek Polacek + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//applet:IF_POWERTOP(APPLET(powertop, _BB_DIR_BIN, _BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_POWERTOP) += powertop.o + +//config:config POWERTOP +//config: bool "powertop" +//config: default y +//config: help +//config: Analyze power consumption on Intel-based laptops + +#include "libbb.h" + +//#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) +#define debug(fmt, ...) ((void)0) + +// XXX This should not be here +#define ENABLE_FEATURE_POWERTOP_PROCIRQ 1 + +#define DEFAULT_SLEEP 10 +#define DEFAULT_SLEEP_STR "10" + +/* Frequency of the ACPI timer */ +#define FREQ_ACPI 3579.545 +#define FREQ_ACPI_1000 3579545 + +/* Max filename length of entry in /sys/devices subsystem */ +#define BIG_SYSNAME_LEN 16 + +typedef unsigned long long ullong; + +struct line { + char *string; + int count; + int disk_count; +}; + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ +#define IRQCOUNT 40 + +struct irqdata { + int active; + int number; + ullong count; + char irq_desc[32]; +}; +#endif + +struct globals { + bool timer_list_read; + smallint nostats; + int headline; + int nlines; + int linesize; + int maxcstate; +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + int total_interrupt; + int interrupt_0; + int percpu_hpet_start; + int percpu_hpet_end; + struct irqdata interrupts[IRQCOUNT]; +#endif + unsigned total_cpus; + ullong start_usage[8]; + ullong last_usage[8]; + ullong start_duration[8]; + ullong last_duration[8]; + char cstate_names[8][16]; + struct line *lines; +#if ENABLE_FEATURE_USE_TERMIOS + struct termios init_settings; +#endif +}; +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + +#if ENABLE_FEATURE_USE_TERMIOS +static void reset_term(void) +{ + tcsetattr_stdin_TCSANOW(&G.init_settings); +} + +static void sig_handler(int signo UNUSED_PARAM) +{ + reset_term(); + exit(EXIT_FAILURE); +} +#endif + +static int write_str_to_file(const char *fname, const char *str) +{ + FILE *fp = fopen_for_write(fname); + if (!fp) + return 1; + fputs(str, fp); + fclose(fp); + return 0; +} + +/* Make it more readable */ +#define start_timer() write_str_to_file("/proc/timer_stats", "1\n") +#define stop_timer() write_str_to_file("/proc/timer_stats", "0\n") + +static void NOINLINE clear_lines(void) +{ + int i; + + for (i = 0; i < G.headline; i++) + free(G.lines[i].string); + free(G.lines); + G.headline = G.linesize = 0; + G.lines = NULL; +} + +static void count_lines(void) +{ + int i; + + for (i = 0; i < G.headline; i++) + G.nlines += G.lines[i].count; +} + +static int line_compare(const void *p1, const void *p2) +{ + const struct line *a = p1; + const struct line *b = p2; + + return (b->count + 50 * b->disk_count) - (a->count + 50 * a->disk_count); +} + +static void do_sort(void) +{ + qsort(G.lines, G.headline, sizeof(struct line), line_compare); +} + +/* + * Save C-state names, usage and duration. Also get maxcstate. + * Reads data from /proc. + */ +static void read_data(ullong *usage, ullong *duration) +{ + DIR *dir; + struct dirent *d; + + dir = opendir("/proc/acpi/processor"); + if (!dir) + return; + + while ((d = readdir(dir)) != NULL) { + FILE *fp; + char buf[192]; + int level = 0; + int len; + + len = strlen(d->d_name); + if (len < 3 || len > BIG_SYSNAME_LEN) + continue; + + sprintf(buf, "/proc/acpi/processor/%s/power", d->d_name); + fp = fopen_for_read(buf); + if (!fp) + continue; + + while (fgets(buf, sizeof(buf), fp)) { + char *p; + + /* Get usage */ + p = strstr(buf, "age["); + if (!p) + continue; + p += 4; + usage[level] += bb_strtoull(p, NULL, 10) + 1; + + /* Get duration */ + p = strstr(buf, "ation["); + if (!p) + continue; + p += 6; + duration[level] += bb_strtoull(p, NULL, 10); + + /* Increment level */ + level++; + + /* Also update maxcstate */ + if (level > G.maxcstate) + G.maxcstate = level; + } + fclose(fp); + } + closedir(dir); +} + +/* Add line and/or update count */ +static void push_line(const char *string, int count) +{ + int i; + + if (!string) + return; + + /* Loop through entries */ + for (i = 0; i < G.headline; i++) { + if (strcmp(string, G.lines[i].string) == 0) { + /* It's already there, only update count */ + G.lines[i].count += count; + return; + } + } + + G.lines = xrealloc_vector(G.lines, 1, G.headline); + + G.lines[G.headline].string = xstrdup(string); + G.lines[G.headline].count = count; + G.lines[G.headline].disk_count = 0; + + /* We added a line */ + G.headline++; +} + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ +static int percpu_hpet_timer(const char *name) +{ + char *p; + long hpet_chan; + + /* This is done once */ + if (!G.timer_list_read) { + FILE *fp; + char buf[80]; + + G.timer_list_read = true; + fp = fopen_for_read("/proc/timer_list"); + if (!fp) + return 0; + + while (fgets(buf, sizeof(buf), fp)) { + p = strstr(buf, "Clock Event Device: hpet"); + if (!p) + continue; + p += sizeof("Clock Event Device: hpet")-1; + if (!isdigit(p[0])) + continue; + hpet_chan = xatoi_positive(p); + if (hpet_chan < G.percpu_hpet_start) + G.percpu_hpet_start = hpet_chan; + if (hpet_chan > G.percpu_hpet_end) + G.percpu_hpet_end = hpet_chan; + } + fclose(fp); + } + + p = strstr(name, "hpet"); + if (!p) + return 0; + + p += 4; + if (!isdigit(p[0])) + return 0; + + hpet_chan = xatoi_positive(p); + if (G.percpu_hpet_start <= hpet_chan && hpet_chan <= G.percpu_hpet_end) + return 1; + + return 0; +} + +static int update_irq(int irq, ullong count) +{ + int unused = IRQCOUNT; + int i; + + for (i = 0; i < IRQCOUNT; i++) { + if (G.interrupts[i].active && G.interrupts[i].number == irq) { + ullong old; + old = G.interrupts[i].count; + G.interrupts[i].count = count; + return count - old; + } + if (!G.interrupts[i].active && unused > i) + unused = i; + } + + G.interrupts[unused].active = 1; + G.interrupts[unused].count = count; + G.interrupts[unused].number = irq; + + return count; +} + +/* + * Read /proc/interrupts, save IRQ counts and IRQ description. + */ +static void do_proc_irq(void) +{ + FILE *fp; + char buf[128]; + + /* Reset values */ + G.interrupt_0 = 0; + G.total_interrupt = 0; + + fp = xfopen_for_read("/proc/interrupts"); + while (fgets(buf, sizeof(buf), fp)) { + char irq_desc[sizeof(" : ") + sizeof(buf)]; + char *p; + const char *name; + int nr = -1; + ullong count; + ullong delta; + int special; + + /* Skip header */ + p = strchr(buf, ':'); + if (!p) + continue; + /* 0: 143646045 153901007 IO-APIC-edge timer + * ^ + */ + /* Deal with non-maskable interrupts -- make up fake numbers */ + special = 0; + if (buf[0] != ' ' && !isdigit(buf[0])) { + if (strncmp(buf, "NMI:", 4) == 0) + nr = 20000; + if (strncmp(buf, "RES:", 4) == 0) + nr = 20001; + if (strncmp(buf, "CAL:", 4) == 0) + nr = 20002; + if (strncmp(buf, "TLB:", 4) == 0) + nr = 20003; + if (strncmp(buf, "TRM:", 4) == 0) + nr = 20004; + if (strncmp(buf, "THR:", 4) == 0) + nr = 20005; + if (strncmp(buf, "SPU:", 4) == 0) + nr = 20006; + special = 1; + } else { + /* bb_strtou don't eat leading spaces, using strtoul */ + nr = strtoul(buf, NULL, 10); /* xato*() wouldn't work */ + } + if (nr == -1) + continue; + + p++; + /* 0: 143646045 153901007 IO-APIC-edge timer + * ^ + */ + /* Count sum of the IRQs */ + count = 0; + while (1) { + char *tmp; + p = skip_whitespace(p); + if (!isdigit(*p)) + break; + count += bb_strtoull(p, &tmp, 10); + p = tmp; + } + /* 0: 143646045 153901007 IO-APIC-edge timer + * NMI: 1 2 Non-maskable interrupts + * ^ + */ + if (!special) { + /* Skip to the interrupt name, e.g. 'timer' */ + p = strchr(p, ' '); + if (!p) + continue; + p = skip_whitespace(p); + } + + name = p; + strchrnul(name, '\n')[0] = '\0'; + /* Save description of the interrupt */ + if (special) + sprintf(irq_desc, " : %s", name); + else + sprintf(irq_desc, " : %s", name); + + delta = update_irq(nr, count); + + /* Skip per CPU timer interrupts */ + if (percpu_hpet_timer(name)) + delta = 0; + if (nr > 0 && delta > 0) + push_line(irq_desc, delta); + if (!nr) + G.interrupt_0 = delta; + else + G.total_interrupt += delta; + } + + fclose(fp); +} +#endif /* ENABLE_FEATURE_POWERTOP_PROCIRQ */ + +#ifdef __i386__ +/* + * Get information about CPU using CPUID opcode. + */ +static void cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, + unsigned int *edx) +{ + /* EAX value specifies what information to return */ + __asm__( + " pushl %%ebx\n" /* Save EBX */ + " cpuid\n" + " movl %%ebx, %1\n" /* Save content of EBX */ + " popl %%ebx\n" /* Restore EBX */ + : "=a"(*eax), /* Output */ + "=r"(*ebx), + "=c"(*ecx), + "=d"(*edx) + : "0"(*eax), /* Input */ + "1"(*ebx), + "2"(*ecx), + "3"(*edx) + /* No clobbered registers */ + ); +} +#endif + +static void NOINLINE print_intel_cstates(void) +{ +#ifdef __i386__ + int bios_table[8] = { 0 }; + int nbios = 0; + DIR *cpudir; + struct dirent *d; + int i; + unsigned eax, ebx, ecx, edx; + + cpudir = opendir("/sys/devices/system/cpu"); + if (!cpudir) + return; + + /* Loop over cpuN entries */ + while ((d = readdir(cpudir)) != NULL) { + DIR *dir; + int len; + char fname[sizeof("/sys/devices/system/cpu//cpuidle//desc") + 2*BIG_SYSNAME_LEN]; + + len = strlen(d->d_name); + if (len < 3 || len > BIG_SYSNAME_LEN) + continue; + + if (!isdigit(d->d_name[3])) + continue; + + len = sprintf(fname, "/sys/devices/system/cpu/%s/cpuidle", d->d_name); + dir = opendir(fname); + if (!dir) + continue; + + /* + * Every C-state has its own stateN directory, that + * contains a `time' and a `usage' file. + */ + while ((d = readdir(dir)) != NULL) { + FILE *fp; + char buf[64]; + int n; + + n = strlen(d->d_name); + if (n < 3 || n > BIG_SYSNAME_LEN) + continue; + + sprintf(fname + len, "/%s/desc", d->d_name); + fp = fopen_for_read(fname); + if (fp) { + char *p = fgets(buf, sizeof(buf), fp); + fclose(fp); + if (!p) + break; + p = strstr(p, "MWAIT "); + if (p) { + int pos; + p += sizeof("MWAIT ") - 1; + pos = (bb_strtoull(p, NULL, 16) >> 4) + 1; + if (pos >= ARRAY_SIZE(bios_table)) + continue; + bios_table[pos]++; + nbios++; + } + } + } + closedir(dir); + } + closedir(cpudir); + + if (!nbios) + return; + + eax = 5; + ebx = ecx = edx = 0; + cpuid(&eax, &ebx, &ecx, &edx); + if (!edx || !(ecx & 1)) + return; + + printf("Your CPU supports the following C-states: "); + i = 0; + while (edx) { + if (edx & 7) + printf("C%u ", i); + edx >>= 4; + i++; + } + bb_putchar('\n'); + + /* Print BIOS C-States */ + printf("Your BIOS reports the following C-states: "); + for (i = 0; i < 8; i++) + if (bios_table[i]) + printf("C%u ", i); + + bb_putchar('\n'); +#endif +} + +static void print_header(void) +{ + printf( + /* Clear the screen */ + "\033[H\033[J" + /* Print the header */ + "\033[7m%.*s\033[0m", 79, "PowerTOP (C) 2007 Intel Corporation\n" + ); +} + +static void show_cstates(char cstate_lines[][64]) +{ + int i; + + for (i = 0; i < 10; i++) + if ((cstate_lines[i][0])) + printf("%s", cstate_lines[i]); +} + +static void show_timerstats(int nostats) +{ + unsigned lines; + + /* Get terminal height */ + get_terminal_width_height(STDOUT_FILENO, NULL, &lines); + + /* We don't have whole terminal just for timerstats */ + lines -= 12; + + if (!nostats) { + int i, n = 0; + + puts("\nTop causes for wakeups:"); + for (i = 0; i < G.headline; i++) { + if ((G.lines[i].count > 0 || G.lines[i].disk_count > 0) + && n++ < lines + ) { + char c = ' '; + if (G.lines[i].disk_count) + c = 'D'; + printf(" %5.1f%% (%5.1f)%c %s\n", + G.lines[i].count * 100.0 / G.nlines, + G.lines[i].count * 1.0 / DEFAULT_SLEEP, c, + G.lines[i].string); + } + } + } else { + bb_putchar('\n'); + bb_error_msg("no stats available; run as root or" + " enable the cpufreq_stats module"); + } +} + +//usage:#define powertop_trivial_usage +//usage: "" +//usage:#define powertop_full_usage "\n\n" +//usage: "Analyze power consumption on Intel-based laptops\n" + +int powertop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) +{ + ullong cur_usage[8]; + ullong cur_duration[8]; + char cstate_lines[12][64]; + char buf[128]; +#if ENABLE_FEATURE_USE_TERMIOS + struct termios new_settings; + struct pollfd pfd[1]; + + pfd[0].fd = 0; + pfd[0].events = POLLIN; +#endif + + INIT_G(); + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + G.percpu_hpet_start = INT_MAX; + G.percpu_hpet_end = INT_MIN; +#endif + + /* Print warning when we don't have superuser privileges */ + if (geteuid() != 0) + bb_error_msg("run as root to collect enough information"); + +#if ENABLE_FEATURE_USE_TERMIOS + /* So we don't forget to reset term settings */ + atexit(reset_term); +#endif + + /* Get number of CPUs */ + G.total_cpus = get_cpu_count(); + + printf("Collecting data for "DEFAULT_SLEEP_STR" seconds\n"); + +#if ENABLE_FEATURE_USE_TERMIOS + tcgetattr(0, (void *)&G.init_settings); + memcpy(&new_settings, &G.init_settings, sizeof(new_settings)); + + /* Turn on unbuffered input, turn off echoing */ + new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); + + bb_signals(BB_FATAL_SIGS, sig_handler); + tcsetattr_stdin_TCSANOW(&new_settings); +#endif + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + /* Collect initial data */ + do_proc_irq(); + do_proc_irq(); +#endif + + /* Read initial usage and duration */ + read_data(&G.start_usage[0], &G.start_duration[0]); + + /* Copy them to "last" */ + memcpy(G.last_usage, G.start_usage, sizeof(G.last_usage)); + memcpy(G.last_duration, G.start_duration, sizeof(G.last_duration)); + + /* Display C-states */ + print_intel_cstates(); + + if (stop_timer()) + G.nostats = 1; + + /* The main loop */ + for (;;) { + double maxsleep = 0.0; + ullong totalticks, totalevents; + int i; + FILE *fp; + double newticks; + + if (start_timer()) + G.nostats = 1; + +#if !ENABLE_FEATURE_USE_TERMIOS + sleep(DEFAULT_SLEEP); +#else + if (safe_poll(pfd, 1, DEFAULT_SLEEP * 1000) > 0) { + unsigned char c; + if (safe_read(STDIN_FILENO, &c, 1) != 1) + break; /* EOF/error */ + if (c == G.init_settings.c_cc[VINTR]) + break; /* ^C */ + if ((c | 0x20) == 'q') + break; + } +#endif + + if (stop_timer()) + G.nostats = 1; + + clear_lines(); +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + do_proc_irq(); +#endif + + /* Clear the stats */ + memset(cur_duration, 0, sizeof(cur_duration)); + memset(cur_usage, 0, sizeof(cur_usage)); + + /* Read them */ + read_data(&cur_usage[0], &cur_duration[0]); + + totalticks = totalevents = 0; + + /* Count totalticks and totalevents */ + for (i = 0; i < 8; i++) { + if (cur_usage[i]) { + totalticks += cur_duration[i] - G.last_duration[i]; + totalevents += cur_usage[i] - G.last_usage[i]; + } + } + + /* Show title bar */ + print_header(); + + /* Clear C-state lines */ + memset(&cstate_lines, 0, sizeof(cstate_lines)); + + if (totalevents == 0 && G.maxcstate <= 1) { + /* This should not happen */ + sprintf(cstate_lines[5], "< Detailed C-state information is not " + "available.>\n"); + } else { + double slept; + double percentage; + + newticks = G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000 - totalticks; + + /* Handle rounding errors: do not display negative values */ + if (newticks < 0) + newticks = 0; + + sprintf(cstate_lines[0], "Cn\t Avg residency\n"); + percentage = newticks * 100.0 / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); + sprintf(cstate_lines[1], "C0 (cpu running) (%4.1f%%)\n", + percentage); + + /* Compute values for individual C-states */ + for (i = 0; i < 8; i++) { + if (cur_usage[i]) { + slept = (cur_duration[i] - G.last_duration[i]) + / (cur_usage[i] - G.last_usage[i] + 0.1) / FREQ_ACPI; + percentage = (cur_duration[i] - G.last_duration[i]) * 100 + / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); + + if (!G.cstate_names[i][0]) + sprintf(G.cstate_names[i], "C%u", i + 1); + sprintf(cstate_lines[i + 2], "%s\t%5.1fms (%4.1f%%)\n", + G.cstate_names[i], slept, percentage); + if (maxsleep < slept) + maxsleep = slept; + } + } + } + + /* Display C-states */ + show_cstates(cstate_lines); + + /* Do timer_stats info */ + buf[0] = '\0'; + totalticks = 0; + + fp = NULL; + if (!G.nostats) + fp = fopen_for_read("/proc/timer_stats"); + if (fp) { + while (fgets(buf, sizeof(buf), fp)) { + const char *count, *process, *func; + char line[512]; + int cnt = 0; + bool defferable = false; + char *p; + int j = 0; + +/* Find char ' ', then eat remaining spaces */ +#define ADVANCE(p) do { \ + (p) = strchr((p), ' '); \ + if (!(p)) \ + continue; \ + *(p) = '\0'; \ + (p)++; \ + (p) = skip_whitespace(p); \ +} while (0) + + if (strstr(buf, "total events")) + break; + + while (isspace(buf[j])) + j++; + + count = &buf[j]; + p = (char *)count; + + /* Skip PID */ + p = strchr(p, ','); + if (!p) + continue; + *p = '\0'; + p++; + + p = skip_whitespace(p); + + /* Get process */ + ADVANCE(p); + process = p; + + /* Get function */ + ADVANCE(p); + func = p; + + if (strcmp(process, "swapper") == 0 + && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0 + ) { + process = "[kernel scheduler]"; + func = "Load balancing tick"; + } + + if (strcmp(process, "insmod") == 0) + process = "[kernel module]"; + if (strcmp(process, "modprobe") == 0) + process = "[kernel module]"; + if (strcmp(process, "swapper") == 0) + process = "[kernel core]"; + + p = strchr(p, '\n'); + + if (strncmp(func, "tick_nohz_", 10) == 0) + continue; + if (strncmp(func, "tick_setup_sched_timer", 20) == 0) + continue; + if (strcmp(process, "powertop") == 0) + continue; + + if (p) + *p = '\0'; + + cnt = bb_strtoull(count, &p, 10); + while (*p != 0) { + if (*p++ == 'D') + defferable = true; + } + if (defferable) + continue; + + if (strchr(process, '[')) + sprintf(line, "%s %s", process, func); + else + sprintf(line, "%s", process); + push_line(line, cnt); + } + fclose(fp); + } + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + if (strstr(buf, "total events")) { + int n = bb_strtoull(buf, NULL, 10) / G.total_cpus; + + if (totalevents == 0) { + /* No C-state info available, use timerstats */ + totalevents = n * G.total_cpus + G.total_interrupt; + if (n < 0) + totalevents += G.interrupt_0 - n; + } + if (n > 0 && n < G.interrupt_0) + push_line("[extra timer interrupt]", G.interrupt_0 - n); + } +#endif + if (totalevents) + printf("\n\033[1mWakeups-from-idle per second : %4.1f\tinterval:" + "%ds\n\033[0m", + (double)totalevents / DEFAULT_SLEEP / G.total_cpus, DEFAULT_SLEEP); + + count_lines(); + do_sort(); + + show_timerstats(G.nostats); + + fflush(stdout); + + /* Clear the stats */ + memset(cur_duration, 0, sizeof(cur_duration)); + memset(cur_usage, 0, sizeof(cur_usage)); + + /* Get new values */ + read_data(&cur_usage[0], &cur_duration[0]); + + /* Save them */ + memcpy(G.last_usage, cur_usage, sizeof(G.last_usage)); + memcpy(G.last_duration, cur_duration, sizeof(G.last_duration)); + } /* for (;;) */ + + bb_putchar('\n'); + + return EXIT_SUCCESS; +} diff --git a/util-linux/Config.src b/util-linux/Config.src index 19b309e57..c71b4de38 100644 --- a/util-linux/Config.src +++ b/util-linux/Config.src @@ -486,17 +486,6 @@ config MORE you will probably find this utility very helpful. If you don't have any need to reading text files, you can leave this disabled. -config FEATURE_USE_TERMIOS - bool "Use termios to manipulate the screen" - default y - depends on MORE || TOP - help - This option allows utilities such as 'more' and 'top' to determine - the size of the screen. If you leave this disabled, your utilities - that display things on the screen will be especially primitive and - will be unable to determine the current screen size, and will be - unable to move the cursor. - config MOUNT bool "mount" default y -- cgit v1.2.3-55-g6feb From a2d27a19197cc5ed787dc2439df0cae58053ea2c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 25 Oct 2010 12:14:21 +0200 Subject: libbb/process_escape_sequence.c: fix recently broken handling of \\ Signed-off-by: Denys Vlasenko --- libbb/process_escape_sequence.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c index 7b1d97f9c..346ecfa1e 100644 --- a/libbb/process_escape_sequence.c +++ b/libbb/process_escape_sequence.c @@ -75,8 +75,8 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) * Manpages tend to support coreutils way. * Update: coreutils added support for \e on 28 Oct 2009. */ static const char charmap[] ALIGN1 = { - 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', - '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', + 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', '\0', + '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\', }; const char *p = charmap; do { @@ -84,8 +84,8 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) q++; break; } - } while (*++p != '\\'); - /* p points to found escape char or '\', + } while (*++p != '\0'); + /* p points to found escape char or NUL, * advance it and find what it translates to. * Note that \NUL and unrecognized sequence \z return '\' * and leave ptr pointing to NUL or z. */ -- cgit v1.2.3-55-g6feb From 373789e5675ffaeaab183dc3093664c737f2bd36 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 26 Oct 2010 02:54:13 +0200 Subject: powertop: code shrink function old new delta process_irq_count_deltas - 729 +729 read_cstate_counts - 358 +358 save_line - 150 +150 clear_lines 80 72 -8 line_compare 18 7 -11 .rodata 145736 145699 -37 powertop_main 2527 2341 -186 push_line 193 - -193 read_data 348 - -348 do_proc_irq 890 - -890 ------------------------------------------------------------------------------ (add/remove: 3/3 grow/shrink: 0/4 up/down: 1237/-1673) Total: -436 bytes Signed-off-by: Denys Vlasenko --- procps/powertop.c | 377 +++++++++++++++++++++++++++--------------------------- 1 file changed, 185 insertions(+), 192 deletions(-) diff --git a/procps/powertop.c b/procps/powertop.c index f35aa5c0a..4b410540e 100644 --- a/procps/powertop.c +++ b/procps/powertop.c @@ -19,20 +19,27 @@ //config: help //config: Analyze power consumption on Intel-based laptops +// XXX This should de configurable +#define ENABLE_FEATURE_POWERTOP_PROCIRQ 1 + #include "libbb.h" + //#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) #define debug(fmt, ...) ((void)0) -// XXX This should not be here -#define ENABLE_FEATURE_POWERTOP_PROCIRQ 1 + +#define BLOATY_HPET_IRQ_NUM_DETECTION 0 +#define MAX_CSTATE_COUNT 8 +#define IRQCOUNT 40 + #define DEFAULT_SLEEP 10 #define DEFAULT_SLEEP_STR "10" /* Frequency of the ACPI timer */ #define FREQ_ACPI 3579.545 -#define FREQ_ACPI_1000 3579545 +#define FREQ_ACPI_1000 3579545 /* Max filename length of entry in /sys/devices subsystem */ #define BIG_SYSNAME_LEN 16 @@ -42,14 +49,12 @@ typedef unsigned long long ullong; struct line { char *string; int count; - int disk_count; + /*int disk_count;*/ }; #if ENABLE_FEATURE_POWERTOP_PROCIRQ -#define IRQCOUNT 40 - struct irqdata { - int active; + smallint active; int number; ullong count; char irq_desc[32]; @@ -57,26 +62,28 @@ struct irqdata { #endif struct globals { - bool timer_list_read; - smallint nostats; - int headline; - int nlines; + int lines_cnt; + int lines_cumulative_count; int linesize; int maxcstate; + unsigned total_cpus; + struct line *lines; + smallint cant_enable_timer_stats; #if ENABLE_FEATURE_POWERTOP_PROCIRQ - int total_interrupt; - int interrupt_0; +# if BLOATY_HPET_IRQ_NUM_DETECTION + smallint scanned_timer_list; int percpu_hpet_start; int percpu_hpet_end; +# endif + int interrupt_0; + int total_interrupt; struct irqdata interrupts[IRQCOUNT]; #endif - unsigned total_cpus; - ullong start_usage[8]; - ullong last_usage[8]; - ullong start_duration[8]; - ullong last_duration[8]; - char cstate_names[8][16]; - struct line *lines; + ullong start_usage[MAX_CSTATE_COUNT]; + ullong last_usage[MAX_CSTATE_COUNT]; + ullong start_duration[MAX_CSTATE_COUNT]; + ullong last_duration[MAX_CSTATE_COUNT]; + char cstate_names[MAX_CSTATE_COUNT][16]; #if ENABLE_FEATURE_USE_TERMIOS struct termios init_settings; #endif @@ -95,7 +102,7 @@ static void reset_term(void) static void sig_handler(int signo UNUSED_PARAM) { reset_term(); - exit(EXIT_FAILURE); + _exit(EXIT_FAILURE); } #endif @@ -116,40 +123,35 @@ static int write_str_to_file(const char *fname, const char *str) static void NOINLINE clear_lines(void) { int i; - - for (i = 0; i < G.headline; i++) + for (i = 0; i < G.lines_cnt; i++) free(G.lines[i].string); free(G.lines); - G.headline = G.linesize = 0; + G.lines_cnt = 0; + G.linesize = 0; G.lines = NULL; } -static void count_lines(void) +static void update_lines_cumulative_count(void) { int i; - - for (i = 0; i < G.headline; i++) - G.nlines += G.lines[i].count; + for (i = 0; i < G.lines_cnt; i++) + G.lines_cumulative_count += G.lines[i].count; } static int line_compare(const void *p1, const void *p2) { const struct line *a = p1; const struct line *b = p2; - - return (b->count + 50 * b->disk_count) - (a->count + 50 * a->disk_count); + return (b->count /*+ 50 * b->disk_count*/) - (a->count /*+ 50 * a->disk_count*/); } -static void do_sort(void) +static void sort_lines(void) { - qsort(G.lines, G.headline, sizeof(struct line), line_compare); + qsort(G.lines, G.lines_cnt, sizeof(G.lines[0]), line_compare); } -/* - * Save C-state names, usage and duration. Also get maxcstate. - * Reads data from /proc. - */ -static void read_data(ullong *usage, ullong *duration) +/* Save C-state usage and duration. Also update maxcstate. */ +static void read_cstate_counts(ullong *usage, ullong *duration) { DIR *dir; struct dirent *d; @@ -161,10 +163,10 @@ static void read_data(ullong *usage, ullong *duration) while ((d = readdir(dir)) != NULL) { FILE *fp; char buf[192]; - int level = 0; + int level; int len; - len = strlen(d->d_name); + len = strlen(d->d_name); /* "CPUnn" */ if (len < 3 || len > BIG_SYSNAME_LEN) continue; @@ -173,28 +175,31 @@ static void read_data(ullong *usage, ullong *duration) if (!fp) continue; +// Example file contents: +// active state: C0 +// max_cstate: C8 +// maximum allowed latency: 2000000000 usec +// states: +// C1: type[C1] promotion[--] demotion[--] latency[001] usage[00006173] duration[00000000000000000000] +// C2: type[C2] promotion[--] demotion[--] latency[001] usage[00085191] duration[00000000000083024907] +// C3: type[C3] promotion[--] demotion[--] latency[017] usage[01017622] duration[00000000017921327182] + level = 0; while (fgets(buf, sizeof(buf), fp)) { - char *p; - - /* Get usage */ - p = strstr(buf, "age["); + char *p = strstr(buf, "age["); if (!p) continue; p += 4; usage[level] += bb_strtoull(p, NULL, 10) + 1; - - /* Get duration */ p = strstr(buf, "ation["); if (!p) continue; p += 6; duration[level] += bb_strtoull(p, NULL, 10); - /* Increment level */ + if (level >= MAX_CSTATE_COUNT-1) + break; level++; - - /* Also update maxcstate */ - if (level > G.maxcstate) + if (level > G.maxcstate) /* update maxcstate */ G.maxcstate = level; } fclose(fp); @@ -203,15 +208,10 @@ static void read_data(ullong *usage, ullong *duration) } /* Add line and/or update count */ -static void push_line(const char *string, int count) +static void save_line(const char *string, int count) { int i; - - if (!string) - return; - - /* Loop through entries */ - for (i = 0; i < G.headline; i++) { + for (i = 0; i < G.lines_cnt; i++) { if (strcmp(string, G.lines[i].string) == 0) { /* It's already there, only update count */ G.lines[i].count += count; @@ -219,28 +219,27 @@ static void push_line(const char *string, int count) } } - G.lines = xrealloc_vector(G.lines, 1, G.headline); - - G.lines[G.headline].string = xstrdup(string); - G.lines[G.headline].count = count; - G.lines[G.headline].disk_count = 0; - - /* We added a line */ - G.headline++; + /* Add new line */ + G.lines = xrealloc_vector(G.lines, 1, G.lines_cnt); + G.lines[G.lines_cnt].string = xstrdup(string); + G.lines[G.lines_cnt].count = count; + /*G.lines[G.lines_cnt].disk_count = 0;*/ + G.lines_cnt++; } #if ENABLE_FEATURE_POWERTOP_PROCIRQ -static int percpu_hpet_timer(const char *name) +static int is_hpet_irq(const char *name) { char *p; +# if BLOATY_HPET_IRQ_NUM_DETECTION long hpet_chan; - /* This is done once */ - if (!G.timer_list_read) { + /* Learn the range of existing hpet timers. This is done once */ + if (!G.scanned_timer_list) { FILE *fp; char buf[80]; - G.timer_list_read = true; + G.scanned_timer_list = true; fp = fopen_for_read("/proc/timer_list"); if (!fp) return 0; @@ -250,7 +249,7 @@ static int percpu_hpet_timer(const char *name) if (!p) continue; p += sizeof("Clock Event Device: hpet")-1; - if (!isdigit(p[0])) + if (!isdigit(*p)) continue; hpet_chan = xatoi_positive(p); if (hpet_chan < G.percpu_hpet_start) @@ -260,49 +259,46 @@ static int percpu_hpet_timer(const char *name) } fclose(fp); } - +# endif +//TODO: optimize p = strstr(name, "hpet"); if (!p) return 0; - p += 4; - if (!isdigit(p[0])) + if (!isdigit(*p)) return 0; - +# if BLOATY_HPET_IRQ_NUM_DETECTION hpet_chan = xatoi_positive(p); - if (G.percpu_hpet_start <= hpet_chan && hpet_chan <= G.percpu_hpet_end) - return 1; - - return 0; + if (hpet_chan < G.percpu_hpet_start || hpet_chan > G.percpu_hpet_end) + return 0; +# endif + return 1; } -static int update_irq(int irq, ullong count) +/* Save new IRQ count, return delta from old one */ +static int save_irq_count(int irq, ullong count) { int unused = IRQCOUNT; int i; - for (i = 0; i < IRQCOUNT; i++) { if (G.interrupts[i].active && G.interrupts[i].number == irq) { - ullong old; - old = G.interrupts[i].count; + ullong old = G.interrupts[i].count; G.interrupts[i].count = count; return count - old; } if (!G.interrupts[i].active && unused > i) unused = i; } - - G.interrupts[unused].active = 1; - G.interrupts[unused].count = count; - G.interrupts[unused].number = irq; - + if (unused < IRQCOUNT) { + G.interrupts[unused].active = 1; + G.interrupts[unused].count = count; + G.interrupts[unused].number = irq; + } return count; } -/* - * Read /proc/interrupts, save IRQ counts and IRQ description. - */ -static void do_proc_irq(void) +/* Read /proc/interrupts, save IRQ counts and IRQ description */ +static void process_irq_count_deltas(void) { FILE *fp; char buf[128]; @@ -316,12 +312,10 @@ static void do_proc_irq(void) char irq_desc[sizeof(" : ") + sizeof(buf)]; char *p; const char *name; - int nr = -1; + int nr; ullong count; ullong delta; - int special; - /* Skip header */ p = strchr(buf, ':'); if (!p) continue; @@ -329,8 +323,9 @@ static void do_proc_irq(void) * ^ */ /* Deal with non-maskable interrupts -- make up fake numbers */ - special = 0; + nr = -1; if (buf[0] != ' ' && !isdigit(buf[0])) { +//TODO: optimize if (strncmp(buf, "NMI:", 4) == 0) nr = 20000; if (strncmp(buf, "RES:", 4) == 0) @@ -345,10 +340,9 @@ static void do_proc_irq(void) nr = 20005; if (strncmp(buf, "SPU:", 4) == 0) nr = 20006; - special = 1; } else { - /* bb_strtou don't eat leading spaces, using strtoul */ - nr = strtoul(buf, NULL, 10); /* xato*() wouldn't work */ + /* bb_strtou doesn't eat leading spaces, using strtoul */ + nr = strtoul(buf, NULL, 10); } if (nr == -1) continue; @@ -357,7 +351,7 @@ static void do_proc_irq(void) /* 0: 143646045 153901007 IO-APIC-edge timer * ^ */ - /* Count sum of the IRQs */ + /* Sum counts for this IRQ */ count = 0; while (1) { char *tmp; @@ -371,7 +365,7 @@ static void do_proc_irq(void) * NMI: 1 2 Non-maskable interrupts * ^ */ - if (!special) { + if (nr < 20000) { /* Skip to the interrupt name, e.g. 'timer' */ p = strchr(p, ' '); if (!p) @@ -382,19 +376,21 @@ static void do_proc_irq(void) name = p; strchrnul(name, '\n')[0] = '\0'; /* Save description of the interrupt */ - if (special) + if (nr < 20000) sprintf(irq_desc, " : %s", name); else sprintf(irq_desc, " : %s", name); - delta = update_irq(nr, count); + delta = save_irq_count(nr, count); /* Skip per CPU timer interrupts */ - if (percpu_hpet_timer(name)) - delta = 0; - if (nr > 0 && delta > 0) - push_line(irq_desc, delta); - if (!nr) + if (is_hpet_irq(name)) + continue; + + if (nr != 0 && delta != 0) + save_line(irq_desc, delta); + + if (nr == 0) G.interrupt_0 = delta; else G.total_interrupt += delta; @@ -402,7 +398,9 @@ static void do_proc_irq(void) fclose(fp); } -#endif /* ENABLE_FEATURE_POWERTOP_PROCIRQ */ +#else /* !ENABLE_FEATURE_POWERTOP_PROCIRQ */ +# define process_irq_count_deltas() ((void)0) +#endif #ifdef __i386__ /* @@ -546,7 +544,7 @@ static void show_cstates(char cstate_lines[][64]) printf("%s", cstate_lines[i]); } -static void show_timerstats(int nostats) +static void show_timerstats(void) { unsigned lines; @@ -556,19 +554,19 @@ static void show_timerstats(int nostats) /* We don't have whole terminal just for timerstats */ lines -= 12; - if (!nostats) { + if (!G.cant_enable_timer_stats) { int i, n = 0; puts("\nTop causes for wakeups:"); - for (i = 0; i < G.headline; i++) { - if ((G.lines[i].count > 0 || G.lines[i].disk_count > 0) + for (i = 0; i < G.lines_cnt; i++) { + if ((G.lines[i].count > 0 /*|| G.lines[i].disk_count > 0*/) && n++ < lines ) { char c = ' '; - if (G.lines[i].disk_count) - c = 'D'; + /*if (G.lines[i].disk_count) + c = 'D';*/ printf(" %5.1f%% (%5.1f)%c %s\n", - G.lines[i].count * 100.0 / G.nlines, + G.lines[i].count * 100.0 / G.lines_cumulative_count, G.lines[i].count * 1.0 / DEFAULT_SLEEP, c, G.lines[i].string); } @@ -580,6 +578,24 @@ static void show_timerstats(int nostats) } } +// Example display from powertop version 1.11 +// Cn Avg residency P-states (frequencies) +// C0 (cpu running) ( 0.5%) 2.00 Ghz 0.0% +// polling 0.0ms ( 0.0%) 1.67 Ghz 0.0% +// C1 mwait 0.0ms ( 0.0%) 1333 Mhz 0.1% +// C2 mwait 0.1ms ( 0.1%) 1000 Mhz 99.9% +// C3 mwait 12.1ms (99.4%) +// +// Wakeups-from-idle per second : 93.6 interval: 15.0s +// no ACPI power usage estimate available +// +// Top causes for wakeups: +// 32.4% ( 26.7) : extra timer interrupt +// 29.0% ( 23.9) : hrtimer_start_range_ns (tick_sched_timer) +// 9.0% ( 7.5) : hrtimer_start (tick_sched_timer) +// 6.5% ( 5.3) : ata_piix +// 5.0% ( 4.1) inetd : hrtimer_start_range_ns (hrtimer_wakeup) + //usage:#define powertop_trivial_usage //usage: "" //usage:#define powertop_full_usage "\n\n" @@ -588,8 +604,8 @@ static void show_timerstats(int nostats) int powertop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) { - ullong cur_usage[8]; - ullong cur_duration[8]; + ullong cur_usage[MAX_CSTATE_COUNT]; + ullong cur_duration[MAX_CSTATE_COUNT]; char cstate_lines[12][64]; char buf[128]; #if ENABLE_FEATURE_USE_TERMIOS @@ -602,7 +618,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) INIT_G(); -#if ENABLE_FEATURE_POWERTOP_PROCIRQ +#if ENABLE_FEATURE_POWERTOP_PROCIRQ && BLOATY_HPET_IRQ_NUM_DETECTION G.percpu_hpet_start = INT_MAX; G.percpu_hpet_end = INT_MIN; #endif @@ -611,11 +627,6 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) if (geteuid() != 0) bb_error_msg("run as root to collect enough information"); -#if ENABLE_FEATURE_USE_TERMIOS - /* So we don't forget to reset term settings */ - atexit(reset_term); -#endif - /* Get number of CPUs */ G.total_cpus = get_cpu_count(); @@ -624,22 +635,19 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) #if ENABLE_FEATURE_USE_TERMIOS tcgetattr(0, (void *)&G.init_settings); memcpy(&new_settings, &G.init_settings, sizeof(new_settings)); - /* Turn on unbuffered input, turn off echoing */ new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); - + /* So we don't forget to reset term settings */ + atexit(reset_term); bb_signals(BB_FATAL_SIGS, sig_handler); tcsetattr_stdin_TCSANOW(&new_settings); #endif -#if ENABLE_FEATURE_POWERTOP_PROCIRQ /* Collect initial data */ - do_proc_irq(); - do_proc_irq(); -#endif + process_irq_count_deltas(); /* Read initial usage and duration */ - read_data(&G.start_usage[0], &G.start_duration[0]); + read_cstate_counts(G.start_usage, G.start_duration); /* Copy them to "last" */ memcpy(G.last_usage, G.start_usage, sizeof(G.last_usage)); @@ -648,20 +656,16 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) /* Display C-states */ print_intel_cstates(); - if (stop_timer()) - G.nostats = 1; + G.cant_enable_timer_stats |= stop_timer(); /* 1 on error */ /* The main loop */ for (;;) { - double maxsleep = 0.0; + /*double maxsleep = 0.0;*/ ullong totalticks, totalevents; int i; FILE *fp; - double newticks; - - if (start_timer()) - G.nostats = 1; + G.cant_enable_timer_stats |= start_timer(); /* 1 on error */ #if !ENABLE_FEATURE_USE_TERMIOS sleep(DEFAULT_SLEEP); #else @@ -675,27 +679,22 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) break; } #endif - - if (stop_timer()) - G.nostats = 1; + G.cant_enable_timer_stats |= stop_timer(); /* 1 on error */ clear_lines(); -#if ENABLE_FEATURE_POWERTOP_PROCIRQ - do_proc_irq(); -#endif + process_irq_count_deltas(); /* Clear the stats */ memset(cur_duration, 0, sizeof(cur_duration)); memset(cur_usage, 0, sizeof(cur_usage)); /* Read them */ - read_data(&cur_usage[0], &cur_duration[0]); - - totalticks = totalevents = 0; + read_cstate_counts(cur_usage, cur_duration); /* Count totalticks and totalevents */ - for (i = 0; i < 8; i++) { - if (cur_usage[i]) { + totalticks = totalevents = 0; + for (i = 0; i < MAX_CSTATE_COUNT; i++) { + if (cur_usage[i] != 0) { totalticks += cur_duration[i] - G.last_duration[i]; totalevents += cur_usage[i] - G.last_usage[i]; } @@ -714,6 +713,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) } else { double slept; double percentage; + double newticks; newticks = G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000 - totalticks; @@ -727,8 +727,8 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) percentage); /* Compute values for individual C-states */ - for (i = 0; i < 8; i++) { - if (cur_usage[i]) { + for (i = 0; i < MAX_CSTATE_COUNT; i++) { + if (cur_usage[i] != 0) { slept = (cur_duration[i] - G.last_duration[i]) / (cur_usage[i] - G.last_usage[i] + 0.1) / FREQ_ACPI; percentage = (cur_duration[i] - G.last_duration[i]) * 100 @@ -738,8 +738,8 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) sprintf(G.cstate_names[i], "C%u", i + 1); sprintf(cstate_lines[i + 2], "%s\t%5.1fms (%4.1f%%)\n", G.cstate_names[i], slept, percentage); - if (maxsleep < slept) - maxsleep = slept; + /*if (maxsleep < slept) + maxsleep = slept;*/ } } } @@ -752,16 +752,34 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) totalticks = 0; fp = NULL; - if (!G.nostats) + if (!G.cant_enable_timer_stats) fp = fopen_for_read("/proc/timer_stats"); if (fp) { +// Examlpe file contents: +// Timer Stats Version: v0.2 +// Sample period: 1.329 s +// 76, 0 swapper hrtimer_start_range_ns (tick_sched_timer) +// 88, 0 swapper hrtimer_start_range_ns (tick_sched_timer) +// 24, 3787 firefox hrtimer_start_range_ns (hrtimer_wakeup) +// 46D, 1136 kondemand/1 do_dbs_timer (delayed_work_timer_fn) +// ... +// 1, 1656 Xorg hrtimer_start_range_ns (hrtimer_wakeup) +// 1, 2159 udisks-daemon hrtimer_start_range_ns (hrtimer_wakeup) +// 331 total events, 249.059 events/sec while (fgets(buf, sizeof(buf), fp)) { const char *count, *process, *func; + char *p; char line[512]; int cnt = 0; - bool defferable = false; - char *p; - int j = 0; +// TODO: optimize + if (strstr(buf, "total events")) + break; + count = skip_whitespace(buf); + p = strchr(count, ','); + if (!p) + continue; + *p++ = '\0'; + p = skip_whitespace(p); /* points to pid */ /* Find char ' ', then eat remaining spaces */ #define ADVANCE(p) do { \ @@ -772,26 +790,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) (p)++; \ (p) = skip_whitespace(p); \ } while (0) - - if (strstr(buf, "total events")) - break; - - while (isspace(buf[j])) - j++; - - count = &buf[j]; - p = (char *)count; - - /* Skip PID */ - p = strchr(p, ','); - if (!p) - continue; - *p = '\0'; - p++; - - p = skip_whitespace(p); - - /* Get process */ + /* Get process name */ ADVANCE(p); process = p; @@ -813,8 +812,6 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) if (strcmp(process, "swapper") == 0) process = "[kernel core]"; - p = strchr(p, '\n'); - if (strncmp(func, "tick_nohz_", 10) == 0) continue; if (strncmp(func, "tick_setup_sched_timer", 20) == 0) @@ -822,22 +819,20 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) if (strcmp(process, "powertop") == 0) continue; - if (p) - *p = '\0'; + strchrnul(p, '\n')[0] = '\0'; cnt = bb_strtoull(count, &p, 10); - while (*p != 0) { + while (*p != '\0') { if (*p++ == 'D') - defferable = true; + goto skip; } - if (defferable) - continue; if (strchr(process, '[')) sprintf(line, "%s %s", process, func); else sprintf(line, "%s", process); - push_line(line, cnt); + save_line(line, cnt); + skip: ; } fclose(fp); } @@ -853,19 +848,17 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) totalevents += G.interrupt_0 - n; } if (n > 0 && n < G.interrupt_0) - push_line("[extra timer interrupt]", G.interrupt_0 - n); + save_line("[extra timer interrupt]", G.interrupt_0 - n); } #endif - if (totalevents) + if (totalevents != 0) printf("\n\033[1mWakeups-from-idle per second : %4.1f\tinterval:" "%ds\n\033[0m", (double)totalevents / DEFAULT_SLEEP / G.total_cpus, DEFAULT_SLEEP); - count_lines(); - do_sort(); - - show_timerstats(G.nostats); - + update_lines_cumulative_count(); + sort_lines(); + show_timerstats(); fflush(stdout); /* Clear the stats */ @@ -873,7 +866,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) memset(cur_usage, 0, sizeof(cur_usage)); /* Get new values */ - read_data(&cur_usage[0], &cur_duration[0]); + read_cstate_counts(cur_usage, cur_duration); /* Save them */ memcpy(G.last_usage, cur_usage, sizeof(G.last_usage)); -- cgit v1.2.3-55-g6feb From c3f1fa10d601eb5e1b92f55fb49bbd59cde71705 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 26 Oct 2010 12:39:36 +0200 Subject: powertop: fixes to output format and code shrink function old new delta process_timer_stats - 631 +631 clear_lines 72 74 +2 process_irq_counts 729 726 -3 .rodata 145699 145530 -169 powertop_main 2341 1510 -831 ------------------------------------------------------------------------------ (add/remove: 2/1 grow/shrink: 1/2 up/down: 1359/-1729) Total: -370 bytes Signed-off-by: Denys Vlasenko --- procps/powertop.c | 330 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 169 insertions(+), 161 deletions(-) diff --git a/procps/powertop.c b/procps/powertop.c index 4b410540e..5792048dc 100644 --- a/procps/powertop.c +++ b/procps/powertop.c @@ -19,7 +19,7 @@ //config: help //config: Analyze power consumption on Intel-based laptops -// XXX This should de configurable +// XXX This should be configurable #define ENABLE_FEATURE_POWERTOP_PROCIRQ 1 #include "libbb.h" @@ -39,7 +39,7 @@ /* Frequency of the ACPI timer */ #define FREQ_ACPI 3579.545 -#define FREQ_ACPI_1000 3579545 +#define FREQ_ACPI_1000 3579545 /* Max filename length of entry in /sys/devices subsystem */ #define BIG_SYSNAME_LEN 16 @@ -62,12 +62,11 @@ struct irqdata { #endif struct globals { + struct line *lines; /* the most often used member */ int lines_cnt; int lines_cumulative_count; - int linesize; int maxcstate; unsigned total_cpus; - struct line *lines; smallint cant_enable_timer_stats; #if ENABLE_FEATURE_POWERTOP_PROCIRQ # if BLOATY_HPET_IRQ_NUM_DETECTION @@ -120,15 +119,16 @@ static int write_str_to_file(const char *fname, const char *str) #define start_timer() write_str_to_file("/proc/timer_stats", "1\n") #define stop_timer() write_str_to_file("/proc/timer_stats", "0\n") -static void NOINLINE clear_lines(void) +static NOINLINE void clear_lines(void) { int i; - for (i = 0; i < G.lines_cnt; i++) - free(G.lines[i].string); - free(G.lines); - G.lines_cnt = 0; - G.linesize = 0; - G.lines = NULL; + if (G.lines) { + for (i = 0; i < G.lines_cnt; i++) + free(G.lines[i].string); + free(G.lines); + G.lines_cnt = 0; + G.lines = NULL; + } } static void update_lines_cumulative_count(void) @@ -220,7 +220,7 @@ static void save_line(const char *string, int count) } /* Add new line */ - G.lines = xrealloc_vector(G.lines, 1, G.lines_cnt); + G.lines = xrealloc_vector(G.lines, 4, G.lines_cnt); G.lines[G.lines_cnt].string = xstrdup(string); G.lines[G.lines_cnt].count = count; /*G.lines[G.lines_cnt].disk_count = 0;*/ @@ -298,7 +298,7 @@ static int save_irq_count(int irq, ullong count) } /* Read /proc/interrupts, save IRQ counts and IRQ description */ -static void process_irq_count_deltas(void) +static void process_irq_counts(void) { FILE *fp; char buf[128]; @@ -399,9 +399,121 @@ static void process_irq_count_deltas(void) fclose(fp); } #else /* !ENABLE_FEATURE_POWERTOP_PROCIRQ */ -# define process_irq_count_deltas() ((void)0) +# define process_irq_counts() ((void)0) #endif +static NOINLINE int process_timer_stats(void) +{ + char buf[128]; + char line[15 + 3 + 128]; + int n; + ullong totalticks; + FILE *fp; + + buf[0] = '\0'; + totalticks = 0; + + fp = NULL; + if (!G.cant_enable_timer_stats) + fp = fopen_for_read("/proc/timer_stats"); + if (fp) { +// Example file contents: +// Timer Stats Version: v0.2 +// Sample period: 1.329 s +// 76, 0 swapper hrtimer_start_range_ns (tick_sched_timer) +// 88, 0 swapper hrtimer_start_range_ns (tick_sched_timer) +// 24, 3787 firefox hrtimer_start_range_ns (hrtimer_wakeup) +// 46D, 1136 kondemand/1 do_dbs_timer (delayed_work_timer_fn) +// ... +// 1, 1656 Xorg hrtimer_start_range_ns (hrtimer_wakeup) +// 1, 2159 udisks-daemon hrtimer_start_range_ns (hrtimer_wakeup) +// 331 total events, 249.059 events/sec + while (fgets(buf, sizeof(buf), fp)) { + const char *count, *process, *func; + char *p; + int cnt; + + count = skip_whitespace(buf); + p = strchr(count, ','); + if (!p) + continue; + *p++ = '\0'; + if (strcmp(strchrnul(count, ' '), " total events") == 0) + break; + p = skip_whitespace(p); /* points to pid */ + +/* Find char ' ', then eat remaining spaces */ +#define ADVANCE(p) do { \ + (p) = strchr((p), ' '); \ + if (!(p)) \ + continue; \ + *(p) = '\0'; \ + (p)++; \ + (p) = skip_whitespace(p); \ +} while (0) + /* Get process name */ + ADVANCE(p); + process = p; + /* Get function */ + ADVANCE(p); + func = p; +#undef ADVANCE + //if (strcmp(process, "swapper") == 0 + // && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0 + //) { + // process = "[kernel scheduler]"; + // func = "Load balancing tick"; + //} + + if (strncmp(func, "tick_nohz_", 10) == 0) + continue; + if (strncmp(func, "tick_setup_sched_timer", 20) == 0) + continue; + //if (strcmp(process, "powertop") == 0) + // continue; + + if (strcmp(process, "insmod") == 0) + process = "[kernel module]"; + if (strcmp(process, "modprobe") == 0) + process = "[kernel module]"; + if (strcmp(process, "swapper") == 0) + process = ""; + + strchrnul(p, '\n')[0] = '\0'; + + { + char *tmp; + cnt = bb_strtoull(count, &tmp, 10); + p = tmp; + } + while (*p != '\0') { + if (*p++ == 'D') /* deferred */ + goto skip; + } + + //if (strchr(process, '[')) + sprintf(line, "%15.15s : %s", process, func); + //else + // sprintf(line, "%s", process); + save_line(line, cnt); + skip: ; + } + fclose(fp); + } + + n = 0; +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + if (strstr(buf, "total events")) { + n = bb_strtoull(buf, NULL, 10) / G.total_cpus; + if (n > 0 && n < G.interrupt_0) { + sprintf(line, " : %s", "extra timer interrupt"); + save_line(line, G.interrupt_0 - n); + } + } +#endif + return n; +} + #ifdef __i386__ /* * Get information about CPU using CPUID opcode. @@ -428,7 +540,7 @@ static void cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, } #endif -static void NOINLINE print_intel_cstates(void) +static NOINLINE void print_intel_cstates(void) { #ifdef __i386__ int bios_table[8] = { 0 }; @@ -462,7 +574,7 @@ static void NOINLINE print_intel_cstates(void) /* * Every C-state has its own stateN directory, that - * contains a `time' and a `usage' file. + * contains a 'time' and a 'usage' file. */ while ((d = readdir(dir)) != NULL) { FILE *fp; @@ -525,25 +637,6 @@ static void NOINLINE print_intel_cstates(void) #endif } -static void print_header(void) -{ - printf( - /* Clear the screen */ - "\033[H\033[J" - /* Print the header */ - "\033[7m%.*s\033[0m", 79, "PowerTOP (C) 2007 Intel Corporation\n" - ); -} - -static void show_cstates(char cstate_lines[][64]) -{ - int i; - - for (i = 0; i < 10; i++) - if ((cstate_lines[i][0])) - printf("%s", cstate_lines[i]); -} - static void show_timerstats(void) { unsigned lines; @@ -556,19 +649,26 @@ static void show_timerstats(void) if (!G.cant_enable_timer_stats) { int i, n = 0; + char strbuf6[6]; + strbuf6[5] = '\0'; puts("\nTop causes for wakeups:"); for (i = 0; i < G.lines_cnt; i++) { if ((G.lines[i].count > 0 /*|| G.lines[i].disk_count > 0*/) && n++ < lines ) { - char c = ' '; - /*if (G.lines[i].disk_count) + /* NB: upstream powertop prints "(wakeups/sec)", + * we print just "(wakeup counts)". + */ + /*char c = ' '; + if (G.lines[i].disk_count) c = 'D';*/ - printf(" %5.1f%% (%5.1f)%c %s\n", - G.lines[i].count * 100.0 / G.lines_cumulative_count, - G.lines[i].count * 1.0 / DEFAULT_SLEEP, c, - G.lines[i].string); + smart_ulltoa5(G.lines[i].count, strbuf6, " KMGTPEZY"); + printf(/*" %5.1f%% (%s)%c %s\n"*/ + " %5.1f%% (%s) %s\n", + G.lines[i].count * 100.0 / G.lines_cumulative_count, + strbuf6, /*c,*/ + G.lines[i].string); } } } else { @@ -606,8 +706,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) { ullong cur_usage[MAX_CSTATE_COUNT]; ullong cur_duration[MAX_CSTATE_COUNT]; - char cstate_lines[12][64]; - char buf[128]; + char cstate_lines[MAX_CSTATE_COUNT + 2][64]; #if ENABLE_FEATURE_USE_TERMIOS struct termios new_settings; struct pollfd pfd[1]; @@ -644,7 +743,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) #endif /* Collect initial data */ - process_irq_count_deltas(); + process_irq_counts(); /* Read initial usage and duration */ read_cstate_counts(G.start_usage, G.start_duration); @@ -660,10 +759,9 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) /* The main loop */ for (;;) { - /*double maxsleep = 0.0;*/ + //double maxsleep = 0.0; ullong totalticks, totalevents; int i; - FILE *fp; G.cant_enable_timer_stats |= start_timer(); /* 1 on error */ #if !ENABLE_FEATURE_USE_TERMIOS @@ -682,7 +780,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) G.cant_enable_timer_stats |= stop_timer(); /* 1 on error */ clear_lines(); - process_irq_count_deltas(); + process_irq_counts(); /* Clear the stats */ memset(cur_duration, 0, sizeof(cur_duration)); @@ -700,8 +798,8 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) } } - /* Show title bar */ - print_header(); + /* Clear the screen */ + printf("\033[H\033[J"); /* Clear C-state lines */ memset(&cstate_lines, 0, sizeof(cstate_lines)); @@ -711,7 +809,6 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) sprintf(cstate_lines[5], "< Detailed C-state information is not " "available.>\n"); } else { - double slept; double percentage; double newticks; @@ -721,7 +818,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) if (newticks < 0) newticks = 0; - sprintf(cstate_lines[0], "Cn\t Avg residency\n"); + sprintf(cstate_lines[0], "Cn\t\t Avg residency\n"); percentage = newticks * 100.0 / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); sprintf(cstate_lines[1], "C0 (cpu running) (%4.1f%%)\n", percentage); @@ -729,6 +826,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) /* Compute values for individual C-states */ for (i = 0; i < MAX_CSTATE_COUNT; i++) { if (cur_usage[i] != 0) { + double slept; slept = (cur_duration[i] - G.last_duration[i]) / (cur_usage[i] - G.last_usage[i] + 0.1) / FREQ_ACPI; percentage = (cur_duration[i] - G.last_duration[i]) * 100 @@ -736,125 +834,35 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) if (!G.cstate_names[i][0]) sprintf(G.cstate_names[i], "C%u", i + 1); - sprintf(cstate_lines[i + 2], "%s\t%5.1fms (%4.1f%%)\n", + sprintf(cstate_lines[i + 2], "%s\t\t%5.1fms (%4.1f%%)\n", G.cstate_names[i], slept, percentage); - /*if (maxsleep < slept) - maxsleep = slept;*/ + //if (maxsleep < slept) + // maxsleep = slept; } } } - /* Display C-states */ - show_cstates(cstate_lines); - - /* Do timer_stats info */ - buf[0] = '\0'; - totalticks = 0; - - fp = NULL; - if (!G.cant_enable_timer_stats) - fp = fopen_for_read("/proc/timer_stats"); - if (fp) { -// Examlpe file contents: -// Timer Stats Version: v0.2 -// Sample period: 1.329 s -// 76, 0 swapper hrtimer_start_range_ns (tick_sched_timer) -// 88, 0 swapper hrtimer_start_range_ns (tick_sched_timer) -// 24, 3787 firefox hrtimer_start_range_ns (hrtimer_wakeup) -// 46D, 1136 kondemand/1 do_dbs_timer (delayed_work_timer_fn) -// ... -// 1, 1656 Xorg hrtimer_start_range_ns (hrtimer_wakeup) -// 1, 2159 udisks-daemon hrtimer_start_range_ns (hrtimer_wakeup) -// 331 total events, 249.059 events/sec - while (fgets(buf, sizeof(buf), fp)) { - const char *count, *process, *func; - char *p; - char line[512]; - int cnt = 0; -// TODO: optimize - if (strstr(buf, "total events")) - break; - count = skip_whitespace(buf); - p = strchr(count, ','); - if (!p) - continue; - *p++ = '\0'; - p = skip_whitespace(p); /* points to pid */ - -/* Find char ' ', then eat remaining spaces */ -#define ADVANCE(p) do { \ - (p) = strchr((p), ' '); \ - if (!(p)) \ - continue; \ - *(p) = '\0'; \ - (p)++; \ - (p) = skip_whitespace(p); \ -} while (0) - /* Get process name */ - ADVANCE(p); - process = p; - - /* Get function */ - ADVANCE(p); - func = p; - - if (strcmp(process, "swapper") == 0 - && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0 - ) { - process = "[kernel scheduler]"; - func = "Load balancing tick"; - } - - if (strcmp(process, "insmod") == 0) - process = "[kernel module]"; - if (strcmp(process, "modprobe") == 0) - process = "[kernel module]"; - if (strcmp(process, "swapper") == 0) - process = "[kernel core]"; - - if (strncmp(func, "tick_nohz_", 10) == 0) - continue; - if (strncmp(func, "tick_setup_sched_timer", 20) == 0) - continue; - if (strcmp(process, "powertop") == 0) - continue; - - strchrnul(p, '\n')[0] = '\0'; - - cnt = bb_strtoull(count, &p, 10); - while (*p != '\0') { - if (*p++ == 'D') - goto skip; - } - - if (strchr(process, '[')) - sprintf(line, "%s %s", process, func); - else - sprintf(line, "%s", process); - save_line(line, cnt); - skip: ; - } - fclose(fp); - } + for (i = 0; i < MAX_CSTATE_COUNT + 2; i++) + if (cstate_lines[i][0]) + printf("%s", cstate_lines[i]); + i = process_timer_stats(); #if ENABLE_FEATURE_POWERTOP_PROCIRQ - if (strstr(buf, "total events")) { - int n = bb_strtoull(buf, NULL, 10) / G.total_cpus; - - if (totalevents == 0) { - /* No C-state info available, use timerstats */ - totalevents = n * G.total_cpus + G.total_interrupt; - if (n < 0) - totalevents += G.interrupt_0 - n; - } - if (n > 0 && n < G.interrupt_0) - save_line("[extra timer interrupt]", G.interrupt_0 - n); + if (totalevents == 0) { + /* No C-state info available, use timerstats */ + totalevents = i * G.total_cpus + G.total_interrupt; + if (i < 0) + totalevents += G.interrupt_0 - i; } #endif - if (totalevents != 0) - printf("\n\033[1mWakeups-from-idle per second : %4.1f\tinterval:" - "%ds\n\033[0m", - (double)totalevents / DEFAULT_SLEEP / G.total_cpus, DEFAULT_SLEEP); + /* Upstream powertop prints wakeups per sec per CPU, + * we print just raw wakeup counts. + */ +//TODO: show real seconds (think about manual refresh) + printf("\nWakeups-from-idle in %u seconds: %llu\n", + DEFAULT_SLEEP, + totalevents + ); update_lines_cumulative_count(); sort_lines(); -- cgit v1.2.3-55-g6feb From d8b687f99257772f62edd7c4641427280841e1c5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 26 Oct 2010 12:42:53 +0200 Subject: powertop: IPIs and hw irqs were swapped, fixing Signed-off-by: Denys Vlasenko --- procps/powertop.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/procps/powertop.c b/procps/powertop.c index 5792048dc..3d98b9bda 100644 --- a/procps/powertop.c +++ b/procps/powertop.c @@ -376,7 +376,7 @@ static void process_irq_counts(void) name = p; strchrnul(name, '\n')[0] = '\0'; /* Save description of the interrupt */ - if (nr < 20000) + if (nr >= 20000) sprintf(irq_desc, " : %s", name); else sprintf(irq_desc, " : %s", name); -- cgit v1.2.3-55-g6feb From a43e969574fca5ba17bb866c2aa249fe16ac0530 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 26 Oct 2010 13:03:31 +0200 Subject: powertop: simplified C-state display code function old new delta .rodata 145530 145514 -16 powertop_main 1510 1403 -107 Signed-off-by: Denys Vlasenko --- procps/powertop.c | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/procps/powertop.c b/procps/powertop.c index 3d98b9bda..8b03a4d12 100644 --- a/procps/powertop.c +++ b/procps/powertop.c @@ -82,7 +82,6 @@ struct globals { ullong last_usage[MAX_CSTATE_COUNT]; ullong start_duration[MAX_CSTATE_COUNT]; ullong last_duration[MAX_CSTATE_COUNT]; - char cstate_names[MAX_CSTATE_COUNT][16]; #if ENABLE_FEATURE_USE_TERMIOS struct termios init_settings; #endif @@ -806,22 +805,19 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) if (totalevents == 0 && G.maxcstate <= 1) { /* This should not happen */ - sprintf(cstate_lines[5], "< Detailed C-state information is not " - "available.>\n"); + strcpy(cstate_lines[0], "C-state information is not available\n"); } else { double percentage; - double newticks; + unsigned newticks; newticks = G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000 - totalticks; - /* Handle rounding errors: do not display negative values */ - if (newticks < 0) + if ((int)newticks < 0) newticks = 0; sprintf(cstate_lines[0], "Cn\t\t Avg residency\n"); percentage = newticks * 100.0 / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); - sprintf(cstate_lines[1], "C0 (cpu running) (%4.1f%%)\n", - percentage); + sprintf(cstate_lines[1], "C0 (cpu running) (%4.1f%%)\n", percentage); /* Compute values for individual C-states */ for (i = 0; i < MAX_CSTATE_COUNT; i++) { @@ -831,11 +827,8 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) / (cur_usage[i] - G.last_usage[i] + 0.1) / FREQ_ACPI; percentage = (cur_duration[i] - G.last_duration[i]) * 100 / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); - - if (!G.cstate_names[i][0]) - sprintf(G.cstate_names[i], "C%u", i + 1); - sprintf(cstate_lines[i + 2], "%s\t\t%5.1fms (%4.1f%%)\n", - G.cstate_names[i], slept, percentage); + sprintf(cstate_lines[i + 2], "C%u\t\t%5.1fms (%4.1f%%)\n", + i + 1, slept, percentage); //if (maxsleep < slept) // maxsleep = slept; } @@ -844,7 +837,7 @@ int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) for (i = 0; i < MAX_CSTATE_COUNT + 2; i++) if (cstate_lines[i][0]) - printf("%s", cstate_lines[i]); + fputs(cstate_lines[i], stdout); i = process_timer_stats(); #if ENABLE_FEATURE_POWERTOP_PROCIRQ -- cgit v1.2.3-55-g6feb From 4c46d854690595bb2c5487aedccebab8de8aafda Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 26 Oct 2010 15:58:47 +0200 Subject: mv: implement -n option function old new delta mv_longopts 23 36 +13 mv_main 510 520 +10 packed_usage 27218 27225 +7 Signed-off-by: Denys Vlasenko --- coreutils/mv.c | 46 +++++++++++++++++++++++++++++++++------------- include/usage.src.h | 12 ------------ 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/coreutils/mv.c b/coreutils/mv.c index 7f49d5bab..245639bd0 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c @@ -16,15 +16,30 @@ #include "libbb.h" #include "libcoreutils/coreutils.h" +//usage:#define mv_trivial_usage +//usage: "[-fin] SOURCE DEST\n" +//usage: "or: mv [-fin] SOURCE... DIRECTORY" +//usage:#define mv_full_usage "\n\n" +//usage: "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n" +//usage: "\nOptions:" +//usage: "\n -f Don't prompt before overwriting" +//usage: "\n -i Interactive, prompt before overwrite" +//usage: "\n -n Don't overwrite an existing file" +//usage: +//usage:#define mv_example_usage +//usage: "$ mv /tmp/foo /bin/bar\n" + #if ENABLE_FEATURE_MV_LONG_OPTIONS static const char mv_longopts[] ALIGN1 = "interactive\0" No_argument "i" "force\0" No_argument "f" + "no-clobber\0" No_argument "n" ; #endif #define OPT_FILEUTILS_FORCE 1 #define OPT_FILEUTILS_INTERACTIVE 2 +#define OPT_FILEUTILS_NOCLOBBER 4 int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mv_main(int argc, char **argv) @@ -40,10 +55,11 @@ int mv_main(int argc, char **argv) #if ENABLE_FEATURE_MV_LONG_OPTIONS applet_long_options = mv_longopts; #endif - // Need at least two arguments - // -f unsets -i, -i unsets -f - opt_complementary = "-2:f-i:i-f"; - flags = getopt32(argv, "fi"); + /* Need at least two arguments. + * If more than one of -f, -i, -n is specified , only the final one + * takes effect (it unsets previous options). */ + opt_complementary = "-2:f-in:i-fn:n-fi"; + flags = getopt32(argv, "fin"); argc -= optind; argv += optind; last = argv[argc - 1]; @@ -68,18 +84,22 @@ int mv_main(int argc, char **argv) } DO_MOVE: - if (dest_exists - && !(flags & OPT_FILEUTILS_FORCE) - && ((access(dest, W_OK) < 0 && isatty(0)) - || (flags & OPT_FILEUTILS_INTERACTIVE)) - ) { - if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { - goto RET_1; /* Ouch! fprintf failed! */ - } - if (!bb_ask_confirmation()) { + if (dest_exists) { + if (flags & OPT_FILEUTILS_NOCLOBBER) goto RET_0; + if (!(flags & OPT_FILEUTILS_FORCE) + && ((access(dest, W_OK) < 0 && isatty(0)) + || (flags & OPT_FILEUTILS_INTERACTIVE)) + ) { + if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { + goto RET_1; /* Ouch! fprintf failed! */ + } + if (!bb_ask_confirmation()) { + goto RET_0; + } } } + if (rename(*argv, dest) < 0) { struct stat source_stat; int source_exists; diff --git a/include/usage.src.h b/include/usage.src.h index f5ddd7ba5..e1810c977 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -2695,18 +2695,6 @@ INSERT "ras3 reset retension rewind rewoffline seek setblk setdensity\n" \ "setpart tell unload unlock weof wset" \ -#define mv_trivial_usage \ - "[-fi] SOURCE DEST\n" \ - "or: mv [-fi] SOURCE... DIRECTORY" -#define mv_full_usage "\n\n" \ - "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n" \ - "\nOptions:" \ - "\n -f Don't prompt before overwriting" \ - "\n -i Interactive, prompt before overwrite" \ - -#define mv_example_usage \ - "$ mv /tmp/foo /bin/bar\n" - #define nameif_trivial_usage \ "[-s] [-c FILE] [{IFNAME MACADDR}]" #define nameif_full_usage "\n\n" \ -- cgit v1.2.3-55-g6feb From 4fa07bd8fafdd5eb64dfe11f43bb420aec5b5f50 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 27 Oct 2010 00:04:50 +0200 Subject: whitespace fix Signed-off-by: Denys Vlasenko --- procps/powertop.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/procps/powertop.c b/procps/powertop.c index 8b03a4d12..5e028f074 100644 --- a/procps/powertop.c +++ b/procps/powertop.c @@ -689,8 +689,8 @@ static void show_timerstats(void) // no ACPI power usage estimate available // // Top causes for wakeups: -// 32.4% ( 26.7) : extra timer interrupt -// 29.0% ( 23.9) : hrtimer_start_range_ns (tick_sched_timer) +// 32.4% ( 26.7) : extra timer interrupt +// 29.0% ( 23.9) : hrtimer_start_range_ns (tick_sched_timer) // 9.0% ( 7.5) : hrtimer_start (tick_sched_timer) // 6.5% ( 5.3) : ata_piix // 5.0% ( 4.1) inetd : hrtimer_start_range_ns (hrtimer_wakeup) -- cgit v1.2.3-55-g6feb From 55a046b4dbca9df876e9bb67a16dde2ee3d9adb0 Mon Sep 17 00:00:00 2001 From: Bob Dunlop Date: Wed, 27 Oct 2010 02:12:29 +0200 Subject: netstat: fix -r display in usage text Signed-off-by: Bob Dunlop Signed-off-by: Denys Vlasenko --- include/usage.src.h | 21 -------------- networking/netstat.c | 78 +++++++++++++++++++++++++++++++++------------------- 2 files changed, 50 insertions(+), 49 deletions(-) diff --git a/include/usage.src.h b/include/usage.src.h index f5ddd7ba5..2f44eaf81 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -2721,27 +2721,6 @@ INSERT " or\n" \ "$ nameif -c /etc/my_mactab_file\n" \ -#define netstat_trivial_usage \ - "[-laentuwxr"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]" -#define netstat_full_usage "\n\n" \ - "Display networking information\n" \ - "\nOptions:" \ - "\n -l Display listening server sockets" \ - "\n -a Display all sockets (default: connected)" \ - "\n -e Display other/more information" \ - "\n -n Don't resolve names" \ - "\n -t Tcp sockets" \ - "\n -u Udp sockets" \ - "\n -w Raw sockets" \ - "\n -x Unix sockets" \ - "\n -r Display routing table" \ - IF_FEATURE_NETSTAT_WIDE( \ - "\n -W Display with no column truncation" \ - ) \ - IF_FEATURE_NETSTAT_PRG( \ - "\n -p Display PID/Program name for sockets" \ - ) - #define nmeter_trivial_usage \ "format_string" #define nmeter_full_usage "\n\n" \ diff --git a/networking/netstat.c b/networking/netstat.c index 3114a3902..4fd8728ce 100644 --- a/networking/netstat.c +++ b/networking/netstat.c @@ -17,16 +17,37 @@ #include "libbb.h" #include "inet_common.h" +//usage:#define netstat_trivial_usage +//usage: "[-"IF_ROUTE("r")"al] [-tuwx] [-en"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]" +//usage:#define netstat_full_usage "\n\n" +//usage: "Display networking information\n" +//usage: "\nOptions:" +//usage: IF_ROUTE( +//usage: "\n -r Routing table" +//usage: ) +//usage: "\n -a All sockets" +//usage: "\n -l Listening sockets" +//usage: "\n Else: connected sockets" +//usage: "\n -t TCP sockets" +//usage: "\n -u UDP sockets" +//usage: "\n -w Raw sockets" +//usage: "\n -x Unix sockets" +//usage: "\n Else: all socket types" +//usage: "\n -e Other/more information" +//usage: "\n -n Don't resolve names" +//usage: IF_FEATURE_NETSTAT_WIDE( +//usage: "\n -W Wide display" +//usage: ) +//usage: IF_FEATURE_NETSTAT_PRG( +//usage: "\n -p Show PID/program name for sockets" +//usage: ) + #define NETSTAT_OPTS "laentuwx" \ IF_ROUTE( "r") \ IF_FEATURE_NETSTAT_WIDE("W") \ IF_FEATURE_NETSTAT_PRG( "p") enum { - OPTBIT_KEEP_OLD = 7, - IF_ROUTE( OPTBIT_ROUTE,) - IF_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,) - IF_FEATURE_NETSTAT_PRG( OPTBIT_PRG ,) OPT_sock_listen = 1 << 0, // l OPT_sock_all = 1 << 1, // a OPT_extended = 1 << 2, // e @@ -35,6 +56,10 @@ enum { OPT_sock_udp = 1 << 5, // u OPT_sock_raw = 1 << 6, // w OPT_sock_unix = 1 << 7, // x + OPTBIT_x = 7, + IF_ROUTE( OPTBIT_ROUTE,) + IF_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,) + IF_FEATURE_NETSTAT_PRG( OPTBIT_PRG ,) OPT_route = IF_ROUTE( (1 << OPTBIT_ROUTE)) + 0, // r OPT_wide = IF_FEATURE_NETSTAT_WIDE((1 << OPTBIT_WIDE )) + 0, // W OPT_prg = IF_FEATURE_NETSTAT_PRG( (1 << OPTBIT_PRG )) + 0, // p @@ -220,7 +245,7 @@ static long extract_socket_inode(const char *lname) static int FAST_FUNC file_act(const char *fileName, struct stat *statbuf UNUSED_PARAM, - void *userData, + void *pid_slash_progname, int depth UNUSED_PARAM) { char *linkname; @@ -231,7 +256,7 @@ static int FAST_FUNC file_act(const char *fileName, inode = extract_socket_inode(linkname); free(linkname); if (inode >= 0) - prg_cache_add(inode, (char *)userData); + prg_cache_add(inode, (char *)pid_slash_progname); } return TRUE; } @@ -241,16 +266,16 @@ static int FAST_FUNC dir_act(const char *fileName, void *userData UNUSED_PARAM, int depth) { - const char *shortName; - char *p, *q; + const char *pid; + char *p, *pid_slash_progname; char cmdline_buf[512]; int i; if (depth == 0) /* "/proc" itself */ return TRUE; /* continue looking one level below /proc */ - shortName = fileName + sizeof("/proc/")-1; /* point after "/proc/" */ - if (!isdigit(shortName[0])) /* skip /proc entries whic aren't processes */ + pid = fileName + sizeof("/proc/")-1; /* point after "/proc/" */ + if (!isdigit(pid[0])) /* skip /proc entries which aren't processes */ return SKIP; p = concat_path_file(fileName, "cmdline"); /* "/proc/PID/cmdline" */ @@ -259,20 +284,19 @@ static int FAST_FUNC dir_act(const char *fileName, if (i < 0) return FALSE; cmdline_buf[i] = '\0'; - q = concat_path_file(shortName, bb_basename(cmdline_buf)); /* "PID/argv0" */ /* go through all files in /proc/PID/fd */ + pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */ p = concat_path_file(fileName, "fd"); i = recursive_action(p, ACTION_RECURSE | ACTION_QUIET, - file_act, NULL, (void *)q, 0); - + file_act, NULL, (void *)pid_slash_progname, 0); free(p); - free(q); + free(pid_slash_progname); if (!i) - return FALSE; /* signal permissions error to caller */ + return FALSE; /* signal permissions error to caller */ - return SKIP; /* caller should not recurse further into this dir. */ + return SKIP; /* caller should not recurse further into this dir */ } static void prg_cache_load(void) @@ -624,25 +648,23 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) /* Option string must match NETSTAT_xxx constants */ opt = getopt32(argv, NETSTAT_OPTS); - if (opt & 0x1) { // -l + if (opt & OPT_sock_listen) { // -l flags &= ~NETSTAT_CONNECTED; flags |= NETSTAT_LISTENING; } - if (opt & 0x2) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a - //if (opt & 0x4) // -e - if (opt & 0x8) flags |= NETSTAT_NUMERIC; // -n - //if (opt & 0x10) // -t: NETSTAT_TCP - //if (opt & 0x20) // -u: NETSTAT_UDP - //if (opt & 0x40) // -w: NETSTAT_RAW - //if (opt & 0x80) // -x: NETSTAT_UNIX - if (opt & OPT_route) { // -r + if (opt & OPT_sock_all) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a + //if (opt & OPT_extended) // -e + if (opt & OPT_noresolve) flags |= NETSTAT_NUMERIC; // -n + //if (opt & OPT_sock_tcp) // -t: NETSTAT_TCP + //if (opt & OPT_sock_udp) // -u: NETSTAT_UDP + //if (opt & OPT_sock_raw) // -w: NETSTAT_RAW + //if (opt & OPT_sock_unix) // -x: NETSTAT_UNIX #if ENABLE_ROUTE + if (opt & OPT_route) { // -r bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended)); return 0; -#else - bb_show_usage(); -#endif } +#endif if (opt & OPT_wide) { // -W net_conn_line = PRINT_NET_CONN_WIDE; net_conn_line_header = PRINT_NET_CONN_HEADER_WIDE; -- cgit v1.2.3-55-g6feb From 3c99d59b5dd4a4dfbcdf5b98f7a9944bff9c925c Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Wed, 27 Oct 2010 02:25:16 +0200 Subject: top: Use _exit() instead of exit() in sighandler Signed-off-by: Marek Polacek Signed-off-by: Denys Vlasenko --- procps/top.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/procps/top.c b/procps/top.c index 4f37878de..f9106fac7 100644 --- a/procps/top.c +++ b/procps/top.c @@ -649,8 +649,9 @@ static void reset_term(void) static void sig_catcher(int sig UNUSED_PARAM) { reset_term(); - exit(EXIT_FAILURE); + _exit(EXIT_FAILURE); } + #endif /* FEATURE_USE_TERMIOS */ /* -- cgit v1.2.3-55-g6feb From dd88ba88f5082b1785539b1fb87af7320515b8c9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 27 Oct 2010 13:10:29 +0200 Subject: netstat: fix IPv6 problem (garbage in scope_id); code shrink function old new delta add_to_prg_cache_if_socket - 253 +253 print_inet_line 226 241 +15 udp_do_one 119 131 +12 tcp_do_one 65 77 +12 unix_do_one 530 529 -1 dir_act 215 207 -8 netstat_main 585 553 -32 .rodata 145592 145525 -67 file_act 255 - -255 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 3/4 up/down: 292/-363) Total: -71 bytes Signed-off-by: Denys Vlasenko --- networking/netstat.c | 109 +++++++++++++++++++++++++++++---------------------- 1 file changed, 62 insertions(+), 47 deletions(-) diff --git a/networking/netstat.c b/networking/netstat.c index 4fd8728ce..485a7d191 100644 --- a/networking/netstat.c +++ b/networking/netstat.c @@ -113,24 +113,25 @@ typedef enum { SS_DISCONNECTING /* in process of disconnecting */ } socket_state; -#define SO_ACCEPTCON (1<<16) /* performed a listen */ -#define SO_WAITDATA (1<<17) /* wait data to read */ -#define SO_NOSPACE (1<<18) /* no space to write */ - -/* Standard printout size */ -#define PRINT_IP_MAX_SIZE 23 -#define PRINT_NET_CONN "%s %6ld %6ld %-23s %-23s %-12s" -#define PRINT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State " +#define SO_ACCEPTCON (1<<16) /* performed a listen */ +#define SO_WAITDATA (1<<17) /* wait data to read */ +#define SO_NOSPACE (1<<18) /* no space to write */ +#define ADDR_NORMAL_WIDTH 23 /* When there are IPv6 connections the IPv6 addresses will be * truncated to none-recognition. The '-W' option makes the * address columns wide enough to accomodate for longest possible * IPv6 addresses, i.e. addresses of the form * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd */ -#define PRINT_IP_MAX_SIZE_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ -#define PRINT_NET_CONN_WIDE "%s %6ld %6ld %-51s %-51s %-12s" -#define PRINT_NET_CONN_HEADER_WIDE "\nProto Recv-Q Send-Q %-51s %-51s State " +#define ADDR_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ +#if ENABLE_FEATURE_NETSTAT_WIDE +# define FMT_NET_CONN_DATA "%s %6ld %6ld %-*s %-*s %-12s" +# define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-*s %-*s State %s\n" +#else +# define FMT_NET_CONN_DATA "%s %6ld %6ld %-23s %-23s %-12s" +# define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State %s\n" +#endif #define PROGNAME_WIDTH 20 #define PROGNAME_WIDTH_STR "20" @@ -146,22 +147,30 @@ struct prg_node { #define PRG_HASH_SIZE 211 struct globals { - const char *net_conn_line; smallint flags; #if ENABLE_FEATURE_NETSTAT_PRG smallint prg_cache_loaded; struct prg_node *prg_hash[PRG_HASH_SIZE]; #endif +#if ENABLE_FEATURE_NETSTAT_PRG + const char *progname_banner; +#endif +#if ENABLE_FEATURE_NETSTAT_WIDE + unsigned addr_width; +#endif }; #define G (*ptr_to_globals) #define flags (G.flags ) -#define net_conn_line (G.net_conn_line ) -#define prg_hash (G.prg_hash ) #define prg_cache_loaded (G.prg_cache_loaded) +#define prg_hash (G.prg_hash ) +#if ENABLE_FEATURE_NETSTAT_PRG +# define progname_banner (G.progname_banner ) +#else +# define progname_banner "" +#endif #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \ - net_conn_line = PRINT_NET_CONN; \ } while (0) @@ -170,10 +179,6 @@ struct globals { /* Deliberately truncating long to unsigned *int* */ #define PRG_HASHIT(x) ((unsigned)(x) % PRG_HASH_SIZE) -#define print_progname_banner() do { \ - if (option_mask32 & OPT_prg) printf(PROGNAME_BANNER); \ -} while (0) - static void prg_cache_add(long inode, char *name) { unsigned hi = PRG_HASHIT(inode); @@ -226,12 +231,12 @@ static long extract_socket_inode(const char *lname) if (strncmp(lname, "socket:[", sizeof("socket:[")-1) == 0) { /* "socket:[12345]", extract the "12345" as inode */ - inode = bb_strtol(lname + sizeof("socket:[")-1, (char**)&lname, 0); + inode = bb_strtoul(lname + sizeof("socket:[")-1, (char**)&lname, 0); if (*lname != ']') inode = -1; } else if (strncmp(lname, "[0000]:", sizeof("[0000]:")-1) == 0) { /* "[0000]:12345", extract the "12345" as inode */ - inode = bb_strtol(lname + sizeof("[0000]:")-1, NULL, 0); + inode = bb_strtoul(lname + sizeof("[0000]:")-1, NULL, 0); if (errno) /* not NUL terminated? */ inode = -1; } @@ -243,7 +248,7 @@ static long extract_socket_inode(const char *lname) return inode; } -static int FAST_FUNC file_act(const char *fileName, +static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName, struct stat *statbuf UNUSED_PARAM, void *pid_slash_progname, int depth UNUSED_PARAM) @@ -267,9 +272,10 @@ static int FAST_FUNC dir_act(const char *fileName, int depth) { const char *pid; - char *p, *pid_slash_progname; + char *pid_slash_progname; + char proc_pid_fname[sizeof("/proc/%u/cmdline") + sizeof(long)*3]; char cmdline_buf[512]; - int i; + int n, len; if (depth == 0) /* "/proc" itself */ return TRUE; /* continue looking one level below /proc */ @@ -278,22 +284,24 @@ static int FAST_FUNC dir_act(const char *fileName, if (!isdigit(pid[0])) /* skip /proc entries which aren't processes */ return SKIP; - p = concat_path_file(fileName, "cmdline"); /* "/proc/PID/cmdline" */ - i = open_read_close(p, cmdline_buf, sizeof(cmdline_buf) - 1); - free(p); - if (i < 0) + len = snprintf(proc_pid_fname, sizeof(proc_pid_fname), "%s/cmdline", fileName); + n = open_read_close(proc_pid_fname, cmdline_buf, sizeof(cmdline_buf) - 1); + if (n < 0) return FALSE; - cmdline_buf[i] = '\0'; + cmdline_buf[n] = '\0'; - /* go through all files in /proc/PID/fd */ + /* go through all files in /proc/PID/fd and check whether they are sockets */ + strcpy(proc_pid_fname + len - (sizeof("cmdline")-1), "fd"); pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */ - p = concat_path_file(fileName, "fd"); - i = recursive_action(p, ACTION_RECURSE | ACTION_QUIET, - file_act, NULL, (void *)pid_slash_progname, 0); - free(p); + n = recursive_action(proc_pid_fname, + ACTION_RECURSE | ACTION_QUIET, + add_to_prg_cache_if_socket, + NULL, + (void *)pid_slash_progname, + 0); free(pid_slash_progname); - if (!i) + if (!n) return FALSE; /* signal permissions error to caller */ return SKIP; /* caller should not recurse further into this dir */ @@ -318,7 +326,6 @@ static void prg_cache_load(void) #else #define prg_cache_clear() ((void)0) -#define print_progname_banner() ((void)0) #endif //ENABLE_FEATURE_NETSTAT_PRG @@ -427,8 +434,11 @@ static void print_inet_line(struct inet_params *param, char *r = ip_port_str( ¶m->remaddr.sa, param->rem_port, proto, flags & NETSTAT_NUMERIC); - printf(net_conn_line, - proto, param->rxq, param->txq, l, r, state_str); + printf(FMT_NET_CONN_DATA, + proto, param->rxq, param->txq, + IF_FEATURE_NETSTAT_WIDE(G.addr_width,) l, + IF_FEATURE_NETSTAT_WIDE(G.addr_width,) r, + state_str); #if ENABLE_FEATURE_NETSTAT_PRG if (option_mask32 & OPT_prg) printf("%."PROGNAME_WIDTH_STR"s", prg_cache_get(param->inode)); @@ -443,6 +453,7 @@ static int FAST_FUNC tcp_do_one(char *line) { struct inet_params param; + memset(¶m, 0, sizeof(param)); if (scan_inet_proc_line(¶m, line)) return 1; @@ -470,6 +481,7 @@ static int FAST_FUNC udp_do_one(char *line) const char *state_str; struct inet_params param; + memset(¶m, 0, sizeof(param)); /* otherwise we display garbage IPv6 scope_ids */ if (scan_inet_proc_line(¶m, line)) return 1; @@ -641,7 +653,6 @@ static void do_info(const char *file, int FAST_FUNC (*proc)(char *)) int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int netstat_main(int argc UNUSED_PARAM, char **argv) { - const char *net_conn_line_header = PRINT_NET_CONN_HEADER; unsigned opt; INIT_G(); @@ -665,12 +676,16 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) return 0; } #endif +#if ENABLE_FEATURE_NETSTAT_WIDE + G.addr_width = ADDR_NORMAL_WIDTH; if (opt & OPT_wide) { // -W - net_conn_line = PRINT_NET_CONN_WIDE; - net_conn_line_header = PRINT_NET_CONN_HEADER_WIDE; + G.addr_width = ADDR_WIDE; } +#endif #if ENABLE_FEATURE_NETSTAT_PRG + progname_banner = ""; if (opt & OPT_prg) { // -p + progname_banner = PROGNAME_BANNER; prg_cache_load(); } #endif @@ -689,9 +704,11 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) printf("(only servers)"); else printf("(w/o servers)"); - printf(net_conn_line_header, "Local Address", "Foreign Address"); - print_progname_banner(); - bb_putchar('\n'); + printf(FMT_NET_CONN_HEADER, + IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Local Address", + IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Foreign Address", + progname_banner + ); } if (flags & NETSTAT_TCP) { do_info("/proc/net/tcp", tcp_do_one); @@ -719,9 +736,7 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) printf("(only servers)"); else printf("(w/o servers)"); - printf("\nProto RefCnt Flags Type State I-Node "); - print_progname_banner(); - printf("Path\n"); + printf("\nProto RefCnt Flags Type State I-Node %sPath\n", progname_banner); do_info("/proc/net/unix", unix_do_one); } prg_cache_clear(); -- cgit v1.2.3-55-g6feb From 9ce642f9746dfc29d119d0680b769677e3ea6da6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 27 Oct 2010 15:26:45 +0200 Subject: libbb: introduce and use common crc32 routine function old new delta crc32_block_endian1 - 37 +37 crc32_block_endian0 - 34 +34 global_crc32_table - 8 +8 file_read 82 87 +5 gzip_main 211 214 +3 xz_crc32 40 35 -5 crc32_table 8 - -8 calculate_gunzip_crc 54 34 -20 lzo_crc32 54 25 -29 cksum_main 298 211 -87 ------------------------------------------------------------------------------ (add/remove: 3/1 grow/shrink: 2/4 up/down: 87/-149) Total: -62 bytes Signed-off-by: Denys Vlasenko --- archival/gzip.c | 16 +++++----------- archival/libunarchive/decompress_unxz.c | 14 +++----------- archival/libunarchive/decompress_unzip.c | 5 +---- archival/lzop.c | 22 ++++++---------------- coreutils/cksum.c | 7 +------ include/libbb.h | 7 +++---- libbb/crc32.c | 24 ++++++++++++++++++++++++ miscutils/flash_eraseall.c | 14 +++----------- util-linux/fdisk_gpt.c | 13 +++---------- 9 files changed, 49 insertions(+), 73 deletions(-) diff --git a/archival/gzip.c b/archival/gzip.c index 32528d96b..4d399063d 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -340,7 +340,7 @@ struct globals { ulg bits_sent; /* bit length of the compressed data */ #endif - uint32_t *crc_32_tab; + /*uint32_t *crc_32_tab;*/ uint32_t crc; /* shift register contents */ }; @@ -393,15 +393,9 @@ static void put_32bit(ulg n) * pointer, then initialize the crc shift register contents instead. * Return the current crc in either case. */ -static uint32_t updcrc(uch * s, unsigned n) +static void updcrc(uch * s, unsigned n) { - uint32_t c = G1.crc; - while (n) { - c = G1.crc_32_tab[(uch)(c ^ *s++)] ^ (c >> 8); - n--; - } - G1.crc = c; - return c; + G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/); } @@ -2104,8 +2098,8 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) ALLOC(uch, G1.window, 2L * WSIZE); ALLOC(ush, G1.prev, 1L << BITS); - /* Initialise the CRC32 table */ - G1.crc_32_tab = crc32_filltable(NULL, 0); + /* Initialize the CRC32 table */ + global_crc32_table = crc32_filltable(NULL, 0); return bbunpack(argv, pack_gzip, append_ext, "gz"); } diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c index faba9ca82..ca427231e 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libunarchive/decompress_unxz.c @@ -22,17 +22,9 @@ /* We use our own crc32 function */ #define XZ_INTERNAL_CRC32 0 -static uint32_t *crc32_table; static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) { - crc = ~crc; - - while (size != 0) { - crc = crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8); - --size; - } - - return ~crc; + return ~crc32_block_endian0(~crc, buf, size, global_crc32_table); } /* We use arch-optimized unaligned accessors */ @@ -53,8 +45,8 @@ unpack_xz_stream(int src_fd, int dst_fd) unsigned char *membuf; IF_DESKTOP(long long) int total = 0; - if (!crc32_table) - crc32_table = crc32_filltable(NULL, /*endian:*/ 0); + if (!global_crc32_table) + global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0); memset(&iobuf, 0, sizeof(iobuf)); /* Preload XZ file signature */ diff --git a/archival/libunarchive/decompress_unzip.c b/archival/libunarchive/decompress_unzip.c index 20fda9d26..cb8a3d737 100644 --- a/archival/libunarchive/decompress_unzip.c +++ b/archival/libunarchive/decompress_unzip.c @@ -925,10 +925,7 @@ static int inflate_block(STATE_PARAM smallint *e) /* Two callsites, both in inflate_get_next_window */ static void calculate_gunzip_crc(STATE_PARAM_ONLY) { - unsigned n; - for (n = 0; n < gunzip_outbuf_count; n++) { - gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8); - } + gunzip_crc = crc32_block_endian0(gunzip_crc, gunzip_window, gunzip_outbuf_count, gunzip_crc_table); gunzip_bytes_out += gunzip_outbuf_count; } diff --git a/archival/lzop.c b/archival/lzop.c index c6e718ad7..acb34fe14 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -393,7 +393,7 @@ typedef struct header_t { } header_t; struct globals { - const uint32_t *lzo_crc32_table; + /*const uint32_t *lzo_crc32_table;*/ chksum_t chksum_in; chksum_t chksum_out; } FIX_ALIASING; @@ -468,19 +468,10 @@ lzo_adler32(uint32_t adler, const uint8_t* buf, unsigned len) static FAST_FUNC uint32_t lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len) { - uint32_t crc; + //if (buf == NULL) - impossible + // return 0; - if (buf == NULL) - return 0; - - crc = ~c; - if (len != 0) do { - crc = G.lzo_crc32_table[(uint8_t)((int)crc ^ *buf)] ^ (crc >> 8); - buf += 1; - len -= 1; - } while (len > 0); - - return ~crc; + return ~crc32_block_endian0(~c, buf, len, global_crc32_table); } /**********************************************************************/ @@ -679,8 +670,7 @@ static NOINLINE smallint lzo_compress(const header_t *h) if (dst_len < src_len) { /* write checksum of compressed block */ if (h->flags & F_ADLER32_C) - write32(lzo_adler32(ADLER32_INIT_VALUE, b2, - dst_len)); + write32(lzo_adler32(ADLER32_INIT_VALUE, b2, dst_len)); if (h->flags & F_CRC32_C) write32(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len)); /* write compressed block data */ @@ -1080,6 +1070,6 @@ int lzop_main(int argc UNUSED_PARAM, char **argv) if (applet_name[0] == 'u') option_mask32 |= OPT_DECOMPRESS; - G.lzo_crc32_table = crc32_filltable(NULL, 0); + global_crc32_table = crc32_filltable(NULL, 0); return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL); } diff --git a/coreutils/cksum.c b/coreutils/cksum.c index 7bf383e2d..7a37e6add 100644 --- a/coreutils/cksum.c +++ b/coreutils/cksum.c @@ -18,7 +18,6 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) off_t length, filesize; int bytes_read; int exit_code = EXIT_SUCCESS; - uint8_t *cp; #if ENABLE_DESKTOP getopt32(argv, ""); /* coreutils 6.9 compat */ @@ -39,11 +38,7 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) #define read_buf bb_common_bufsiz1 while ((bytes_read = safe_read(fd, read_buf, sizeof(read_buf))) > 0) { - cp = (uint8_t *) read_buf; - length += bytes_read; - do { - crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *cp++]; - } while (--bytes_read); + crc = crc32_block_endian1(crc, read_buf, bytes_read, crc32_table); } close(fd); diff --git a/include/libbb.h b/include/libbb.h index d14728ed0..587a5f952 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1543,11 +1543,10 @@ void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; -/* TODO: add global crc32_table pointer and create - * LE and BE functions to calculate crc32 over given bytes. - * Currently we have about five reimplementations... - */ +extern uint32_t *global_crc32_table; uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; +uint32_t crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; +uint32_t crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; typedef struct masks_labels_t { const char *labels; diff --git a/libbb/crc32.c b/libbb/crc32.c index 520b1ffb9..2cc6ea779 100644 --- a/libbb/crc32.c +++ b/libbb/crc32.c @@ -18,6 +18,8 @@ #include "libbb.h" +uint32_t *global_crc32_table; + uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) { uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320; @@ -40,3 +42,25 @@ uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) return crc_table - 256; } + +uint32_t FAST_FUNC crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) +{ + const void *end = (uint8_t*)buf + len; + + while (buf != end) { + val = (val << 8) ^ crc_table[(val >> 24) ^ *(uint8_t*)buf]; + buf = (uint8_t*)buf + 1; + } + return val; +} + +uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) +{ + const void *end = (uint8_t*)buf + len; + + while (buf != end) { + val = crc_table [(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); + buf = (uint8_t*)buf + 1; + } + return val; +} diff --git a/miscutils/flash_eraseall.c b/miscutils/flash_eraseall.c index 53aad3d52..b832cc1dd 100644 --- a/miscutils/flash_eraseall.c +++ b/miscutils/flash_eraseall.c @@ -42,15 +42,6 @@ but mtd/jffs2-user.h is gone now (at least 2.6.31.6 does not have it anymore) #define cpu_to_je16(v) ((jint16_t){(v)}) #define cpu_to_je32(v) ((jint32_t){(v)}) -static uint32_t crc32(uint32_t val, const void *ss, int len, - uint32_t *crc32_table) -{ - const unsigned char *s = ss; - while (--len >= 0) - val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); - return val; -} - static void show_progress(mtd_info_t *meminfo, erase_info_t *erase) { printf("\rErasing %u Kibyte @ %x - %2u%% complete.", @@ -131,8 +122,9 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) cleanmarker.totlen = cpu_to_je32(8); } - cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, - crc32_table)); + cleanmarker.hdr_crc = cpu_to_je32( + crc32_block_endian0(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, crc32_table) + ); } /* Don't want to destroy progress indicator by bb_error_msg's */ diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c index 98803ec88..4dfb5b227 100644 --- a/util-linux/fdisk_gpt.c +++ b/util-linux/fdisk_gpt.c @@ -46,8 +46,6 @@ static unsigned int n_parts; static unsigned int part_array_len; static unsigned int part_entry_len; -static uint32_t *crc32_table; - static inline gpt_partition * gpt_part(int i) { @@ -61,12 +59,7 @@ gpt_part(int i) static uint32_t gpt_crc32(void *buf, int len) { - uint32_t crc = 0xffffffff; - - for (; len > 0; len--, buf++) { - crc = crc32_table[(crc ^ *((char *)buf)) & 0xff] ^ (crc >> 8); - } - return crc ^ 0xffffffff; + return 0xffffffff ^ crc32_block_endian0(0xffffffff, buf, len, global_crc32_table); } static void @@ -160,8 +153,8 @@ check_gpt_label(void) return 0; } - if (!crc32_table) { - crc32_table = crc32_filltable(NULL, 0); + if (!global_crc32_table) { + global_crc32_table = crc32_filltable(NULL, 0); } crc = SWAP_LE32(gpt_hdr->hdr_crc32); -- cgit v1.2.3-55-g6feb From db9ccc57728ccc7ca3c949437828e3d6d9d2dc5d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Oct 2010 02:36:17 +0200 Subject: netstat: was using buffers one byte short for scanf (no place for NUL). fixing Signed-off-by: Denys Vlasenko --- networking/netstat.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/networking/netstat.c b/networking/netstat.c index 485a7d191..2a83af3ac 100644 --- a/networking/netstat.c +++ b/networking/netstat.c @@ -395,11 +395,14 @@ struct inet_params { static int scan_inet_proc_line(struct inet_params *param, char *line) { int num; - char local_addr[64], rem_addr[64]; + /* IPv6 /proc files use 32-char hex representation + * of IPv6 address, followed by :PORT_IN_HEX + */ + char local_addr[33], rem_addr[33]; /* 32 + 1 for NUL */ num = sscanf(line, - "%*d: %64[0-9A-Fa-f]:%X " - "%64[0-9A-Fa-f]:%X %X " + "%*d: %32[0-9A-Fa-f]:%X " + "%32[0-9A-Fa-f]:%X %X " "%lX:%lX %*X:%*X " "%*X %d %*d %ld ", local_addr, ¶m->local_port, -- cgit v1.2.3-55-g6feb From 16cc80e9890c0409921b0463e5678649a893ae7f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 28 Oct 2010 05:38:11 +0200 Subject: crc32: cleanups, no code changes Signed-off-by: Denys Vlasenko --- libbb/crc32.c | 2 +- util-linux/fdisk_gpt.c | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libbb/crc32.c b/libbb/crc32.c index 2cc6ea779..c63bf0772 100644 --- a/libbb/crc32.c +++ b/libbb/crc32.c @@ -59,7 +59,7 @@ uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned l const void *end = (uint8_t*)buf + len; while (buf != end) { - val = crc_table [(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); + val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); buf = (uint8_t*)buf + 1; } return val; diff --git a/util-linux/fdisk_gpt.c b/util-linux/fdisk_gpt.c index 4dfb5b227..1ab1293de 100644 --- a/util-linux/fdisk_gpt.c +++ b/util-linux/fdisk_gpt.c @@ -55,11 +55,10 @@ gpt_part(int i) return (gpt_partition *)&part_array[i * part_entry_len]; } -/* TODO: move to libbb */ static uint32_t gpt_crc32(void *buf, int len) { - return 0xffffffff ^ crc32_block_endian0(0xffffffff, buf, len, global_crc32_table); + return ~crc32_block_endian0(0xffffffff, buf, len, global_crc32_table); } static void -- cgit v1.2.3-55-g6feb From 78b286fea51ef137d660b91037c89376115a1994 Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Wed, 27 Oct 2010 19:52:40 +0300 Subject: login: free fromhost upon cleaning up Signed-off-by: Alexander Shishkin Signed-off-by: Denys Vlasenko --- loginutils/login.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/loginutils/login.c b/loginutils/login.c index e104fbb93..3065eaa5b 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -364,6 +364,10 @@ int login_main(int argc UNUSED_PARAM, char **argv) if (++count == 3) { syslog(LOG_WARNING, "invalid password for '%s'%s", username, fromhost); + + if (ENABLE_FEATURE_CLEAN_UP) + free(fromhost); + return EXIT_FAILURE; } username[0] = '\0'; @@ -401,6 +405,9 @@ int login_main(int argc UNUSED_PARAM, char **argv) if (pw->pw_uid == 0) syslog(LOG_INFO, "root login%s", fromhost); + if (ENABLE_FEATURE_CLEAN_UP) + free(fromhost); + /* well, a simple setexeccon() here would do the job as well, * but let's play the game for now */ IF_SELINUX(set_current_security_context(user_sid);) -- cgit v1.2.3-55-g6feb From 776509544123c68bbc128c0fdb2f699062d294cf Mon Sep 17 00:00:00 2001 From: Alexander Shishkin Date: Thu, 28 Oct 2010 06:10:03 +0200 Subject: mount: pass NULL, not "", as "data" to mount syscall if we have no opts When mounting a filesystem without any additional options (data parameter to the mount(2) syscall), pass NULL instead of an empty string like GNU mount does. This fixes, for example mounting cgroup fs with bbox mount. Signed-off-by: Alexander Shishkin Signed-off-by: Denys Vlasenko --- util-linux/mount.c | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/util-linux/mount.c b/util-linux/mount.c index 3ac8ce093..0f213bb30 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -332,7 +332,7 @@ static void append_mount_options(char **oldopts, const char *newopts) } // Use the mount_options list to parse options into flags. -// Also return list of unrecognized options if unrecognized != NULL +// Also update list of unrecognized options if unrecognized != NULL static long parse_mount_options(char *options, char **unrecognized) { long flags = MS_SILENT; @@ -348,25 +348,35 @@ static long parse_mount_options(char *options, char **unrecognized) // FIXME: use hasmntopt() // Find this option in mount_options for (i = 0; i < ARRAY_SIZE(mount_options); i++) { - if (!strcasecmp(option_str, options)) { + if (strcasecmp(option_str, options) == 0) { long fl = mount_options[i]; - if (fl < 0) flags &= fl; - else flags |= fl; - break; + if (fl < 0) + flags &= fl; + else + flags |= fl; + goto found; } option_str += strlen(option_str) + 1; } - // If unrecognized not NULL, append unrecognized mount options - if (unrecognized && i == ARRAY_SIZE(mount_options)) { + // We did not recognize this option. + // If "unrecognized" is not NULL, append option there. + // Note that we should not append *empty* option - + // in this case we want to pass NULL, not "", to "data" + // parameter of mount(2) syscall. + // This is crucial for filesystems that don't accept + // any arbitrary mount options, like cgroup fs: + // "mount -t cgroup none /mnt" + if (options[0] && unrecognized) { // Add it to strflags, to pass on to kernel - i = *unrecognized ? strlen(*unrecognized) : 0; - *unrecognized = xrealloc(*unrecognized, i + strlen(options) + 2); + char *p = *unrecognized; + unsigned len = p ? strlen(p) : 0; + *unrecognized = p = xrealloc(p, len + strlen(options) + 2); // Comma separated if it's not the first one - if (i) (*unrecognized)[i++] = ','; - strcpy((*unrecognized)+i, options); + if (len) p[len++] = ','; + strcpy(p + len, options); } - + found: if (!comma) break; // Advance to next option -- cgit v1.2.3-55-g6feb