From d4e4fdb5ce5ccc067b3d35d877f7a7d978869517 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 3 Jul 2017 21:31:16 +0200 Subject: fixes for bugs found by make_single_applets.sh Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 20 ++++++++++++++++---- libbb/getopt32.c | 4 +--- libbb/vfork_daemon_rexec.c | 3 ++- 3 files changed, 19 insertions(+), 8 deletions(-) (limited to 'libbb') diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 7f0d62060..2dea2b43a 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -78,6 +78,17 @@ #endif +unsigned FAST_FUNC string_array_len(char **argv) +{ + char **start = argv; + + while (*argv) + argv++; + + return argv - start; +} + + #if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; #else @@ -868,10 +879,7 @@ static int busybox_main(char **argv) # if NUM_APPLETS > 0 void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) { - int argc = 1; - - while (argv[argc]) - argc++; + int argc = string_array_len(argv); /* Reinit some shared global data */ xfunc_error_retval = EXIT_FAILURE; @@ -993,7 +1001,11 @@ int main(int argc UNUSED_PARAM, char **argv) } /* applet_names in this case is just "applet\0\0" */ lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv)); +# if ENABLE_BUILD_LIBBUSYBOX + return SINGLE_APPLET_MAIN(string_array_len(argv), argv); +# else return SINGLE_APPLET_MAIN(argc, argv); +# endif #elif !ENABLE_BUSYBOX && NUM_APPLETS == 0 diff --git a/libbb/getopt32.c b/libbb/getopt32.c index b87b83538..80f4cc060 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -379,9 +379,7 @@ getopt32(char **argv, const char *applet_opts, ...) int spec_flgs = 0; /* skip 0: some applets cheat: they do not actually HAVE argv[0] */ - argc = 1; - while (argv[argc]) - argc++; + argc = 1 + string_array_len(argv + 1); va_start(p, applet_opts); diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index fd481bf6e..2695f99ee 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -16,6 +16,7 @@ */ #include "busybox.h" /* uses applet tables */ +#include "NUM_APPLETS.h" /* This does a fork/exec in one call, using vfork(). Returns PID of new child, * -1 for failure. Runs argv[0], searching path if that has no / in it. */ @@ -156,7 +157,7 @@ int FAST_FUNC run_nofork_applet(int applet_no, char **argv) int FAST_FUNC spawn_and_wait(char **argv) { int rc; -#if ENABLE_FEATURE_PREFER_APPLETS +#if ENABLE_FEATURE_PREFER_APPLETS && (NUM_APPLETS > 1) int a = find_applet_by_name(argv[0]); if (a >= 0) { -- cgit v1.2.3-55-g6feb From d1f222c3b00839b289f5d04a69b3c704101d17b2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 4 Jul 2017 16:01:12 +0200 Subject: Change BB_EXTRA_VERSION: now it needs to contain any spaces/parenthesis Before this change, BB_EXTRA_VERSION of "" resulted in: "BusyBox v1.28.0.git () multi-call binary" message, after the fix it is: "BusyBox v1.28.0.git multi-call binary" While at it, eliminate BB_BT and BANNER single-use macros. Signed-off-by: Denys Vlasenko --- Makefile.flags | 2 +- libbb/messages.c | 6 ++---- 2 files changed, 3 insertions(+), 5 deletions(-) (limited to 'libbb') diff --git a/Makefile.flags b/Makefile.flags index 65021de25..f3c897b06 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -15,7 +15,7 @@ CPPFLAGS += \ -include include/autoconf.h \ -D_GNU_SOURCE -DNDEBUG \ $(if $(CONFIG_LFS),-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) \ - -D"BB_VER=KBUILD_STR($(BB_VER))" -DBB_BT=AUTOCONF_TIMESTAMP + -D"BB_VER=KBUILD_STR($(BB_VER))" CFLAGS += $(call cc-option,-Wall,) CFLAGS += $(call cc-option,-Wshadow,) diff --git a/libbb/messages.c b/libbb/messages.c index cb0836de8..27fd14ecc 100644 --- a/libbb/messages.c +++ b/libbb/messages.c @@ -14,12 +14,10 @@ /* allow version to be extended, via CFLAGS */ #ifndef BB_EXTRA_VERSION -#define BB_EXTRA_VERSION BB_BT +#define BB_EXTRA_VERSION " ("AUTOCONF_TIMESTAMP")" #endif -#define BANNER "BusyBox v" BB_VER " (" BB_EXTRA_VERSION ")" - -const char bb_banner[] ALIGN1 = BANNER; +const char bb_banner[] ALIGN1 = "BusyBox v" BB_VER BB_EXTRA_VERSION; const char bb_msg_memory_exhausted[] ALIGN1 = "out of memory"; -- cgit v1.2.3-55-g6feb From a8cf9c5a3ffd1601872d1ab14c5be00fde29209c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 4 Jul 2017 18:49:24 +0200 Subject: libbb: new function bb_getgroups() - allocating wrapper around getgroups() function old new delta bb_getgroups - 111 +111 nexpr 843 757 -86 ------------------------------------------------------------------------------ (add/remove: 2/0 grow/shrink: 0/1 up/down: 111/-86) Total: 25 bytes Signed-off-by: Denys Vlasenko --- coreutils/test.c | 33 +++++++-------------------------- include/libbb.h | 9 +++++++++ libbb/bb_getgroups.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 26 deletions(-) create mode 100644 libbb/bb_getgroups.c (limited to 'libbb') diff --git a/coreutils/test.c b/coreutils/test.c index edc625f57..edcf2a2d8 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -563,26 +563,11 @@ static int binop(void) /*return 1; - NOTREACHED */ } - static void initialize_group_array(void) { - int n; - - /* getgroups may be expensive, try to use it only once */ - ngroups = 32; - do { - /* FIXME: ash tries so hard to not die on OOM, - * and we spoil it with just one xrealloc here */ - /* We realloc, because test_main can be entered repeatedly by shell. - * Testcase (ash): 'while true; do test -x some_file; done' - * and watch top. (some_file must have owner != you) */ - n = ngroups; - group_array = xrealloc(group_array, n * sizeof(gid_t)); - ngroups = getgroups(n, group_array); - } while (ngroups > n); + group_array = bb_getgroups(&ngroups, NULL); } - /* Return non-zero if GID is one that we have in our groups list. */ //XXX: FIXME: duplicate of existing libbb function? // see toplevel TODO file: @@ -610,14 +595,10 @@ static int is_a_group_member(gid_t gid) /* Do the same thing access(2) does, but use the effective uid and gid, and don't make the mistake of telling root that any file is executable. */ -static int test_eaccess(char *path, int mode) +static int test_eaccess(struct stat *st, int mode) { - struct stat st; unsigned int euid = geteuid(); - if (stat(path, &st) < 0) - return -1; - if (euid == 0) { /* Root can read or write any file. */ if (mode != X_OK) @@ -625,16 +606,16 @@ static int test_eaccess(char *path, int mode) /* Root can execute any file that has any one of the execute * bits set. */ - if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) + if (st->st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) return 0; } - if (st.st_uid == euid) /* owner */ + if (st->st_uid == euid) /* owner */ mode <<= 6; - else if (is_a_group_member(st.st_gid)) + else if (is_a_group_member(st->st_gid)) mode <<= 3; - if (st.st_mode & mode) + if (st->st_mode & mode) return 0; return -1; @@ -667,7 +648,7 @@ static int filstat(char *nm, enum token mode) i = W_OK; if (mode == FILEX) i = X_OK; - return test_eaccess(nm, i) == 0; + return test_eaccess(&s, i) == 0; } if (is_file_type(mode)) { if (mode == FILREG) diff --git a/include/libbb.h b/include/libbb.h index 557978e66..1c9de3af0 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1033,6 +1033,15 @@ void die_if_bad_username(const char* name) FAST_FUNC; #else #define die_if_bad_username(name) ((void)(name)) #endif +/* + * Returns (-1) terminated malloced result of getgroups(). + * Reallocs group_array (useful for repeated calls). + * ngroups is an initial size of array. It is rounded up to 32 for realloc. + * ngroups is updated on return. + * ngroups can be NULL: bb_getgroups(NULL, NULL) is valid usage. + * Dies on errors (on Linux, only xrealloc can cause this, not internal getgroups call). + */ +gid_t *bb_getgroups(int *ngroups, gid_t *group_array) FAST_FUNC; #if ENABLE_FEATURE_UTMP void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); diff --git a/libbb/bb_getgroups.c b/libbb/bb_getgroups.c new file mode 100644 index 000000000..59ae53738 --- /dev/null +++ b/libbb/bb_getgroups.c @@ -0,0 +1,47 @@ +/* + * Utility routines. + * + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-y += bb_getgroups.o + +#include "libbb.h" + +gid_t* FAST_FUNC bb_getgroups(int *ngroups, gid_t *group_array) +{ + int n = ngroups ? *ngroups : 0; + + /* getgroups may be a bit expensive, try to use it only once */ + if (n < 32) + n = 32; + + for (;;) { +// FIXME: ash tries so hard to not die on OOM (when we are called from test), +// and we spoil it with just one xrealloc here + group_array = xrealloc(group_array, (n+1) * sizeof(group_array[0])); + n = getgroups(n, group_array); + /* + * If buffer is too small, kernel does not return new_n > n. + * It returns -1 and EINVAL: + */ + if (n >= 0) { + /* Terminator for bb_getgroups(NULL, NULL) usage */ + group_array[n] = (gid_t) -1; + break; + } + if (errno == EINVAL) { /* too small? */ + /* This is the way to ask kernel how big the array is */ + n = getgroups(0, group_array); + continue; + } + /* Some other error (should never happen on Linux) */ + bb_perror_msg_and_die("getgroups"); + } + + if (ngroups) + *ngroups = n; + return group_array; +} -- cgit v1.2.3-55-g6feb From 69a5ec9dccfd183cdf6bee7b994336670755cd47 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 7 Jul 2017 19:08:56 +0200 Subject: main: fix the case where user has "halt" as login shell. Closes 9986 halt::0:0::/:/sbin/halt function old new delta run_applet_and_exit 748 751 +3 run_applet_no_and_exit 467 459 -8 Signed-off-by: Denys Vlasenko --- include/libbb.h | 2 +- libbb/appletlib.c | 10 +++++++--- libbb/vfork_daemon_rexec.c | 2 +- shell/ash.c | 2 +- shell/hush.c | 2 +- 5 files changed, 11 insertions(+), 7 deletions(-) (limited to 'libbb') diff --git a/include/libbb.h b/include/libbb.h index 1c9de3af0..0317c7d6a 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1117,7 +1117,7 @@ int spawn_and_wait(char **argv) FAST_FUNC; int run_nofork_applet(int applet_no, char **argv) FAST_FUNC; #ifndef BUILD_INDIVIDUAL extern int find_applet_by_name(const char *name) FAST_FUNC; -extern void run_applet_no_and_exit(int a, char **argv) NORETURN FAST_FUNC; +extern void run_applet_no_and_exit(int a, const char *name, char **argv) NORETURN FAST_FUNC; #endif /* Helpers for daemonization. diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 2dea2b43a..df6584978 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -877,13 +877,17 @@ static int busybox_main(char **argv) # endif # if NUM_APPLETS > 0 -void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) +void FAST_FUNC run_applet_no_and_exit(int applet_no, const char *name, char **argv) { int argc = string_array_len(argv); /* Reinit some shared global data */ xfunc_error_retval = EXIT_FAILURE; - applet_name = bb_get_last_path_component_nostrip(argv[0]); + /* + * We do not use argv[0]: do not want to repeat massaging of + * "-/sbin/halt" -> "halt", for example. + */ + applet_name = name; /* Special case. POSIX says "test --help" * should be no different from e.g. "test --foo". @@ -927,7 +931,7 @@ static NORETURN void run_applet_and_exit(const char *name, char **argv) { int applet = find_applet_by_name(name); if (applet >= 0) - run_applet_no_and_exit(applet, argv); + run_applet_no_and_exit(applet, name, argv); } # endif diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 2695f99ee..576534ee5 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -180,7 +180,7 @@ int FAST_FUNC spawn_and_wait(char **argv) * as of yet (and that should probably always stay true). */ /* xfunc_error_retval and applet_name are init by: */ - run_applet_no_and_exit(a, argv); + run_applet_no_and_exit(a, argv[0], argv); } # endif } diff --git a/shell/ash.c b/shell/ash.c index b7635a823..8c2098dd9 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7717,7 +7717,7 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** clearenv(); while (*envp) putenv(*envp++); - run_applet_no_and_exit(applet_no, argv); + run_applet_no_and_exit(applet_no, cmd, argv); } /* re-exec ourselves with the new arguments */ execve(bb_busybox_exec_path, argv, envp); diff --git a/shell/hush.c b/shell/hush.c index 4ba6b3fdd..cf6d8cd9f 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -7063,7 +7063,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, /* Do not leak open fds from opened script files etc */ close_all_FILE_list(); debug_printf_exec("running applet '%s'\n", argv[0]); - run_applet_no_and_exit(a, argv); + run_applet_no_and_exit(a, argv[0], argv); } # endif /* Re-exec ourselves */ -- cgit v1.2.3-55-g6feb From 12a4f9afe702b89c616610d3a29bf08257c6bace Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 10 Jul 2017 09:17:43 +0200 Subject: libbb: do not die if setgid/setuid(real_id) on startup fails Based on a patch from Steven McDonald : This makes 'unshare --user' work correctly in the case where the user's shell is provided by busybox itself. 'unshare --user' creates a new user namespace without any uid mappings. As a result, /bin/busybox is setuid nobody:nogroup within the namespace, as that is the only user. However, since no uids are mapped, attempting to call setgid/setuid fails, even though this would do nothing: $ unshare --user ./busybox.broken ash ash: setgid: Invalid argument 'unshare --map-root-user' still works, but because Linux only allows uid/gid mappings to be set up once, creating a root mapping makes such a namespace useless for creating multi-user containers. With this patch, setgid and setuid will not be called in the case where they would do nothing, which is always the case inside a new user namespace because all uids are effectively mapped to nobody: $ id -u 1000 $ ls -lh busybox.fixed -rwsr-xr-x 1 root root 826.2K May 21 00:33 busybox.fixed $ unshare --user ./busybox.fixed ash $ id -u 65534 Signed-off-by: Denys Vlasenko --- libbb/appletlib.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) (limited to 'libbb') diff --git a/libbb/appletlib.c b/libbb/appletlib.c index df6584978..b9fbbd1f2 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -681,8 +681,21 @@ static void check_suid(int applet_no) if (geteuid()) bb_error_msg_and_die("must be suid to work properly"); } else if (APPLET_SUID(applet_no) == BB_SUID_DROP) { - xsetgid(rgid); /* drop all privileges */ - xsetuid(ruid); + /* + * Drop all privileges. + * + * Don't check for errors: in normal use, they are impossible, + * and in special cases, exiting is harmful. Example: + * 'unshare --user' when user's shell is also from busybox. + * + * 'unshare --user' creates a new user namespace without any + * uid mappings. Thus, busybox binary is setuid nobody:nogroup + * within the namespace, as that is the only user. However, + * since no uids are mapped, calls to setgid/setuid + * fail (even though they would do nothing). + */ + setgid(rgid); + setuid(ruid); } # if ENABLE_FEATURE_SUID_CONFIG ret: ; -- cgit v1.2.3-55-g6feb From 75e90b15482184db83f03c67b53d4220888c6c9d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Jul 2017 10:47:18 +0200 Subject: cat: fix "cat -An" ignoring -n; make numbering go througn all files function old new delta cat_main 418 428 +10 Signed-off-by: Denys Vlasenko --- coreutils/cat.c | 44 +++++++++++++++++++++++++++++--------------- coreutils/nl.c | 20 -------------------- libbb/print_numbered_lines.c | 1 + 3 files changed, 30 insertions(+), 35 deletions(-) (limited to 'libbb') diff --git a/coreutils/cat.c b/coreutils/cat.c index 178f96b09..a9ba68d6b 100644 --- a/coreutils/cat.c +++ b/coreutils/cat.c @@ -101,27 +101,32 @@ * to achieve "cat -v" effect. The actual effect would be "users pissed off * by gratuitous incompatibility". */ -#define CATV_OPT_e (1<<0) -#define CATV_OPT_t (1<<1) -#define CATV_OPT_v (1<<2) +#define CAT_OPT_e (1<<0) +#define CAT_OPT_t (1<<1) +#define CAT_OPT_v (1<<2) +/* -A occupies bit (1<<3) */ +#define CAT_OPT_n ((1<<4) * ENABLE_FEATURE_CATN) +#define CAT_OPT_b ((1<<5) * ENABLE_FEATURE_CATN) static int catv(unsigned opts, char **argv) { int retval = EXIT_SUCCESS; int fd; +#if ENABLE_FEATURE_CATN + unsigned lineno = 0; + unsigned eol_char = (opts & (CAT_OPT_n|CAT_OPT_b)) ? '\n' : 0x100; + unsigned skip_num_on = (opts & CAT_OPT_b) ? '\n' : 0x100; + bool eol_seen = 1; +#endif - BUILD_BUG_ON(CATV_OPT_e != VISIBLE_ENDLINE); - BUILD_BUG_ON(CATV_OPT_t != VISIBLE_SHOW_TABS); + BUILD_BUG_ON(CAT_OPT_e != VISIBLE_ENDLINE); + BUILD_BUG_ON(CAT_OPT_t != VISIBLE_SHOW_TABS); #if 0 /* These consts match, we can just pass "opts" to visible() */ - if (opts & CATV_OPT_e) + if (opts & CAT_OPT_e) flags |= VISIBLE_ENDLINE; - if (opts & CATV_OPT_t) + if (opts & CAT_OPT_t) flags |= VISIBLE_SHOW_TABS; #endif - /* Read from stdin if there's nothing else to do. */ - if (!argv[0]) - *--argv = (char*)"-"; - #define read_buf bb_common_bufsiz1 setup_common_bufsiz(); do { @@ -141,6 +146,11 @@ static int catv(unsigned opts, char **argv) for (i = 0; i < res; i++) { unsigned char c = read_buf[i]; char buf[sizeof("M-^c")]; +#if ENABLE_FEATURE_CATN + if (eol_seen && c != skip_num_on) + printf("%6u ", ++lineno); + eol_seen = (c == eol_char); +#endif visible(c, buf, opts); fputs(buf, stdout); } @@ -151,12 +161,13 @@ static int catv(unsigned opts, char **argv) fflush_stdout_and_exit(retval); } +#undef CAT_OPT_n +#undef CAT_OPT_b #endif int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int cat_main(int argc UNUSED_PARAM, char **argv) { - struct number_state ns; unsigned opts; IF_FEATURE_CATV(opt_complementary = "Aetv"; /* -A == -vet */) @@ -164,10 +175,13 @@ int cat_main(int argc UNUSED_PARAM, char **argv) opts = getopt32(argv, IF_FEATURE_CATV("etvA") IF_FEATURE_CATN("nb") "u"); argv += optind; + /* Read from stdin if there's nothing else to do. */ + if (!argv[0]) + *--argv = (char*)"-"; + #if ENABLE_FEATURE_CATV if (opts & 7) return catv(opts, argv); -//BUG: -v,-e,-t,-A ignore -nb opts >>= 4; #endif @@ -175,8 +189,8 @@ int cat_main(int argc UNUSED_PARAM, char **argv) # define CAT_OPT_n (1<<0) # define CAT_OPT_b (1<<1) if (opts & (CAT_OPT_n|CAT_OPT_b)) { /* -n or -b */ - if (!*argv) - *--argv = (char*)"-"; + struct number_state ns; + ns.width = 6; ns.start = 1; ns.inc = 1; diff --git a/coreutils/nl.c b/coreutils/nl.c index 5c64923bb..dc468a90b 100644 --- a/coreutils/nl.c +++ b/coreutils/nl.c @@ -35,26 +35,6 @@ #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) { diff --git a/libbb/print_numbered_lines.c b/libbb/print_numbered_lines.c index 702aed1ea..9a8a51440 100644 --- a/libbb/print_numbered_lines.c +++ b/libbb/print_numbered_lines.c @@ -24,6 +24,7 @@ void FAST_FUNC print_numbered_lines(struct number_state *ns, const char *filenam fputs(ns->empty_str, stdout); free(line); } + ns->start = N; fclose(fp); } -- cgit v1.2.3-55-g6feb From a03ac6067764549f4ae25f9a34e1ee9b0d2bb4f2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Jul 2017 14:22:09 +0200 Subject: libbb: safe_write should not return EINTR Signed-off-by: Denys Vlasenko --- libbb/safe_write.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) (limited to 'libbb') diff --git a/libbb/safe_write.c b/libbb/safe_write.c index 8f7628016..aad50f5e0 100644 --- a/libbb/safe_write.c +++ b/libbb/safe_write.c @@ -13,9 +13,17 @@ ssize_t FAST_FUNC safe_write(int fd, const void *buf, size_t count) { ssize_t n; - do { + for (;;) { n = write(fd, buf, count); - } while (n < 0 && errno == EINTR); + if (n >= 0 || errno != EINTR) + break; + /* Some callers set errno=0, are upset when they see EINTR. + * Returning EINTR is wrong since we retry write(), + * the "error" was transient. + */ + errno = 0; + /* repeat the write() */ + } return n; } -- cgit v1.2.3-55-g6feb From 5f7904b6d11355a2010ebd10960d6a5d469301cc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Jul 2017 16:03:43 +0200 Subject: libbb/dump: fix a few broken commits and shrink code function old new delta next 310 294 -16 Signed-off-by: Denys Vlasenko --- libbb/dump.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'libbb') diff --git a/libbb/dump.c b/libbb/dump.c index 87c1dce13..bc0c1ec80 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -58,7 +58,7 @@ static NOINLINE int bb_dump_size(FS *fs) const char *p; int prec; - /* figure out the data block bb_dump_size needed for each format unit */ + /* figure out the data block size needed for each format unit */ for (cur_size = 0, fu = fs->nextfu; fu; fu = fu->nextfu) { if (fu->bcnt) { cur_size += fu->bcnt * fu->reps; @@ -320,7 +320,7 @@ static void do_skip(priv_dumper_t *dumper, const char *fname, int statok) if (!(S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode) || S_ISFIFO(sbuf.st_mode)) && dumper->pub.dump_skip >= sbuf.st_size ) { - /* If bb_dump_size valid and pub.dump_skip >= size */ + /* If st_size is valid and pub.dump_skip >= st_size */ dumper->pub.dump_skip -= sbuf.st_size; dumper->address += sbuf.st_size; return; @@ -339,12 +339,14 @@ static NOINLINE int next(priv_dumper_t *dumper) int statok; for (;;) { - if (*dumper->argv) { + char *fname = *dumper->argv; + + if (fname) { + dumper->argv++; dumper->next__done = statok = 1; - if (!(freopen(*dumper->argv, "r", stdin))) { - bb_simple_perror_msg(*dumper->argv); + if (!freopen(fname, "r", stdin)) { + bb_simple_perror_msg(fname); dumper->exitval = 1; - ++dumper->argv; continue; } } else { @@ -355,9 +357,7 @@ static NOINLINE int next(priv_dumper_t *dumper) statok = 0; } if (dumper->pub.dump_skip) - do_skip(dumper, statok ? *dumper->argv : "stdin", statok); - if (*dumper->argv) - ++dumper->argv; + do_skip(dumper, statok ? fname : "stdin", statok); if (!dumper->pub.dump_skip) return 1; } @@ -670,7 +670,7 @@ int FAST_FUNC bb_dump_dump(dumper_t *pub_dumper, char **argv) FS *tfs; int blocksize; - /* figure out the data block bb_dump_size */ + /* figure out the data block size */ blocksize = 0; tfs = dumper->pub.fshead; while (tfs) { -- cgit v1.2.3-55-g6feb From 63214a68f1b553e09ae18956cd7e4ec9543535c5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Jul 2017 16:18:16 +0200 Subject: libbb/dump: allow skipping over stdin too function old new delta next 294 265 -29 Signed-off-by: Denys Vlasenko --- libbb/dump.c | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) (limited to 'libbb') diff --git a/libbb/dump.c b/libbb/dump.c index bc0c1ec80..189277297 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -311,20 +311,18 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) } } -static void do_skip(priv_dumper_t *dumper, const char *fname, int statok) +static void do_skip(priv_dumper_t *dumper, const char *fname) { struct stat sbuf; - if (statok) { - xfstat(STDIN_FILENO, &sbuf, fname); - if (!(S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode) || S_ISFIFO(sbuf.st_mode)) - && dumper->pub.dump_skip >= sbuf.st_size - ) { - /* If st_size is valid and pub.dump_skip >= st_size */ - dumper->pub.dump_skip -= sbuf.st_size; - dumper->address += sbuf.st_size; - return; - } + xfstat(STDIN_FILENO, &sbuf, fname); + if (S_ISREG(sbuf.st_mode) + && dumper->pub.dump_skip >= sbuf.st_size + ) { + /* If st_size is valid and pub.dump_skip >= st_size */ + dumper->pub.dump_skip -= sbuf.st_size; + dumper->address += sbuf.st_size; + return; } if (fseeko(stdin, dumper->pub.dump_skip, SEEK_SET)) { bb_simple_perror_msg_and_die(fname); @@ -336,14 +334,11 @@ static void do_skip(priv_dumper_t *dumper, const char *fname, int statok) static NOINLINE int next(priv_dumper_t *dumper) { - int statok; - for (;;) { - char *fname = *dumper->argv; + const char *fname = *dumper->argv; if (fname) { dumper->argv++; - dumper->next__done = statok = 1; if (!freopen(fname, "r", stdin)) { bb_simple_perror_msg(fname); dumper->exitval = 1; @@ -352,13 +347,11 @@ static NOINLINE int next(priv_dumper_t *dumper) } else { if (dumper->next__done) return 0; /* no next file */ - dumper->next__done = 1; -//why stat of stdin is specially prohibited? - statok = 0; } + dumper->next__done = 1; if (dumper->pub.dump_skip) - do_skip(dumper, statok ? fname : "stdin", statok); - if (!dumper->pub.dump_skip) + do_skip(dumper, fname ? fname : "stdin"); + if (dumper->pub.dump_skip == 0) return 1; } /* NOTREACHED */ -- cgit v1.2.3-55-g6feb From 90678f0cd72e39806b159a551af85265608219b6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Jul 2017 16:29:30 +0200 Subject: xxd: allow "-" as file name meaning stdin Signed-off-by: Denys Vlasenko --- libbb/dump.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'libbb') diff --git a/libbb/dump.c b/libbb/dump.c index 189277297..211a1ed9e 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -339,10 +339,12 @@ static NOINLINE int next(priv_dumper_t *dumper) if (fname) { dumper->argv++; - if (!freopen(fname, "r", stdin)) { - bb_simple_perror_msg(fname); - dumper->exitval = 1; - continue; + if (NOT_LONE_DASH(fname)) { + if (!freopen(fname, "r", stdin)) { + bb_simple_perror_msg(fname); + dumper->exitval = 1; + continue; + } } } else { if (dumper->next__done) -- cgit v1.2.3-55-g6feb From 7d7c7bb2205b92359ac88f3469d3af672e2be929 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 14 Jul 2017 20:17:17 +0200 Subject: libbb: hide getnetbyaddr() inside "#if ENABLE_FEATURE_ETC_NETWORKS" block Signed-off-by: Denys Vlasenko --- libbb/inet_common.c | 46 +++++++++++++++++++--------------------------- 1 file changed, 19 insertions(+), 27 deletions(-) (limited to 'libbb') diff --git a/libbb/inet_common.c b/libbb/inet_common.c index 5b4a4a10b..04259f47b 100644 --- a/libbb/inet_common.c +++ b/libbb/inet_common.c @@ -11,6 +11,12 @@ #include "libbb.h" #include "inet_common.h" +#if 0 +# define dbg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg(...) ((void)0) +#endif + int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostfirst) { struct hostent *hp; @@ -33,9 +39,7 @@ int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostf } /* If we expect this to be a hostname, try hostname database first */ if (hostfirst) { -#ifdef DEBUG - bb_error_msg("gethostbyname(%s)", name); -#endif + dbg("gethostbyname(%s)", name); hp = gethostbyname(name); if (hp) { memcpy(&s_in->sin_addr, hp->h_addr_list[0], @@ -45,9 +49,7 @@ int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostf } #if ENABLE_FEATURE_ETC_NETWORKS /* Try the NETWORKS database to see if this is a known network. */ -#ifdef DEBUG - bb_error_msg("getnetbyname(%s)", name); -#endif + dbg("getnetbyname(%s)", name); np = getnetbyname(name); if (np) { s_in->sin_addr.s_addr = htonl(np->n_net); @@ -61,8 +63,8 @@ int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostf #ifdef DEBUG res_init(); _res.options |= RES_DEBUG; - bb_error_msg("gethostbyname(%s)", name); #endif + dbg("gethostbyname(%s)", name); hp = gethostbyname(name); if (!hp) { return -1; @@ -93,17 +95,12 @@ char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t ne smallint is_host; if (s_in->sin_family != AF_INET) { -#ifdef DEBUG - bb_error_msg("rresolve: unsupported address family %d!", - s_in->sin_family); -#endif + dbg("rresolve: unsupported address family %d!", s_in->sin_family); errno = EAFNOSUPPORT; return NULL; } nip = s_in->sin_addr.s_addr; -#ifdef DEBUG - bb_error_msg("rresolve: %08x mask:%08x num:%08x", (unsigned)nip, netmask, numeric); -#endif + dbg("rresolve: %08x mask:%08x num:%08x", (unsigned)nip, netmask, numeric); if (numeric & 0x0FFF) return xmalloc_sockaddr2dotted_noport((void*)s_in); if (nip == INADDR_ANY) { @@ -117,10 +114,8 @@ char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t ne pn = cache; while (pn) { if (pn->nip == nip && pn->is_host == is_host) { -#ifdef DEBUG - bb_error_msg("rresolve: found %s %08x in cache", + dbg("rresolve: found %s %08x in cache", (is_host ? "host" : "net"), (unsigned)nip); -#endif return xstrdup(pn->name); } pn = pn->next; @@ -128,19 +123,18 @@ char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t ne name = NULL; if (is_host) { -#ifdef DEBUG - bb_error_msg("sockaddr2host_noport(%08x)", (unsigned)nip); -#endif + dbg("sockaddr2host_noport(%08x)", (unsigned)nip); name = xmalloc_sockaddr2host_noport((void*)s_in); - } else if (ENABLE_FEATURE_ETC_NETWORKS) { + } +#if ENABLE_FEATURE_ETC_NETWORKS + else { struct netent *np; -#ifdef DEBUG - bb_error_msg("getnetbyaddr(%08x)", (unsigned)ntohl(nip)); -#endif + dbg("getnetbyaddr(%08x)", (unsigned)ntohl(nip)); np = getnetbyaddr(ntohl(nip), AF_INET); if (np) name = xstrdup(np->n_name); } +#endif if (!name) name = xmalloc_sockaddr2dotted_noport((void*)s_in); @@ -183,10 +177,8 @@ int FAST_FUNC INET6_resolve(const char *name, struct sockaddr_in6 *sin6) char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric) { if (sin6->sin6_family != AF_INET6) { -#ifdef DEBUG - bb_error_msg("rresolve: unsupported address family %d!", + dbg("rresolve: unsupported address family %d!", sin6->sin6_family); -#endif errno = EAFNOSUPPORT; return NULL; } -- cgit v1.2.3-55-g6feb From e5b1f5af737078dfe4baba79dd0bc5a3b7616ad0 Mon Sep 17 00:00:00 2001 From: Johannes Schindelin Date: Fri, 14 Jul 2017 16:11:43 +0200 Subject: copyfd: guard use of munmap() with #if (windows builds need this) Signed-off-by: Johannes Schindelin Signed-off-by: Denys Vlasenko --- libbb/copyfd.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'libbb') diff --git a/libbb/copyfd.c b/libbb/copyfd.c index 7e3531903..921fe3f81 100644 --- a/libbb/copyfd.c +++ b/libbb/copyfd.c @@ -119,8 +119,11 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) } out: +/* some environments don't have munmap(), hide it in #if */ +#if CONFIG_FEATURE_COPYBUF_KB > 4 if (buffer_size > 4 * 1024) munmap(buffer, buffer_size); +#endif return status ? -1 : total; } -- cgit v1.2.3-55-g6feb From a3df2fa5250730c84ea0e5ad839f44435888818e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 15 Jul 2017 20:49:32 +0200 Subject: config: merge "Busybox Settings" and "Busybox Library Tuning" into one menu Tweak a few help texts while at it Signed-off-by: Denys Vlasenko --- Config.in | 98 +++++++++++++++++++++++++++------------------------ libbb/Config.src | 13 +++---- libbb/common_bufsiz.c | 1 + 3 files changed, 59 insertions(+), 53 deletions(-) (limited to 'libbb') diff --git a/Config.in b/Config.in index 892c1d79d..45ddc4377 100644 --- a/Config.in +++ b/Config.in @@ -90,10 +90,14 @@ config BUSYBOX help The busybox applet provides general help regarding busybox and allows the included applets to be listed. It's also required - if applet links are to be installed at runtime. + if applet links are to be installed at runtime. If you unselect + this option, running busybox without any arguments will give + just a cryptic error message: - If you can live without these features disabling this will save - some space. + $ busybox + busybox: applet not found + + Running "busybox APPLET [ARGS...]" will still work, of course. config FEATURE_INSTALLER bool "Support --install [-s] to install applet links at runtime" @@ -112,6 +116,17 @@ config INSTALL_NO_USR will install applets only to /bin and /sbin, never to /usr/bin or /usr/sbin. +config LFS + bool "Build with Large File Support (for accessing files > 2 GB)" + default y + help + If you want to build BusyBox with large file support, then enable + this option. This will have no effect if your kernel or your C + library lacks large file support for large files. Some of the + programs that can benefit from large file support include dd, gzip, + cp, mount, tar, and many others. If you want to access files larger + than 2 Gigabytes, enable this option. Otherwise, leave it set to 'N'. + config PAM bool "Support PAM (Pluggable Authentication Modules)" default n @@ -136,18 +151,6 @@ config FEATURE_DEVPTS /dev/ttyp will be used. To use this option, you should have devpts mounted. -config FEATURE_CLEAN_UP - bool "Clean up all memory before exiting (usually not needed)" - default n - help - As a size optimization, busybox normally exits without explicitly - freeing dynamically allocated memory or closing files. This saves - space since the OS will clean up for us, but it can confuse debuggers - like valgrind, which report tons of memory and resource leaks. - - Don't enable this unless you have a really good reason to clean - things up manually. - config FEATURE_UTMP bool "Support utmp file" default y @@ -177,7 +180,7 @@ config FEATURE_PIDFILE on applets which require pidfiles to run. config PID_FILE_PATH - string "Path to directory for pidfile" + string "Directory for pidfiles" default "/var/run" depends on FEATURE_PIDFILE help @@ -269,24 +272,6 @@ config FEATURE_SUID_CONFIG_QUIET check this option to avoid users to be notified about missing permissions. -config SELINUX - bool "Support NSA Security Enhanced Linux" - default n - select PLATFORM_LINUX - help - Enable support for SELinux in applets ls, ps, and id. Also provide - the option of compiling in SELinux applets. - - If you do not have a complete SELinux userland installed, this stuff - will not compile. Specifially, libselinux 1.28 or better is - directly required by busybox. If the installation is located in a - non-standard directory, provide it by invoking make as follows: - CFLAGS=-I \ - LDFLAGS=-L \ - make - - Most people will leave this set to 'N'. - config FEATURE_PREFER_APPLETS bool "exec prefers applets" default n @@ -311,6 +296,36 @@ config BUSYBOX_EXEC_PATH executable. If you haven't got /proc, set this to wherever you want to run BusyBox from. +config SELINUX + bool "Support NSA Security Enhanced Linux" + default n + select PLATFORM_LINUX + help + Enable support for SELinux in applets ls, ps, and id. Also provide + the option of compiling in SELinux applets. + + If you do not have a complete SELinux userland installed, this stuff + will not compile. Specifially, libselinux 1.28 or better is + directly required by busybox. If the installation is located in a + non-standard directory, provide it by invoking make as follows: + CFLAGS=-I \ + LDFLAGS=-L \ + make + + Most people will leave this set to 'N'. + +config FEATURE_CLEAN_UP + bool "Clean up all memory before exiting (usually not needed)" + default n + help + As a size optimization, busybox normally exits without explicitly + freeing dynamically allocated memory or closing files. This saves + space since the OS will clean up for us, but it can confuse debuggers + like valgrind, which report tons of memory and resource leaks. + + Don't enable this unless you have a really good reason to clean + things up manually. + # These are auto-selected by other options config FEATURE_SYSLOG @@ -452,17 +467,6 @@ config FEATURE_SHARED_BUSYBOX ### ### Say 'N' unless you know what you are doing. -config LFS - bool "Build with Large File Support (for accessing files > 2 GB)" - default y - help - If you want to build BusyBox with large file support, then enable - this option. This will have no effect if your kernel or your C - library lacks large file support for large files. Some of the - programs that can benefit from large file support include dd, gzip, - cp, mount, tar, and many others. If you want to access files larger - than 2 Gigabytes, enable this option. Otherwise, leave it set to 'N'. - config CROSS_COMPILER_PREFIX string "Cross Compiler prefix" default "" @@ -669,10 +673,10 @@ config EFENCE endchoice -endmenu - source libbb/Config.in +endmenu + comment "Applets" source archival/Config.in diff --git a/libbb/Config.src b/libbb/Config.src index c51640305..16c79dbf0 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -3,7 +3,7 @@ # see scripts/kbuild/config-language.txt. # -menu "Busybox Library Tuning" +comment "Library Tuning" INSERT @@ -66,7 +66,7 @@ config FEATURE_FAST_TOP bool "Faster /proc scanning code (+100 bytes)" default n # all "fast or small" options default to small help - This option makes top (and ps) ~20% faster (or 20% less CPU hungry), + This option makes top and ps ~20% faster (or 20% less CPU hungry), but code size is slightly bigger. config FEATURE_ETC_NETWORKS @@ -302,13 +302,17 @@ config FEATURE_VERBOSE_CP_MESSAGE default n help Error messages with this feature enabled: + $ cp file /does_not_exist/file cp: cannot create '/does_not_exist/file': Path does not exist $ cp file /vmlinuz/file cp: cannot stat '/vmlinuz/file': Path has non-directory component + If this feature is not enabled, they will be, respectively: + cp: cannot create '/does_not_exist/file': No such file or directory cp: cannot stat '/vmlinuz/file': Not a directory + This will cost you ~60 bytes. config FEATURE_USE_SENDFILE @@ -376,7 +380,4 @@ config FEATURE_HWIB bool "Support infiniband HW" default y help - Support for printing infiniband addresses in - network applets. - -endmenu + Support for printing infiniband addresses in network applets. diff --git a/libbb/common_bufsiz.c b/libbb/common_bufsiz.c index 2847eb57d..f1124ba0e 100644 --- a/libbb/common_bufsiz.c +++ b/libbb/common_bufsiz.c @@ -19,6 +19,7 @@ //config: //config: At link time, "text" is padded to a full page. At runtime, all "text" //config: pages are mapped RO and executable. +//config: //config: "Data" starts on the next page boundary, but is not padded //config: to a full page at the end. "Bss" starts wherever "data" ends. //config: At runtime, "data" pages are mapped RW and they are file-backed -- cgit v1.2.3-55-g6feb