From 1e3cce681426cffe6d30efed2a1f6cf1f3277e00 Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Sat, 3 May 2014 16:34:36 +0200 Subject: which: rewrite function old new delta which_main 237 212 -25 Signed-off-by: Denys Vlasenko --- debianutils/which.c | 83 +++++++++++++++-------------------------------------- 1 file changed, 23 insertions(+), 60 deletions(-) diff --git a/debianutils/which.c b/debianutils/which.c index 760bcdcad..d50e7a0d3 100644 --- a/debianutils/which.c +++ b/debianutils/which.c @@ -1,13 +1,9 @@ /* vi: set sw=4 ts=4: */ /* - * Which implementation for busybox - * * Copyright (C) 1999-2004 by Erik Andersen * Copyright (C) 2006 Gabriel Somlo * * Licensed under GPLv2 or later, see file LICENSE in this source tree. - * - * Based on which from debianutils */ //usage:#define which_trivial_usage @@ -24,76 +20,43 @@ int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int which_main(int argc UNUSED_PARAM, char **argv) { - IF_DESKTOP(int opt;) - int status = EXIT_SUCCESS; - char *path; - char *p; + const char *env_path; + int status = 0; + + env_path = getenv("PATH"); + if (!env_path) + env_path = bb_default_root_path; opt_complementary = "-1"; /* at least one argument */ - IF_DESKTOP(opt =) getopt32(argv, "a"); + getopt32(argv, "a"); argv += optind; - /* This matches what is seen on e.g. ubuntu. - * "which" there is a shell script. */ - path = getenv("PATH"); - if (!path) { - path = (char*)bb_PATH_root_path; - putenv(path); - path += 5; /* skip "PATH=" */ - } - do { -#if ENABLE_DESKTOP -/* Much bloat just to support -a */ - if (strchr(*argv, '/')) { - if (file_is_executable(*argv)) { - puts(*argv); - continue; - } - status = EXIT_FAILURE; - } else { - char *path2 = xstrdup(path); - char *tmp = path2; + int missing = 1; - p = find_executable(*argv, &tmp); - if (!p) - status = EXIT_FAILURE; - else { - print: - puts(p); - free(p); - if (opt) { - /* -a: show matches in all PATH components */ - if (tmp) { - p = find_executable(*argv, &tmp); - if (p) - goto print; - } - } - } - free(path2); - } -#else -/* Just ignoring -a */ + /* If file contains a slash don't use PATH */ if (strchr(*argv, '/')) { if (file_is_executable(*argv)) { + missing = 0; puts(*argv); - continue; } } else { - char *path2 = xstrdup(path); - char *tmp = path2; - p = find_executable(*argv, &tmp); - free(path2); - if (p) { + char *path; + char *tmp; + char *p; + + path = tmp = xstrdup(env_path); + while ((p = find_executable(*argv, &tmp)) != NULL) { + missing = 0; puts(p); free(p); - continue; + if (!option_mask32) /* -a not set */ + break; } + free(path); } - status = EXIT_FAILURE; -#endif - } while (*(++argv) != NULL); + status |= missing; + } while (*++argv); - fflush_stdout_and_exit(status); + return status; } -- cgit v1.2.3-55-g6feb From e3366d696cf4ef34cdc30aee2612418f81ba986c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 3 May 2014 16:35:15 +0200 Subject: trylink: emit names of linked executables Signed-off-by: Denys Vlasenko --- scripts/trylink | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/trylink b/scripts/trylink index 85095235c..5da494fbb 100755 --- a/scripts/trylink +++ b/scripts/trylink @@ -300,6 +300,8 @@ int main(int argc, char **argv) } rm -- "$sharedlib_dir/applet.c" $EXE.out $STRIP -s --remove-section=.note --remove-section=.comment $EXE + # Let user see that we do something - list the names of created binaries: + echo "$EXE" done Date: Sun, 11 May 2014 00:00:52 +0200 Subject: getty: explain when setsid() fails. no code changes Signed-off-by: Denys Vlasenko --- loginutils/getty.c | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/loginutils/getty.c b/loginutils/getty.c index 0f060ae6c..4b1b73bef 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -556,6 +556,16 @@ int getty_main(int argc UNUSED_PARAM, char **argv) // pid, getppid(), // getsid(0), getpgid(0)); bb_perror_msg_and_die("setsid"); + /* + * When we can end up here? + * Example: setsid() fails when run alone in interactive shell: + * # getty 115200 /dev/tty2 + * because shell's child (getty) is put in a new process group. + * But doesn't fail if shell is not interactive + * (and therefore doesn't create process groups for pipes), + * or if getty is not the first process in the process group: + * # true | getty 115200 /dev/tty2 + */ } /* Looks like we are already a session leader. * In this case (setsid failed) we may still have ctty, -- cgit v1.2.3-55-g6feb From 17f8418ea75410c3fbf9c9558f50f22cb8808e3e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 19 May 2014 16:23:50 +0200 Subject: Add conditional support for -v / --verbose MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With FEATURE_VERBOSE off, practically no size change. With it on: function old new delta remove_file 493 556 +63 install_main 719 765 +46 bb_make_directory 383 419 +36 rmdir_main 162 191 +29 copy_file 1516 1544 +28 mv_main 502 525 +23 cmp_main 677 693 +16 bbconfig_config_bz2 5264 5279 +15 mkdir_main 158 168 +10 install_longopts 66 76 +10 rm_main 167 175 +8 nexpr 840 846 +6 scan_tree 275 280 +5 fsck_main 1807 1811 +4 ed_main 2541 2545 +4 expand_one_var 1574 1575 +1 swap_on_off_main 420 418 -2 parse_command 1443 1440 -3 redirect 1279 1274 -5 do_load 946 918 -28 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 16/4 up/down: 304/-38) Total: 266 bytes Based on the patch by Igor Živković. Signed-off-by: Denys Vlasenko --- coreutils/Config.src | 10 ++++++++++ coreutils/cp.c | 1 - coreutils/install.c | 14 +++++++++++--- coreutils/mkdir.c | 8 ++++++-- coreutils/mv.c | 8 +++++++- coreutils/rm.c | 3 ++- coreutils/rmdir.c | 10 ++++++++-- include/libbb.h | 2 ++ libbb/copy_file.c | 4 ++++ libbb/make_directory.c | 4 ++++ libbb/remove_file.c | 8 ++++++++ 11 files changed, 62 insertions(+), 10 deletions(-) diff --git a/coreutils/Config.src b/coreutils/Config.src index 33defa4db..68c717883 100644 --- a/coreutils/Config.src +++ b/coreutils/Config.src @@ -739,6 +739,16 @@ config YES yes is used to repeatedly output a specific string, or the default string `y'. +comment "Common options" + +config FEATURE_VERBOSE + bool "Support verbose options (usually -v) for various applets" + default y + help + Enable cp -v, rm -v and similar messages. + Also enables long option (--verbose) if it exists. + Without this option, -v is accepted but ignored. + comment "Common options for cp and mv" depends on CP || MV diff --git a/coreutils/cp.c b/coreutils/cp.c index de2e512be..247ed0fda 100644 --- a/coreutils/cp.c +++ b/coreutils/cp.c @@ -79,7 +79,6 @@ int cp_main(int argc, char **argv) "parents\0" No_argument "\xff" ; #endif - // -v (--verbose) is ignored flags = getopt32(argv, FILEUTILS_CP_OPTSTR "arPv"); /* Options of cp from GNU coreutils 6.10: * -a, --archive diff --git a/coreutils/install.c b/coreutils/install.c index 445497f9a..6c88ae11c 100644 --- a/coreutils/install.c +++ b/coreutils/install.c @@ -28,6 +28,9 @@ #if ENABLE_FEATURE_INSTALL_LONG_OPTIONS static const char install_longopts[] ALIGN1 = + IF_FEATURE_VERBOSE( + "verbose\0" No_argument "v" + ) "directory\0" No_argument "d" "preserve-timestamps\0" No_argument "p" "strip\0" No_argument "s" @@ -89,6 +92,7 @@ int install_main(int argc, char **argv) const char *gid_str; const char *uid_str; const char *mode_str; + int mkdir_flags = FILEUTILS_RECUR; int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE; int opts; int min_args = 1; @@ -120,7 +124,6 @@ int install_main(int argc, char **argv) #endif opt_complementary = "s--d:d--s" IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z")); /* -c exists for backwards compatibility, it's needed */ - /* -v is ignored ("print name of each created directory") */ /* -b is ignored ("make a backup of each existing destination file") */ opts = getopt32(argv, "cvb" "Ddpsg:m:o:" IF_SELINUX("Z:"), &gid_str, &mode_str, &uid_str IF_SELINUX(, &scontext)); @@ -141,6 +144,11 @@ int install_main(int argc, char **argv) } #endif + if ((opts & OPT_v) && FILEUTILS_VERBOSE) { + mkdir_flags |= FILEUTILS_VERBOSE; + copy_flags |= FILEUTILS_VERBOSE; + } + /* preserve access and modification time, this is GNU behaviour, * BSD only preserves modification time */ if (opts & OPT_PRESERVE_TIME) { @@ -171,14 +179,14 @@ int install_main(int argc, char **argv) /* GNU coreutils 6.9 does not set uid:gid * on intermediate created directories * (only on last one) */ - if (bb_make_directory(dest, 0755, FILEUTILS_RECUR)) { + if (bb_make_directory(dest, 0755, mkdir_flags)) { ret = EXIT_FAILURE; goto next; } } else { if (opts & OPT_MKDIR_LEADING) { char *ddir = xstrdup(dest); - bb_make_directory(dirname(ddir), 0755, FILEUTILS_RECUR); + bb_make_directory(dirname(ddir), 0755, mkdir_flags); /* errors are not checked. copy_file * will fail if dir is not created. */ free(ddir); diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c index 4a8e43e43..864edfb0a 100644 --- a/coreutils/mkdir.c +++ b/coreutils/mkdir.c @@ -48,7 +48,9 @@ static const char mkdir_longopts[] ALIGN1 = #if ENABLE_SELINUX "context\0" Required_argument "Z" #endif +#if ENABLE_FEATURE_VERBOSE "verbose\0" No_argument "v" +#endif ; #endif @@ -67,7 +69,7 @@ int mkdir_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_MKDIR_LONG_OPTIONS applet_long_options = mkdir_longopts; #endif - opt = getopt32(argv, "m:p" IF_SELINUX("Z:") "v", &smode IF_SELINUX(,&scontext)); + opt = getopt32(argv, "m:pv" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); if (opt & 1) { mode_t mmode = 0777; if (!bb_parse_mode(smode, &mmode)) { @@ -77,8 +79,10 @@ int mkdir_main(int argc UNUSED_PARAM, char **argv) } if (opt & 2) flags |= FILEUTILS_RECUR; + if ((opt & 4) && FILEUTILS_VERBOSE) + flags |= FILEUTILS_VERBOSE; #if ENABLE_SELINUX - if (opt & 4) { + if (opt & 8) { selinux_or_die(); setfscreatecon_or_die(scontext); } diff --git a/coreutils/mv.c b/coreutils/mv.c index f127dfabd..50571755b 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c @@ -33,13 +33,17 @@ static const char mv_longopts[] ALIGN1 = "interactive\0" No_argument "i" "force\0" No_argument "f" "no-clobber\0" No_argument "n" + IF_FEATURE_VERBOSE( "verbose\0" No_argument "v" + ) ; #endif #define OPT_FORCE (1 << 0) #define OPT_INTERACTIVE (1 << 1) #define OPT_NOCLOBBER (1 << 2) +#define OPT_VERBOSE ((1 << 3) * ENABLE_FEATURE_VERBOSE) + int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mv_main(int argc, char **argv) @@ -58,7 +62,6 @@ int mv_main(int argc, char **argv) /* 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). - * -v is accepted but ignored. */ opt_complementary = "-2:f-in:i-fn:n-fi"; flags = getopt32(argv, "finv"); @@ -148,6 +151,9 @@ int mv_main(int argc, char **argv) status = 1; } RET_0: + if (flags & OPT_VERBOSE) { + printf("'%s' -> '%s'\n", *argv, dest); + } if (dest != last) { free((void *) dest); } diff --git a/coreutils/rm.c b/coreutils/rm.c index 042fba162..d0ad81dfc 100644 --- a/coreutils/rm.c +++ b/coreutils/rm.c @@ -38,7 +38,6 @@ int rm_main(int argc UNUSED_PARAM, char **argv) unsigned opt; opt_complementary = "f-i:i-f"; - /* -v (verbose) is ignored */ opt = getopt32(argv, "fiRrv"); argv += optind; if (opt & 1) @@ -47,6 +46,8 @@ int rm_main(int argc UNUSED_PARAM, char **argv) flags |= FILEUTILS_INTERACTIVE; if (opt & (8|4)) flags |= FILEUTILS_RECUR; + if ((opt & 16) && FILEUTILS_VERBOSE) + flags |= FILEUTILS_VERBOSE; if (*argv != NULL) { do { diff --git a/coreutils/rmdir.c b/coreutils/rmdir.c index cc2dea010..0792a1c8e 100644 --- a/coreutils/rmdir.c +++ b/coreutils/rmdir.c @@ -31,7 +31,7 @@ #define PARENTS (1 << 0) -//efine VERBOSE (1 << 1) //accepted but ignored +#define VERBOSE ((1 << 1) * ENABLE_FEATURE_VERBOSE) #define IGNORE_NON_EMPTY (1 << 2) int rmdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -44,10 +44,12 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_RMDIR_LONG_OPTIONS static const char rmdir_longopts[] ALIGN1 = "parents\0" No_argument "p" - "verbose\0" No_argument "v" /* Debian etch: many packages fail to be purged or installed * because they desperately want this option: */ "ignore-fail-on-non-empty\0" No_argument "\xff" + IF_FEATURE_VERBOSE( + "verbose\0" No_argument "v" + ) ; applet_long_options = rmdir_longopts; #endif @@ -62,6 +64,10 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) path = *argv; while (1) { + if (flags & VERBOSE) { + printf("rmdir: removing directory, '%s'\n", path); + } + if (rmdir(path) < 0) { #if ENABLE_FEATURE_RMDIR_LONG_OPTIONS if ((flags & IGNORE_NON_EMPTY) && errno == ENOTEMPTY) diff --git a/include/libbb.h b/include/libbb.h index afdee38c4..a1a0dc18c 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -334,6 +334,8 @@ enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */ FILEUTILS_SET_SECURITY_CONTEXT = 1 << 10, #endif FILEUTILS_IGNORE_CHMOD_ERR = 1 << 11, + /* -v */ + FILEUTILS_VERBOSE = (1 << 12) * ENABLE_FEATURE_VERBOSE, }; #define FILEUTILS_CP_OPTSTR "pdRfilsLH" IF_SELINUX("c") extern int remove_file(const char *path, int flags) FAST_FUNC; diff --git a/libbb/copy_file.c b/libbb/copy_file.c index 9333a8d49..a4be875d2 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c @@ -389,5 +389,9 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) bb_perror_msg("can't preserve %s of '%s'", "permissions", dest); } + if (flags & FILEUTILS_VERBOSE) { + printf("'%s' -> '%s'\n", source, dest); + } + return retval; } diff --git a/libbb/make_directory.c b/libbb/make_directory.c index 7826b90f5..89352ca1f 100644 --- a/libbb/make_directory.c +++ b/libbb/make_directory.c @@ -99,6 +99,10 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags) if (!c) { goto ret0; } + } else { + if (flags & FILEUTILS_VERBOSE) { + printf("created directory: '%s'\n", path); + } } if (!c) { diff --git a/libbb/remove_file.c b/libbb/remove_file.c index 5b75f7f30..eaca293d9 100644 --- a/libbb/remove_file.c +++ b/libbb/remove_file.c @@ -78,6 +78,10 @@ int FAST_FUNC remove_file(const char *path, int flags) return -1; } + if (flags & FILEUTILS_VERBOSE) { + printf("removed directory: '%s'\n", path); + } + return status; } @@ -98,5 +102,9 @@ int FAST_FUNC remove_file(const char *path, int flags) return -1; } + if (flags & FILEUTILS_VERBOSE) { + printf("removed '%s'\n", path); + } + return 0; } -- cgit v1.2.3-55-g6feb From fd0640e5a12f74b7ab1d918cf884df0c59402c5a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 26 May 2014 15:01:13 +0200 Subject: modprobe-small: fix safe_strncpy truncating last char of module name Signed-off-by: Denys Vlasenko --- modutils/modprobe-small.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c index 91e0c1380..b7990bff1 100644 --- a/modutils/modprobe-small.c +++ b/modutils/modprobe-small.c @@ -297,7 +297,7 @@ static int pathname_matches_modname(const char *pathname, const char *modname) char name[MODULE_NAME_LEN]; const char *fname = bb_get_last_path_component_nostrip(pathname); const char *suffix = strrstr(fname, ".ko"); - safe_strncpy(name, fname, suffix - fname); + safe_strncpy(name, fname, suffix - fname + 1); replace(name, '-', '_'); r = (strcmp(name, modname) == 0); return r; -- cgit v1.2.3-55-g6feb From 1b90e031c3a3bd6dc5c2a34193ec6e9727b79a39 Mon Sep 17 00:00:00 2001 From: Joshua Judson Rosen Date: Tue, 20 May 2014 01:02:18 -0400 Subject: syslogd: avoid spurious ftrunctate() calls for "-b 0" Forgetting to re-set log_file->size after truncating to zero discards log-data for the next 1 second following an oversize-induced purge, when we shouldn't necessarily throw that data away. Signed-off-by: Joshua Judson Rosen Signed-off-by: Denys Vlasenko --- sysklogd/syslogd.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index a6a4ff25c..2c959ff1b 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c @@ -663,7 +663,13 @@ static void log_locally(time_t now, char *msg, logFile_t *log_file) close(log_file->fd); goto reopen; } + + /* We don't get here unless G.logFileRotate == 0; + * in which case don't bother unlinking and reopening, + * just truncate and reset size to match: + */ ftruncate(log_file->fd, 0); + log_file->size = 0; } log_file->size += #endif -- cgit v1.2.3-55-g6feb From b905d6c2eaaf7ad92a50dccc7b91ee19dd9424b7 Mon Sep 17 00:00:00 2001 From: Joshua Judson Rosen Date: Tue, 20 May 2014 01:02:19 -0400 Subject: syslogd: remember to un-writelock log-files even when called with "-b 0" Signed-off-by: Joshua Judson Rosen Signed-off-by: Denys Vlasenko --- sysklogd/syslogd.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index 2c959ff1b..d77fc9475 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c @@ -670,6 +670,10 @@ static void log_locally(time_t now, char *msg, logFile_t *log_file) */ ftruncate(log_file->fd, 0); log_file->size = 0; +#ifdef SYSLOGD_WRLOCK + fl.l_type = F_UNLCK; + fcntl(log_file->fd, F_SETLKW, &fl); +#endif } log_file->size += #endif -- cgit v1.2.3-55-g6feb From 9aa6ffb22b712d4e928604e291f954b02237e8cd Mon Sep 17 00:00:00 2001 From: Joshua Judson Rosen Date: Tue, 20 May 2014 01:02:20 -0400 Subject: syslogd: Unify unlink/truncate + unlock log-rotation logic Always unlink + reopen, rather than sometimes using ftruncate(); using a single code-path reduces the opportunity for either mistakes or duplicate code. Signed-off-by: Joshua Judson Rosen Signed-off-by: Denys Vlasenko --- sysklogd/syslogd.c | 30 +++++++++++------------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/sysklogd/syslogd.c b/sysklogd/syslogd.c index d77fc9475..f75851085 100644 --- a/sysklogd/syslogd.c +++ b/sysklogd/syslogd.c @@ -648,32 +648,24 @@ static void log_locally(time_t now, char *msg, logFile_t *log_file) } /* newFile == "f.0" now */ rename(log_file->path, newFile); - /* Incredibly, if F and F.0 are hardlinks, POSIX - * _demands_ that rename returns 0 but does not - * remove F!!! - * (hardlinked F/F.0 pair was observed after - * power failure during rename()). - * Ensure old file is gone: - */ - unlink(log_file->path); -#ifdef SYSLOGD_WRLOCK - fl.l_type = F_UNLCK; - fcntl(log_file->fd, F_SETLKW, &fl); -#endif - close(log_file->fd); - goto reopen; } - /* We don't get here unless G.logFileRotate == 0; - * in which case don't bother unlinking and reopening, - * just truncate and reset size to match: + /* We may or may not have just renamed the file away; + * if we didn't rename because we aren't keeping any backlog, + * then it's time to clobber the file. If we did rename it..., + * incredibly, if F and F.0 are hardlinks, POSIX _demands_ + * that rename returns 0 but does not remove F!!! + * (hardlinked F/F.0 pair was observed after + * power failure during rename()). + * So ensure old file is gone in any case: */ - ftruncate(log_file->fd, 0); - log_file->size = 0; + unlink(log_file->path); #ifdef SYSLOGD_WRLOCK fl.l_type = F_UNLCK; fcntl(log_file->fd, F_SETLKW, &fl); #endif + close(log_file->fd); + goto reopen; } log_file->size += #endif -- cgit v1.2.3-55-g6feb From 85090c162b322a4ffe53d251e59bbfc212a829ee Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 16 Jun 2014 00:17:00 +0200 Subject: udhcpc: make hostname sanitization optional. Closes 3979 Signed-off-by: Denys Vlasenko --- networking/udhcp/Config.src | 11 +++++++++++ networking/udhcp/dhcpc.c | 4 ++++ 2 files changed, 15 insertions(+) diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src index 6bfa398ea..c34c8d6f0 100644 --- a/networking/udhcp/Config.src +++ b/networking/udhcp/Config.src @@ -84,6 +84,17 @@ config FEATURE_UDHCPC_ARPING will DHCPDECLINE the offer if the address is in use, and restart the discover process. +config FEATURE_UDHCPC_SANITIZEOPT + bool "Do not pass malformed host and domain names" + default y + depends on UDHCPC + help + If selected, udhcpc will check some options (such as option 12 - + hostname) and if they don't look like valid hostnames + (for example, if they start with dash or contain spaces), + they will be replaced with string "bad" when exporting + to the environment. + config FEATURE_UDHCP_PORT bool "Enable '-P port' option for udhcpd and udhcpc" default n diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index 7dfc160e2..e468b7bbb 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -136,6 +136,7 @@ static int mton(uint32_t mask) return i; } +#if ENABLE_FEATURE_UDHCPC_SANITIZEOPT /* Check if a given label represents a valid DNS label * Return pointer to the first character after the label upon success, * NULL otherwise. @@ -192,6 +193,9 @@ static int good_hostname(const char *name) name++; } } +#else +# define good_hostname(name) 1 +#endif /* Create "opt_name=opt_value" string */ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name) -- cgit v1.2.3-55-g6feb From 14158b4127dba30466c50147b868a6a89702960b Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Tue, 17 Jun 2014 17:09:17 +0200 Subject: find: add optional support for '-exec ... {} +' function old new delta do_exec - 309 +309 parse_params 1416 1487 +71 find_main 342 406 +64 packed_usage 29958 30014 +56 func_exec 138 127 -11 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/1 up/down: 500/-11) Total: 489 bytes Signed-off-by: Bartosz Golaszewski Signed-off-by: Denys Vlasenko --- findutils/find.c | 156 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 141 insertions(+), 15 deletions(-) diff --git a/findutils/find.c b/findutils/find.c index 6d34f4d68..8ac3da7a0 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -137,6 +137,16 @@ //config: Support the 'find -exec' option for executing commands based upon //config: the files matched. //config: +//config:config FEATURE_FIND_EXEC_PLUS +//config: bool "Enable -exec ... {} +" +//config: default y +//config: depends on FEATURE_FIND_EXEC +//config: help +//config: Support the 'find -exec ... {} +' option for executing commands +//config: for all matched files at once. +//config: Without this option, -exec + is a synonym for -exec ; +//config: (IOW: it works correctly, but without expected speedup) +//config: //config:config FEATURE_FIND_USER //config: bool "Enable -user: username/uid matching" //config: default y @@ -319,6 +329,9 @@ //usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by" //usage: "\n file name. Fails if CMD exits with nonzero" //usage: ) +//usage: IF_FEATURE_FIND_EXEC_PLUS( +//usage: "\n -exec CMD ARG + Run CMD with {} replaced by list of file names" +//usage: ) //usage: IF_FEATURE_FIND_DELETE( //usage: "\n -delete Delete current file/directory. Turns on -depth option" //usage: ) @@ -337,8 +350,12 @@ # define FNM_CASEFOLD 0 #endif -#define dbg(...) ((void)0) -/* #define dbg(...) bb_error_msg(__VA_ARGS__) */ +#if 1 +# define dbg(...) ((void)0) +#else +# define dbg(...) bb_error_msg(__VA_ARGS__) +#endif + /* This is a NOEXEC applet. Be very careful! */ @@ -375,7 +392,20 @@ IF_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;)) IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;)) IF_FEATURE_FIND_PRUNE( ACTS(prune)) IF_FEATURE_FIND_DELETE( ACTS(delete)) -IF_FEATURE_FIND_EXEC( ACTS(exec, char **exec_argv; unsigned *subst_count; int exec_argc;)) +IF_FEATURE_FIND_EXEC( ACTS(exec, + char **exec_argv; /* -exec ARGS */ + unsigned *subst_count; + int exec_argc; /* count of ARGS */ + IF_FEATURE_FIND_EXEC_PLUS( + /* + * filelist is NULL if "exec ;" + * non-NULL if "exec +" + */ + char **filelist; + int filelist_idx; + int file_len; + ) + )) IF_FEATURE_FIND_GROUP( ACTS(group, gid_t gid;)) IF_FEATURE_FIND_LINKS( ACTS(links, char links_char; int links_count;)) @@ -452,7 +482,6 @@ static int exec_actions(action ***appp, const char *fileName, const struct stat return rc ^ TRUE; /* restore TRUE bit */ } - #if !FNM_CASEFOLD static char *strcpy_upcase(char *dst, const char *src) { @@ -576,17 +605,56 @@ ACTF(inum) } #endif #if ENABLE_FEATURE_FIND_EXEC -ACTF(exec) +static int do_exec(action_exec *ap, const char *fileName) { int i, rc; -#if ENABLE_USE_PORTABLE_CODE - char **argv = alloca(sizeof(char*) * (ap->exec_argc + 1)); -#else /* gcc 4.3.1 generates smaller code: */ - char *argv[ap->exec_argc + 1]; -#endif - for (i = 0; i < ap->exec_argc; i++) - argv[i] = xmalloc_substitute_string(ap->exec_argv[i], ap->subst_count[i], "{}", fileName); - argv[i] = NULL; /* terminate the list */ +# if ENABLE_FEATURE_FIND_EXEC_PLUS + int size = ap->exec_argc + ap->filelist_idx + 1; +# else + int size = ap->exec_argc + 1; +# endif +# if ENABLE_USE_PORTABLE_CODE + char **argv = alloca(sizeof(char*) * size); +# else /* gcc 4.3.1 generates smaller code: */ + char *argv[size]; +# endif + char **pp = argv; + + for (i = 0; i < ap->exec_argc; i++) { + const char *arg = ap->exec_argv[i]; + +# if ENABLE_FEATURE_FIND_EXEC_PLUS + if (ap->filelist) { + /* Handling "-exec +" + * Only one exec_argv[i] has substitution in it. + * Expand that one exec_argv[i] into file list. + */ + if (ap->subst_count[i] == 0) { + *pp++ = xstrdup(arg); + } else { + int j = 0; + while (ap->filelist[j]) { + *pp++ = xmalloc_substitute_string(arg, 1, "{}", ap->filelist[j]); + free(ap->filelist[j]); + j++; + } + } + } else +# endif + { + /* Handling "-exec ;" */ + *pp++ = xmalloc_substitute_string(arg, ap->subst_count[i], "{}", fileName); + } + } + *pp = NULL; /* terminate the list */ + +# if ENABLE_FEATURE_FIND_EXEC_PLUS + if (ap->filelist) { + ap->filelist[0] = NULL; + ap->filelist_idx = 0; + ap->file_len = 0; + } +# endif rc = spawn_and_wait(argv); if (rc < 0) @@ -597,6 +665,48 @@ ACTF(exec) free(argv[i++]); return rc == 0; /* return 1 if exitcode 0 */ } +ACTF(exec) +{ +# if ENABLE_FEATURE_FIND_EXEC_PLUS + if (ap->filelist) { + int rc = 0; + + /* If we have lots of files already, exec the command */ + if (ap->file_len >= 32*1024) + rc = do_exec(ap, NULL); + + ap->file_len += strlen(fileName) + sizeof(char*) + 1; + ap->filelist = xrealloc_vector(ap->filelist, 8, ap->filelist_idx); + ap->filelist[ap->filelist_idx++] = xstrdup(fileName); + return rc == 0; /* return 1 if exitcode 0 */ + } +# endif + return do_exec(ap, fileName); +} +# if ENABLE_FEATURE_FIND_EXEC_PLUS +static int flush_exec_plus(void) +{ + action *ap; + action **app; + action ***appp = G.actions; + while ((app = *appp++) != NULL) { + while ((ap = *app++) != NULL) { + if (ap->f == (action_fp)func_exec) { + action_exec *ae = (void*)ap; + if (ae->filelist_idx != 0) { + int rc = do_exec(ae, NULL); +# if ENABLE_FEATURE_FIND_NOT + if (ap->invert) rc = !rc; +# endif + if (rc) + return rc; + } + } + } + } + return 0; +} +# endif #endif #if ENABLE_FEATURE_FIND_USER ACTF(user) @@ -1037,6 +1147,7 @@ static action*** parse_params(char **argv) else if (parm == PARM_exec) { int i; action_exec *ap; + IF_FEATURE_FIND_EXEC_PLUS(int all_subst = 0;) dbg("%d", __LINE__); G.need_print = 0; ap = ALLOC_ACTION(exec); @@ -1049,10 +1160,13 @@ static action*** parse_params(char **argv) // executes "echo Foo >FILENAME<", // find -exec echo Foo ">{}<" "+" // executes "echo Foo FILENAME1 FILENAME2 FILENAME3...". - // TODO (so far we treat "+" just like ";") if ((argv[0][0] == ';' || argv[0][0] == '+') && argv[0][1] == '\0' ) { +# if ENABLE_FEATURE_FIND_EXEC_PLUS + if (argv[0][0] == '+') + ap->filelist = xzalloc(sizeof(ap->filelist[0])); +# endif break; } argv++; @@ -1062,8 +1176,17 @@ static action*** parse_params(char **argv) bb_error_msg_and_die(bb_msg_requires_arg, arg); ap->subst_count = xmalloc(ap->exec_argc * sizeof(int)); i = ap->exec_argc; - while (i--) + while (i--) { ap->subst_count[i] = count_strstr(ap->exec_argv[i], "{}"); + IF_FEATURE_FIND_EXEC_PLUS(all_subst += ap->subst_count[i];) + } +# if ENABLE_FEATURE_FIND_EXEC_PLUS + /* + * coreutils expects {} to appear only once in "-exec +" + */ + if (all_subst != 1 && ap->filelist) + bb_error_msg_and_die("only one '{}' allowed for -exec +"); +# endif } #endif #if ENABLE_FEATURE_FIND_PAREN @@ -1335,8 +1458,11 @@ int find_main(int argc UNUSED_PARAM, char **argv) 0) /* depth */ ) { status = EXIT_FAILURE; + goto out; } } + IF_FEATURE_FIND_EXEC_PLUS(status = flush_exec_plus();) +out: return status; } -- cgit v1.2.3-55-g6feb From 6be3a5242ce4855734a4cdd5770b6ea7adaf2b3d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 19 Jun 2014 11:32:11 +0200 Subject: find: exit code fixes for find -exec function old new delta func_exec 127 100 -27 Signed-off-by: Denys Vlasenko --- findutils/find.c | 17 +++++++++-------- testsuite/find.tests | 26 ++++++++++++++++++++++++++ 2 files changed, 35 insertions(+), 8 deletions(-) diff --git a/findutils/find.c b/findutils/find.c index 8ac3da7a0..493f72e61 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -634,6 +634,7 @@ static int do_exec(action_exec *ap, const char *fileName) } else { int j = 0; while (ap->filelist[j]) { + /* 2nd arg here should be ap->subst_count[i], but it is always 1: */ *pp++ = xmalloc_substitute_string(arg, 1, "{}", ap->filelist[j]); free(ap->filelist[j]); j++; @@ -669,16 +670,16 @@ ACTF(exec) { # if ENABLE_FEATURE_FIND_EXEC_PLUS if (ap->filelist) { - int rc = 0; + int rc; + ap->filelist = xrealloc_vector(ap->filelist, 8, ap->filelist_idx); + ap->filelist[ap->filelist_idx++] = xstrdup(fileName); + ap->file_len += strlen(fileName) + sizeof(char*) + 1; /* If we have lots of files already, exec the command */ + rc = 1; if (ap->file_len >= 32*1024) rc = do_exec(ap, NULL); - - ap->file_len += strlen(fileName) + sizeof(char*) + 1; - ap->filelist = xrealloc_vector(ap->filelist, 8, ap->filelist_idx); - ap->filelist[ap->filelist_idx++] = xstrdup(fileName); - return rc == 0; /* return 1 if exitcode 0 */ + return rc; } # endif return do_exec(ap, fileName); @@ -698,8 +699,8 @@ static int flush_exec_plus(void) # if ENABLE_FEATURE_FIND_NOT if (ap->invert) rc = !rc; # endif - if (rc) - return rc; + if (rc == 0) + return 1; } } } diff --git a/testsuite/find.tests b/testsuite/find.tests index 345d1e82e..f041106c3 100755 --- a/testsuite/find.tests +++ b/testsuite/find.tests @@ -15,6 +15,32 @@ testing "find -type f" \ "./testfile\n" \ "" "" +optional FEATURE_FIND_EXEC +testing "find -exec exitcode 1" \ + "cd find.tempdir && find testfile -exec true {} \; 2>&1; echo \$?" \ + "0\n" \ + "" "" +SKIP= +optional FEATURE_FIND_EXEC_PLUS +testing "find -exec exitcode 2" \ + "cd find.tempdir && find testfile -exec true {} + 2>&1; echo \$?" \ + "0\n" \ + "" "" +SKIP= +# Surprisingly, "-exec false ;" results in exitcode 0! "-exec false +" is different!!! +optional FEATURE_FIND_EXEC +testing "find -exec exitcode 3" \ + "cd find.tempdir && find testfile -exec false {} \; 2>&1; echo \$?" \ + "0\n" \ + "" "" +SKIP= +optional FEATURE_FIND_EXEC_PLUS +testing "find -exec exitcode 4" \ + "cd find.tempdir && find testfile -exec false {} + 2>&1; echo \$?" \ + "1\n" \ + "" "" +SKIP= + # testing "description" "command" "result" "infile" "stdin" rm -rf find.tempdir -- cgit v1.2.3-55-g6feb From f92f1d0181853b989f9377debb56902e3e21c9a8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 22 Jun 2014 13:54:40 +0200 Subject: find: use sysconf(_SC_ARG_MAX) to determine the command-line size limit The find utility uses a hardcoded value of 32 * 1024 as the limit of the command-line length when calling 'find -exec ... {} +'. This results in over 4 times more execve() calls than in coreutils' find. This patch uses the limit defined in system headers. Based on the patch by Bartosz Golaszewski . Signed-off-by: Denys Vlasenko --- findutils/find.c | 4 +++- findutils/xargs.c | 26 ++++++++++---------------- include/libbb.h | 8 ++++++++ libbb/Kbuild.src | 1 + libbb/sysconf.c | 16 ++++++++++++++++ 5 files changed, 38 insertions(+), 17 deletions(-) create mode 100644 libbb/sysconf.c diff --git a/findutils/find.c b/findutils/find.c index 493f72e61..56a7ed3ab 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -419,6 +419,7 @@ struct globals { smallint need_print; smallint xdev_on; recurse_flags_t recurse_flags; + IF_FEATURE_FIND_EXEC_PLUS(unsigned max_argv_len;) } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { \ @@ -428,6 +429,7 @@ struct globals { /* we have to zero it out because of NOEXEC */ \ memset(&G, 0, sizeof(G)); \ IF_FEATURE_FIND_MAXDEPTH(G.minmaxdepth[1] = INT_MAX;) \ + IF_FEATURE_FIND_EXEC_PLUS(G.max_argv_len = bb_arg_max() - 2048;) \ G.need_print = 1; \ G.recurse_flags = ACTION_RECURSE; \ } while (0) @@ -677,7 +679,7 @@ ACTF(exec) ap->file_len += strlen(fileName) + sizeof(char*) + 1; /* If we have lots of files already, exec the command */ rc = 1; - if (ap->file_len >= 32*1024) + if (ap->file_len >= G.max_argv_len) rc = do_exec(ap, NULL); return rc; } diff --git a/findutils/xargs.c b/findutils/xargs.c index 0ba5b566d..76c4747fe 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c @@ -523,12 +523,7 @@ int xargs_main(int argc, char **argv) argc++; } - /* -s NUM default. fileutils-4.4.2 uses 128k, but I heasitate - * to use such a big value - first need to change code to use - * growable buffer instead of fixed one. - */ - n_max_chars = 32 * 1024; - /* Make smaller if system does not allow our default value. + /* * The Open Group Base Specifications Issue 6: * "The xargs utility shall limit the command line length such that * when the command line is invoked, the combined argument @@ -536,16 +531,15 @@ int xargs_main(int argc, char **argv) * in the System Interfaces volume of IEEE Std 1003.1-2001) * shall not exceed {ARG_MAX}-2048 bytes". */ - { - long arg_max = 0; -#if defined _SC_ARG_MAX - arg_max = sysconf(_SC_ARG_MAX) - 2048; -#elif defined ARG_MAX - arg_max = ARG_MAX - 2048; -#endif - if (arg_max > 0 && n_max_chars > arg_max) - n_max_chars = arg_max; - } + n_max_chars = bb_arg_max(); + if (n_max_chars > 32 * 1024) + n_max_chars = 32 * 1024; + /* + * POSIX suggests substracting 2048 bytes from sysconf(_SC_ARG_MAX) + * so that the process may safely modify its environment. + */ + n_max_chars -= 2048; + if (opt & OPT_UPTO_SIZE) { n_max_chars = xatou_range(max_chars, 1, INT_MAX); } diff --git a/include/libbb.h b/include/libbb.h index a1a0dc18c..fa69a7fe6 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -731,6 +731,14 @@ extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST /* Never returns NULL */ extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; +#if defined ARG_MAX +# define bb_arg_max() ((unsigned)ARG_MAX) +#elif defined _SC_ARG_MAX +unsigned bb_arg_max(void) FAST_FUNC; +#else +# define bb_arg_max() ((unsigned)(32 * 1024)) +#endif + #define SEAMLESS_COMPRESSION (0 \ || ENABLE_FEATURE_SEAMLESS_XZ \ || ENABLE_FEATURE_SEAMLESS_LZMA \ diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 6578d1171..62680bd52 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -92,6 +92,7 @@ lib-y += skip_whitespace.o lib-y += speed_table.o lib-y += str_tolower.o lib-y += strrstr.o +lib-y += sysconf.o lib-y += time.o lib-y += trim.o lib-y += u_signal_names.o diff --git a/libbb/sysconf.c b/libbb/sysconf.c new file mode 100644 index 000000000..c5fa5e001 --- /dev/null +++ b/libbb/sysconf.c @@ -0,0 +1,16 @@ +/* vi: set sw=4 ts=4: */ +/* + * Various system configuration helpers. + * + * Copyright (C) 2014 Bartosz Golaszewski + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" + +#if defined _SC_ARG_MAX +unsigned FAST_FUNC bb_arg_max(void) +{ + return sysconf(_SC_ARG_MAX); +} +#endif -- cgit v1.2.3-55-g6feb From 5d2e409ef8224dc32fde59702e8ec90b231441ed Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Sun, 22 Jun 2014 14:01:13 +0200 Subject: libbb: use a wrapper around sysconf(_SC_CLK_TCK) to save a few bytes function old new delta bb_sc_clk_tck - 10 +10 timescmd 118 113 -5 print_route 1763 1758 -5 mpstat_main 1288 1283 -5 iostat_main 1947 1942 -5 INET_setroute 879 871 -8 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/5 up/down: 10/-28) Total: -18 bytes Signed-off-by: Bartosz Golaszewski Signed-off-by: Denys Vlasenko --- include/libbb.h | 1 + libbb/sysconf.c | 6 ++++++ networking/libiproute/iproute.c | 2 +- networking/route.c | 2 +- procps/iostat.c | 7 +------ procps/mpstat.c | 8 +------- shell/ash.c | 2 +- 7 files changed, 12 insertions(+), 16 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index fa69a7fe6..7a3610bb9 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -738,6 +738,7 @@ unsigned bb_arg_max(void) FAST_FUNC; #else # define bb_arg_max() ((unsigned)(32 * 1024)) #endif +unsigned bb_clk_tck(void) FAST_FUNC; #define SEAMLESS_COMPRESSION (0 \ || ENABLE_FEATURE_SEAMLESS_XZ \ diff --git a/libbb/sysconf.c b/libbb/sysconf.c index c5fa5e001..4dbffbebd 100644 --- a/libbb/sysconf.c +++ b/libbb/sysconf.c @@ -14,3 +14,9 @@ unsigned FAST_FUNC bb_arg_max(void) return sysconf(_SC_ARG_MAX); } #endif + +/* Return the number of clock ticks per second. */ +unsigned FAST_FUNC bb_clk_tck(void) +{ + return sysconf(_SC_CLK_TCK); +} diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c index f8a67d9ee..ec4d8ba03 100644 --- a/networking/libiproute/iproute.c +++ b/networking/libiproute/iproute.c @@ -73,7 +73,7 @@ static unsigned get_hz(void) fclose(fp); } if (!hz_internal) - hz_internal = sysconf(_SC_CLK_TCK); + hz_internal = bb_clk_tck(); return hz_internal; } diff --git a/networking/route.c b/networking/route.c index 4235ea72c..24cc2eb5a 100644 --- a/networking/route.c +++ b/networking/route.c @@ -283,7 +283,7 @@ static NOINLINE void INET_setroute(int action, char **args) if (k == KW_IPVx_IRTT) { rt->rt_flags |= RTF_IRTT; rt->rt_irtt = xatoul(args_m1); - rt->rt_irtt *= (sysconf(_SC_CLK_TCK) / 100); /* FIXME */ + rt->rt_irtt *= (bb_clk_tck() / 100); /* FIXME */ #if 0 /* FIXME: do we need to check anything of this? */ if (rt->rt_irtt < 1 || rt->rt_irtt > (120 * HZ)) { bb_error_msg_and_die("bad irtt"); diff --git a/procps/iostat.c b/procps/iostat.c index 978d23430..8d272c87c 100644 --- a/procps/iostat.c +++ b/procps/iostat.c @@ -109,11 +109,6 @@ enum { OPT_m = 1 << 5, }; -static ALWAYS_INLINE unsigned get_user_hz(void) -{ - return sysconf(_SC_CLK_TCK); -} - static ALWAYS_INLINE int this_is_smp(void) { return (G.total_cpus > 1); @@ -414,7 +409,7 @@ int iostat_main(int argc UNUSED_PARAM, char **argv) memset(&stats_data, 0, sizeof(stats_data)); /* Get number of clock ticks per sec */ - G.clk_tck = get_user_hz(); + G.clk_tck = bb_clk_tck(); /* Determine number of CPUs */ G.total_cpus = get_cpu_count(); diff --git a/procps/mpstat.c b/procps/mpstat.c index aa5a5c73f..c628d6215 100644 --- a/procps/mpstat.c +++ b/procps/mpstat.c @@ -775,12 +775,6 @@ static void main_loop(void) /* Initialization */ -/* Get number of clock ticks per sec */ -static ALWAYS_INLINE unsigned get_hz(void) -{ - return sysconf(_SC_CLK_TCK); -} - static void alloc_struct(int cpus) { int i; @@ -873,7 +867,7 @@ int mpstat_main(int UNUSED_PARAM argc, char **argv) G.cpu_nr = get_cpu_count(); /* Get number of clock ticks per sec */ - G.hz = get_hz(); + G.hz = bb_clk_tck(); /* Calculate number of interrupts per processor */ G.irqcpu_nr = get_irqcpu_nr(PROCFS_INTERRUPTS, NR_IRQS) + NR_IRQCPU_PREALLOC; diff --git a/shell/ash.c b/shell/ash.c index cabeb40c5..dc7a9bf4f 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12759,7 +12759,7 @@ timescmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) const unsigned char *p; struct tms buf; - clk_tck = sysconf(_SC_CLK_TCK); + clk_tck = bb_clk_tck(); times(&buf); p = timescmd_str; -- cgit v1.2.3-55-g6feb From 3ed81cf0529145d04299c4cd48b1aaab2fe36193 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Sun, 22 Jun 2014 16:30:41 +0200 Subject: unit-tests: implement the unit-testing framework This set of patches adds a simple unit-testing framework to Busybox unit-tests: add some helper macros for unit-test framework implementation unit-tests: implement the unit-testing framework unit-tests: add basic documentation on writing the unit test cases unit-tests: modify the Makefile 'test' target to run unit-tests too unit-tests: add two example test cases unit-tests: modify the existing strrstr test code to use the unit-test framework Signed-off-by: Bartosz Golaszewski Signed-off-by: Denys Vlasenko --- Config.in | 8 ++++ Makefile.custom | 4 ++ docs/unit-tests.txt | 50 +++++++++++++++++++ include/libbb.h | 135 ++++++++++++++++++++++++++++++++++++++++++++++++++++ include/platform.h | 3 ++ libbb/bbunit.c | 90 +++++++++++++++++++++++++++++++++++ libbb/obscure.c | 38 +++++++++++++++ libbb/strrstr.c | 19 +++----- 8 files changed, 335 insertions(+), 12 deletions(-) create mode 100644 docs/unit-tests.txt create mode 100644 libbb/bbunit.c diff --git a/Config.in b/Config.in index b6eaea541..b83beb52d 100644 --- a/Config.in +++ b/Config.in @@ -675,6 +675,14 @@ config DEBUG_PESSIMIZE in a much bigger executable that more closely matches the source code. +config UNIT_TEST + bool "Build unit tests" + default n + help + Say Y here if you want to build unit tests (both the framework and + test cases) as a Busybox applet. This results in bigger code, so you + probably don't want this option in production builds. + config WERROR bool "Abort compilation on any warning" default n diff --git a/Makefile.custom b/Makefile.custom index 8c95ef2d4..f8a12831d 100644 --- a/Makefile.custom +++ b/Makefile.custom @@ -55,7 +55,11 @@ endif # (cp -pPR is POSIX-compliant (cp -dpR or cp -a would not be)) .PHONY: check .PHONY: test +ifeq ($(CONFIG_UNIT_TEST),y) +UNIT_CMD = ./busybox unit +endif check test: busybox busybox.links + $(UNIT_CMD) test -d $(objtree)/testsuite || cp -pPR $(srctree)/testsuite $(objtree) bindir=$(objtree) srcdir=$(srctree)/testsuite \ $(SHELL) -c "cd $(objtree)/testsuite && $(srctree)/testsuite/runtest $(if $(KBUILD_VERBOSE:0=),-v)" diff --git a/docs/unit-tests.txt b/docs/unit-tests.txt new file mode 100644 index 000000000..0fb522086 --- /dev/null +++ b/docs/unit-tests.txt @@ -0,0 +1,50 @@ +Busybox unit test framework +=========================== + +This document describes what you need to do to write test cases using the +Busybox unit test framework. + + +Building unit tests +------------------- + +The framework and all tests are built as a regular Busybox applet if option +CONFIG_UNIT_TEST (found in General Configuration -> Debugging Options) is set. + + +Writing test cases +------------------ + +Unit testing interface can be found in include/bbunit.h. + +Tests can be placed in any .c file in Busybox tree - preferably right next to +the functions they test. Test cases should be enclosed within an #if, and +should start with BBUNIT_DEFINE_TEST macro and end with BBUNIT_ENDTEST within +the test curly brackets. If an assertion fails the test ends immediately, ie. +the following assertions will not be reached. Any code placed after +BBUNIT_ENDTEST is executed regardless of the test result. Here's an example: + +#if ENABLE_UNIT_TEST + +BBUNIT_DEFINE_TEST(test_name) +{ + int *i; + + i = malloc(sizeof(int)); + BBUNIT_ASSERT_NOTNULL(i); + *i = 2; + BBUNIT_ASSERT_EQ((*i)*(*i), 4); + + BBUNIT_ENDTEST; + + free(i); +} + +#endif /* ENABLE_UNIT_TEST */ + + +Running the unit test suite +--------------------------- + +To run the tests you can either directly run 'busybox unit' or use 'make test' +to run both the unit tests (if compiled) and regular test suite. diff --git a/include/libbb.h b/include/libbb.h index 7a3610bb9..cede50cc2 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1941,6 +1941,141 @@ static ALWAYS_INLINE unsigned char bb_ascii_tolower(unsigned char a) #define isprint_asciionly(a) ((unsigned)((a) - 0x20) <= 0x7e - 0x20) +/* Simple unit-testing framework */ + +typedef void (*bbunit_testfunc)(void); + +struct bbunit_listelem { + struct bbunit_listelem* next; + const char* name; + bbunit_testfunc testfunc; +}; + +void bbunit_registertest(struct bbunit_listelem* test); +void bbunit_settestfailed(void); + +#define BBUNIT_DEFINE_TEST(NAME) \ + static void bbunit_##NAME##_test(void); \ + static struct bbunit_listelem bbunit_##NAME##_elem = { \ + .name = #NAME, \ + .testfunc = bbunit_##NAME##_test, \ + }; \ + static void INIT_LAST bbunit_##NAME##_register(void) \ + { \ + bbunit_registertest(&bbunit_##NAME##_elem); \ + } \ + static void bbunit_##NAME##_test(void) + +/* + * Both 'goto bbunit_end' and 'break' are here only to get rid + * of compiler warnings. + */ +#define BBUNIT_ENDTEST \ + do { \ + goto bbunit_end; \ + bbunit_end: \ + break; \ + } while (0) + +#define BBUNIT_PRINTASSERTFAIL \ + do { \ + bb_error_msg( \ + "[ERROR] Assertion failed in file %s, line %d", \ + __FILE__, __LINE__); \ + } while (0) + +#define BBUNIT_ASSERTION_FAILED \ + do { \ + bbunit_settestfailed(); \ + goto bbunit_end; \ + } while (0) + +/* + * Assertions. + * For now we only offer assertions which cause tests to fail + * immediately. In the future 'expects' might be added too - + * similar to those offered by the gtest framework. + */ +#define BBUNIT_ASSERT_EQ(EXPECTED, ACTUAL) \ + do { \ + if ((EXPECTED) != (ACTUAL)) { \ + BBUNIT_PRINTASSERTFAIL; \ + bb_error_msg("[ERROR] '%s' isn't equal to '%s'", \ + #EXPECTED, #ACTUAL); \ + BBUNIT_ASSERTION_FAILED; \ + } \ + } while (0) + +#define BBUNIT_ASSERT_NOTEQ(EXPECTED, ACTUAL) \ + do { \ + if ((EXPECTED) == (ACTUAL)) { \ + BBUNIT_PRINTASSERTFAIL; \ + bb_error_msg("[ERROR] '%s' is equal to '%s'", \ + #EXPECTED, #ACTUAL); \ + BBUNIT_ASSERTION_FAILED; \ + } \ + } while (0) + +#define BBUNIT_ASSERT_NOTNULL(PTR) \ + do { \ + if ((PTR) == NULL) { \ + BBUNIT_PRINTASSERTFAIL; \ + bb_error_msg("[ERROR] '%s' is NULL!", #PTR); \ + BBUNIT_ASSERTION_FAILED; \ + } \ + } while (0) + +#define BBUNIT_ASSERT_NULL(PTR) \ + do { \ + if ((PTR) != NULL) { \ + BBUNIT_PRINTASSERTFAIL; \ + bb_error_msg("[ERROR] '%s' is not NULL!", #PTR); \ + BBUNIT_ASSERTION_FAILED; \ + } \ + } while (0) + +#define BBUNIT_ASSERT_FALSE(STATEMENT) \ + do { \ + if ((STATEMENT)) { \ + BBUNIT_PRINTASSERTFAIL; \ + bb_error_msg("[ERROR] Statement '%s' evaluated to true!", \ + #STATEMENT); \ + BBUNIT_ASSERTION_FAILED; \ + } \ + } while (0) + +#define BBUNIT_ASSERT_TRUE(STATEMENT) \ + do { \ + if (!(STATEMENT)) { \ + BBUNIT_PRINTASSERTFAIL; \ + bb_error_msg("[ERROR] Statement '%s' evaluated to false!", \ + #STATEMENT); \ + BBUNIT_ASSERTION_FAILED; \ + } \ + } while (0) + +#define BBUNIT_ASSERT_STREQ(STR1, STR2) \ + do { \ + if (strcmp(STR1, STR2) != 0) { \ + BBUNIT_PRINTASSERTFAIL; \ + bb_error_msg("[ERROR] Strings '%s' and '%s' " \ + "are not the same", STR1, STR2); \ + BBUNIT_ASSERTION_FAILED; \ + } \ + } while (0) + +#define BBUNIT_ASSERT_STRNOTEQ(STR1, STR2) \ + do { \ + if (strcmp(STR1, STR2) == 0) { \ + BBUNIT_PRINTASSERTFAIL; \ + bb_error_msg("[ERROR] Strings '%s' and '%s' " \ + "are the same, but were " \ + "expected to differ", STR1, STR2); \ + BBUNIT_ASSERTION_FAILED; \ + } \ + } while (0) + + POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/include/platform.h b/include/platform.h index 92f775551..413c2224c 100644 --- a/include/platform.h +++ b/include/platform.h @@ -76,6 +76,9 @@ # define UNUSED_PARAM_RESULT #endif +/* used by unit test machinery to run registration functions */ +#define INIT_LAST __attribute__ ((constructor(2000))) + /* -fwhole-program makes all symbols local. The attribute externally_visible * forces a symbol global. */ #if __GNUC_PREREQ(4,1) diff --git a/libbb/bbunit.c b/libbb/bbunit.c new file mode 100644 index 000000000..256014441 --- /dev/null +++ b/libbb/bbunit.c @@ -0,0 +1,90 @@ +/* vi: set sw=4 ts=4: */ +/* + * bbunit: Simple unit-testing framework for Busybox. + * + * Copyright (C) 2014 by Bartosz Golaszewski + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +//kbuild:lib-$(CONFIG_UNIT_TEST) += bbunit.o +//applet:IF_UNIT_TEST(APPLET(unit, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//usage:#define unit_trivial_usage +//usage: "" +//usage:#define unit_full_usage "\n\n" +//usage: "Run the unit-test suite" + +#include "libbb.h" + +#define WANT_TIMING 0 + +static llist_t *tests = NULL; +static unsigned tests_registered = 0; +static int test_retval; + +void bbunit_registertest(struct bbunit_listelem *test) +{ + llist_add_to_end(&tests, test); + tests_registered++; +} + +void bbunit_settestfailed(void) +{ + test_retval = -1; +} + +#if WANT_TIMING +static void timeval_diff(struct timeval* res, + const struct timeval* x, + const struct timeval* y) +{ + long udiff = x->tv_usec - y->tv_usec; + + res->tv_sec = x->tv_sec - y->tv_sec - (udiff < 0); + res->tv_usec = (udiff >= 0 ? udiff : udiff + 1000000); +} +#endif + +int unit_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) MAIN_EXTERNALLY_VISIBLE; +int unit_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + unsigned tests_run = 0; + unsigned tests_failed = 0; +#if WANT_TIMING + struct timeval begin; + struct timeval end; + struct timeval time_spent; + gettimeofday(&begin, NULL); +#endif + + bb_error_msg("Running %d test(s)...", tests_registered); + for (;;) { + struct bbunit_listelem* el = llist_pop(&tests); + if (!el) + break; + bb_error_msg("Case: [%s]", el->name); + test_retval = 0; + el->testfunc(); + if (test_retval < 0) { + bb_error_msg("[ERROR] [%s]: TEST FAILED", el->name); + tests_failed++; + } + tests_run++; + el = el->next; + } + +#if WANT_TIMING + gettimeofday(&end, NULL); + timeval_diff(&time_spent, &end, &begin); + bb_error_msg("Elapsed time %u.%06u seconds" + (int)time_spent.tv_sec, + (int)time_spent.tv_usec); +#endif + if (tests_failed > 0) { + bb_error_msg("[ERROR] %u test(s) FAILED", tests_failed); + return EXIT_FAILURE; + } + bb_error_msg("All tests passed"); + return EXIT_SUCCESS; +} diff --git a/libbb/obscure.c b/libbb/obscure.c index 24c4ac917..ad17d1ff1 100644 --- a/libbb/obscure.c +++ b/libbb/obscure.c @@ -182,3 +182,41 @@ int FAST_FUNC obscure(const char *old, const char *newval, const struct passwd * } return 0; } + +#if ENABLE_UNIT_TEST + +/* Test obscure_msg() instead of obscure() in order not to print anything. */ + +static const struct passwd pw = { + .pw_name = (char *)"johndoe", + .pw_gecos = (char *)"John Doe", +}; + +BBUNIT_DEFINE_TEST(obscure_weak_pass) +{ + /* Empty password */ + BBUNIT_ASSERT_NOTNULL(obscure_msg("Ad4#21?'S|", "", &pw)); + /* Pure numbers */ + BBUNIT_ASSERT_NOTNULL(obscure_msg("Ad4#21?'S|", "23577315", &pw)); + /* Similar to pw_name */ + BBUNIT_ASSERT_NOTNULL(obscure_msg("Ad4#21?'S|", "johndoe123%", &pw)); + /* Similar to pw_gecos, reversed */ + BBUNIT_ASSERT_NOTNULL(obscure_msg("Ad4#21?'S|", "eoD nhoJ^44@", &pw)); + /* Similar to the old password */ + BBUNIT_ASSERT_NOTNULL(obscure_msg("Ad4#21?'S|", "d4#21?'S", &pw)); + /* adjacent letters */ + BBUNIT_ASSERT_NOTNULL(obscure_msg("Ad4#21?'S|", "qwerty123", &pw)); + /* Many similar chars */ + BBUNIT_ASSERT_NOTNULL(obscure_msg("Ad4#21?'S|", "^33Daaaaaa1", &pw)); + + BBUNIT_ENDTEST; +} + +BBUNIT_DEFINE_TEST(obscure_strong_pass) +{ + BBUNIT_ASSERT_NULL(obscure_msg("Rt4##2&:'|", "}(^#rrSX3S*22", &pw)); + + BBUNIT_ENDTEST; +} + +#endif /* ENABLE_UNIT_TEST */ diff --git a/libbb/strrstr.c b/libbb/strrstr.c index d8823fc51..93d970a1b 100644 --- a/libbb/strrstr.c +++ b/libbb/strrstr.c @@ -7,13 +7,7 @@ * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -#ifdef __DO_STRRSTR_TEST -#include -#include -#include -#else #include "libbb.h" -#endif /* * The strrstr() function finds the last occurrence of the substring needle @@ -34,8 +28,9 @@ char* FAST_FUNC strrstr(const char *haystack, const char *needle) } } -#ifdef __DO_STRRSTR_TEST -int main(int argc, char **argv) +#if ENABLE_UNIT_TEST + +BBUNIT_DEFINE_TEST(strrstr) { static const struct { const char *h, *n; @@ -59,13 +54,13 @@ int main(int argc, char **argv) i = 0; while (i < sizeof(test_array) / sizeof(test_array[0])) { const char *r = strrstr(test_array[i].h, test_array[i].n); - printf("'%s' vs. '%s': '%s' - ", test_array[i].h, test_array[i].n, r); if (r == NULL) r = test_array[i].h - 1; - printf("%s\n", r == test_array[i].h + test_array[i].pos ? "PASSED" : "FAILED"); + BBUNIT_ASSERT_EQ(r, test_array[i].h + test_array[i].pos); i++; } - return 0; + BBUNIT_ENDTEST; } -#endif + +#endif /* ENABLE_UNIT_TEST */ -- cgit v1.2.3-55-g6feb From ea23c25e96f74d2e248f790b20e15f18ff91beba Mon Sep 17 00:00:00 2001 From: Isaac Dunham Date: Sun, 22 Jun 2014 20:44:25 +0200 Subject: unlink: new applet function old new delta unlink_main - 45 +45 packed_usage 29667 29686 +19 Signed-off-by: Isaac Dunham Signed-off-by: Denys Vlasenko --- coreutils/unlink.c | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 coreutils/unlink.c diff --git a/coreutils/unlink.c b/coreutils/unlink.c new file mode 100644 index 000000000..3b7d0fb2b --- /dev/null +++ b/coreutils/unlink.c @@ -0,0 +1,34 @@ +/* vi: set sw=4 ts=4: */ +/* unlink for busybox + * + * Copyright (C) 2014 Isaac Dunham + * + * Licensed under GPLv2, see LICENSE in this source tree + */ + +//config:config UNLINK +//config: bool "unlink" +//config: default y +//config: help +//config: unlink deletes a file by calling unlink() + +//kbuild:lib-$(CONFIG_UNLINK) += unlink.o + +//applet:IF_UNLINK(APPLET(unlink, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//usage:#define unlink_trivial_usage +//usage: "FILE" +//usage:#define unlink_full_usage "\n\n" +//usage: "Delete FILE by calling unlink()" + +#include "libbb.h" + +int unlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int unlink_main(int argc UNUSED_PARAM, char **argv) +{ + opt_complementary = "=1"; /* must have exactly 1 param */ + getopt32(argv, ""); + argv += optind; + xunlink(argv[0]); + return 0; +} -- cgit v1.2.3-55-g6feb From 5aeae36e2b8bcee19c8eb189f55b19febaab4c42 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 25 Jun 2014 15:39:27 +0200 Subject: libbb: fix compile failure if both ARG_MAX and _SC_ARG_MAX are defined Signed-off-by: Denys Vlasenko --- libbb/sysconf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/sysconf.c b/libbb/sysconf.c index 4dbffbebd..031901980 100644 --- a/libbb/sysconf.c +++ b/libbb/sysconf.c @@ -8,7 +8,7 @@ */ #include "libbb.h" -#if defined _SC_ARG_MAX +#if !defined(ARG_MAX) && defined(_SC_ARG_MAX) unsigned FAST_FUNC bb_arg_max(void) { return sysconf(_SC_ARG_MAX); -- cgit v1.2.3-55-g6feb From de3cae1348f212effd3f2838301596d15c6b3e54 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 25 Jun 2014 16:23:59 +0200 Subject: ftpd: support deprecated XPWD command Signed-off-by: Denys Vlasenko --- networking/ftpd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/networking/ftpd.c b/networking/ftpd.c index 33db964fa..b4d73e55d 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c @@ -1085,6 +1085,8 @@ enum { const_PASV = mk_const4('P', 'A', 'S', 'V'), const_PORT = mk_const4('P', 'O', 'R', 'T'), const_PWD = mk_const3('P', 'W', 'D'), + /* Same as PWD. Reportedly used by windows ftp client */ + const_XPWD = mk_const4('X', 'P', 'W', 'D'), const_QUIT = mk_const4('Q', 'U', 'I', 'T'), const_REST = mk_const4('R', 'E', 'S', 'T'), const_RETR = mk_const4('R', 'E', 'T', 'R'), @@ -1292,7 +1294,7 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) WRITE_OK(FTP_ALLOOK); else if (cmdval == const_SYST) cmdio_write_raw(STR(FTP_SYSTOK)" UNIX Type: L8\r\n"); - else if (cmdval == const_PWD) + else if (cmdval == const_PWD || cmdval == const_XPWD) handle_pwd(); else if (cmdval == const_CWD) handle_cwd(); -- cgit v1.2.3-55-g6feb From cbf3bfa57a419202c2bc26f3ff8ae21d3d3bf8b2 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Tue, 24 Jun 2014 12:12:58 +0200 Subject: nanddump: correct rounding to next page (lead to infinite loop) The rounding to next page formula was wrong: ex: (len | ~(meminfo->writesize - 1)) + 1; len=128K writesize=4K (len | ~(meminfo->writesize - 1)) + 1 => 4 294 963 201 ?! correct rounding formula: ((len - 1) | (meminfo->writesize - 1)) + 1 => 128K len = 130K ((len - 1) | (meminfo->writesize - 1)) + 1 => 132K modprobe nandsim parts="20,20" badblocks="22,23" without patch: nanddump /dev/mtd1 | wc -c [...] infinite loop with the patch: nanddump /dev/mtd1 | wc -c 327680 Signed-off-by: Richard Genoud Signed-off-by: Denys Vlasenko --- miscutils/nandwrite.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c index e3f9b565d..8c4da802f 100644 --- a/miscutils/nandwrite.c +++ b/miscutils/nandwrite.c @@ -64,8 +64,8 @@ static void dump_bad(struct mtd_info_user *meminfo, unsigned len, int oob) unsigned char buf[meminfo->writesize]; unsigned count; - /* round len to the next page */ - len = (len | ~(meminfo->writesize - 1)) + 1; + /* round len to the next page only if len is not already on a page */ + len = ((len - 1) | (meminfo->writesize - 1)) + 1; memset(buf, 0xff, sizeof(buf)); for (count = 0; count < len; count += meminfo->writesize) { -- cgit v1.2.3-55-g6feb From f17fbe1d365d935b486ece2172043d3eeb8a999b Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Tue, 24 Jun 2014 12:12:59 +0200 Subject: nanddump: add options --bb=skipbad and padbad In mtd-utils, the bad block options changed in favor of --bb=[skipbad|padbad|dumpbad] and omitbad has been removed. This patch add the --bb=skipbad and padbad methods to busybox' nanddump. padbad is the current default behaviour. The difference between skipbad and omitbad is this one: On a 16K block NAND, if the 1st block of mtd0 is bad, we'll have: nanddump -b -l 16384 /dev/mtd0 | wc -c 0 nanddump --bb=skipbad -l 16384 /dev/mtd0 | wc -c 16384 <- data from 1st good block Signed-off-by: Richard Genoud Signed-off-by: Denys Vlasenko --- miscutils/nandwrite.c | 65 ++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 56 insertions(+), 9 deletions(-) diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c index 8c4da802f..a64b95bc5 100644 --- a/miscutils/nandwrite.c +++ b/miscutils/nandwrite.c @@ -36,7 +36,7 @@ //usage: "\n -s ADDR Start address" //usage:#define nanddump_trivial_usage -//usage: "[-o] [-b] [-s ADDR] [-l LEN] [-f FILE] MTD_DEVICE" +//usage: "[-o] [-b|--bb=padbad|skipbad] [-s ADDR] [-l LEN] [-f FILE] MTD_DEVICE" //usage:#define nanddump_full_usage "\n\n" //usage: "Dump MTD_DEVICE\n" //usage: "\n -o Dump oob data" @@ -44,6 +44,12 @@ //usage: "\n -s ADDR Start address" //usage: "\n -l LEN Length" //usage: "\n -f FILE Dump to file ('-' for stdout)" +//usage: "\n --bb=METHOD:" +//usage: "\n skipbad: skip bad blocks" +//usage: "\n padbad: substitute bad blocks by 0xff (default)" +//usage: "\n The difference between omit and skip bad block is that in the omit" +//usage: "\n case, the length of the bad block is counted as part of the total" +//usage: "\n dump length, and in the skip case, it's not." #include "libbb.h" #include @@ -57,6 +63,11 @@ #define OPT_b (1 << 2) #define OPT_f (1 << 3) #define OPT_l (1 << 4) +#define OPT_bb (1 << 5) /* must be the last one in the list */ + +#define BB_PADBAD (1 << 0) +#define BB_SKIPBAD (1 << 1) +#define BB_OMITBAD (1 << 2) /* helper for writing out 0xff for bad blocks pad */ static void dump_bad(struct mtd_info_user *meminfo, unsigned len, int oob) @@ -102,6 +113,7 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) /* Buffer for OOB data */ unsigned char *oobbuf; unsigned opts; + unsigned bb_method = BB_PADBAD; int fd; ssize_t cnt; unsigned mtdoffset, meminfo_writesize, blockstart, limit; @@ -109,11 +121,14 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) struct mtd_info_user meminfo; struct mtd_oob_buf oob; unsigned char *filebuf; - const char *opt_s = "0", *opt_f = "-", *opt_l; + const char *opt_s = "0", *opt_f = "-", *opt_l, *opt_bb; + static const char nanddump_longopts[] ALIGN1 = + "bb\0" Required_argument "\xff"; /* no short equivalent */ if (IS_NANDDUMP) { opt_complementary = "=1"; - opts = getopt32(argv, "os:bf:l:", &opt_s, &opt_f, &opt_l); + applet_long_options = nanddump_longopts; + opts = getopt32(argv, "os:bf:l:", &opt_s, &opt_f, &opt_l, &opt_bb); } else { /* nandwrite */ opt_complementary = "-1:?2"; opts = getopt32(argv, "ps:", &opt_s); @@ -138,6 +153,20 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) if (length < meminfo.size - mtdoffset) end_addr = mtdoffset + length; } + if (IS_NANDDUMP) { + if ((opts & OPT_b) && (opts & OPT_bb)) + bb_show_usage(); + if (opts & OPT_b) + bb_method = BB_OMITBAD; + if (opts & OPT_bb) { + if (!strcmp("skipbad", opt_bb)) + bb_method = BB_SKIPBAD; + else if (!strcmp("padbad", opt_bb)) + bb_method = BB_PADBAD; + else + bb_show_usage(); + } + } /* Pull it into a CPU register (hopefully) - smaller code that way */ meminfo_writesize = meminfo.writesize; @@ -162,9 +191,16 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) tmp = next_good_eraseblock(fd, &meminfo, blockstart); if (tmp != blockstart) { /* bad block(s), advance mtdoffset */ - if (IS_NANDDUMP && !(opts & OPT_b)) { - int bad_len = MIN(tmp, end_addr) - mtdoffset; - dump_bad(&meminfo, bad_len, opts & OPT_o); + if (IS_NANDDUMP) { + if (bb_method == BB_PADBAD) { + int bad_len = MIN(tmp, end_addr) - mtdoffset; + dump_bad(&meminfo, bad_len, opts & OPT_o); + } + /* with option skipbad, increase the total length */ + if (bb_method == BB_SKIPBAD) { + end_addr += (tmp - blockstart); + } + /* omitbad: do nothing */ } mtdoffset = tmp; } @@ -182,9 +218,20 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart); if (IS_NANDWRITE) printf("Writing at 0x%08x\n", mtdoffset); - else if (mtdoffset > blockstart && !(opts & OPT_b)) { - int bad_len = MIN(mtdoffset, limit) - blockstart; - dump_bad(&meminfo, bad_len, opts & OPT_o); + else if (mtdoffset > blockstart) { + if (bb_method == BB_PADBAD) { + /* dump FF padded bad block */ + int bad_len = MIN(mtdoffset, limit) - blockstart; + dump_bad(&meminfo, bad_len, opts & OPT_o); + } else if (bb_method == BB_SKIPBAD) { + /* for skipbad, increase the length */ + if ((end_addr + mtdoffset - blockstart) > end_addr) + end_addr += (mtdoffset - blockstart); + else + end_addr = ~0; + limit = MIN(meminfo.size, end_addr); + } + /* omitbad: do nothing */ } if (mtdoffset >= limit) break; -- cgit v1.2.3-55-g6feb From 8feb25956f788026099c44103f1b5c440bfe3598 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Wed, 25 Jun 2014 17:33:34 +0200 Subject: nanddump: kill -b Omit bad block since mtd-utils 1.4.7, the omit bad block method has been removed. (cf commit d8b8f780ec3c916f3990e9227d6bfbb22bf42ef8) Signed-off-by: Richard Genoud Signed-off-by: Denys Vlasenko --- miscutils/nandwrite.c | 38 ++++++++++++-------------------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c index a64b95bc5..509c06412 100644 --- a/miscutils/nandwrite.c +++ b/miscutils/nandwrite.c @@ -36,20 +36,16 @@ //usage: "\n -s ADDR Start address" //usage:#define nanddump_trivial_usage -//usage: "[-o] [-b|--bb=padbad|skipbad] [-s ADDR] [-l LEN] [-f FILE] MTD_DEVICE" +//usage: "[-o] [--bb=padbad|skipbad] [-s ADDR] [-l LEN] [-f FILE] MTD_DEVICE" //usage:#define nanddump_full_usage "\n\n" //usage: "Dump MTD_DEVICE\n" //usage: "\n -o Dump oob data" -//usage: "\n -b Omit bad block from the dump" //usage: "\n -s ADDR Start address" //usage: "\n -l LEN Length" //usage: "\n -f FILE Dump to file ('-' for stdout)" //usage: "\n --bb=METHOD:" //usage: "\n skipbad: skip bad blocks" //usage: "\n padbad: substitute bad blocks by 0xff (default)" -//usage: "\n The difference between omit and skip bad block is that in the omit" -//usage: "\n case, the length of the bad block is counted as part of the total" -//usage: "\n dump length, and in the skip case, it's not." #include "libbb.h" #include @@ -60,14 +56,12 @@ #define OPT_p (1 << 0) /* nandwrite only */ #define OPT_o (1 << 0) /* nanddump only */ #define OPT_s (1 << 1) -#define OPT_b (1 << 2) -#define OPT_f (1 << 3) -#define OPT_l (1 << 4) -#define OPT_bb (1 << 5) /* must be the last one in the list */ +#define OPT_f (1 << 2) +#define OPT_l (1 << 3) +#define OPT_bb (1 << 4) /* must be the last one in the list */ #define BB_PADBAD (1 << 0) #define BB_SKIPBAD (1 << 1) -#define BB_OMITBAD (1 << 2) /* helper for writing out 0xff for bad blocks pad */ static void dump_bad(struct mtd_info_user *meminfo, unsigned len, int oob) @@ -128,7 +122,7 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) if (IS_NANDDUMP) { opt_complementary = "=1"; applet_long_options = nanddump_longopts; - opts = getopt32(argv, "os:bf:l:", &opt_s, &opt_f, &opt_l, &opt_bb); + opts = getopt32(argv, "os:f:l:", &opt_s, &opt_f, &opt_l, &opt_bb); } else { /* nandwrite */ opt_complementary = "-1:?2"; opts = getopt32(argv, "ps:", &opt_s); @@ -153,19 +147,13 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) if (length < meminfo.size - mtdoffset) end_addr = mtdoffset + length; } - if (IS_NANDDUMP) { - if ((opts & OPT_b) && (opts & OPT_bb)) - bb_show_usage(); - if (opts & OPT_b) - bb_method = BB_OMITBAD; - if (opts & OPT_bb) { - if (!strcmp("skipbad", opt_bb)) - bb_method = BB_SKIPBAD; - else if (!strcmp("padbad", opt_bb)) - bb_method = BB_PADBAD; - else - bb_show_usage(); - } + if (IS_NANDDUMP && (opts & OPT_bb)) { + if (strcmp("skipbad", opt_bb) == 0) + bb_method = BB_SKIPBAD; + else if (strcmp("padbad", opt_bb) == 0) + bb_method = BB_PADBAD; + else + bb_show_usage(); } /* Pull it into a CPU register (hopefully) - smaller code that way */ @@ -200,7 +188,6 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) if (bb_method == BB_SKIPBAD) { end_addr += (tmp - blockstart); } - /* omitbad: do nothing */ } mtdoffset = tmp; } @@ -231,7 +218,6 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) end_addr = ~0; limit = MIN(meminfo.size, end_addr); } - /* omitbad: do nothing */ } if (mtdoffset >= limit) break; -- cgit v1.2.3-55-g6feb From 2a870d091e86687c8b7b9e14b9c75815d40d7053 Mon Sep 17 00:00:00 2001 From: Richard Genoud Date: Wed, 25 Jun 2014 17:38:30 +0200 Subject: nanddump: change default to --bb=skipbad since mtd-utils 1.4.7, the default behaviour of nanddump is skipbad (commit 2521d4f1b6b9866a9c89f3c11a4f6a3d763ff1d7) Signed-off-by: Richard Genoud Signed-off-by: Denys Vlasenko --- miscutils/nandwrite.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c index 509c06412..29ff351a3 100644 --- a/miscutils/nandwrite.c +++ b/miscutils/nandwrite.c @@ -107,7 +107,7 @@ int nandwrite_main(int argc UNUSED_PARAM, char **argv) /* Buffer for OOB data */ unsigned char *oobbuf; unsigned opts; - unsigned bb_method = BB_PADBAD; + unsigned bb_method = BB_SKIPBAD; int fd; ssize_t cnt; unsigned mtdoffset, meminfo_writesize, blockstart, limit; -- cgit v1.2.3-55-g6feb From 0b0ccd457016d6a4eaa3e79bd65a852ea7d4294b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 26 Jun 2014 12:07:48 +0200 Subject: ftpd: optimize writes of LIST results a bit function old new delta handle_dir_common 201 207 +6 Signed-off-by: Denys Vlasenko --- networking/ftpd.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/networking/ftpd.c b/networking/ftpd.c index b4d73e55d..e724734df 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c @@ -709,6 +709,7 @@ handle_dir_common(int opts) * which can be problematic in chroot */ ls_fd = popen_ls((opts & LONG_LISTING) ? "-l" : "-1"); ls_fp = xfdopen_for_read(ls_fd); +/* FIXME: filenames with embedded newlines are mishandled */ if (opts & USE_CTRL_CONN) { /* STAT */ @@ -729,16 +730,20 @@ handle_dir_common(int opts) int remote_fd = get_remote_transfer_fd(" Directory listing"); if (remote_fd >= 0) { while (1) { - line = xmalloc_fgetline(ls_fp); + unsigned len; + + line = xmalloc_fgets(ls_fp); if (!line) break; /* I've seen clients complaining when they * are fed with ls output with bare '\n'. - * Pity... that would be much simpler. + * Replace trailing "\n\0" with "\r\n". */ -/* TODO: need to s/LF/NUL/g here */ - xwrite_str(remote_fd, line); - xwrite(remote_fd, "\r\n", 2); + len = strlen(line); + if (len != 0) /* paranoia check */ + line[len - 1] = '\r'; + line[len] = '\n'; + xwrite(remote_fd, line, len + 1); free(line); } } -- cgit v1.2.3-55-g6feb From 5f8daefb835687e428215f90d26fdf1f0206149d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 26 Jun 2014 16:40:28 +0200 Subject: awk: fix handling of "if ... break ; else ..." - closes 7226 Signed-off-by: Denys Vlasenko --- editors/awk.c | 2 ++ testsuite/awk.tests | 16 ++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/editors/awk.c b/editors/awk.c index d0e3781e7..f487163af 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -1540,12 +1540,14 @@ static void chain_group(void) debug_printf_parse("%s: OC_BREAK\n", __func__); n = chain_node(OC_EXEC); n->a.n = break_ptr; + chain_expr(t_info); break; case OC_CONTINUE: debug_printf_parse("%s: OC_CONTINUE\n", __func__); n = chain_node(OC_EXEC); n->a.n = continue_ptr; + chain_expr(t_info); break; /* delete, next, nextfile, return, exit */ diff --git a/testsuite/awk.tests b/testsuite/awk.tests index 132afc6a9..9e6952ffd 100755 --- a/testsuite/awk.tests +++ b/testsuite/awk.tests @@ -295,6 +295,22 @@ testing "awk -e and ARGC" \ "" SKIP= +# The examples are in fact not valid awk programs (break/continue +# can only be used inside loops). +# But we do accept them outside of loops. +# We had a bug with misparsing "break ; else" sequence. +# Test that *that* bug is fixed, using simplest possible scripts: +testing "awk break" \ + "awk -f - 2>&1; echo \$?" \ + "0\n" \ + "" \ + 'BEGIN { if (1) break; else a = 1 }' +testing "awk continue" \ + "awk -f - 2>&1; echo \$?" \ + "0\n" \ + "" \ + 'BEGIN { if (1) continue; else a = 1 }' + # testing "description" "command" "result" "infile" "stdin" exit $FAILCOUNT -- cgit v1.2.3-55-g6feb From a6ae999b3b30ad522272325bac4c69b153150108 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 27 Jun 2014 12:24:39 +0200 Subject: ftpd: escape chroot prior to re-executing ls helper When we merely chdir to saved "real" root fd, exec("proc/self/exe") works for static executables but not for dynamic ones (they can't find their interpreter). With this patch, we also *chroot* to real root. As a bonus, this gives us proper usernames, timezone conversion etc. function old new delta popen_ls 203 259 +56 ftpd_main 2362 2366 +4 Signed-off-by: Denys Vlasenko --- networking/ftpd.c | 53 +++++++++++++++++++++-------------------------------- 1 file changed, 21 insertions(+), 32 deletions(-) diff --git a/networking/ftpd.c b/networking/ftpd.c index e724734df..839a85d73 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c @@ -620,16 +620,12 @@ popen_ls(const char *opt) const char *argv[5]; struct fd_pair outfd; pid_t pid; - +#if !BB_MMU + int cur_fd = xopen(".", O_RDONLY | O_DIRECTORY); +#endif argv[0] = "ftpd"; argv[1] = opt; /* "-l" or "-1" */ -#if BB_MMU argv[2] = "--"; -#else - /* NOMMU ftpd ls helper chdirs to argv[2], - * preventing peer from seeing real root. */ - argv[2] = xrealloc_getcwd_or_warn(NULL); -#endif argv[3] = G.ftp_arg; argv[4] = NULL; @@ -651,16 +647,6 @@ popen_ls(const char *opt) pid = BB_MMU ? xfork() : xvfork(); if (pid == 0) { /* child */ -#if !BB_MMU - /* On NOMMU, we want to execute a child - copy of ourself. - * In chroot we usually can't do it. Thus we chdir - * out of the chroot back to original root, - * and (see later below) execute bb_busybox_exec_path - * relative to current directory */ - if (fchdir(G.root_fd) != 0) - _exit(127); - /*close(G.root_fd); - close_on_exec_on() took care of this */ -#endif /* NB: close _first_, then move fd! */ close(outfd.rd); xmove_fd(outfd.wr, STDOUT_FILENO); @@ -674,19 +660,25 @@ popen_ls(const char *opt) /* memset(&G, 0, sizeof(G)); - ls_main does it */ exit(ls_main(ARRAY_SIZE(argv) - 1, (char**) argv)); #else - /* + 1: we must use relative path here if in chroot. - * For example, execv("/proc/self/exe") will fail, since - * it looks for "/proc/self/exe" _relative to chroot!_ */ - execv(bb_busybox_exec_path + 1, (char**) argv); + /* On NOMMU, we want to execute a child - copy of ourself + * in order to unblock parent after vfork. + * In chroot we usually can't re-exec. Thus we escape + * out of the chroot back to original root. + */ + if (G.root_fd >= 0) { + if (fchdir(G.root_fd) != 0 || chroot(".") != 0) + _exit(127); + /*close(G.root_fd); - close_on_exec_on() took care of this */ + } + /* Child expects directory to list on fd #3 */ + xmove_fd(cur_fd, 3); + execv(bb_busybox_exec_path, (char**) argv); _exit(127); #endif } /* parent */ close(outfd.wr); -#if !BB_MMU - free((char*)argv[2]); -#endif return outfd.rd; } @@ -705,8 +697,6 @@ handle_dir_common(int opts) if (!(opts & USE_CTRL_CONN) && !port_or_pasv_was_seen()) return; /* port_or_pasv_was_seen emitted error response */ - /* -n prevents user/groupname display, - * which can be problematic in chroot */ ls_fd = popen_ls((opts & LONG_LISTING) ? "-l" : "-1"); ls_fp = xfdopen_for_read(ls_fd); /* FIXME: filenames with embedded newlines are mishandled */ @@ -1139,11 +1129,10 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) opts = getopt32(argv, "l1vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose, &verbose_S); if (opts & (OPT_l|OPT_1)) { /* Our secret backdoor to ls */ -/* TODO: pass -n? It prevents user/group resolution, which may not work in chroot anyway */ /* TODO: pass -A? It shows dot files */ /* TODO: pass --group-directories-first? would be nice, but ls doesn't do that yet */ - xchdir(argv[2]); - argv[2] = (char*)"--"; + if (fchdir(3) != 0) + _exit(127); /* memset(&G, 0, sizeof(G)); - ls_main does it */ return ls_main(argc, argv); } @@ -1185,9 +1174,9 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY); close_on_exec_on(G.root_fd); #endif - - if (argv[optind]) { - xchroot(argv[optind]); + argv += optind; + if (argv[0]) { + xchroot(argv[0]); } //umask(077); - admin can set umask before starting us -- cgit v1.2.3-55-g6feb From 27c290f7f29fc57385d53893bfd7301db4708e9c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 27 Jun 2014 12:37:00 +0200 Subject: ftpd: for LIST, open current directory *in the child* Last change introduced an open fd leak. This is the fix. Signed-off-by: Denys Vlasenko --- networking/ftpd.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/networking/ftpd.c b/networking/ftpd.c index 839a85d73..e7cf5f431 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c @@ -620,9 +620,7 @@ popen_ls(const char *opt) const char *argv[5]; struct fd_pair outfd; pid_t pid; -#if !BB_MMU - int cur_fd = xopen(".", O_RDONLY | O_DIRECTORY); -#endif + argv[0] = "ftpd"; argv[1] = opt; /* "-l" or "-1" */ argv[2] = "--"; @@ -646,6 +644,9 @@ popen_ls(const char *opt) /*fflush_all(); - so far we dont use stdio on output */ pid = BB_MMU ? xfork() : xvfork(); if (pid == 0) { +#if !BB_MMU + int cur_fd; +#endif /* child */ /* NB: close _first_, then move fd! */ close(outfd.rd); @@ -660,6 +661,7 @@ popen_ls(const char *opt) /* memset(&G, 0, sizeof(G)); - ls_main does it */ exit(ls_main(ARRAY_SIZE(argv) - 1, (char**) argv)); #else + cur_fd = xopen(".", O_RDONLY | O_DIRECTORY); /* On NOMMU, we want to execute a child - copy of ourself * in order to unblock parent after vfork. * In chroot we usually can't re-exec. Thus we escape -- cgit v1.2.3-55-g6feb From 9d7cbdeee3545d36db201a2d822cd2bd10074add Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 27 Jun 2014 13:53:35 +0200 Subject: ftpd: do not use root_fd if we are not in chroot Signed-off-by: Denys Vlasenko --- networking/ftpd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/networking/ftpd.c b/networking/ftpd.c index e7cf5f431..2d2a3a44c 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c @@ -1173,11 +1173,14 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) applet_name = xasprintf("%s[%u]", applet_name, (int)getpid()); #if !BB_MMU - G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY); - close_on_exec_on(G.root_fd); + G.root_fd = -1; #endif argv += optind; if (argv[0]) { +#if !BB_MMU + G.root_fd = xopen("/", O_RDONLY | O_DIRECTORY); + close_on_exec_on(G.root_fd); +#endif xchroot(argv[0]); } -- cgit v1.2.3-55-g6feb From 1b487ea8a69ac90b530e9ccd161a5b1b21e604c7 Mon Sep 17 00:00:00 2001 From: Michael Gernoth Date: Fri, 27 Jun 2014 14:08:29 +0200 Subject: stat: fix printing selinux context and null-dereference busybox stat tries to always print the selinux context, even if it is not requested which leads to a segmentation fault due to dereferencing a null-pointer. This also changes the format-string used to print the context to so it actually produces useful output. Signed-off-by: Michael Gernoth Signed-off-by: Denys Vlasenko --- coreutils/stat.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/coreutils/stat.c b/coreutils/stat.c index dc9d81c35..769fac078 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c @@ -655,7 +655,7 @@ static bool do_stat(const char *filename, const char *format) ); # if ENABLE_SELINUX if (option_mask32 & OPT_SELINUX) - printf(" %lc\n", *scontext); + printf(" %s\n", scontext); else bb_putchar('\n'); # endif @@ -700,7 +700,8 @@ static bool do_stat(const char *filename, const char *format) (unsigned long) statbuf.st_gid, (gw_ent != NULL) ? gw_ent->gr_name : "UNKNOWN"); # if ENABLE_SELINUX - printf(" S_Context: %lc\n", *scontext); + if (option_mask32 & OPT_SELINUX) + printf(" S_Context: %s\n", scontext); # endif printf("Access: %s\n", human_time(statbuf.st_atime)); printf("Modify: %s\n", human_time(statbuf.st_mtime)); -- cgit v1.2.3-55-g6feb From a9dc7c2f59dc5e92870d2d46316ea5c1f14740e3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 30 Jun 2014 10:14:34 +0200 Subject: lzop: add overflow check See CVE-2014-4607 http://www.openwall.com/lists/oss-security/2014/06/26/20 function old new delta lzo1x_decompress_safe 1010 1031 +21 Signed-off-by: Denys Vlasenko --- archival/libarchive/liblzo.h | 2 ++ archival/libarchive/lzo1x_d.c | 3 +++ 2 files changed, 5 insertions(+) diff --git a/archival/libarchive/liblzo.h b/archival/libarchive/liblzo.h index 843997cb9..4596620fe 100644 --- a/archival/libarchive/liblzo.h +++ b/archival/libarchive/liblzo.h @@ -76,11 +76,13 @@ # define TEST_IP (ip < ip_end) # define NEED_IP(x) \ if ((unsigned)(ip_end - ip) < (unsigned)(x)) goto input_overrun +# define TEST_IV(x) if ((x) > (unsigned)0 - (511)) goto input_overrun # undef TEST_OP /* don't need both of the tests here */ # define TEST_OP 1 # define NEED_OP(x) \ if ((unsigned)(op_end - op) < (unsigned)(x)) goto output_overrun +# define TEST_OV(x) if ((x) > (unsigned)0 - (511)) goto output_overrun #define HAVE_ANY_OP 1 diff --git a/archival/libarchive/lzo1x_d.c b/archival/libarchive/lzo1x_d.c index 9bc1270da..40b167e68 100644 --- a/archival/libarchive/lzo1x_d.c +++ b/archival/libarchive/lzo1x_d.c @@ -92,6 +92,7 @@ int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len, ip++; NEED_IP(1); } + TEST_IV(t); t += 15 + *ip++; } /* copy literals */ @@ -224,6 +225,7 @@ int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len, ip++; NEED_IP(1); } + TEST_IV(t); t += 31 + *ip++; } #if defined(COPY_DICT) @@ -265,6 +267,7 @@ int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len, ip++; NEED_IP(1); } + TEST_IV(t); t += 7 + *ip++; } #if defined(COPY_DICT) -- cgit v1.2.3-55-g6feb From d3633b7e9c5dae78343a8552f54b0efa61074380 Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Mon, 30 Jun 2014 13:06:39 +0200 Subject: fatattr: new applet function old new delta fatattr_main - 281 +281 packed_usage 29821 29871 +50 bit_to_char - 10 +10 applet_names 2472 2480 +8 applet_main 1436 1440 +4 applet_nameofs 718 720 +2 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 4/0 up/down: 355/0) Total: 355 bytes Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- util-linux/fatattr.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 util-linux/fatattr.c diff --git a/util-linux/fatattr.c b/util-linux/fatattr.c new file mode 100644 index 000000000..0f8d63268 --- /dev/null +++ b/util-linux/fatattr.c @@ -0,0 +1,104 @@ +/* vi: set sw=4 ts=4: */ +/* + * Display or change file attributes on a fat file system + * + * Copyright 2005 H. Peter Anvin + * Busybox'ed (2014) by Pascal Bellard + * + * This file can be redistributed under the terms of the GNU General + * Public License + */ +//config:config FATATTR +//config: bool "fatattr" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: fatattr lists or changes the file attributes on a fat file system. + +//applet:IF_FATATTR(APPLET(fatattr, BB_DIR_BIN, BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_FATATTR) += fatattr.o + +//usage:#define fatattr_trivial_usage +//usage: "[-+rhsvda] FILE..." +//usage:#define fatattr_full_usage "\n\n" +//usage: "Change file attributes on FAT filesystem\n" +//usage: "\n - Clear attributes" +//usage: "\n + Set attributes" +//usage: "\n r Read only" +//usage: "\n h Hidden" +//usage: "\n s System" +//usage: "\n v Volume label" +//usage: "\n d Directory" +//usage: "\n a Archive" + +#include "libbb.h" +/* linux/msdos_fs.h says: */ +#ifndef FAT_IOCTL_GET_ATTRIBUTES +# define FAT_IOCTL_GET_ATTRIBUTES _IOR('r', 0x10, __u32) +# define FAT_IOCTL_SET_ATTRIBUTES _IOW('r', 0x11, __u32) +#endif + +/* Currently supports only the FAT flags, not the NTFS ones. + * Extra space at the end is a hack to print space separator in file listing. + * Let's hope no one ever passes space as an option char :) + */ +static const char bit_to_char[] = "rhsvda67 "; + +static inline unsigned long get_flag(char c) +{ + const char *fp = strchr(bit_to_char, c); + if (!fp) + bb_error_msg_and_die("invalid character '%c'", c); + return 1 << (fp - bit_to_char); +} + +static unsigned decode_arg(const char *arg) +{ + unsigned fl = 0; + while (*++arg) + fl |= get_flag(*arg); + return fl; +} + +int fatattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int fatattr_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned set_mask = 0; + unsigned clear_mask = 0; + + for (;;) { + unsigned fl; + char *arg = *++argv; + + if (!arg) + bb_show_usage(); + if (arg[0] != '-' && arg[0] != '+') + break; + fl = decode_arg(arg); + if (arg[0] == '+') + set_mask |= fl; + else + clear_mask |= fl; + } + + do { + int fd, i; + uint32_t attr; + + fd = xopen(*argv, O_RDONLY); + xioctl(fd, FAT_IOCTL_GET_ATTRIBUTES, &attr); + attr = (attr | set_mask) & ~clear_mask; + if (set_mask | clear_mask) + xioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr); + else { + for (i = 0; bit_to_char[i]; i++) { + bb_putchar((attr & 1) ? bit_to_char[i] : ' '); + attr >>= 1; + } + puts(*argv); + } + close(fd); + } while (*++argv); + + return EXIT_SUCCESS; +} -- cgit v1.2.3-55-g6feb From bf0f2c7aa6ab5c33c05b4620a6bfa286bd38c9f9 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Thu, 26 Jun 2014 14:31:05 +0200 Subject: Rename INIT_LAST to INIT_FUNC to avoid confusion We don't have an INIT_FIRST, so let's rename INIT_LAST to INIT_FUNC to imply that the function is called at program start-up. Also: the priority argument for __attribute__((constructor)) isn't used, so let's remove it. Signed-off-by: Bartosz Golaszewski Signed-off-by: Denys Vlasenko --- include/libbb.h | 2 +- include/platform.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index cede50cc2..858084bc5 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1960,7 +1960,7 @@ void bbunit_settestfailed(void); .name = #NAME, \ .testfunc = bbunit_##NAME##_test, \ }; \ - static void INIT_LAST bbunit_##NAME##_register(void) \ + static void INIT_FUNC bbunit_##NAME##_register(void) \ { \ bbunit_registertest(&bbunit_##NAME##_elem); \ } \ diff --git a/include/platform.h b/include/platform.h index 413c2224c..09c7ccd9c 100644 --- a/include/platform.h +++ b/include/platform.h @@ -76,8 +76,8 @@ # define UNUSED_PARAM_RESULT #endif -/* used by unit test machinery to run registration functions */ -#define INIT_LAST __attribute__ ((constructor(2000))) +/* used by unit test machinery to run registration functions before calling main() */ +#define INIT_FUNC __attribute__ ((constructor)) /* -fwhole-program makes all symbols local. The attribute externally_visible * forces a symbol global. */ -- cgit v1.2.3-55-g6feb From 184b2669175e562d58894e22f6320cebf3316c25 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 30 Jun 2014 17:19:17 +0200 Subject: cpio: reinstate "options:" line in help text Otherwise, help text is confusing: where do operation modes end and where options start? Signed-off-by: Denys Vlasenko --- archival/cpio.c | 1 + 1 file changed, 1 insertion(+) diff --git a/archival/cpio.c b/archival/cpio.c index 1cce7c8b4..454648d68 100644 --- a/archival/cpio.c +++ b/archival/cpio.c @@ -65,6 +65,7 @@ //usage: IF_FEATURE_CPIO_P( //usage: "\n -p DIR Copy files to DIR" //usage: ) +//usage: "\nOptions:" //usage: "\n -d Make leading directories" //usage: "\n -m Preserve mtime" //usage: "\n -v Verbose" -- cgit v1.2.3-55-g6feb