From ab518eea9c41235a3fcde80f3ea99669eaade621 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 16 Mar 2017 16:49:37 +0100 Subject: mount: create loop devices with LO_FLAGS_AUTOCLEAR flag The "autolooped" mount (mount [-oloop] IMAGE /DIR/DIR) always creates AUTOCLEARed loopdevs, so that umounting drops them (and this does not require any code in the umount userspace). This happens since circa linux-2.6.25: commit 96c5865559cee0f9cbc5173f3c949f6ce3525581 Date: Wed Feb 6 01:36:27 2008 -0800 Subject: Allow auto-destruction of loop devices IOW: in this case, umount does not have to use -d to drop the loopdev. The explicit loop mount (mount /dev/loopN /DIR/DIR) does not do this. In this case, umount without -d should not drop loopdev. Unfortunately, bbox umount currently always implies -d, this probably needs fixing. function old new delta set_loop 537 597 +60 singlemount 1101 1138 +37 losetup_main 419 432 +13 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 110/0) Total: 110 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'include') diff --git a/include/libbb.h b/include/libbb.h index b054e0559..e97efcb6e 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1329,10 +1329,15 @@ extern int get_linux_version_code(void) FAST_FUNC; extern char *query_loop(const char *device) FAST_FUNC; extern int del_loop(const char *device) FAST_FUNC; -/* If *devname is not NULL, use that name, otherwise try to find free one, +/* + * If *devname is not NULL, use that name, otherwise try to find free one, * malloc and return it in *devname. - * return value: 1: read-only loopdev was setup, 0: rw, < 0: error */ -extern int set_loop(char **devname, const char *file, unsigned long long offset, int ro) FAST_FUNC; + * return value is the opened fd to the loop device, or < on error + */ +extern int set_loop(char **devname, const char *file, unsigned long long offset, unsigned flags) FAST_FUNC; +/* These constants match linux/loop.h (without BB_ prefix): */ +#define BB_LO_FLAGS_READ_ONLY 1 +#define BB_LO_FLAGS_AUTOCLEAR 4 /* Like bb_ask below, but asks on stdin with no timeout. */ char *bb_ask_stdin(const char * prompt) FAST_FUNC; -- cgit v1.2.3-55-g6feb From d88f94a5df3a2edb8ba56fab5c13674b452f87ab Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 5 Apr 2017 18:17:17 +0200 Subject: nl: new applet; also implement cat -nb (similar functionality to nl) function old new delta nl_main - 201 +201 print_numbered_lines - 115 +115 cat_main 36 149 +113 static.nl_longopts - 106 +106 packed_usage 31081 31182 +101 applet_main 1488 1492 +4 applet_names 2575 2578 +3 applet_suid 93 94 +1 applet_install_loc 186 187 +1 ------------------------------------------------------------------------------ (add/remove: 4/0 grow/shrink: 6/0 up/down: 645/0) Total: 645 bytes Signed-off-by: Denys Vlasenko --- coreutils/cat.c | 43 +++++++++++++++++++++--- coreutils/nl.c | 100 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ include/libbb.h | 10 ++++++ 3 files changed, 149 insertions(+), 4 deletions(-) create mode 100644 coreutils/nl.c (limited to 'include') diff --git a/coreutils/cat.c b/coreutils/cat.c index 65978887e..4169d9516 100644 --- a/coreutils/cat.c +++ b/coreutils/cat.c @@ -15,15 +15,31 @@ //applet:IF_CAT(APPLET_NOFORK(cat, cat, BB_DIR_BIN, BB_SUID_DROP, cat)) -//kbuild:lib-$(CONFIG_CAT) += cat.o +//kbuild:lib-$(CONFIG_CAT) += cat.o +// For -n: +//kbuild:lib-$(CONFIG_CAT) += nl.o /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/cat.html */ //usage:#define cat_trivial_usage -//usage: "[FILE]..." +//usage: "[-n] [FILE]..." //usage:#define cat_full_usage "\n\n" //usage: "Concatenate FILEs and print them to stdout" +//usage: "\n -n Number output lines" +/* + Longopts not implemented yet: + --number-nonblank number nonempty output lines, overrides -n + --number number all output lines + Not implemented yet: + -A, --show-all equivalent to -vET + -e equivalent to -vE + -E, --show-ends display $ at end of each line + -s, --squeeze-blank suppress repeated empty output lines + -t equivalent to -vT + -T, --show-tabs display TAB characters as ^I + -v, --show-nonprinting use ^ and M- notation, except for LFD and TAB +*/ //usage: //usage:#define cat_example_usage //usage: "$ cat /proc/uptime\n" @@ -61,7 +77,26 @@ int bb_cat(char **argv) int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int cat_main(int argc UNUSED_PARAM, char **argv) { - getopt32(argv, "u"); + struct number_state ns; + unsigned opt; + + /* -u is ignored */ + opt = getopt32(argv, "nbu"); argv += optind; - return bb_cat(argv); + if (!(opt & 3)) /* no -n or -b */ + return bb_cat(argv); + + if (!*argv) + *--argv = (char*)"-"; + ns.width = 6; + ns.start = 1; + ns.inc = 1; + ns.sep = "\t"; + ns.empty_str = "\n"; + ns.all = !(opt & 2); /* -n without -b */ + ns.nonempty = (opt & 2); /* -b (with or without -n) */ + do { + print_numbered_lines(&ns, *argv); + } while (*++argv); + fflush_stdout_and_exit(EXIT_SUCCESS); } diff --git a/coreutils/nl.c b/coreutils/nl.c new file mode 100644 index 000000000..97931f334 --- /dev/null +++ b/coreutils/nl.c @@ -0,0 +1,100 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config NL +//config: bool "nl" +//config: default y +//config: help +//config: nl is used to number lines of files. + +//applet:IF_UNIQ(APPLET(nl, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_UNIQ) += nl.o + +//usage:#define nl_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define nl_full_usage "\n\n" +//usage: "Write FILEs to standard output with line numbers added\n" +//usage: "\n -b STYLE Which lines to number - a: all, t: nonempty, n: none" +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^TODO: support "pBRE": number only lines thatmatch regexp BRE" +////usage: "\n -f STYLE footer lines" +////usage: "\n -h STYLE header lines" +////usage: "\n -d CC use CC for separating logical pages" +//usage: "\n -i N Line number increment" +////usage: "\n -l NUMBER group of NUMBER empty lines counted as one" +////usage: "\n -n FORMAT lneft justified, no leading zeros; rn or rz" +////usage: "\n -p do not reset line numbers at logical pages (huh?)" +//usage: "\n -s STRING Use STRING as line number separator" +//usage: "\n -v N Start from N" +//usage: "\n -w N Width of line numbers" + +/* By default, selects -v1 -i1 -l1 -sTAB -w6 -nrn -hn -bt -fn */ + +#include "libbb.h" + +void FAST_FUNC print_numbered_lines(struct number_state *ns, const char *filename) +{ + FILE *fp = fopen_or_warn_stdin(filename); + unsigned N = ns->start; + char *line; + + while ((line = xmalloc_fgetline(fp)) != NULL) { + if (ns->all + || (ns->nonempty && line[0]) + ) { + printf("%*u%s%s\n", ns->width, N, ns->sep, line); + N += ns->inc; + } else if (ns->empty_str) + fputs(ns->empty_str, stdout); + free(line); + } + + fclose(fp); +} + +int nl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int nl_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opt; + struct number_state ns; + const char *opt_b = "t"; + enum { + OPT_p = (1 << 0), + }; +#if ENABLE_LONG_OPTS + static const char nl_longopts[] ALIGN1 = + "body-numbering\0" Required_argument "b" + // "footer-numbering\0" Required_argument "f" - not implemented yet + // "header-numbering\0" Required_argument "h" - not implemented yet + // "section-delimiter\0" Required_argument "d" - not implemented yet + "line-increment\0" Required_argument "i" + // "join-blank-lines\0" Required_argument "l" - not implemented yet + // "number-format\0" Required_argument "n" - not implemented yet + "no-renumber\0" No_argument "p" // no-op so far + "number-separator\0" Required_argument "s" + "starting-line-number\0"Required_argument "v" + "number-width\0" Required_argument "w" + ; + + applet_long_options = nl_longopts; +#endif + ns.width = 6; + ns.start = 1; + ns.inc = 1; + ns.sep = "\t"; + opt = getopt32(argv, "pw:+s:v:+i:+b:", &ns.width, &ns.sep, &ns.start, &ns.inc, &opt_b); + ns.all = (opt_b[0] == 'a'); + ns.nonempty = (opt_b[0] == 't'); + ns.empty_str = xasprintf("%*s\n", ns.width + strlen(ns.sep), ""); + + argv += optind; + if (!*argv) + *--argv = (char*)"-"; + + do { + print_numbered_lines(&ns, *argv); + } while (*++argv); + + fflush_stdout_and_exit(EXIT_SUCCESS); +} diff --git a/include/libbb.h b/include/libbb.h index e97efcb6e..a2c699b54 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1271,6 +1271,16 @@ int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; void bb_displayroutes(int noresolve, int netstatfmt) FAST_FUNC; #endif +struct number_state { + unsigned width; + unsigned start; + unsigned inc; + const char *sep; + const char *empty_str; + smallint all, nonempty; +}; +void print_numbered_lines(struct number_state *ns, const char *filename) FAST_FUNC; + /* Networking */ /* This structure defines protocol families and their handlers. */ -- cgit v1.2.3-55-g6feb From 8a134ec68075fc2fd415558bcf6a37cda3ff285f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 11 Apr 2017 07:34:56 +0200 Subject: libbb: move isqrt from factor, use it in diff too Signed-off-by: Denys Vlasenko --- coreutils/factor.c | 19 +---------------- editors/diff.c | 11 ---------- include/libbb.h | 2 ++ libbb/isqrt.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 63 insertions(+), 29 deletions(-) create mode 100644 libbb/isqrt.c (limited to 'include') diff --git a/coreutils/factor.c b/coreutils/factor.c index f910fdb44..11cc04f92 100644 --- a/coreutils/factor.c +++ b/coreutils/factor.c @@ -44,24 +44,7 @@ typedef unsigned long half_t; #error Cant find an integer type which is half as wide as ullong #endif -/* Returns such x that x+1 > sqrt(N) */ -static inline half_t isqrt(wide_t N) -{ - half_t x; - unsigned shift; - - shift = WIDE_BITS - 2; - x = 0; - do { - x = (x << 1) + 1; - if ((wide_t)x * x > (N >> shift)) - x--; /* whoops, that +1 was too much */ - shift -= 2; - } while ((int)shift >= 0); - return x; -} - -static NOINLINE half_t isqrt_odd(wide_t N) +static half_t isqrt_odd(wide_t N) { half_t s = isqrt(N); /* Subtract 1 from even s, odd s won't change: */ diff --git a/editors/diff.c b/editors/diff.c index 0eb825cfb..3304edb26 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -295,17 +295,6 @@ static int search(const int *c, int k, int y, const struct cand *list) } } -static unsigned isqrt(unsigned n) -{ - unsigned x = 1; - while (1) { - const unsigned y = x; - x = ((n / x) + x) >> 1; - if (x <= (y + 1) && x >= (y - 1)) - return x; - } -} - static void stone(const int *a, int n, const int *b, int *J, int pref) { const unsigned isq = isqrt(n); diff --git a/include/libbb.h b/include/libbb.h index a2c699b54..04071639a 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -342,6 +342,8 @@ extern int *const bb_errno; uint64_t bb_bswap_64(uint64_t x) FAST_FUNC; #endif +unsigned long FAST_FUNC isqrt(unsigned long long N); + unsigned long long monotonic_ns(void) FAST_FUNC; unsigned long long monotonic_us(void) FAST_FUNC; unsigned long long monotonic_ms(void) FAST_FUNC; diff --git a/libbb/isqrt.c b/libbb/isqrt.c new file mode 100644 index 000000000..817b7d036 --- /dev/null +++ b/libbb/isqrt.c @@ -0,0 +1,60 @@ +/* + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-y += isqrt.o + +#ifndef ISQRT_TEST +# include "libbb.h" +#else +/* gcc -DISQRT_TEST -Wall -O2 isqrt.c -oisqrt && ./isqrt $((RANDOM*RANDOM)) */ +# include +# include +# include +# define FAST_FUNC /* nothing */ +#endif + +/* Returns such x that x+1 > sqrt(N) */ +unsigned long FAST_FUNC isqrt(unsigned long long N) +{ + unsigned long x; + unsigned shift; +#define LL_WIDTH_BITS (unsigned)(sizeof(N)*8) + + shift = LL_WIDTH_BITS - 2; + x = 0; + do { + x = (x << 1) + 1; + if ((unsigned long long)x * x > (N >> shift)) + x--; /* whoops, that +1 was too much */ + shift -= 2; + } while ((int)shift >= 0); + return x; +} + +#ifdef ISQRT_TEST +int main(int argc, char **argv) +{ + unsigned long long n = argv[1] ? strtoull(argv[1], NULL, 0) : time(NULL); + for (;;) { + unsigned long h; + n--; + h = isqrt(n); + if (!(n & 0xffff)) + printf("isqrt(%llx)=%lx\n", n, h); + if ((unsigned long long)h * h > n) { + printf("BAD1: isqrt(%llx)=%lx\n", n, h); + return 1; + } + h++; + if ((unsigned long long)h * h != 0 /* this can overflow to 0 - not a bug */ + && (unsigned long long)h * h <= n) + { + printf("BAD2: isqrt(%llx)=%lx\n", n, h); + return 1; + } + } +} +#endif -- cgit v1.2.3-55-g6feb From d9eb40c18519d10aac3b3d008aa7e338ae830b72 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 12 Apr 2017 15:48:19 +0200 Subject: fix errors found with make_single_applets.sh Signed-off-by: Denys Vlasenko --- coreutils/cat.c | 27 --------------------------- coreutils/who.c | 5 +++-- include/libbb.h | 2 +- libbb/bb_cat.c | 33 +++++++++++++++++++++++++++++++++ libbb/print_numbered_lines.c | 29 +++++++++++++++++++++++++++++ procps/kill.c | 10 +++++----- 6 files changed, 71 insertions(+), 35 deletions(-) create mode 100644 libbb/bb_cat.c create mode 100644 libbb/print_numbered_lines.c (limited to 'include') diff --git a/coreutils/cat.c b/coreutils/cat.c index 4169d9516..96970b19d 100644 --- a/coreutils/cat.c +++ b/coreutils/cat.c @@ -16,8 +16,6 @@ //applet:IF_CAT(APPLET_NOFORK(cat, cat, BB_DIR_BIN, BB_SUID_DROP, cat)) //kbuild:lib-$(CONFIG_CAT) += cat.o -// For -n: -//kbuild:lib-$(CONFIG_CAT) += nl.o /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/cat.html */ @@ -49,31 +47,6 @@ /* This is a NOFORK applet. Be very careful! */ - -int bb_cat(char **argv) -{ - int fd; - int retval = EXIT_SUCCESS; - - if (!*argv) - argv = (char**) &bb_argv_dash; - - do { - fd = open_or_warn_stdin(*argv); - if (fd >= 0) { - /* This is not a xfunc - never exits */ - off_t r = bb_copyfd_eof(fd, STDOUT_FILENO); - if (fd != STDIN_FILENO) - close(fd); - if (r >= 0) - continue; - } - retval = EXIT_FAILURE; - } while (*++argv); - - return retval; -} - int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int cat_main(int argc UNUSED_PARAM, char **argv) { diff --git a/coreutils/who.c b/coreutils/who.c index ec9d25159..4adead77e 100644 --- a/coreutils/who.c +++ b/coreutils/who.c @@ -40,11 +40,12 @@ // APPLET_ODDNAME:name main location suid_type help //applet:IF_USERS(APPLET_ODDNAME(users, who, BB_DIR_USR_BIN, BB_SUID_DROP, users)) -//applet:IF_USERS(APPLET_ODDNAME(w, who, BB_DIR_USR_BIN, BB_SUID_DROP, w)) +//applet:IF_W( APPLET_ODDNAME(w, who, BB_DIR_USR_BIN, BB_SUID_DROP, w)) //applet:IF_WHO( APPLET( who, BB_DIR_USR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_USERS) += who.o -//kbuild:lib-$(CONFIG_WHO) += who.o +//kbuild:lib-$(CONFIG_W) += who.o +//kbuild:lib-$(CONFIG_WHO) += who.o /* BB_AUDIT SUSv3 _NOT_ compliant -- missing options -b, -d, -l, -m, -p, -q, -r, -s, -t, -T, -u; Missing argument 'file'. */ diff --git a/include/libbb.h b/include/libbb.h index 04071639a..2c30bde6f 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1247,7 +1247,7 @@ extern void bb_logenv_override(void) FAST_FUNC; /* Applets which are useful from another applets */ -int bb_cat(char** argv); +int bb_cat(char** argv) FAST_FUNC; /* If shell needs them, they exist even if not enabled as applets */ int echo_main(int argc, char** argv) IF_ECHO(MAIN_EXTERNALLY_VISIBLE); int printf_main(int argc, char **argv) IF_PRINTF(MAIN_EXTERNALLY_VISIBLE); diff --git a/libbb/bb_cat.c b/libbb/bb_cat.c new file mode 100644 index 000000000..0a4a350fb --- /dev/null +++ b/libbb/bb_cat.c @@ -0,0 +1,33 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//kbuild:lib-y += bb_cat.o + +#include "libbb.h" + +int FAST_FUNC bb_cat(char **argv) +{ + int fd; + int retval = EXIT_SUCCESS; + + if (!*argv) + argv = (char**) &bb_argv_dash; + + do { + fd = open_or_warn_stdin(*argv); + if (fd >= 0) { + /* This is not a xfunc - never exits */ + off_t r = bb_copyfd_eof(fd, STDOUT_FILENO); + if (fd != STDIN_FILENO) + close(fd); + if (r >= 0) + continue; + } + retval = EXIT_FAILURE; + } while (*++argv); + + return retval; +} diff --git a/libbb/print_numbered_lines.c b/libbb/print_numbered_lines.c new file mode 100644 index 000000000..702aed1ea --- /dev/null +++ b/libbb/print_numbered_lines.c @@ -0,0 +1,29 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//kbuild:lib-y += print_numbered_lines.o + +#include "libbb.h" + +void FAST_FUNC print_numbered_lines(struct number_state *ns, const char *filename) +{ + FILE *fp = fopen_or_warn_stdin(filename); + unsigned N = ns->start; + char *line; + + while ((line = xmalloc_fgetline(fp)) != NULL) { + if (ns->all + || (ns->nonempty && line[0]) + ) { + printf("%*u%s%s\n", ns->width, N, ns->sep, line); + N += ns->inc; + } else if (ns->empty_str) + fputs(ns->empty_str, stdout); + free(line); + } + + fclose(fp); +} diff --git a/procps/kill.c b/procps/kill.c index 7ae5beead..975a3e8c5 100644 --- a/procps/kill.c +++ b/procps/kill.c @@ -201,7 +201,7 @@ int kill_main(int argc UNUSED_PARAM, char **argv) pid_t sid; procps_status_t* p = NULL; /* compat: exitcode 2 is "no one was signaled" */ - int ret = 2; + errors = 2; /* Find out our session id */ sid = getsid(pid); @@ -229,7 +229,7 @@ int kill_main(int argc UNUSED_PARAM, char **argv) arg = *args++; if (arg[0] != '-' || arg[1] != 'o') { bb_error_msg("bad option '%s'", arg); - ret = 1; + errors = 1; goto resume; } arg += 2; @@ -238,21 +238,21 @@ int kill_main(int argc UNUSED_PARAM, char **argv) omit = bb_strtoi(arg, NULL, 10); if (errno) { bb_error_msg("invalid number '%s'", arg); - ret = 1; + errors = 1; goto resume; } if (p->pid == omit) goto dont_kill; } kill(p->pid, signo); - ret = 0; + errors = 0; dont_kill: ; } resume: /* And let them continue */ if (signo != SIGSTOP && signo != SIGCONT) kill(-1, SIGCONT); - return ret; + return errors; } #if ENABLE_KILL || ENABLE_KILLALL -- cgit v1.2.3-55-g6feb From 835ad3a984c5590ae4f6c94f2f0781ea049d1ae8 Mon Sep 17 00:00:00 2001 From: Kaarle Ritvanen Date: Wed, 12 Apr 2017 00:58:46 +0300 Subject: libbb: GETOPT_RESET macro Signed-off-by: Kaarle Ritvanen Signed-off-by: Denys Vlasenko --- include/libbb.h | 22 ++++++++++++++++++++++ libbb/getopt32.c | 8 +------- libbb/vfork_daemon_rexec.c | 28 ++-------------------------- runit/sv.c | 7 +------ shell/shell_common.c | 8 +------- util-linux/getopt.c | 7 +------ 6 files changed, 28 insertions(+), 52 deletions(-) (limited to 'include') diff --git a/include/libbb.h b/include/libbb.h index 2c30bde6f..11d022fb5 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1178,6 +1178,28 @@ extern uint32_t option_mask32; extern uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; +/* BSD-derived getopt() functions require that optind be set to 1 in + * order to reset getopt() state. This used to be generally accepted + * way of resetting getopt(). However, glibc's getopt() + * has additional getopt() state beyond optind (specifically, glibc + * extensions ('+' and '-' at the start of the string), and requires + * that optind be set to zero to reset its state. BSD-derived versions + * of getopt() misbehaved if optind is set to 0 in order to reset getopt(), + * and glibc's getopt() used to coredump if optind is set 1 in order + * to reset getopt(). + * Then BSD introduced additional variable "optreset" which + * be set to 1 in order to reset getopt(). Sigh. Standards, anyone? + * + * By ~2008, OpenBSD 3.4 was changed to survive glibc-like optind = 0 + * (to interpret it as if optreset was set). + */ +#ifdef __GLIBC__ +#define GETOPT_RESET() (optind = 0) +#else /* BSD style */ +#define GETOPT_RESET() (optind = 1) +#endif + + /* Having next pointer as a first member allows easy creation * of "llist-compatible" structs, and using llist_FOO functions * on them. diff --git a/libbb/getopt32.c b/libbb/getopt32.c index 497fc016f..3104826ef 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -576,13 +576,7 @@ getopt32(char **argv, const char *applet_opts, ...) * run_nofork_applet() does this, but we might end up here * also via gunzip_main() -> gzip_main(). Play safe. */ -#ifdef __GLIBC__ - optind = 0; -#else /* BSD style */ - optind = 1; - /* optreset = 1; */ -#endif - /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ + GETOPT_RESET(); /* Note: just "getopt() <= 0" will not work well for * "fake" short options, like this one: diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 2e7dc2d9b..fd481bf6e 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -121,28 +121,8 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) /* In case getopt() or getopt32() was already called: * reset the libc getopt() function, which keeps internal state. - * - * BSD-derived getopt() functions require that optind be set to 1 in - * order to reset getopt() state. This used to be generally accepted - * way of resetting getopt(). However, glibc's getopt() - * has additional getopt() state beyond optind, and requires that - * optind be set to zero to reset its state. So the unfortunate state of - * affairs is that BSD-derived versions of getopt() misbehave if - * optind is set to 0 in order to reset getopt(), and glibc's getopt() - * will core dump if optind is set 1 in order to reset getopt(). - * - * More modern versions of BSD require that optreset be set to 1 in - * order to reset getopt(). Sigh. Standards, anyone? */ -#ifdef __GLIBC__ - optind = 0; -#else /* BSD style */ - optind = 1; - /* optreset = 1; */ -#endif - /* optarg = NULL; opterr = 1; optopt = 63; - do we need this too? */ - /* (values above are what they initialized to in glibc and uclibc) */ - /* option_mask32 = 0; - not needed, no applet depends on it being 0 */ + GETOPT_RESET(); argc = 1; while (argv[argc]) @@ -167,11 +147,7 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) restore_nofork_data(&old); /* Other globals can be simply reset to defaults */ -#ifdef __GLIBC__ - optind = 0; -#else /* BSD style */ - optind = 1; -#endif + GETOPT_RESET(); return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ } diff --git a/runit/sv.c b/runit/sv.c index 9e2132259..64f1ae395 100644 --- a/runit/sv.c +++ b/runit/sv.c @@ -688,12 +688,7 @@ int svc_main(int argc UNUSED_PARAM, char **argv) /* getopt32() was already called: * reset the libc getopt() function, which keeps internal state. */ -#ifdef __GLIBC__ - optind = 0; -#else /* BSD style */ - optind = 1; - /* optreset = 1; */ -#endif + GETOPT_RESET(); do { if (opts & 1) { diff --git a/shell/shell_common.c b/shell/shell_common.c index 549b17ca1..fb86e680f 100644 --- a/shell/shell_common.c +++ b/shell/shell_common.c @@ -401,13 +401,7 @@ shell_builtin_ulimit(char **argv) /* In case getopt was already called: * reset the libc getopt() function, which keeps internal state. */ -#ifdef __GLIBC__ - optind = 0; -#else /* BSD style */ - optind = 1; - /* optreset = 1; */ -#endif - /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ + GETOPT_RESET(); argc = 1; while (argv[argc]) diff --git a/util-linux/getopt.c b/util-linux/getopt.c index 63294c520..79d54854b 100644 --- a/util-linux/getopt.c +++ b/util-linux/getopt.c @@ -246,12 +246,7 @@ static int generate_output(char **argv, int argc, const char *optstr, const stru /* We used it already in main() in getopt32(), * we *must* reset getopt(3): */ -#ifdef __GLIBC__ - optind = 0; -#else /* BSD style */ - optind = 1; - /* optreset = 1; */ -#endif + GETOPT_RESET(); while (1) { #if ENABLE_FEATURE_GETOPT_LONG -- cgit v1.2.3-55-g6feb From 352ddd3d216131757ac278e97a09ce2f4d7f53f0 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 12 Apr 2017 20:21:34 +0200 Subject: Tweak GETOPT_RESET comment Signed-off-by: Denys Vlasenko --- include/libbb.h | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'include') diff --git a/include/libbb.h b/include/libbb.h index 11d022fb5..777a4a884 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1176,19 +1176,17 @@ extern const char *applet_long_options; #endif extern uint32_t option_mask32; extern uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; - - /* BSD-derived getopt() functions require that optind be set to 1 in * order to reset getopt() state. This used to be generally accepted * way of resetting getopt(). However, glibc's getopt() * has additional getopt() state beyond optind (specifically, glibc - * extensions ('+' and '-' at the start of the string), and requires + * extensions such as '+' and '-' at the start of the string), and requires * that optind be set to zero to reset its state. BSD-derived versions * of getopt() misbehaved if optind is set to 0 in order to reset getopt(), * and glibc's getopt() used to coredump if optind is set 1 in order * to reset getopt(). - * Then BSD introduced additional variable "optreset" which - * be set to 1 in order to reset getopt(). Sigh. Standards, anyone? + * Then BSD introduced additional variable "optreset" which should be + * set to 1 in order to reset getopt(). Sigh. Standards, anyone? * * By ~2008, OpenBSD 3.4 was changed to survive glibc-like optind = 0 * (to interpret it as if optreset was set). -- cgit v1.2.3-55-g6feb From 517a82c5b6b5e279f3e96a6774445a2952ca312b Mon Sep 17 00:00:00 2001 From: Kaarle Ritvanen Date: Sat, 2 Jan 2016 00:20:39 +0200 Subject: login: move check_securetty to libbb Signed-off-by: Kaarle Ritvanen Signed-off-by: Denys Vlasenko --- include/libbb.h | 5 +++++ libbb/Kbuild.src | 1 + libbb/securetty.c | 22 ++++++++++++++++++++++ loginutils/login.c | 19 ------------------- 4 files changed, 28 insertions(+), 19 deletions(-) create mode 100644 libbb/securetty.c (limited to 'include') diff --git a/include/libbb.h b/include/libbb.h index 777a4a884..6b33ffad6 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1481,6 +1481,11 @@ extern void selinux_or_die(void) FAST_FUNC; #define SETUP_ENV_NO_CHDIR (1 << 4) void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC; void nuke_str(char *str) FAST_FUNC; +#if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM +int check_securetty(const char *short_tty) FAST_FUNC; +#else +static ALWAYS_INLINE int check_securetty(const char *short_tty UNUSED_PARAM) { return 1; } +#endif int check_password(const struct passwd *pw, const char *plaintext) FAST_FUNC; int ask_and_check_password_extended(const struct passwd *pw, int timeout, const char *prompt) FAST_FUNC; int ask_and_check_password(const struct passwd *pw) FAST_FUNC; diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 898a51a89..49493c501 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -83,6 +83,7 @@ lib-y += safe_gethostname.o lib-y += safe_poll.o lib-y += safe_strncpy.o lib-y += safe_write.o +lib-y += securetty.o lib-y += setup_environment.o lib-y += signals.o lib-y += simplify_path.o diff --git a/libbb/securetty.c b/libbb/securetty.c new file mode 100644 index 000000000..176cee129 --- /dev/null +++ b/libbb/securetty.c @@ -0,0 +1,22 @@ +/* vi: set sw=4 ts=4: */ +/* + * /etc/securetty checking. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "libbb.h" + +int FAST_FUNC check_securetty(const char *short_tty) +{ + char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */ + parser_t *parser = config_open2("/etc/securetty", fopen_for_read); + while (config_read(parser, &buf, 1, 1, "# \t", PARSE_NORMAL)) { + if (strcmp(buf, short_tty) == 0) + break; + buf = NULL; + } + config_close(parser); + /* buf != NULL here if config file was not found, empty + * or line was found which equals short_tty */ + return buf != NULL; +} diff --git a/loginutils/login.c b/loginutils/login.c index d1757a65d..661a87448 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -175,25 +175,6 @@ static void die_if_nologin(void) # define die_if_nologin() ((void)0) #endif -#if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM -static int check_securetty(const char *short_tty) -{ - char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */ - parser_t *parser = config_open2("/etc/securetty", fopen_for_read); - while (config_read(parser, &buf, 1, 1, "# \t", PARSE_NORMAL)) { - if (strcmp(buf, short_tty) == 0) - break; - buf = NULL; - } - config_close(parser); - /* buf != NULL here if config file was not found, empty - * or line was found which equals short_tty */ - return buf != NULL; -} -#else -static ALWAYS_INLINE int check_securetty(const char *short_tty UNUSED_PARAM) { return 1; } -#endif - #if ENABLE_SELINUX static void initselinux(char *username, char *full_tty, security_context_t *user_sid) -- cgit v1.2.3-55-g6feb From 335681ca8e39144fa19814f7ba10d0fe760e4055 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 13 Apr 2017 12:57:04 +0200 Subject: su: FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY When this feature is enabled, blank passwords are not accepted by su unless the user is on a secure TTY defined in /etc/securetty. This resembles the default PAM configuration of some Linux distros which specify the nullok_secure option for pam_unix.so. Based on patch by Kaarle Ritvanen Signed-off-by: Denys Vlasenko --- include/libbb.h | 1 + libbb/correct_password.c | 4 ++-- loginutils/su.c | 27 ++++++++++++++++++++++----- 3 files changed, 25 insertions(+), 7 deletions(-) (limited to 'include') diff --git a/include/libbb.h b/include/libbb.h index 6b33ffad6..b889dd7d7 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1486,6 +1486,7 @@ int check_securetty(const char *short_tty) FAST_FUNC; #else static ALWAYS_INLINE int check_securetty(const char *short_tty UNUSED_PARAM) { return 1; } #endif +#define CHECKPASS_PW_HAS_EMPTY_PASSWORD 2 int check_password(const struct passwd *pw, const char *plaintext) FAST_FUNC; int ask_and_check_password_extended(const struct passwd *pw, int timeout, const char *prompt) FAST_FUNC; int ask_and_check_password(const struct passwd *pw) FAST_FUNC; diff --git a/libbb/correct_password.c b/libbb/correct_password.c index 513c93028..3436edc30 100644 --- a/libbb/correct_password.c +++ b/libbb/correct_password.c @@ -88,7 +88,7 @@ int FAST_FUNC check_password(const struct passwd *pw, const char *plaintext) /* Ask the user for a password. - * Return 1 without asking if PW has an empty password. + * Return CHECKPASS_PW_HAS_EMPTY_PASSWORD without asking if PW has an empty password. * Return -1 on EOF, error while reading input, or timeout. * Return 1 if the user gives the correct password for entry PW, * 0 if not. @@ -105,7 +105,7 @@ int FAST_FUNC ask_and_check_password_extended(const struct passwd *pw, pw_pass = get_passwd(pw, buffer); if (!pw_pass[0]) /* empty password field? */ - return 1; + return CHECKPASS_PW_HAS_EMPTY_PASSWORD; plaintext = bb_ask(STDIN_FILENO, timeout, prompt); if (!plaintext) { diff --git a/loginutils/su.c b/loginutils/su.c index d04b85fb1..f2cd799ae 100644 --- a/loginutils/su.c +++ b/loginutils/su.c @@ -23,6 +23,11 @@ //config: bool "If user's shell is not in /etc/shells, disallow -s PROG" //config: default y //config: depends on SU +//config: +//config:config FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY +//config: bool "Disallow blank passwords from TTYs other than specified in /etc/securetty" +//config: default n +//config: depends on SU //applet:/* Needs to be run by root or be suid root - needs to change uid and gid: */ //applet:IF_SU(APPLET(su, BB_DIR_BIN, BB_SUID_REQUIRE)) @@ -79,6 +84,7 @@ int su_main(int argc UNUSED_PARAM, char **argv) char user_buf[64]; #endif const char *old_user; + int r; /* Note: we don't use "'+': stop at first non-option" idiom here. * For su, "SCRIPT ARGS" or "-c CMD ARGS" do not stop option parsing: @@ -99,6 +105,11 @@ int su_main(int argc UNUSED_PARAM, char **argv) argv++; } + tty = xmalloc_ttyname(STDIN_FILENO); + if (!tty) + tty = "none"; + tty = skip_dev_pfx(tty); + if (ENABLE_FEATURE_SU_SYSLOG) { /* The utmp entry (via getlogin) is probably the best way to * identify the user, especially if someone su's from a su-shell. @@ -112,20 +123,26 @@ int su_main(int argc UNUSED_PARAM, char **argv) pw = getpwuid(cur_uid); old_user = pw ? xstrdup(pw->pw_name) : ""; } - tty = xmalloc_ttyname(2); - if (!tty) { - tty = "none"; - } openlog(applet_name, 0, LOG_AUTH); } pw = xgetpwnam(opt_username); - if (cur_uid == 0 || ask_and_check_password(pw) > 0) { + r = 1; + if (cur_uid != 0) + r = ask_and_check_password(pw); + if (r > 0) { + if (ENABLE_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY + && r == CHECKPASS_PW_HAS_EMPTY_PASSWORD + && !check_securetty(tty) + ) { + goto fail; + } if (ENABLE_FEATURE_SU_SYSLOG) syslog(LOG_NOTICE, "%c %s %s:%s", '+', tty, old_user, opt_username); } else { + fail: if (ENABLE_FEATURE_SU_SYSLOG) syslog(LOG_NOTICE, "%c %s %s:%s", '-', tty, old_user, opt_username); -- cgit v1.2.3-55-g6feb From a3de0b3b86deb37c2adc993c6357c1a31b7ecb5b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 13 Apr 2017 13:04:05 +0200 Subject: libbb: make check_password() also return CHECKPASS_PW_HAS_EMPTY_PASSWORD Signed-off-by: Denys Vlasenko --- include/libbb.h | 4 ++-- libbb/correct_password.c | 4 ++-- libbb/securetty.c | 6 ++++-- loginutils/login.c | 2 +- loginutils/su.c | 2 +- 5 files changed, 10 insertions(+), 8 deletions(-) (limited to 'include') diff --git a/include/libbb.h b/include/libbb.h index b889dd7d7..9b72c97be 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1482,9 +1482,9 @@ extern void selinux_or_die(void) FAST_FUNC; void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC; void nuke_str(char *str) FAST_FUNC; #if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM -int check_securetty(const char *short_tty) FAST_FUNC; +int is_tty_secure(const char *short_tty) FAST_FUNC; #else -static ALWAYS_INLINE int check_securetty(const char *short_tty UNUSED_PARAM) { return 1; } +static ALWAYS_INLINE int is_tty_secure(const char *short_tty UNUSED_PARAM) { return 1; } #endif #define CHECKPASS_PW_HAS_EMPTY_PASSWORD 2 int check_password(const struct passwd *pw, const char *plaintext) FAST_FUNC; diff --git a/libbb/correct_password.c b/libbb/correct_password.c index 3436edc30..f4635a5bc 100644 --- a/libbb/correct_password.c +++ b/libbb/correct_password.c @@ -63,7 +63,7 @@ static const char *get_passwd(const struct passwd *pw, char buffer[SHADOW_BUFSIZ } /* - * Return 1 if PW has an empty password. + * Return CHECKPASS_PW_HAS_EMPTY_PASSWORD if PW has an empty password. * Return 1 if the user gives the correct password for entry PW, * 0 if not. * NULL pw means "just fake it for login with bad username" @@ -77,7 +77,7 @@ int FAST_FUNC check_password(const struct passwd *pw, const char *plaintext) pw_pass = get_passwd(pw, buffer); if (!pw_pass[0]) { /* empty password field? */ - return 1; + return CHECKPASS_PW_HAS_EMPTY_PASSWORD; } encrypted = pw_encrypt(plaintext, /*salt:*/ pw_pass, 1); diff --git a/libbb/securetty.c b/libbb/securetty.c index 176cee129..67a123689 100644 --- a/libbb/securetty.c +++ b/libbb/securetty.c @@ -6,7 +6,7 @@ */ #include "libbb.h" -int FAST_FUNC check_securetty(const char *short_tty) +int FAST_FUNC is_tty_secure(const char *short_tty) { char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */ parser_t *parser = config_open2("/etc/securetty", fopen_for_read); @@ -17,6 +17,8 @@ int FAST_FUNC check_securetty(const char *short_tty) } config_close(parser); /* buf != NULL here if config file was not found, empty - * or line was found which equals short_tty */ + * or line was found which equals short_tty. + * In all these cases, we report "this tty is secure". + */ return buf != NULL; } diff --git a/loginutils/login.c b/loginutils/login.c index 661a87448..be05def09 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -486,7 +486,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) if (opt & LOGIN_OPT_f) break; /* -f USER: success without asking passwd */ - if (pw->pw_uid == 0 && !check_securetty(short_tty)) + if (pw->pw_uid == 0 && !is_tty_secure(short_tty)) goto auth_failed; /* Don't check the password if password entry is empty (!) */ diff --git a/loginutils/su.c b/loginutils/su.c index f2cd799ae..ef74aa77d 100644 --- a/loginutils/su.c +++ b/loginutils/su.c @@ -134,7 +134,7 @@ int su_main(int argc UNUSED_PARAM, char **argv) if (r > 0) { if (ENABLE_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY && r == CHECKPASS_PW_HAS_EMPTY_PASSWORD - && !check_securetty(tty) + && !is_tty_secure(tty) ) { goto fail; } -- cgit v1.2.3-55-g6feb