From eb08b6ed5cc7bb764658cd7a3b829e2b3aac4abc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 19 Jun 2010 17:51:06 +0200 Subject: sed: trivial code shrink -18 bytes Signed-off-by: Denys Vlasenko --- editors/sed.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/editors/sed.c b/editors/sed.c index 28f0c7318..7af8f867a 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -1333,7 +1333,6 @@ int sed_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_in_place) bb_error_msg_and_die(bb_msg_requires_arg, "-i"); add_input_file(stdin); - process_files(); } else { int i; FILE *file; @@ -1379,9 +1378,13 @@ int sed_main(int argc UNUSED_PARAM, char **argv) free(G.outname); G.outname = NULL; } - if (G.input_file_count > G.current_input_file) - process_files(); + /* Here, to handle "sed 'cmds' nonexistent_file" case we did: + * if (G.current_input_file >= G.input_file_count) + * return status; + * but it's not needed since process_files() works correctly + * in this case too. */ } + process_files(); return status; } -- cgit v1.2.3-55-g6feb From fdd7b566ecdc174907f38d9389b28ba842d2b4bf Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Fri, 18 Jun 2010 22:37:42 -0700 Subject: A few minor portability improvements Signed-off-by: Dan Fandrich Signed-off-by: Denys Vlasenko --- archival/libunarchive/unxz/xz_config.h | 2 ++ include/platform.h | 4 ++-- libbb/xconnect.c | 1 + networking/ipcalc.c | 4 ++-- shell/hush.c | 2 +- 5 files changed, 8 insertions(+), 5 deletions(-) diff --git a/archival/libunarchive/unxz/xz_config.h b/archival/libunarchive/unxz/xz_config.h index ff90eff26..a4141e136 100644 --- a/archival/libunarchive/unxz/xz_config.h +++ b/archival/libunarchive/unxz/xz_config.h @@ -32,7 +32,9 @@ #define memeq(a, b, size) (memcmp(a, b, size) == 0) #define memzero(buf, size) memset(buf, 0, size) +#ifndef min #define min(x, y) ((x) < (y) ? (x) : (y)) +#endif #define min_t(type, x, y) min(x, y) /* diff --git a/include/platform.h b/include/platform.h index f87add552..4bd7a3d2e 100644 --- a/include/platform.h +++ b/include/platform.h @@ -168,10 +168,10 @@ #if defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ # define BB_BIG_ENDIAN 1 # define BB_LITTLE_ENDIAN 0 -#elif __BYTE_ORDER == __BIG_ENDIAN +#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN # define BB_BIG_ENDIAN 1 # define BB_LITTLE_ENDIAN 0 -#elif __BYTE_ORDER == __LITTLE_ENDIAN +#elif (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || defined(__386__) # define BB_BIG_ENDIAN 0 # define BB_LITTLE_ENDIAN 1 #else diff --git a/libbb/xconnect.c b/libbb/xconnect.c index c3ee633e4..2de6de7c5 100644 --- a/libbb/xconnect.c +++ b/libbb/xconnect.c @@ -7,6 +7,7 @@ * Licensed under GPLv2, see file LICENSE in this tarball for details. */ +#include #include /* netinet/in.h needs it */ #include #include diff --git a/networking/ipcalc.c b/networking/ipcalc.c index 17b216354..87f31fdb5 100644 --- a/networking/ipcalc.c +++ b/networking/ipcalc.c @@ -12,11 +12,11 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ +#include "libbb.h" + #include #include -#include "libbb.h" - #define CLASS_A_NETMASK ntohl(0xFF000000) #define CLASS_B_NETMASK ntohl(0xFFFF0000) #define CLASS_C_NETMASK ntohl(0xFFFFFF00) diff --git a/shell/hush.c b/shell/hush.c index 4832e2c48..e64c923b4 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1217,7 +1217,7 @@ static void hush_exit(int exitcode) static int check_and_run_traps(int sig) { - static const struct timespec zero_timespec = { 0, 0 }; + static const struct timespec zero_timespec; smalluint save_rcode; int last_sig = 0; -- cgit v1.2.3-55-g6feb From 0635ddd8f7bbd8ed40ef4e5e01ff116ee959fa34 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Fri, 18 Jun 2010 22:36:45 -0700 Subject: Added code for nonstandard function strsep() Signed-off-by: Dan Fandrich Signed-off-by: Denys Vlasenko --- include/platform.h | 6 ++++++ libbb/platform.c | 27 +++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/include/platform.h b/include/platform.h index 4bd7a3d2e..0dadf42bd 100644 --- a/include/platform.h +++ b/include/platform.h @@ -16,6 +16,7 @@ #define HAVE_SETBIT 1 #define HAVE_STRCASESTR 1 #define HAVE_STRCHRNUL 1 +#define HAVE_STRSEP 1 #define HAVE_STRSIGNAL 1 #define HAVE_VASPRINTF 1 @@ -353,6 +354,7 @@ typedef unsigned smalluint; # undef HAVE_SETBIT # undef HAVE_STRCASESTR # undef HAVE_STRCHRNUL +# undef HAVE_STRSEP # undef HAVE_STRSIGNAL # undef HAVE_VASPRINTF #endif @@ -391,6 +393,10 @@ extern char *strcasestr(const char *s, const char *pattern) FAST_FUNC; extern char *strchrnul(const char *s, int c) FAST_FUNC; #endif +#ifndef HAVE_STRSEP +extern char *strsep(char **stringp, const char *delim) FAST_FUNC; +#endif + #ifndef HAVE_STRSIGNAL /* Not exactly the same: instead of "Stopped" it shows "STOP" etc */ # define strsignal(sig) get_signame(sig) diff --git a/libbb/platform.c b/libbb/platform.c index 17ad3f75a..7a8b17657 100644 --- a/libbb/platform.c +++ b/libbb/platform.c @@ -107,3 +107,30 @@ char* FAST_FUNC strcasestr(const char *s, const char *pattern) return 0; } #endif + +#ifndef HAVE_STRSEP +/* Copyright (C) 2004 Free Software Foundation, Inc. */ +char* FAST_FUNC strsep(char **stringp, const char *delim) +{ + char *start = *stringp; + char *ptr; + + if (!start) + return NULL; + + if (!*delim) + ptr = start + strlen(start); + else { + ptr = strpbrk(start, delim); + if (!ptr) { + *stringp = NULL; + return start; + } + } + + *ptr = '\0'; + *stringp = ptr + 1; + + return start; +} +#endif -- cgit v1.2.3-55-g6feb From ebeac1685a6230abcf73ca36755e3bb208bfd569 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Fri, 18 Jun 2010 22:36:10 -0700 Subject: Define GNU-specific link options in one place This makes them easier to change to support a non-GNU toolchain. Signed-off-by: Dan Fandrich Signed-off-by: Denys Vlasenko --- scripts/trylink | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/scripts/trylink b/scripts/trylink index 164f5274c..021374aa9 100755 --- a/scripts/trylink +++ b/scripts/trylink @@ -85,6 +85,11 @@ LDLIBS="$7" # The --sort-section option is not supported by older versions of ld SORT_SECTION=`check_cc "-Wl,--sort-section,alignment" ""` +START_GROUP="-Wl,--start-group" +END_GROUP="-Wl,--end-group" + +INFO_OPTS="-Wl,--warn-common -Wl,-Map,$EXE.map -Wl,--verbose" + # gold may not support --sort-common (yet) SORT_COMMON=`check_cc "-Wl,--sort-common" ""` @@ -114,13 +119,13 @@ LDLIBS=`echo "$LDLIBS" | xargs -n1 | sort | uniq | xargs` echo "Trying libraries: $LDLIBS" # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` -test "x$l_list" != "x" && l_list="-Wl,--start-group $l_list -Wl,--end-group" +test "x$l_list" != "x" && l_list="$START_GROUP $l_list $END_GROUP" try $CC $CFLAGS $LDFLAGS \ -o $EXE \ $SORT_COMMON \ $SORT_SECTION \ $GC_SECTIONS \ - -Wl,--start-group $O_FILES $A_FILES -Wl,--end-group \ + $START_GROUP $O_FILES $A_FILES $END_GROUP \ $l_list \ || { echo "Failed: $l_list" @@ -138,14 +143,14 @@ while test "$LDLIBS"; do without_one=`echo " $LDLIBS " | sed "s/ $one / /g" | xargs` # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" l_list=`echo "$without_one" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` - test x"$l_list" != x"" && l_list="-Wl,--start-group $l_list -Wl,--end-group" + test x"$l_list" != x"" && l_list="$START_GROUP $l_list $END_GROUP" $debug && echo "Trying -l options: '$l_list'" try $CC $CFLAGS $LDFLAGS \ -o $EXE \ $SORT_COMMON \ $SORT_SECTION \ $GC_SECTIONS \ - -Wl,--start-group $O_FILES $A_FILES -Wl,--end-group \ + $START_GROUP $O_FILES $A_FILES $END_GROUP \ $l_list if test $? = 0; then echo " Library $one is not needed, excluding it" @@ -169,7 +174,7 @@ done # Make the binary with final, minimal list of libs echo "Final link with: ${LDLIBS:-}" l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` -test "x$l_list" != "x" && l_list="-Wl,--start-group $l_list -Wl,--end-group" +test "x$l_list" != "x" && l_list="$START_GROUP $l_list $END_GROUP" # --verbose gives us gobs of info to stdout (e.g. linker script used) if ! test -f busybox_ldscript; then try $CC $CFLAGS $LDFLAGS \ @@ -177,11 +182,9 @@ if ! test -f busybox_ldscript; then $SORT_COMMON \ $SORT_SECTION \ $GC_SECTIONS \ - -Wl,--start-group $O_FILES $A_FILES -Wl,--end-group \ + $START_GROUP $O_FILES $A_FILES $END_GROUP \ $l_list \ - -Wl,--warn-common \ - -Wl,-Map,$EXE.map \ - -Wl,--verbose \ + $INFO_OPTS \ || { cat $EXE.out exit 1 @@ -200,11 +203,9 @@ else $SORT_SECTION \ $GC_SECTIONS \ -Wl,-T,busybox_ldscript \ - -Wl,--start-group $O_FILES $A_FILES -Wl,--end-group \ + $START_GROUP $O_FILES $A_FILES $END_GROUP \ $l_list \ - -Wl,--warn-common \ - -Wl,-Map,$EXE.map \ - -Wl,--verbose \ + $INFO_OPTS \ || { cat $EXE.out exit 1 @@ -233,11 +234,9 @@ if test "$CONFIG_BUILD_LIBBUSYBOX" = y; then -Wl,--undefined=lbb_main \ $SORT_COMMON \ $SORT_SECTION \ - -Wl,--start-group $A_FILES -Wl,--end-group \ + $START_GROUP $A_FILES $END_GROUP \ $l_list \ - -Wl,--warn-common \ - -Wl,-Map,$EXE.map \ - -Wl,--verbose \ + $INFO_OPTS \ || { echo "Linking $EXE failed" cat $EXE.out @@ -255,11 +254,9 @@ if test "$CONFIG_FEATURE_SHARED_BUSYBOX" = y; then $SORT_COMMON \ $SORT_SECTION \ $GC_SECTIONS \ - -Wl,--start-group $O_FILES -Wl,--end-group \ + $START_GROUP $O_FILES $END_GROUP \ -L"$sharedlib_dir" -lbusybox \ - -Wl,--warn-common \ - -Wl,-Map,$EXE.map \ - -Wl,--verbose \ + $INFO_OPTS \ || { echo "Linking $EXE failed" cat $EXE.out -- cgit v1.2.3-55-g6feb From 134d0eb114ac67693eb62bb030dd537eca71c48d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 19 Jun 2010 20:07:23 +0200 Subject: cosmetics on top of Dan's patches Signed-off-by: Denys Vlasenko --- archival/libunarchive/unxz/xz_config.h | 4 ++-- networking/ipcalc.c | 4 +--- scripts/trylink | 1 - 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/archival/libunarchive/unxz/xz_config.h b/archival/libunarchive/unxz/xz_config.h index a4141e136..187e1cbed 100644 --- a/archival/libunarchive/unxz/xz_config.h +++ b/archival/libunarchive/unxz/xz_config.h @@ -32,9 +32,9 @@ #define memeq(a, b, size) (memcmp(a, b, size) == 0) #define memzero(buf, size) memset(buf, 0, size) -#ifndef min +#undef min +#undef min_t #define min(x, y) ((x) < (y) ? (x) : (y)) -#endif #define min_t(type, x, y) min(x, y) /* diff --git a/networking/ipcalc.c b/networking/ipcalc.c index 87f31fdb5..265009ad8 100644 --- a/networking/ipcalc.c +++ b/networking/ipcalc.c @@ -11,10 +11,8 @@ * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include "libbb.h" - -#include +/* After libbb.h, because on some systems it needs other includes */ #include #define CLASS_A_NETMASK ntohl(0xFF000000) diff --git a/scripts/trylink b/scripts/trylink index 021374aa9..5994a757b 100755 --- a/scripts/trylink +++ b/scripts/trylink @@ -87,7 +87,6 @@ SORT_SECTION=`check_cc "-Wl,--sort-section,alignment" ""` START_GROUP="-Wl,--start-group" END_GROUP="-Wl,--end-group" - INFO_OPTS="-Wl,--warn-common -Wl,-Map,$EXE.map -Wl,--verbose" # gold may not support --sort-common (yet) -- cgit v1.2.3-55-g6feb From e15a6c82dff9f85cfb2ee5ff32b00cbd722c7d92 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 19 Jun 2010 20:42:02 +0200 Subject: added Config.in to .gitignore Signed-off-by: Denys Vlasenko --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 53bd540a2..7d2cca67c 100644 --- a/.gitignore +++ b/.gitignore @@ -7,6 +7,7 @@ *.a *.s Kbuild +Config.in # # Never ignore these -- cgit v1.2.3-55-g6feb From 4a96617095f40e3cfcf148a8a7d5d83f71079aa1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 19 Jun 2010 21:44:01 +0200 Subject: xargs: bump default -sNUM up to 32k. Use sysconf() to trim it down if necessary function old new delta xargs_main 819 830 +11 Signed-off-by: Denys Vlasenko --- findutils/xargs.c | 52 +++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/findutils/xargs.c b/findutils/xargs.c index 46a62cbf1..7b9f1fb73 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c @@ -59,14 +59,6 @@ //config: are not special. #include "libbb.h" -/* COMPAT: SYSV version defaults size (and has a max value of) to 470. - We try to make it as large as possible. */ -#if !defined(ARG_MAX) && defined(_SC_ARG_MAX) -# define ARG_MAX sysconf(_SC_ARG_MAX) -#endif -#if !defined(ARG_MAX) -# define ARG_MAX 470 -#endif /* This is a NOEXEC applet. Be very careful! */ @@ -440,35 +432,43 @@ int xargs_main(int argc, char **argv) argc++; } - /* The Open Group Base Specifications Issue 6: + /* -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 * and environment lists (see the exec family of functions * in the System Interfaces volume of IEEE Std 1003.1-2001) * shall not exceed {ARG_MAX}-2048 bytes". */ - n_max_chars = ARG_MAX; /* might be calling sysconf(_SC_ARG_MAX) */ - if (n_max_chars < 4*1024); /* paranoia */ - n_max_chars = 4*1024; - n_max_chars -= 2048; - /* Sanity check for systems with huge ARG_MAX defines (e.g., Suns which - * have it at 1 meg). Things will work fine with a large ARG_MAX - * but it will probably hurt the system more than it needs to; - * an array of this size is allocated. - */ - if (n_max_chars > 20 * 1024) - n_max_chars = 20 * 1024; - + { + 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; + } if (opt & OPT_UPTO_SIZE) { - size_t n_chars = 0; n_max_chars = xatou_range(max_chars, 1, INT_MAX); + } + /* Account for prepended fixed arguments */ + { + size_t n_chars = 0; for (i = 0; argv[i]; i++) { n_chars += strlen(argv[i]) + 1; } n_max_chars -= n_chars; - if (n_max_chars <= 0) { - bb_error_msg_and_die("can't fit single argument within argument list size limit"); - } + } + /* Sanity check */ + if (n_max_chars <= 0) { + bb_error_msg_and_die("can't fit single argument within argument list size limit"); } buf = xzalloc(n_max_chars + 1); @@ -476,6 +476,8 @@ int xargs_main(int argc, char **argv) n_max_arg = n_max_chars; if (opt & OPT_UPTO_NUMBER) { n_max_arg = xatou_range(max_args, 1, INT_MAX); + /* Not necessary, we use growable args[]: */ + /* if (n_max_arg > n_max_chars) n_max_arg = n_max_chars */ } /* Allocate pointers for execvp */ -- cgit v1.2.3-55-g6feb From 91d7ee31f766a13595c1042d375f8374f2c3675f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 19 Jun 2010 22:15:20 +0200 Subject: tweak TODO file Signed-off-by: Denys Vlasenko --- TODO | 118 ++++++------------------------------------------------------------- 1 file changed, 10 insertions(+), 108 deletions(-) diff --git a/TODO b/TODO index af4c467c2..6f8cd8a32 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,8 @@ Busybox TODO +Harvest patches from +http://git.openembedded.org/cgit.cgi/openembedded/tree/recipes/busybox/ + Stuff that needs to be done. This is organized by who plans to get around to doing it eventually, but that doesn't mean they "own" the item. If you want to do one of these bounce an email off the person it's listed under to see if they @@ -9,9 +12,6 @@ between your work and theirs. But otherwise, all of these are fair game. Rob Landley suggested this: Implement bb_realpath() that can handle NULL on non-glibc. - Remove obsolete _() wrapper crud for internationalization we don't do. - Figure out where we need utf8 support, and add it. - sh The command shell situation is a mess. We have two different shells that don't really share any code, and the "standalone shell" doesn't @@ -31,7 +31,7 @@ Rob Landley suggested this: How much internationalization should we do? The low hanging fruit is UTF-8 character set support. We should do this. - (Vodz pointed out the shell's cmdedit as needing work here. What else?) + See TODO_unicode file. We also have lots of hardwired english text messages. Consolidating this into some kind of message table not only makes translation easier, but @@ -59,6 +59,7 @@ Rob Landley suggested this: Turning libbb into a real dll is another possibility, especially if libbb could export some of the other library interfaces we've already more or less got the code for (like zlib). + buildroot - Make a "dogfood" option Busybox 1.1 will be capable of replacing most gnu packages for real world use, such as developing software or in a live CD. It needs wider testing. @@ -78,22 +79,25 @@ Rob Landley suggested this: One example of an existing system that does this already is Firmware Linux: http://www.landley.net/code/firmware + initramfs Busybox should have a sample initramfs build script. This depends on bbsh, mdev, and switch_root. + mkdep Write a mkdep that doesn't segfault if there's a directory it doesn't have permission to read, isn't based on manually editing the output of lexx and yacc, doesn't make such a mess under include/config, etc. + Group globals into unions of structures. Go through and turn all the global and static variables into structures, and have all those structures be in a big union shared between processes, so busybox uses less bss. (This is a big win on nommu machines.) See sed.c and mdev.c for examples. + Go through bugs.busybox.net and close out all of that somehow. This one's open to everybody, but I'll wind up doing it... - Bernhard Reutner-Fischer suggests to look at these: New debug options: -Wlarger-than-127 @@ -177,40 +181,6 @@ Memory Allocation call free might also be optimized out by the compiler if written right, so we can yank those #ifdefs too, and generally clean up the code. --- -Switch CONFIG_SYMBOLS to ENABLE_SYMBOLS - - In busybox 1.0 and earlier, configuration was done by CONFIG_SYMBOLS - that were either defined or undefined to indicate whether the symbol was - selected in the .config file. They were used with #ifdefs, ala: - - #ifdef CONFIG_SYMBOL - if (other_test) { - do_code(); - } - #endif - - In 1.1, we have new ENABLE_SYMBOLS which are always defined (as 0 or 1), - meaning you can still use them for preprocessor tests by replacing - "#ifdef CONFIG_SYMBOL" with "#if ENABLE_SYMBOL". But more importantly, we - can use them as a true or false test in normal C code: - - if (ENABLE_SYMBOL && other_test) { - do_code(); - } - - (Optimizing away if() statements that resolve to a constant value - is known as "dead code elimination", an optimization so old and simple that - Turbo Pascal for DOS did it twenty years ago. Even modern mini-compilers - like the Tiny C Compiler (tcc) and the Small Device C Compiler (SDCC) - perform dead code elimination.) - - Right now, busybox.h is #including both "config.h" (defining the - CONFIG_SYMBOLS) and "bb_config.h" (defining the ENABLE_SYMBOLS). At some - point in the future, it would be nice to wean ourselves off of the - CONFIG versions. (Among other things, some defective build environments - leak the Linux kernel's CONFIG_SYMBOLS into the system's standard #include - files. We've experienced collisions before.) ---- FEATURE_CLEAN_UP This is more an unresolved issue than a to-do item. More thought is needed. @@ -266,12 +236,7 @@ Minor stuff: --- unify progress_meter. wget, flash_eraseall, pipe_progress, fbsplash, setfiles. --- - support start-stop-daemon -d - -Code cleanup: - -Replace deprecated functions. - + support start-stop-daemon -d --- vdprintf() -> similar sized functionality --- @@ -296,8 +261,6 @@ vdprintf() -> similar sized functionality The first step would to generate a file/matrix what is already archived (also IPV6) -* ntpdate/ntpd (see ntpclient and openntp for examples) - * implement 'at' * rpcbind (former portmap) or equivalent @@ -311,64 +274,3 @@ vdprintf() -> similar sized functionality most likely there is more * even more support for statistics: mpstat, iostat, powertop.... - - -Unicode work needed: - -Unicode support uses libc multibyte functions if LOCALE_SUPPORT is on -(in this case, the code will also support many more encodings), -or uses a limited subset of re-implemented multibyte functions -which only understand "one byte == one char" and unicode. -This is useful if you build against uclibc with locale support disabled. - -Unicode-dependent applets must call check_unicode_in_env() when they -begin executing. - -Applet code may conditionalize on UNICODE_SUPPORT in order to use -more efficient code if unicode support is not requested. - -Available functions (if you need more, implement them in libbb/unicode.c -so that they work without LOCALE_SUPPORT too): - -int bb_mbstrlen(str) - multibyte-aware strlen -size_t mbstowcs(wdest, src, n) -size_t wcstombs(dest, wsrc, n) -size_t wcrtomb(str, wc, wstate) -int iswspace(wc) -int iswalnum(wc) -int iswpunct(wc) - -Applets which only need to align columns on screen correctly: - -ls - already done, use source as an example -df -dumpleases -lsmod - -Applets which need to account for Unicode chars -while processing the output: - -[un]expand -fold -man -watch -cut (-b and -c are currently the same, needs fixing) - -These applets need to ensure that unicode input -is handled correctly (say, sequence): - -getty, login -rm -i -unzip (overwrite prompt) - -Viewers/editors are more difficult (many cases to get right). -libbb/lineedit.c is an example how to do it: - -less, most, ed, vi -awk -[ef]grep -sed - -Probably needs some specialized work: - -loadkeys -- cgit v1.2.3-55-g6feb From ba73cfd28464f9ef926dfd27e264215d4c4f8b1f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 20 Jun 2010 02:40:56 +0200 Subject: unxz: update from XZ embedded git function old new delta rc_reset - 21 +21 unpack_xz_stream 2342 2357 +15 lzma_reset 102 64 -38 lzma_len 506 443 -63 xz_dec_lzma2_run 1438 1374 -64 xz_dec_reset 73 - -73 lzma_main 2517 2183 -334 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 1/4 up/down: 36/-572) Total: -536 bytes Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_unxz.c | 52 +++----- archival/libunarchive/unxz/xz.h | 139 +++++++++++++------- archival/libunarchive/unxz/xz_dec_lzma2.c | 200 ++++++++++++++++------------- archival/libunarchive/unxz/xz_dec_stream.c | 17 +-- archival/libunarchive/unxz/xz_private.h | 41 +++++- 5 files changed, 270 insertions(+), 179 deletions(-) diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c index 1302e29fb..800680fef 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libunarchive/decompress_unxz.c @@ -12,10 +12,11 @@ #include "libbb.h" #include "unarchive.h" -#define XZ_REALLOC_DICT_BUF(ptr, size) xrealloc(ptr, size) #define XZ_FUNC FAST_FUNC #define XZ_EXTERN static +#define XZ_DEC_DYNALLOC + /* Skip check (rather than fail) of unsupported hash functions */ #define XZ_DEC_ANY_CHECK 1 @@ -40,15 +41,9 @@ static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) #define put_unaligned_le32(val, buf) move_to_unaligned16(buf, SWAP_LE32(val)) #define put_unaligned_be32(val, buf) move_to_unaligned16(buf, SWAP_BE32(val)) -#include "unxz/xz.h" -#include "unxz/xz_config.h" - #include "unxz/xz_dec_bcj.c" #include "unxz/xz_dec_lzma2.c" #include "unxz/xz_dec_stream.c" -#include "unxz/xz_lzma2.h" -#include "unxz/xz_private.h" -#include "unxz/xz_stream.h" IF_DESKTOP(long long) int FAST_FUNC unpack_xz_stream(int src_fd, int dst_fd) @@ -57,63 +52,50 @@ unpack_xz_stream(int src_fd, int dst_fd) struct xz_dec *state; unsigned char *membuf; IF_DESKTOP(long long) int total = 0; - enum { - IN_SIZE = 4 * 1024, - OUT_SIZE = 60 * 1024, - }; if (!crc32_table) crc32_table = crc32_filltable(NULL, /*endian:*/ 0); - membuf = xmalloc(IN_SIZE + OUT_SIZE); + membuf = xmalloc(2 * BUFSIZ); memset(&iobuf, 0, sizeof(iobuf)); iobuf.in = membuf; - iobuf.out = membuf + IN_SIZE; - iobuf.out_size = OUT_SIZE; + iobuf.out = membuf + BUFSIZ; + iobuf.out_size = BUFSIZ; - state = xz_dec_init(64*1024); /* initial dict of 64k */ + /* Limit memory usage to about 64 MiB. */ + state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); while (1) { enum xz_ret r; - int insz, rd, outpos; - iobuf.in_size -= iobuf.in_pos; - insz = iobuf.in_size; - if (insz) - memmove(membuf, membuf + iobuf.in_pos, insz); - iobuf.in_pos = 0; - rd = IN_SIZE - insz; - if (rd) { - rd = safe_read(src_fd, membuf + insz, rd); + if (iobuf.in_pos == iobuf.in_size) { + int rd = safe_read(src_fd, membuf, BUFSIZ); if (rd < 0) { bb_error_msg(bb_msg_read_error); total = -1; break; } - iobuf.in_size = insz + rd; + iobuf.in_size = rd; + iobuf.in_pos = 0; } // bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", // iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); r = xz_dec_run(state, &iobuf); // bb_error_msg(" 0, the decoder is initialized to work in multi-call mode. - * dict_max number of bytes of memory is preallocated for the LZMA2 - * dictionary. This way there is no risk that xz_dec_run() could run out - * of memory, since xz_dec_run() will never allocate any memory. Instead, - * if the preallocated dictionary is too small for decoding the given input - * stream, xz_dec_run() will return XZ_MEMLIMIT_ERROR. Thus, it is important - * to know what kind of data will be decoded to avoid allocating excessive - * amount of memory for the dictionary. - * - * LZMA2 dictionary is always 2^n bytes or 2^n + 2^(n-1) bytes (the latter - * sizes are less common in practice). In the kernel, dictionary sizes of - * 64 KiB, 128 KiB, 256 KiB, 512 KiB, and 1 MiB are probably the only - * reasonable values. - * - * If dict_max == 0, the decoder is initialized to work in single-call mode. - * In single-call mode, xz_dec_run() decodes the whole stream at once. The - * caller must provide enough output space or the decoding will fail. The - * output space is used as the dictionary buffer, which is why there is - * no need to allocate the dictionary as part of the decoder's internal - * state. + * multi-call decoding. This is ignored in single-call mode + * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes + * or 2^n + 2^(n-1) bytes (the latter sizes are less common + * in practice), so other values for dict_max don't make sense. + * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB, + * 512 KiB, and 1 MiB are probably the only reasonable values, + * except for kernel and initramfs images where a bigger + * dictionary can be fine and useful. + * + * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at + * once. The caller must provide enough output space or the decoding will + * fail. The output space is used as the dictionary buffer, which is why + * there is no need to allocate the dictionary as part of the decoder's + * internal state. * * Because the output buffer is used as the workspace, streams encoded using - * a big dictionary are not a problem in single-call. It is enough that the - * output buffer is big enough to hold the actual uncompressed data; it + * a big dictionary are not a problem in single-call mode. It is enough that + * the output buffer is big enough to hold the actual uncompressed data; it * can be smaller than the dictionary size stored in the stream headers. * + * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes + * of memory is preallocated for the LZMA2 dictionary. This way there is no + * risk that xz_dec_run() could run out of memory, since xz_dec_run() will + * never allocate any memory. Instead, if the preallocated dictionary is too + * small for decoding the given input stream, xz_dec_run() will return + * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be + * decoded to avoid allocating excessive amount of memory for the dictionary. + * + * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC): + * dict_max specifies the maximum allowed dictionary size that xz_dec_run() + * may allocate once it has parsed the dictionary size from the stream + * headers. This way excessive allocations can be avoided while still + * limiting the maximum memory usage to a sane value to prevent running the + * system out of memory when decompressing streams from untrusted sources. + * * On success, xz_dec_init() returns a pointer to struct xz_dec, which is - * ready to be used with xz_dec_run(). On error, xz_dec_init() returns NULL. + * ready to be used with xz_dec_run(). If memory allocation fails, + * xz_dec_init() returns NULL. */ -XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(uint32_t dict_max); +XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( + enum xz_mode mode, uint32_t dict_max); /** * xz_dec_run() - Run the XZ decoder * @s: Decoder state allocated using xz_dec_init() * @b: Input and output buffers * - * In multi-call mode, this function may return any of the values listed in - * enum xz_ret. - * - * In single-call mode, this function never returns XZ_OK. If an error occurs - * in single-call mode (return value is not XZ_STREAM_END), b->in_pos and - * b->out_pos are not modified, and the contents of the output buffer from - * b->out[b->out_pos] onward are undefined. - * - * NOTE: In single-call mode, the contents of the output buffer are undefined - * also after XZ_BUF_ERROR. This is because with some filter chains, there - * may be a second pass over the output buffer, and this pass cannot be - * properly done if the output buffer is truncated. Thus, you cannot give - * the single-call decoder a too small buffer and then expect to get that - * amount valid data from the beginning of the stream. You must use the - * multi-call decoder if you don't want to uncompress the whole stream. + * The possible return values depend on build options and operation mode. + * See enum xz_ret for details. + * + * NOTE: If an error occurs in single-call mode (return value is not + * XZ_STREAM_END), b->in_pos and b->out_pos are not modified, and the + * contents of the output buffer from b->out[b->out_pos] onward are + * undefined. This is true even after XZ_BUF_ERROR, because with some filter + * chains, there may be a second pass over the output buffer, and this pass + * cannot be properly done if the output buffer is truncated. Thus, you + * cannot give the single-call decoder a too small buffer and then expect to + * get that amount valid data from the beginning of the stream. You must use + * the multi-call decoder if you don't want to uncompress the whole stream. */ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b); diff --git a/archival/libunarchive/unxz/xz_dec_lzma2.c b/archival/libunarchive/unxz/xz_dec_lzma2.c index 37de6fc32..da71cb4d4 100644 --- a/archival/libunarchive/unxz/xz_dec_lzma2.c +++ b/archival/libunarchive/unxz/xz_dec_lzma2.c @@ -34,7 +34,8 @@ * * In multi-call mode, also these are true: * end == size - * size <= allocated + * size <= size_max + * allocated <= size * * Most of these variables are size_t to support single-call mode, * in which the dictionary variables address the actual output @@ -74,11 +75,20 @@ struct dictionary { uint32_t size; /* - * Amount of memory allocated for the dictionary. A special - * value of zero indicates that we are in single-call mode, - * where the output buffer works as the dictionary. + * Maximum allowed dictionary size in multi-call mode. + * This is ignored in single-call mode. + */ + uint32_t size_max; + + /* + * Amount of memory currently allocated for the dictionary. + * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC, + * size_max is always the same as the allocated size.) */ uint32_t allocated; + + /* Operation mode */ + enum xz_mode mode; }; /* Range decoder */ @@ -120,31 +130,31 @@ struct lzma_len_dec { }; struct lzma_dec { - /* - * LZMA properties or related bit masks (number of literal - * context bits, a mask dervied from the number of literal - * position bits, and a mask dervied from the number - * position bits) - */ - uint32_t lc; - uint32_t literal_pos_mask; /* (1 << lp) - 1 */ - uint32_t pos_mask; /* (1 << pb) - 1 */ - - /* Types of the most recently seen LZMA symbols */ - enum lzma_state state; - /* Distances of latest four matches */ uint32_t rep0; uint32_t rep1; uint32_t rep2; uint32_t rep3; + /* Types of the most recently seen LZMA symbols */ + enum lzma_state state; + /* * Length of a match. This is updated so that dict_repeat can * be called again to finish repeating the whole match. */ uint32_t len; + /* + * LZMA properties or related bit masks (number of literal + * context bits, a mask dervied from the number of literal + * position bits, and a mask dervied from the number + * position bits) + */ + uint32_t lc; + uint32_t literal_pos_mask; /* (1 << lp) - 1 */ + uint32_t pos_mask; /* (1 << pb) - 1 */ + /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ uint16_t is_match[STATES][POS_STATES_MAX]; @@ -201,49 +211,59 @@ struct lzma_dec { uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; }; +struct lzma2_dec { + /* Position in xz_dec_lzma2_run(). */ + enum lzma2_seq { + SEQ_CONTROL, + SEQ_UNCOMPRESSED_1, + SEQ_UNCOMPRESSED_2, + SEQ_COMPRESSED_0, + SEQ_COMPRESSED_1, + SEQ_PROPERTIES, + SEQ_LZMA_PREPARE, + SEQ_LZMA_RUN, + SEQ_COPY + } sequence; + + /* Next position after decoding the compressed size of the chunk. */ + enum lzma2_seq next_sequence; + + /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ + uint32_t uncompressed; + + /* + * Compressed size of LZMA chunk or compressed/uncompressed + * size of uncompressed chunk (64 KiB at maximum) + */ + uint32_t compressed; + + /* + * True if dictionary reset is needed. This is false before + * the first chunk (LZMA or uncompressed). + */ + bool need_dict_reset; + + /* + * True if new LZMA properties are needed. This is false + * before the first LZMA chunk. + */ + bool need_props; +}; + struct xz_dec_lzma2 { - /* LZMA2 */ - struct { - /* Position in xz_dec_lzma2_run(). */ - enum lzma2_seq { - SEQ_CONTROL, - SEQ_UNCOMPRESSED_1, - SEQ_UNCOMPRESSED_2, - SEQ_COMPRESSED_0, - SEQ_COMPRESSED_1, - SEQ_PROPERTIES, - SEQ_LZMA_PREPARE, - SEQ_LZMA_RUN, - SEQ_COPY - } sequence; - - /* - * Next position after decoding the compressed size of - * the chunk. - */ - enum lzma2_seq next_sequence; - - /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ - uint32_t uncompressed; - - /* - * Compressed size of LZMA chunk or compressed/uncompressed - * size of uncompressed chunk (64 KiB at maximum) - */ - uint32_t compressed; - - /* - * True if dictionary reset is needed. This is false before - * the first chunk (LZMA or uncompressed). - */ - bool need_dict_reset; - - /* - * True if new LZMA properties are needed. This is false - * before the first LZMA chunk. - */ - bool need_props; - } lzma2; + /* + * The order below is important on x86 to reduce code size and + * it shouldn't hurt on other platforms. Everything up to and + * including lzma.pos_mask are in the first 128 bytes on x86-32, + * which allows using smaller instructions to access those + * variables. On x86-64, fewer variables fit into the first 128 + * bytes, but this is still the best order without sacrificing + * the readability by splitting the structures. + */ + struct rc_dec rc; + struct dictionary dict; + struct lzma2_dec lzma2; + struct lzma_dec lzma; /* * Temporary buffer which holds small number of input bytes between @@ -253,10 +273,6 @@ struct xz_dec_lzma2 { uint32_t size; uint8_t buf[3 * LZMA_IN_REQUIRED]; } temp; - - struct dictionary dict; - struct rc_dec rc; - struct lzma_dec lzma; }; /************** @@ -269,7 +285,7 @@ struct xz_dec_lzma2 { */ static void XZ_FUNC dict_reset(struct dictionary *dict, struct xz_buf *b) { - if (dict->allocated == 0) { + if (DEC_IS_SINGLE(dict->mode)) { dict->buf = b->out + b->out_pos; dict->end = b->out_size - b->out_pos; } @@ -379,7 +395,7 @@ static void XZ_FUNC dict_uncompressed( if (dict->full < dict->pos) dict->full = dict->pos; - if (dict->allocated != 0) { + if (DEC_IS_MULTI(dict->mode)) { if (dict->pos == dict->end) dict->pos = 0; @@ -404,7 +420,7 @@ static uint32_t XZ_FUNC dict_flush(struct dictionary *dict, struct xz_buf *b) { size_t copy_size = dict->pos - dict->start; - if (dict->allocated != 0) { + if (DEC_IS_MULTI(dict->mode)) { if (dict->pos == dict->end) dict->pos = 0; @@ -422,7 +438,7 @@ static uint32_t XZ_FUNC dict_flush(struct dictionary *dict, struct xz_buf *b) *****************/ /* Reset the range decoder. */ -static __always_inline void XZ_FUNC rc_reset(struct rc_dec *rc) +static void XZ_FUNC rc_reset(struct rc_dec *rc) { rc->range = (uint32_t)-1; rc->code = 0; @@ -1088,28 +1104,27 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( return XZ_OK; } -XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create(uint32_t dict_max) +XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( + enum xz_mode mode, uint32_t dict_max) { - struct xz_dec_lzma2 *s; - - /* Maximum supported dictionary by this implementation is 3 GiB. */ - if (dict_max > ((uint32_t)3 << 30)) - return NULL; - - s = kmalloc(sizeof(*s), GFP_KERNEL); + struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL); if (s == NULL) return NULL; - if (dict_max > 0) { + s->dict.mode = mode; + s->dict.size_max = dict_max; + + if (DEC_IS_PREALLOC(mode)) { s->dict.buf = vmalloc(dict_max); if (s->dict.buf == NULL) { kfree(s); return NULL; } + } else if (DEC_IS_DYNALLOC(mode)) { + s->dict.buf = NULL; + s->dict.allocated = 0; } - s->dict.allocated = dict_max; - return s; } @@ -1123,18 +1138,23 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset( s->dict.size = 2 + (props & 1); s->dict.size <<= (props >> 1) + 11; - if (s->dict.allocated > 0 && s->dict.allocated < s->dict.size) { -#ifdef XZ_REALLOC_DICT_BUF - s->dict.buf = XZ_REALLOC_DICT_BUF(s->dict.buf, s->dict.size); - if (!s->dict.buf) - return XZ_MEMLIMIT_ERROR; - s->dict.allocated = s->dict.size; -#else - return XZ_MEMLIMIT_ERROR; -#endif - } + if (DEC_IS_MULTI(s->dict.mode)) { + if (s->dict.size > s->dict.size_max) + return XZ_MEMLIMIT_ERROR; - s->dict.end = s->dict.size; + s->dict.end = s->dict.size; + + if (DEC_IS_DYNALLOC(s->dict.mode)) { + if (s->dict.allocated < s->dict.size) { + vfree(s->dict.buf); + s->dict.buf = vmalloc(s->dict.size); + if (s->dict.buf == NULL) { + s->dict.allocated = 0; + return XZ_MEM_ERROR; + } + } + } + } s->lzma.len = 0; @@ -1148,7 +1168,7 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset( XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s) { - if (s->dict.allocated > 0) + if (DEC_IS_MULTI(s->dict.mode)) vfree(s->dict.buf); kfree(s); diff --git a/archival/libunarchive/unxz/xz_dec_stream.c b/archival/libunarchive/unxz/xz_dec_stream.c index 21db283fb..bdcbf1ba3 100644 --- a/archival/libunarchive/unxz/xz_dec_stream.c +++ b/archival/libunarchive/unxz/xz_dec_stream.c @@ -48,8 +48,8 @@ struct xz_dec { /* Type of the integrity check calculated from uncompressed data */ enum xz_check check_type; - /* True if we are operating in single-call mode. */ - bool single_call; + /* Operation mode */ + enum xz_mode mode; /* * True if the next call to xz_dec_run() is allowed to return @@ -737,14 +737,14 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b) size_t out_start; enum xz_ret ret; - if (s->single_call) + if (DEC_IS_SINGLE(s->mode)) xz_dec_reset(s); in_start = b->in_pos; out_start = b->out_pos; ret = dec_main(s, b); - if (s->single_call) { + if (DEC_IS_SINGLE(s->mode)) { if (ret == XZ_OK) ret = b->in_pos == b->in_size ? XZ_DATA_ERROR : XZ_BUF_ERROR; @@ -767,21 +767,22 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b) return ret; } -XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init(uint32_t dict_max) +XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( + enum xz_mode mode, uint32_t dict_max) { struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL); if (s == NULL) return NULL; - s->single_call = dict_max == 0; + s->mode = mode; #ifdef XZ_DEC_BCJ - s->bcj = xz_dec_bcj_create(s->single_call); + s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode)); if (s->bcj == NULL) goto error_bcj; #endif - s->lzma2 = xz_dec_lzma2_create(dict_max); + s->lzma2 = xz_dec_lzma2_create(mode, dict_max); if (s->lzma2 == NULL) goto error_lzma2; diff --git a/archival/libunarchive/unxz/xz_private.h b/archival/libunarchive/unxz/xz_private.h index f4e0b4010..145649a83 100644 --- a/archival/libunarchive/unxz/xz_private.h +++ b/archival/libunarchive/unxz/xz_private.h @@ -53,6 +53,45 @@ # include "xz_config.h" #endif +/* If no specific decoding mode is requested, enable support for all modes. */ +#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \ + && !defined(XZ_DEC_DYNALLOC) +# define XZ_DEC_SINGLE +# define XZ_DEC_PREALLOC +# define XZ_DEC_DYNALLOC +#endif + +/* + * The DEC_IS_foo(mode) macros are used in "if" statements. If only some + * of the supported modes are enabled, these macros will evaluate to true or + * false at compile time and thus allow the compiler to omit unneeded code. + */ +#ifdef XZ_DEC_SINGLE +# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE) +#else +# define DEC_IS_SINGLE(mode) (false) +#endif + +#ifdef XZ_DEC_PREALLOC +# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC) +#else +# define DEC_IS_PREALLOC(mode) (false) +#endif + +#ifdef XZ_DEC_DYNALLOC +# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC) +#else +# define DEC_IS_DYNALLOC(mode) (false) +#endif + +#if !defined(XZ_DEC_SINGLE) +# define DEC_IS_MULTI(mode) (true) +#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC) +# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE) +#else +# define DEC_IS_MULTI(mode) (false) +#endif + /* * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ. * XZ_DEC_BCJ is used to enable generic support for BCJ decoders. @@ -71,7 +110,7 @@ * before calling xz_dec_lzma2_run(). */ XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( - uint32_t dict_max); + enum xz_mode mode, uint32_t dict_max); /* * Decode the LZMA2 properties (one byte) and reset the decoder. Return -- cgit v1.2.3-55-g6feb From d2b738a6d27ceab834c35382100948a2fdd55b44 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Jun 2010 02:16:51 +0200 Subject: decompress_unxz: use common string Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_unxz.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c index 800680fef..5d7513a2e 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libunarchive/decompress_unxz.c @@ -92,7 +92,7 @@ unpack_xz_stream(int src_fd, int dst_fd) break; } if (r != XZ_OK && r != XZ_UNSUPPORTED_CHECK) { - bb_error_msg("corrupted or unsupported data"); + bb_error_msg("corrupted data"); total = -1; break; } -- cgit v1.2.3-55-g6feb From a8b594fda7cbfcc2aadf9779ee40b264eeec86b2 Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Mon, 21 Jun 2010 02:17:29 +0200 Subject: conspy: new applet Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- miscutils/conspy.c | 472 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 miscutils/conspy.c diff --git a/miscutils/conspy.c b/miscutils/conspy.c new file mode 100644 index 000000000..7ba7959a2 --- /dev/null +++ b/miscutils/conspy.c @@ -0,0 +1,472 @@ +/* vi: set sw=4 ts=4: */ +/* + * A text-mode VNC like program for Linux virtual terminals. + * + * pascal.bellard@ads-lu.com + * + * Based on Russell Stuart's conspy.c + * http://ace-host.stuart.id.au/russell/files/conspy.c + * + * Licensed under GPLv2 or later, see file License in this tarball for details. + * + * example : conspy num shared access to console num + * or conspy -d num screenshot of console num + * or conspy -cs num poor man's GNU screen like + */ + +//applet:IF_CONSPY(APPLET(conspy, _BB_DIR_BIN, _BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_CONSPY) += conspy.o + +//config:config CONSPY +//config: bool "conspy" +//config: default n +//config: help +//config: A text-mode VNC like program for Linux virtual terminals. +//config: example : conspy num shared access to console num +//config: or conspy -d num screenshot of console num +//config: or conspy -cs num poor man's GNU screen like + +//usage:#define conspy_trivial_usage +//usage: "[-vcsndf] [-x ROW] [-y LINE] [CONSOLE_NO]" +//usage:#define conspy_full_usage "\n\n" +//usage: "A text-mode VNC like program for Linux virtual consoles." +//usage: "\nTo exit, quickly press ESC 3 times." +//usage: "\n" +//usage: "\nOptions:" +//usage: "\n -v Don't send keystrokes to the console" +//usage: "\n -c Create missing devices in /dev" +//usage: "\n -s Open a SHELL session" +//usage: "\n -n Black & white" +//usage: "\n -d Dump console to stdout" +//usage: "\n -f Follow cursor" +//usage: "\n -x ROW Starting row" +//usage: "\n -y LINE Starting line" + +#include "libbb.h" +#include + +struct screen_info { + unsigned char lines, rows, cursor_x, cursor_y; +}; + +#define CHAR(x) ((x)[0]) +#define ATTR(x) ((x)[1]) +#define NEXT(x) ((x)+=2) +#define DATA(x) (* (short *) (x)) + +struct globals { + char* data; + int size; + int x, y; + int kbd_fd; + unsigned width; + unsigned height; + char mask; + char last_attr; + struct screen_info info; + struct termios term_orig; +}; + +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + +static void screen_read_close(int fd, char *data) +{ + unsigned i, j; + + xread(fd, data, G.size); + G.last_attr = 0; + for (i = 0; i < G.info.lines; i++) { + for (j = 0; j < G.info.rows; j++, NEXT(data)) { + unsigned x = j - G.x; // if will catch j < G.x too + unsigned y = i - G.y; // if will catch i < G.y too + + if (CHAR(data) < ' ') + CHAR(data) = ' '; + if (y >= G.height || x >= G.width) + DATA(data) = 0; + } + } + close(fd); +} + +static void screen_char(char *data) +{ + if (((G.last_attr - ATTR(data)) & G.mask) != 0) { + // BLGCRMOW + static const char color[8] = "04261537"; + + printf("\033[%c;4%c;3%cm", + (ATTR(data) & 8) ? '1' // bold + : '0', // defaults + color[(ATTR(data) >> 4) & 7], color[ATTR(data) & 7]); + G.last_attr = ATTR(data); + } + bb_putchar(CHAR(data)); +} + +#define clrscr() printf("\033[1;1H" "\033[0J") +#define curoff() printf("\033[?25l") + +static void curon(void) +{ + printf("\033[?25h"); +} + +static void gotoxy(int row, int line) +{ + printf("\033[%u;%uH", line + 1, row + 1); +} + +static void screen_dump(char *data) +{ + int space, linefeed, line, row; + int linecnt = G.info.lines - G.y; + + data += 2 * G.y * G.info.rows; + for (linefeed = line = 0; line < linecnt && line < G.height; line++) { + for (space = row = 0; row < G.info.rows; row++, NEXT(data)) { + unsigned tty_row = row - G.x; // if will catch row < G.x too + + if (tty_row >= G.width) + continue; + space++; + if (((G.last_attr - ATTR(data)) & G.mask) && CHAR(data) == ' ') + continue; + while (linefeed != 0) { + bb_putchar('\r'); + bb_putchar('\n'); + linefeed--; + } + while (--space) + bb_putchar(' '); + screen_char(data); + } + linefeed++; + } +} + +static void curmove(void) +{ + unsigned cx = G.info.cursor_x - G.x; + unsigned cy = G.info.cursor_y - G.y; + + if (cx >= G.width || cy >= G.height) { + curoff(); + } else { + curon(); + gotoxy(cx, cy); + } + fflush_all(); +} + +static void cleanup(int code) +{ + curon(); + fflush_all(); + tcsetattr(G.kbd_fd, TCSANOW, &G.term_orig); + if (ENABLE_FEATURE_CLEAN_UP) { + free(ptr_to_globals); + close(G.kbd_fd); + } + // Reset attributes + if (G.mask != 0) + printf("\033[0m"); + bb_putchar('\n'); + if (code > 1) + kill_myself_with_sig(code); // does not return + exit(code); +} + +static void get_initial_data(const char* vcsa_name) +{ + int size; + int fd = xopen(vcsa_name, O_RDONLY); + xread(fd, &G.info, 4); + G.size = size = G.info.rows * G.info.lines * 2; + G.width = G.height = UINT_MAX; + G.data = xzalloc(2 * size); + screen_read_close(fd, G.data); +} + +static void create_cdev_if_doesnt_exist(const char* name, dev_t dev) +{ + int fd = open(name, O_RDONLY); + if (fd != -1) + close(fd); + else if (errno == ENOENT) + mknod(name, S_IFCHR | 0660, dev); +} + +static NOINLINE void start_shell_in_child(const char* tty_name) +{ + int pid = vfork(); + if (pid < 0) { + bb_perror_msg_and_die("vfork"); + } + if (pid == 0) { + struct termios termchild; + char *shell = getenv("SHELL"); + + if (!shell) + shell = (char *) DEFAULT_SHELL; + signal(SIGHUP, SIG_IGN); + // set tty as a controlling tty + setsid(); + // make tty to be input, output, error + close(0); + xopen(tty_name, O_RDWR); // uses fd 0 + xdup2(0, 1); + xdup2(0, 2); + ioctl(0, TIOCSCTTY, 1); + tcsetpgrp(0, getpid()); + tcgetattr(0, &termchild); + termchild.c_lflag |= ECHO; + termchild.c_oflag |= ONLCR | XTABS; + termchild.c_iflag |= ICRNL; + termchild.c_iflag &= ~IXOFF; + tcsetattr_stdin_TCSANOW(&termchild); + execl(shell, shell, "-i", (char *) NULL); + bb_simple_perror_msg_and_die(shell); + } +} + +enum { + FLAG_v, // view only + FLAG_c, // create device if need + FLAG_s, // session + FLAG_n, // no colors + FLAG_d, // dump screen + FLAG_f, // follow cursor +}; +#define FLAG(x) (1 << FLAG_##x) + +int conspy_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE; +int conspy_main(int argc UNUSED_PARAM, char **argv) +{ + char *buffer[2]; + char vcsa_name[sizeof("/dev/vcsa") + 2]; + char tty_name[sizeof("/dev/tty") + 2]; +#define keybuf bb_common_bufsiz1 + struct termios termbuf; + unsigned opts; + unsigned ttynum; + int poll_timeout_ms; + int current; + int ioerror_count; + int key_count; + int escape_count; + int nokeys; +#if ENABLE_LONG_OPTS + static const char getopt_longopts[] ALIGN1 = + "viewonly\0" No_argument "v" + "createdevice\0" No_argument "c" + "session\0" No_argument "s" + "nocolors\0" No_argument "n" + "dump\0" No_argument "d" + "follow\0" No_argument "f" + ; + + applet_long_options = getopt_longopts; +#endif + INIT_G(); + strcpy(vcsa_name, "/dev/vcsa"); + + opt_complementary = "x+:y+"; // numeric params + opts = getopt32(argv, "vcsndfx:y:", &G.x, &G.y); + argv += optind; + ttynum = 0; + if (argv[0]) { + ttynum = xatou_range(argv[0], 0, 63); + sprintf(vcsa_name + sizeof("/dev/vcsa")-1, "%u", ttynum); + } + sprintf(tty_name, "%s%u", "/dev/tty", ttynum); + if (!(opts & FLAG(n))) + G.mask = 0xff; + if (opts & FLAG(c)) { + if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v)) + create_cdev_if_doesnt_exist(tty_name, makedev(4, ttynum)); + create_cdev_if_doesnt_exist(vcsa_name, makedev(7, 128 + ttynum)); + } + if ((opts & FLAG(s)) && ttynum) { + start_shell_in_child(tty_name); + } + + get_initial_data(vcsa_name); + G.kbd_fd = xopen(CURRENT_TTY, O_RDONLY); + if (opts & FLAG(d)) { + screen_dump(G.data); + bb_putchar('\n'); + if (ENABLE_FEATURE_CLEAN_UP) { + free(ptr_to_globals); + close(G.kbd_fd); + } + return 0; + } + + bb_signals(BB_FATAL_SIGS, cleanup); + // All characters must be passed through to us unaltered + tcgetattr(G.kbd_fd, &G.term_orig); + termbuf = G.term_orig; + termbuf.c_iflag &= ~(BRKINT|INLCR|ICRNL|IXON|IXOFF|IUCLC|IXANY|IMAXBEL); + termbuf.c_oflag &= ~(OPOST); + termbuf.c_lflag &= ~(ISIG|ICANON|ECHO); + termbuf.c_cc[VMIN] = 1; + termbuf.c_cc[VTIME] = 0; + tcsetattr(G.kbd_fd, TCSANOW, &termbuf); + buffer[0] = G.data; + buffer[1] = G.data + G.size; + poll_timeout_ms = 250; + ioerror_count = key_count = escape_count = nokeys = current = 0; + while (1) { + struct pollfd pfd; + int vcsa_handle; + int bytes_read; + int i, j; + int next = 1 - current; + char *data = buffer[next]; + char *old = buffer[current]; + + // Close & re-open vcsa in case they have + // swapped virtual consoles + vcsa_handle = xopen(vcsa_name, O_RDONLY); + xread(vcsa_handle, &G.info, 4); + if (G.size != (G.info.rows * G.info.lines * 2)) { + cleanup(1); + } + i = G.width; + j = G.height; + get_terminal_width_height(G.kbd_fd, &G.width, &G.height); + if ((option_mask32 & FLAG(f))) { + int nx = G.info.cursor_x - G.width + 1; + int ny = G.info.cursor_y - G.height + 1; + + if (G.info.cursor_x < G.x) { + G.x = G.info.cursor_x; + i = 0; // force refresh + } + if (nx > G.x) { + G.x = nx; + i = 0; // force refresh + } + if (G.info.cursor_y < G.y) { + G.y = G.info.cursor_y; + i = 0; // force refresh + } + if (ny > G.y) { + G.y = ny; + i = 0; // force refresh + } + } + + // Scan console data and redraw our tty where needed + screen_read_close(vcsa_handle, data); + if (i != G.width || j != G.height) { + clrscr(); + screen_dump(data); + } + else for (i = 0; i < G.info.lines; i++) { + char *last = last; + char *first = NULL; + int iy = i - G.y; + + if (iy >= (int) G.height) + break; + for (j = 0; j < G.info.rows; j++) { + last = data; + if (DATA(data) != DATA(old) && iy >= 0) { + unsigned jx = j - G.x; + + last = NULL; + if (first == NULL && jx < G.width) { + first = data; + gotoxy(jx, iy); + } + } + NEXT(old); + NEXT(data); + } + if (first == NULL) + continue; + if (last == NULL) + last = data; + + // Write the data to the screen + for (; first < last; NEXT(first)) + screen_char(first); + } + current = next; + curmove(); + + // Wait for local user keypresses + pfd.fd = G.kbd_fd; + pfd.events = POLLIN; + bytes_read = 0; + switch (poll(&pfd, 1, poll_timeout_ms)) { + case -1: + if (errno != EINTR) + cleanup(1); + break; + case 0: + if (++nokeys >= 4) + nokeys = escape_count = 0; + break; + default: + // Read the keys pressed + bytes_read = read(G.kbd_fd, keybuf + key_count, + sizeof(keybuf) - key_count); + if (bytes_read < 0) + cleanup(1); + + // Do exit processing + for (i = 0; i < bytes_read; i++) { + if (keybuf[key_count + i] != '\033') + escape_count = 0; + else if (++escape_count >= 3) + cleanup(0); + } + } + poll_timeout_ms = 250; + + // Insert all keys pressed into the virtual console's input + // buffer. Don't do this if the virtual console is in scan + // code mode - giving ASCII characters to a program expecting + // scan codes will confuse it. + if (!(option_mask32 & FLAG(v)) && escape_count == 0) { + int handle, result; + long kbd_mode; + + key_count += bytes_read; + handle = xopen(tty_name, O_WRONLY); + result = ioctl(handle, KDGKBMODE, &kbd_mode); + if (result == -1) + /* nothing */; + else if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE) + key_count = 0; // scan code mode + else { + for (i = 0; i < key_count && result != -1; i++) + result = ioctl(handle, TIOCSTI, keybuf + i); + key_count -= i; + if (key_count) + memmove(keybuf, keybuf + i, key_count); + // If there is an application on console which reacts + // to keypresses, we need to make our first sleep + // shorter to quickly redraw whatever it printed there. + poll_timeout_ms = 20; + } + // Close & re-open tty in case they have + // swapped virtual consoles + close(handle); + + // We sometimes get spurious IO errors on the TTY + // as programs close and re-open it + if (result != -1) + ioerror_count = 0; + else if (errno != EIO || ++ioerror_count > 4) + cleanup(1); + } + } +} -- cgit v1.2.3-55-g6feb From 05a550b48abe8490264cacf14b68534c2f8ac3ed Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Jun 2010 04:00:16 +0200 Subject: fix errors in detecting non-modified areas function old new delta screen_char 100 102 +2 cleanup 84 86 +2 screen_dump 215 210 -5 conspy_main 1503 1491 -12 Signed-off-by: Denys Vlasenko --- miscutils/conspy.c | 49 +++++++++++++++++++++++++------------------------ 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 7ba7959a2..ae471a3fa 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -62,7 +62,6 @@ struct globals { int kbd_fd; unsigned width; unsigned height; - char mask; char last_attr; struct screen_info info; struct termios term_orig; @@ -73,6 +72,17 @@ struct globals { SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ } while (0) +enum { + FLAG_v, // view only + FLAG_c, // create device if need + FLAG_s, // session + FLAG_n, // no colors + FLAG_d, // dump screen + FLAG_f, // follow cursor +}; +#define FLAG(x) (1 << FLAG_##x) +#define BW (option_mask32 & FLAG(n)) + static void screen_read_close(int fd, char *data) { unsigned i, j; @@ -95,7 +105,7 @@ static void screen_read_close(int fd, char *data) static void screen_char(char *data) { - if (((G.last_attr - ATTR(data)) & G.mask) != 0) { + if (!BW && G.last_attr != ATTR(data)) { // BLGCRMOW static const char color[8] = "04261537"; @@ -123,29 +133,32 @@ static void gotoxy(int row, int line) static void screen_dump(char *data) { - int space, linefeed, line, row; + int linefeed_cnt; + int line, row; int linecnt = G.info.lines - G.y; data += 2 * G.y * G.info.rows; - for (linefeed = line = 0; line < linecnt && line < G.height; line++) { - for (space = row = 0; row < G.info.rows; row++, NEXT(data)) { + linefeed_cnt = 0; + for (line = 0; line < linecnt && line < G.height; line++) { + int space_cnt = 0; + for (row = 0; row < G.info.rows; row++, NEXT(data)) { unsigned tty_row = row - G.x; // if will catch row < G.x too if (tty_row >= G.width) continue; - space++; - if (((G.last_attr - ATTR(data)) & G.mask) && CHAR(data) == ' ') + space_cnt++; + if (BW && (CHAR(data) | ' ') == ' ') continue; - while (linefeed != 0) { + while (linefeed_cnt != 0) { bb_putchar('\r'); bb_putchar('\n'); - linefeed--; + linefeed_cnt--; } - while (--space) + while (--space_cnt) bb_putchar(' '); screen_char(data); } - linefeed++; + linefeed_cnt++; } } @@ -173,7 +186,7 @@ static void cleanup(int code) close(G.kbd_fd); } // Reset attributes - if (G.mask != 0) + if (!BW) printf("\033[0m"); bb_putchar('\n'); if (code > 1) @@ -234,16 +247,6 @@ static NOINLINE void start_shell_in_child(const char* tty_name) } } -enum { - FLAG_v, // view only - FLAG_c, // create device if need - FLAG_s, // session - FLAG_n, // no colors - FLAG_d, // dump screen - FLAG_f, // follow cursor -}; -#define FLAG(x) (1 << FLAG_##x) - int conspy_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE; int conspy_main(int argc UNUSED_PARAM, char **argv) { @@ -284,8 +287,6 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) sprintf(vcsa_name + sizeof("/dev/vcsa")-1, "%u", ttynum); } sprintf(tty_name, "%s%u", "/dev/tty", ttynum); - if (!(opts & FLAG(n))) - G.mask = 0xff; if (opts & FLAG(c)) { if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v)) create_cdev_if_doesnt_exist(tty_name, makedev(4, ttynum)); -- cgit v1.2.3-55-g6feb From adbbee46ad0661bf695d2bfe7a07ebced4bbe780 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Jun 2010 07:17:23 +0200 Subject: bootchartd: added optional compat features Signed-off-by: Denys Vlasenko --- include/libbb.h | 1 + init/Config.src | 14 ----- init/bootchartd.c | 154 ++++++++++++++++++++++++++++++++++++++++++++---------- procps/sysctl.c | 1 + 4 files changed, 127 insertions(+), 43 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 22c72d9ee..5e962fdb6 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1125,6 +1125,7 @@ typedef struct parser_t { } parser_t; parser_t* config_open(const char *filename) FAST_FUNC; parser_t* config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) FAST_FUNC; +/* delims[0] is a comment char (use '\0' to disable), the rest are token delimiters */ int config_read(parser_t *parser, char **tokens, unsigned flags, const char *delims) FAST_FUNC; #define config_read(parser, tokens, max, min, str, flags) \ config_read(parser, tokens, ((flags) | (((min) & 0xFF) << 8) | ((max) & 0xFF)), str) diff --git a/init/Config.src b/init/Config.src index 2e9208150..590e29890 100644 --- a/init/Config.src +++ b/init/Config.src @@ -122,18 +122,4 @@ config MESG Mesg controls access to your terminal by others. It is typically used to allow or disallow other users to write to your terminal -config BOOTCHARTD - bool "bootchartd" - default y - help - bootchartd is commonly used to profile the boot process - for the purpose of speeding it up. In this case, it is started - by the kernel as the init process. This is configured by adding - the init=/sbin/bootchartd option to the kernel command line. - - It can also be used to monitor the resource usage of a specific - application or the running system in general. In this case, - bootchartd is started interactively by running bootchartd start - and stopped using bootchartd stop. - endmenu diff --git a/init/bootchartd.c b/init/bootchartd.c index d1f9ed30e..1ed4f99fc 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -2,7 +2,58 @@ /* * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ + +//config:config BOOTCHARTD +//config: bool "bootchartd" +//config: default y +//config: help +//config: bootchartd is commonly used to profile the boot process +//config: for the purpose of speeding it up. In this case, it is started +//config: by the kernel as the init process. This is configured by adding +//config: the init=/sbin/bootchartd option to the kernel command line. +//config: +//config: It can also be used to monitor the resource usage of a specific +//config: application or the running system in general. In this case, +//config: bootchartd is started interactively by running bootchartd start +//config: and stopped using bootchartd stop. +//config: +//config:config FEATURE_BOOTCHARTD_BLOATED_HEADER +//config: bool "bootchartd" +//config: default y +//config: depends on BOOTCHARTD +//config: help +//config: Create extended header file compatible with "big" bootchartd. +//config: "Big" bootchartd is a shell script and it dumps some +//config: "convenient" info int the header, such as: +//config: title = Boot chart for `hostname` (`date`) +//config: system.uname = `uname -srvm` +//config: system.release = `cat /etc/DISTRO-release` +//config: system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount) +//config: system.kernel.options = `cat /proc/cmdline` +//config: This data is not mandatory for bootchart graph generation, +//config: and is considered bloat. Nevertheless, this option +//config: makes bootchartd applet to dump a subset of it. +//config: +//config:config FEATURE_BOOTCHARTD_CONFIG_FILE +//config: bool "bootchartd" +//config: default y +//config: depends on BOOTCHARTD +//config: help +//config: Create extended header file compatible with "big" bootchartd. +//config: "Big" bootchartd is a shell script and it dumps some +//config: "convenient" info int the header, such as: +//config: title = Boot chart for `hostname` (`date`) +//config: system.uname = `uname -srvm` +//config: system.release = `cat /etc/DISTRO-release` +//config: system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount) +//config: system.kernel.options = `cat /proc/cmdline` +//config: This data is not mandatory for bootchart graph generation, +//config: and is considered bloat. Nevertheless, this option +//config: makes bootchartd applet to dump a subset of it. + #include "libbb.h" +/* After libbb.h, since it needs sys/types.h on some systems */ +#include #include #ifndef MS_SILENT # define MS_SILENT (1 << 15) @@ -19,15 +70,16 @@ #define DO_SIGNAL_SYNC 1 -//Not supported: $PWD/bootchartd.conf and /etc/bootchartd.conf - +//$PWD/bootchartd.conf and /etc/bootchartd.conf: +//supported options: +//# Sampling period (in seconds) +//SAMPLE_PERIOD=0.2 +// +//not yet supported: //# tmpfs size //# (32 MB should suffice for ~20 minutes worth of log data, but YMMV) //TMPFS_SIZE=32m // -//# Sampling period (in seconds) -//SAMPLE_PERIOD=0.2 -// //# Whether to enable and store BSD process accounting information. The //# kernel needs to be configured to enable v3 accounting //# (CONFIG_BSD_PROCESS_ACCT_V3). accton from the GNU accounting utilities @@ -126,7 +178,7 @@ static int dump_procs(FILE *fp, int look_for_login_process) return found_login_process; } -static char *make_tempdir(const char *prog) +static char *make_tempdir(void) { char template[] = "/tmp/bootchart.XXXXXX"; char *tempdir = xstrdup(mkdtemp(template)); @@ -151,18 +203,10 @@ static char *make_tempdir(const char *prog) } else { xchdir(tempdir); } - { - FILE *header_fp = xfopen("header", "w"); - if (prog) - fprintf(header_fp, "profile.process = %s\n", prog); - fputs("version = "BC_VERSION_STR"\n", header_fp); - fclose(header_fp); - } - return tempdir; } -static void do_logging(void) +static void do_logging(int sample_pariod_us) { //# Enable process accounting if configured //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then @@ -205,26 +249,61 @@ static void do_logging(void) } fflush_all(); wait_more: - usleep(200*1000); + usleep(sample_pariod_us); } // [ -e kernel_pacct ] && accton off } -static void finalize(char *tempdir) +static void finalize(char *tempdir, const char *prog) { //# Stop process accounting if configured //local pacct= //[ -e kernel_pacct ] && pacct=kernel_pacct - //( - // echo "version = $VERSION" - // echo "title = Boot chart for $( hostname | sed q ) ($( date ))" - // echo "system.uname = $( uname -srvm | sed q )" - // echo "system.release = $( sed q /etc/SuSE-release )" - // echo "system.cpu = $( grep '^model name' /proc/cpuinfo | sed q ) ($cpucount)" - // echo "system.kernel.options = $( sed q /proc/cmdline )" - //) >> header + FILE *header_fp = xfopen("header", "w"); + + if (prog) + fprintf(header_fp, "profile.process = %s\n", prog); + + fputs("version = "BC_VERSION_STR"\n", header_fp); + + if (ENABLE_FEATURE_BOOTCHARTD_BLOATED_HEADER) { + char *hostname; + char *kcmdline; + time_t t; + struct tm tm_time; + /* x2 for possible localized data */ + char date_buf[sizeof("Mon Jun 21 05:29:03 CEST 2010") * 2]; + struct utsname unamebuf; + + hostname = safe_gethostname(); + time(&t); + localtime_r(&t, &tm_time); + strftime(date_buf, sizeof(date_buf), "%a %b %e %H:%M:%S %Z %Y", &tm_time); + fprintf(header_fp, "title = Boot chart for %s (%s)\n", hostname, date_buf); + if (ENABLE_FEATURE_CLEAN_UP) + free(hostname); + + uname(&unamebuf); /* never fails */ + /* same as uname -srvm */ + fprintf(header_fp, "system.uname = %s %s %s %s\n", + unamebuf.sysname, + unamebuf.release, + unamebuf.version, + unamebuf.machine + ); + + //system.release = `cat /etc/DISTRO-release` + //system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount) + + kcmdline = xmalloc_open_read_close("/proc/cmdline", NULL); + /* kcmdline includes trailing "\n" */ + fprintf(header_fp, "system.kernel.options = %s", kcmdline); + if (ENABLE_FEATURE_CLEAN_UP) + free(kcmdline); + } + fclose(header_fp); /* Package log files */ system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct @@ -256,6 +335,7 @@ static void finalize(char *tempdir) int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bootchartd_main(int argc UNUSED_PARAM, char **argv) { + int sample_pariod_us; pid_t parent_pid, logger_pid; smallint cmd; enum { @@ -287,7 +367,23 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) cmd = CMD_PID1; } - /* Here we are in START or INIT state. Create logger child: */ + /* Here we are in START or INIT state */ + + /* Read config file: */ + sample_pariod_us = 200 * 1000; + if (ENABLE_FEATURE_BOOTCHARTD_CONFIG_FILE) { + char* token[2]; + parser_t *parser = config_open2("/etc/bootchartd.conf" + 5, fopen_for_read); + if (!parser) + parser = config_open2("/etc/bootchartd.conf", fopen_for_read); + while (config_read(parser, token, 2, 0, "#=", PARSE_NORMAL & ~PARSE_COLLAPSE)) { + if (strcmp(token[0], "SAMPLE_PERIOD") == 0 && token[1]) + sample_pariod_us = atof(token[1]) * 1000000; + } + config_close(parser); + } + + /* Create logger child: */ logger_pid = fork_or_rexec(argv); if (logger_pid == 0) { /* child */ @@ -312,9 +408,9 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) if (cmd == CMD_PID1 && !getenv("PATH")) putenv((char*)bb_PATH_root_path); - tempdir = make_tempdir(cmd == CMD_START ? argv[2] : NULL); - do_logging(); - finalize(tempdir); + tempdir = make_tempdir(); + do_logging(sample_pariod_us); + finalize(tempdir, cmd == CMD_START ? argv[2] : NULL); return EXIT_SUCCESS; } diff --git a/procps/sysctl.c b/procps/sysctl.c index 7a5bf1435..fc601d637 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -212,6 +212,7 @@ static int sysctl_handle_preload_file(const char *filename) //TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value // (but _whitespace_ from ends should be trimmed first (and we do it right)) //TODO: "var==1" is mishandled (must use "=1" as a value, but uses "1") +// can it be fixed by removing PARSE_COLLAPSE bit? while (config_read(parser, token, 2, 2, "# \t=", PARSE_NORMAL)) { char *tp; sysctl_dots_to_slashes(token[0]); -- cgit v1.2.3-55-g6feb From 6d9c88ad982dbe9cb9d5c375f42a4eb8d4aef39f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 21 Jun 2010 07:25:36 +0200 Subject: fix config help text Signed-off-by: Denys Vlasenko --- init/bootchartd.c | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/init/bootchartd.c b/init/bootchartd.c index 1ed4f99fc..2d9770c4c 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -39,17 +39,8 @@ //config: default y //config: depends on BOOTCHARTD //config: help -//config: Create extended header file compatible with "big" bootchartd. -//config: "Big" bootchartd is a shell script and it dumps some -//config: "convenient" info int the header, such as: -//config: title = Boot chart for `hostname` (`date`) -//config: system.uname = `uname -srvm` -//config: system.release = `cat /etc/DISTRO-release` -//config: system.cpu = `grep '^model name' /proc/cpuinfo | head -1` ($cpucount) -//config: system.kernel.options = `cat /proc/cmdline` -//config: This data is not mandatory for bootchart graph generation, -//config: and is considered bloat. Nevertheless, this option -//config: makes bootchartd applet to dump a subset of it. +//config: Enable reading and parsing of $PWD/bootchartd.conf +//config: and /etc/bootchartd.conf files. #include "libbb.h" /* After libbb.h, since it needs sys/types.h on some systems */ -- cgit v1.2.3-55-g6feb From fc6f6e933c20e6016d19339ac472f6af3d05d4c3 Mon Sep 17 00:00:00 2001 From: Marek Polacek Date: Tue, 22 Jun 2010 12:53:35 +0200 Subject: rev: new applet text data bss dec hexfilename 377 0 0 377 179rev.o Signed-off-by: Marek Polacek Signed-off-by: Denys Vlasenko --- util-linux/rev.c | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) create mode 100644 util-linux/rev.c diff --git a/util-linux/rev.c b/util-linux/rev.c new file mode 100644 index 000000000..fa3a453ae --- /dev/null +++ b/util-linux/rev.c @@ -0,0 +1,121 @@ +/* + * rev implementation for busybox + * + * Copyright (C) 2010 Marek Polacek + * + * Licensed under GPLv2, see file License in this tarball for details. + */ + +//applet:IF_REV(APPLET(rev, _BB_DIR_BIN, _BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_REV) += rev.o + +//config:config REV +//config: bool "rev" +//config: default y +//config: help +//config: Reverse lines of a file or files. + +//usage:#define rev_trivial_usage +//usage: "[FILE]..." +//usage:#define rev_full_usage "\n\n" +//usage: "Reverse lines of FILE" + +#include "libbb.h" +#include "unicode.h" + +#undef CHAR_T +#if ENABLE_UNICODE_SUPPORT +# define CHAR_T wchar_t +#else +# define CHAR_T char +#endif + +/* In-place invert */ +static void strrev(CHAR_T *s, int len) +{ + int i; + + if (len != 0) { + len--; + if (len != 0 && s[len] == '\n') + len--; + } + + for (i = 0; i < len; i++, len--) { + CHAR_T c = s[i]; + s[i] = s[len]; + s[len] = c; + } +} + +int rev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int rev_main(int argc UNUSED_PARAM, char **argv) +{ + int retval; + size_t bufsize; + char *buf; + + init_unicode(); + + getopt32(argv, ""); + argv += optind; + if (!argv[0]) + argv = (char **)&bb_argv_dash; + + retval = EXIT_SUCCESS; + bufsize = 256; + buf = xmalloc(bufsize); + do { + size_t pos; + FILE *fp; + + fp = fopen_or_warn_stdin(*argv++); + if (!fp) { + retval = EXIT_FAILURE; + continue; + } + + pos = 0; + while (1) { + /* Read one line */ + buf[bufsize - 1] = 1; /* not 0 */ + if (!fgets(buf + pos, bufsize - pos, fp)) + break; /* EOF/error */ + if (buf[bufsize - 1] == '\0' /* fgets filled entire buffer */ + && buf[bufsize - 2] != '\n' /* and did not read '\n' */ + && !feof(fp) + ) { + /* Line is too long, extend buffer */ + pos = bufsize - 1; + bufsize += 64 + bufsize / 8; + buf = xrealloc(buf, bufsize); + continue; + } + + /* Process and print it */ +#if ENABLE_UNICODE_SUPPORT + { + wchar_t *tmp = xmalloc(bufsize * sizeof(wchar_t)); + /* Convert to wchar_t (might error out!) */ + int len = mbstowcs(tmp, buf, bufsize); + if (len >= 0) { + strrev(tmp, len); + /* Convert back to char */ + wcstombs(buf, tmp, bufsize); + } + free(tmp); + } +#else + strrev(buf, strlen(buf)); +#endif + fputs(buf, stdout); + } + fclose(fp); + } while (*argv); + + if (ENABLE_FEATURE_CLEAN_UP) + free(buf); + + fflush_stdout_and_exit(retval); +} -- cgit v1.2.3-55-g6feb From 64606c6d01f5b86b62541b12dd4f475635d47270 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 22 Jun 2010 18:33:15 +0200 Subject: typo fix Signed-off-by: Denys Vlasenko --- init/bootchartd.c | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/init/bootchartd.c b/init/bootchartd.c index 2d9770c4c..f7de13e2f 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -197,7 +197,7 @@ static char *make_tempdir(void) return tempdir; } -static void do_logging(int sample_pariod_us) +static void do_logging(int sample_period_us) { //# Enable process accounting if configured //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then @@ -240,7 +240,7 @@ static void do_logging(int sample_pariod_us) } fflush_all(); wait_more: - usleep(sample_pariod_us); + usleep(sample_period_us); } // [ -e kernel_pacct ] && accton off @@ -326,7 +326,7 @@ static void finalize(char *tempdir, const char *prog) int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bootchartd_main(int argc UNUSED_PARAM, char **argv) { - int sample_pariod_us; + int sample_period_us; pid_t parent_pid, logger_pid; smallint cmd; enum { @@ -361,7 +361,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) /* Here we are in START or INIT state */ /* Read config file: */ - sample_pariod_us = 200 * 1000; + sample_period_us = 200 * 1000; if (ENABLE_FEATURE_BOOTCHARTD_CONFIG_FILE) { char* token[2]; parser_t *parser = config_open2("/etc/bootchartd.conf" + 5, fopen_for_read); @@ -369,7 +369,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) parser = config_open2("/etc/bootchartd.conf", fopen_for_read); while (config_read(parser, token, 2, 0, "#=", PARSE_NORMAL & ~PARSE_COLLAPSE)) { if (strcmp(token[0], "SAMPLE_PERIOD") == 0 && token[1]) - sample_pariod_us = atof(token[1]) * 1000000; + sample_period_us = atof(token[1]) * 1000000; } config_close(parser); } @@ -400,7 +400,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) putenv((char*)bb_PATH_root_path); tempdir = make_tempdir(); - do_logging(sample_pariod_us); + do_logging(sample_period_us); finalize(tempdir, cmd == CMD_START ? argv[2] : NULL); return EXIT_SUCCESS; } -- cgit v1.2.3-55-g6feb From 1b8e2b0e7620c5f80d93f4b7a5a225afe76c65da Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Wed, 23 Jun 2010 20:25:00 +0200 Subject: conspy: code shrink ~200 bytes Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- miscutils/conspy.c | 87 ++++++++++++++++++++++++++---------------------------- 1 file changed, 42 insertions(+), 45 deletions(-) diff --git a/miscutils/conspy.c b/miscutils/conspy.c index ae471a3fa..0a5fdccad 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -63,6 +63,12 @@ struct globals { unsigned width; unsigned height; char last_attr; + int ioerror_count; + int key_count; + int escape_count; + int nokeys; + int current; + int vcsa_fd; struct screen_info info; struct termios term_orig; }; @@ -83,11 +89,12 @@ enum { #define FLAG(x) (1 << FLAG_##x) #define BW (option_mask32 & FLAG(n)) -static void screen_read_close(int fd, char *data) +static void screen_read_close(void) { unsigned i, j; + char *data = G.data + G.current; - xread(fd, data, G.size); + xread(G.vcsa_fd, data, G.size); G.last_attr = 0; for (i = 0; i < G.info.lines; i++) { for (j = 0; j < G.info.rows; j++, NEXT(data)) { @@ -100,7 +107,7 @@ static void screen_read_close(int fd, char *data) DATA(data) = 0; } } - close(fd); + close(G.vcsa_fd); } static void screen_char(char *data) @@ -131,13 +138,13 @@ static void gotoxy(int row, int line) printf("\033[%u;%uH", line + 1, row + 1); } -static void screen_dump(char *data) +static void screen_dump(void) { int linefeed_cnt; int line, row; int linecnt = G.info.lines - G.y; + char *data = G.data + G.current + (2 * G.y * G.info.rows); - data += 2 * G.y * G.info.rows; linefeed_cnt = 0; for (line = 0; line < linecnt && line < G.height; line++) { int space_cnt = 0; @@ -197,12 +204,12 @@ static void cleanup(int code) static void get_initial_data(const char* vcsa_name) { int size; - int fd = xopen(vcsa_name, O_RDONLY); - xread(fd, &G.info, 4); + G.vcsa_fd = xopen(vcsa_name, O_RDONLY); + xread(G.vcsa_fd, &G.info, 4); G.size = size = G.info.rows * G.info.lines * 2; G.width = G.height = UINT_MAX; G.data = xzalloc(2 * size); - screen_read_close(fd, G.data); + screen_read_close(); } static void create_cdev_if_doesnt_exist(const char* name, dev_t dev) @@ -250,7 +257,6 @@ static NOINLINE void start_shell_in_child(const char* tty_name) int conspy_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE; int conspy_main(int argc UNUSED_PARAM, char **argv) { - char *buffer[2]; char vcsa_name[sizeof("/dev/vcsa") + 2]; char tty_name[sizeof("/dev/tty") + 2]; #define keybuf bb_common_bufsiz1 @@ -258,11 +264,6 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) unsigned opts; unsigned ttynum; int poll_timeout_ms; - int current; - int ioerror_count; - int key_count; - int escape_count; - int nokeys; #if ENABLE_LONG_OPTS static const char getopt_longopts[] ALIGN1 = "viewonly\0" No_argument "v" @@ -276,7 +277,6 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) applet_long_options = getopt_longopts; #endif INIT_G(); - strcpy(vcsa_name, "/dev/vcsa"); opt_complementary = "x+:y+"; // numeric params opts = getopt32(argv, "vcsndfx:y:", &G.x, &G.y); @@ -284,8 +284,8 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) ttynum = 0; if (argv[0]) { ttynum = xatou_range(argv[0], 0, 63); - sprintf(vcsa_name + sizeof("/dev/vcsa")-1, "%u", ttynum); } + sprintf(vcsa_name, "/dev/vcsa%u", ttynum); sprintf(tty_name, "%s%u", "/dev/tty", ttynum); if (opts & FLAG(c)) { if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v)) @@ -299,7 +299,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) get_initial_data(vcsa_name); G.kbd_fd = xopen(CURRENT_TTY, O_RDONLY); if (opts & FLAG(d)) { - screen_dump(G.data); + screen_dump(); bb_putchar('\n'); if (ENABLE_FEATURE_CLEAN_UP) { free(ptr_to_globals); @@ -318,23 +318,21 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) termbuf.c_cc[VMIN] = 1; termbuf.c_cc[VTIME] = 0; tcsetattr(G.kbd_fd, TCSANOW, &termbuf); - buffer[0] = G.data; - buffer[1] = G.data + G.size; poll_timeout_ms = 250; - ioerror_count = key_count = escape_count = nokeys = current = 0; while (1) { struct pollfd pfd; - int vcsa_handle; int bytes_read; int i, j; - int next = 1 - current; - char *data = buffer[next]; - char *old = buffer[current]; + char *data, *old; + old = G.data + G.current; + G.current = G.size - G.current; + data = G.data + G.current; + // Close & re-open vcsa in case they have // swapped virtual consoles - vcsa_handle = xopen(vcsa_name, O_RDONLY); - xread(vcsa_handle, &G.info, 4); + G.vcsa_fd = xopen(vcsa_name, O_RDONLY); + xread(G.vcsa_fd, &G.info, 4); if (G.size != (G.info.rows * G.info.lines * 2)) { cleanup(1); } @@ -364,10 +362,10 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) } // Scan console data and redraw our tty where needed - screen_read_close(vcsa_handle, data); + screen_read_close(); if (i != G.width || j != G.height) { clrscr(); - screen_dump(data); + screen_dump(); } else for (i = 0; i < G.info.lines; i++) { char *last = last; @@ -399,7 +397,6 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) for (; first < last; NEXT(first)) screen_char(first); } - current = next; curmove(); // Wait for local user keypresses @@ -407,26 +404,26 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) pfd.events = POLLIN; bytes_read = 0; switch (poll(&pfd, 1, poll_timeout_ms)) { + char *k; case -1: if (errno != EINTR) cleanup(1); break; case 0: - if (++nokeys >= 4) - nokeys = escape_count = 0; + if (++G.nokeys >= 4) + G.nokeys = G.escape_count = 0; break; default: // Read the keys pressed - bytes_read = read(G.kbd_fd, keybuf + key_count, - sizeof(keybuf) - key_count); + k = keybuf + G.key_count; + bytes_read = read(G.kbd_fd, k, sizeof(keybuf) - G.key_count); if (bytes_read < 0) cleanup(1); // Do exit processing for (i = 0; i < bytes_read; i++) { - if (keybuf[key_count + i] != '\033') - escape_count = 0; - else if (++escape_count >= 3) + if (k[i] != '\033') G.escape_count = 0; + else if (++G.escape_count >= 3) cleanup(0); } } @@ -436,23 +433,23 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) // buffer. Don't do this if the virtual console is in scan // code mode - giving ASCII characters to a program expecting // scan codes will confuse it. - if (!(option_mask32 & FLAG(v)) && escape_count == 0) { + if (!(option_mask32 & FLAG(v)) && G.escape_count == 0) { int handle, result; long kbd_mode; - key_count += bytes_read; + G.key_count += bytes_read; handle = xopen(tty_name, O_WRONLY); result = ioctl(handle, KDGKBMODE, &kbd_mode); if (result == -1) /* nothing */; else if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE) - key_count = 0; // scan code mode + G.key_count = 0; // scan code mode else { - for (i = 0; i < key_count && result != -1; i++) + for (i = 0; i < G.key_count && result != -1; i++) result = ioctl(handle, TIOCSTI, keybuf + i); - key_count -= i; - if (key_count) - memmove(keybuf, keybuf + i, key_count); + G.key_count -= i; + if (G.key_count) + memmove(keybuf, keybuf + i, G.key_count); // If there is an application on console which reacts // to keypresses, we need to make our first sleep // shorter to quickly redraw whatever it printed there. @@ -465,8 +462,8 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) // We sometimes get spurious IO errors on the TTY // as programs close and re-open it if (result != -1) - ioerror_count = 0; - else if (errno != EIO || ++ioerror_count > 4) + G.ioerror_count = 0; + else if (errno != EIO || ++G.ioerror_count > 4) cleanup(1); } } -- cgit v1.2.3-55-g6feb From da75f4484469ca0122b80de69bf3b75a6be71efc Mon Sep 17 00:00:00 2001 From: Andreas Bühmann Date: Thu, 24 Jun 2010 04:32:37 +0200 Subject: ash: <> redir should not truncate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Andreas Bühmann Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 +- shell/ash_test/ash-redir/redir9.right | 2 ++ shell/ash_test/ash-redir/redir9.tests | 4 ++++ 3 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 shell/ash_test/ash-redir/redir9.right create mode 100644 shell/ash_test/ash-redir/redir9.tests diff --git a/shell/ash.c b/shell/ash.c index f581b5bdf..1f8f90a09 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -4938,7 +4938,7 @@ openredirect(union node *redir) break; case NFROMTO: fname = redir->nfile.expfname; - f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666); + f = open(fname, O_RDWR|O_CREAT, 0666); if (f < 0) goto ecreate; break; diff --git a/shell/ash_test/ash-redir/redir9.right b/shell/ash_test/ash-redir/redir9.right new file mode 100644 index 000000000..34c2512e4 --- /dev/null +++ b/shell/ash_test/ash-redir/redir9.right @@ -0,0 +1,2 @@ +Ok +Done:0 diff --git a/shell/ash_test/ash-redir/redir9.tests b/shell/ash_test/ash-redir/redir9.tests new file mode 100644 index 000000000..8befa611c --- /dev/null +++ b/shell/ash_test/ash-redir/redir9.tests @@ -0,0 +1,4 @@ +echo Ok >file.tmp +cat 0<>file.tmp +echo Done:$? +rm file.tmp -- cgit v1.2.3-55-g6feb From dd8adde3866ac22bd510348b733bb29e1662ac6d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 24 Jun 2010 05:00:50 +0200 Subject: *: introduce and use bb_unsetenv_and_free function old new delta bb_unsetenv_and_free - 17 +17 tcpudpsvd_main 1819 1810 -9 safe_setenv 58 47 -11 udhcp_run_script 630 616 -14 make_device 1683 1663 -20 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/4 up/down: 17/-54) Total: -37 bytes Signed-off-by: Denys Vlasenko --- include/libbb.h | 1 + libbb/xfuncs_printf.c | 5 +++++ miscutils/crond.c | 3 +-- networking/tcpudp.c | 3 +-- networking/udhcp/dhcpc.c | 3 +-- util-linux/mdev.c | 6 ++---- 6 files changed, 11 insertions(+), 10 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 5e962fdb6..58719a85b 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -408,6 +408,7 @@ void xchdir(const char *path) FAST_FUNC; void xchroot(const char *path) FAST_FUNC; void xsetenv(const char *key, const char *value) FAST_FUNC; void bb_unsetenv(const char *key) FAST_FUNC; +void bb_unsetenv_and_free(char *key) FAST_FUNC; void xunlink(const char *pathname) FAST_FUNC; void xstat(const char *pathname, struct stat *buf) FAST_FUNC; int xopen(const char *pathname, int flags) FAST_FUNC; diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c index 03aeaaa38..f021493b1 100644 --- a/libbb/xfuncs_printf.c +++ b/libbb/xfuncs_printf.c @@ -323,6 +323,11 @@ void FAST_FUNC bb_unsetenv(const char *var) free(tp); } +void FAST_FUNC bb_unsetenv_and_free(char *var) +{ + bb_unsetenv(var); + free(var); +} // Die with an error message if we can't set gid. (Because resource limits may // limit this user to a given number of processes, and if that fills up the diff --git a/miscutils/crond.c b/miscutils/crond.c index f51159233..4a3103cb9 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c @@ -264,8 +264,7 @@ static void safe_setenv(char **pvar_val, const char *var, const char *val) char *var_val = *pvar_val; if (var_val) { - bb_unsetenv(var_val); - free(var_val); + bb_unsetenv_and_free(var_val); } *pvar_val = xasprintf("%s=%s", var, val); putenv(*pvar_val); diff --git a/networking/tcpudp.c b/networking/tcpudp.c index 42845df0e..b32fad624 100644 --- a/networking/tcpudp.c +++ b/networking/tcpudp.c @@ -85,8 +85,7 @@ static void undo_xsetenv(void) char **pp = env_cur = &env_var[0]; while (*pp) { char *var = *pp; - bb_unsetenv(var); - free(var); + bb_unsetenv_and_free(var); *pp++ = NULL; } } diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index c2b21c695..de1b79844 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -327,8 +327,7 @@ static void udhcp_run_script(struct dhcp_packet *packet, const char *name) for (curr = envp; *curr; curr++) { log2(" %s", *curr); - bb_unsetenv(*curr); - free(*curr); + bb_unsetenv_and_free(*curr); } free(envp); } diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 217075660..b4042c07e 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -374,10 +374,8 @@ static void make_device(char *path, int delete) putenv(s1); if (system(command) == -1) bb_perror_msg("can't run '%s'", command); - unsetenv("SUBSYSTEM"); - free(s1); - unsetenv("MDEV"); - free(s); + bb_unsetenv_and_free(s1); + bb_unsetenv_and_free(s); free(command); } -- cgit v1.2.3-55-g6feb From a091d45c3beb767ce9cb530ab0a81aee1238495d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 24 Jun 2010 05:05:12 +0200 Subject: smemcap: new applet Signed-off-by: Denys Vlasenko --- procps/smemcap.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 procps/smemcap.c diff --git a/procps/smemcap.c b/procps/smemcap.c new file mode 100644 index 000000000..cdcc891a1 --- /dev/null +++ b/procps/smemcap.c @@ -0,0 +1,152 @@ +/* + smemcap - a tool for meaningful memory reporting + + Copyright 2008-2009 Matt Mackall + + This software may be used and distributed according to the terms of + the GNU General Public License version 2 or later, incorporated + herein by reference. +*/ + +//applet:IF_SMEMCAP(APPLET(smemcap, _BB_DIR_USR_BIN, _BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_SMEMCAP) += smemcap.o + +//config:config SMEMCAP +//config: bool "smemcap" +//config: default y +//config: help +//config: smemcap is a tool for capturing process data for smem, +//config: a memory usage statistic tool. + +#include "libbb.h" + +struct tar_header { + char name[100]; /* 0-99 */ + char mode[8]; /* 100-107 */ + char uid[8]; /* 108-115 */ + char gid[8]; /* 116-123 */ + char size[12]; /* 124-135 */ + char mtime[12]; /* 136-147 */ + char chksum[8]; /* 148-155 */ + char typeflag; /* 156-156 */ + char linkname[100]; /* 157-256 */ + /* POSIX: "ustar" NUL "00" */ + /* GNU tar: "ustar " NUL */ + /* Normally it's defined as magic[6] followed by + * version[2], but we put them together to save code. + */ + char magic[8]; /* 257-264 */ + char uname[32]; /* 265-296 */ + char gname[32]; /* 297-328 */ + char devmajor[8]; /* 329-336 */ + char devminor[8]; /* 337-344 */ + char prefix[155]; /* 345-499 */ + char padding[12]; /* 500-512 (pad to exactly TAR_512) */ +}; + +struct fileblock { + struct fileblock *next; + char data[512]; +}; + +static void writeheader(const char *path, struct stat *sb, int type) +{ + struct tar_header header; + int i, sum; + + memset(&header, 0, 512); + strcpy(header.name, path); + sprintf(header.mode, "%o", sb->st_mode & 0777); + /* careful to not overflow fields! */ + sprintf(header.uid, "%o", sb->st_uid & 07777777); + sprintf(header.gid, "%o", sb->st_gid & 07777777); + sprintf(header.size, "%o", (unsigned)sb->st_size); + sprintf(header.mtime, "%llo", sb->st_mtime & 077777777777LL); + header.typeflag = type; + //strcpy(header.magic, "ustar "); - do we want to be standard-compliant? + + /* Calculate and store the checksum (the sum of all of the bytes of + * the header). The checksum field must be filled with blanks for the + * calculation. The checksum field is formatted differently from the + * other fields: it has 6 digits, a NUL, then a space -- rather than + * digits, followed by a NUL like the other fields... */ + header.chksum[7] = ' '; + sum = ' ' * 7; + for (i = 0; i < 512; i++) + sum += ((unsigned char*)&header)[i]; + sprintf(header.chksum, "%06o", sum); + + xwrite(STDOUT_FILENO, &header, 512); +} + +static void archivefile(const char *path) +{ + struct fileblock *start, *cur; + struct fileblock **prev = &start; + int fd, r; + unsigned size = 0; + struct stat s; + + /* buffer the file */ + fd = xopen(path, O_RDONLY); + do { + cur = xzalloc(sizeof(*cur)); + *prev = cur; + prev = &cur->next; + r = full_read(fd, cur->data, 512); + if (r > 0) + size += r; + } while (r == 512); + + /* write archive header */ + fstat(fd, &s); + close(fd); + s.st_size = size; + writeheader(path, &s, '0'); + + /* dump file contents */ + for (cur = start; (int)size > 0; size -= 512) { + xwrite(STDOUT_FILENO, cur->data, 512); + start = cur; + cur = cur->next; + free(start); + } +} + +static void archivejoin(const char *sub, const char *name) +{ + char path[sizeof(long long)*3 + sizeof("/cmdline")]; + sprintf(path, "%s/%s", sub, name); + archivefile(path); +} + +//usage:#define smemcap_trivial_usage ">SMEMDATA.TAR" +//usage:#define smemcap_full_usage "\n\n" +//usage: "Collect memory usage data in /proc and write it to stdout" + +int smemcap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + DIR *d; + struct dirent *de; + + xchdir("/proc"); + d = xopendir("."); + + archivefile("meminfo"); + archivefile("version"); + while ((de = readdir(d)) != NULL) { + if (isdigit(de->d_name[0])) { + struct stat s; + memset(&s, 0, sizeof(s)); + s.st_mode = 0555; + writeheader(de->d_name, &s, '5'); + archivejoin(de->d_name, "smaps"); + archivejoin(de->d_name, "cmdline"); + archivejoin(de->d_name, "stat"); + } + } + + return EXIT_SUCCESS; +} -- cgit v1.2.3-55-g6feb From a54985b27919313e97a2b49fe4b5f87824886d92 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 24 Jun 2010 17:50:00 +0200 Subject: conspy: document attribute byte format Signed-off-by: Denys Vlasenko --- miscutils/conspy.c | 42 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 0a5fdccad..b443c9133 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -62,7 +62,7 @@ struct globals { int kbd_fd; unsigned width; unsigned height; - char last_attr; + uint8_t last_attr; int ioerror_count; int key_count; int escape_count; @@ -112,17 +112,43 @@ static void screen_read_close(void) static void screen_char(char *data) { - if (!BW && G.last_attr != ATTR(data)) { - // BLGCRMOW + uint8_t attr = ATTR(data); + + if (!BW && G.last_attr != attr) { +// Attribute layout for VGA compatible text videobuffer: +// blinking text +// |red bkgd +// ||green bkgd +// |||blue bkgd +// vvvv +// 00000000 <- lsb bit on the right +// bold text / text 8th bit +// red text +// green text +// blue text +// TODO: apparently framebuffer-based console uses different layout +// (bug? attempt to get 8th text bit in better position?) +// red bkgd +// |green bkgd +// ||blue bkgd +// vvv +// 00000000 <- lsb bit on the right +// bold text +// red text +// green text +// blue text +// text 8th bit + // converting RGB color bit triad to BGR: static const char color[8] = "04261537"; + G.last_attr = attr; printf("\033[%c;4%c;3%cm", - (ATTR(data) & 8) ? '1' // bold - : '0', // defaults - color[(ATTR(data) >> 4) & 7], color[ATTR(data) & 7]); - G.last_attr = ATTR(data); + (attr & 8) ? '1' : '0', // bold text / reset all + color[(attr >> 4) & 7], // bkgd color + color[attr & 7] // text color + ); } - bb_putchar(CHAR(data)); + putchar(CHAR(data)); } #define clrscr() printf("\033[1;1H" "\033[0J") -- cgit v1.2.3-55-g6feb From eff6d593437afa91f7fb7c418e13dfb2ddb6886b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 24 Jun 2010 20:23:40 +0200 Subject: ntpd: step correction to variables had wrong sign, fixing Signed-off-by: Denys Vlasenko --- networking/ntpd.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/networking/ntpd.c b/networking/ntpd.c index 6d9183a4b..14c3a5fbb 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -603,9 +603,9 @@ reset_peer_stats(peer_t *p, double offset) for (i = 0; i < NUM_DATAPOINTS; i++) { if (small_ofs) { - p->filter_datapoint[i].d_recv_time -= offset; + p->filter_datapoint[i].d_recv_time += offset; if (p->filter_datapoint[i].d_offset != 0) { - p->filter_datapoint[i].d_offset -= offset; + p->filter_datapoint[i].d_offset += offset; } } else { p->filter_datapoint[i].d_recv_time = G.cur_time; @@ -614,13 +614,12 @@ reset_peer_stats(peer_t *p, double offset) } } if (small_ofs) { - p->lastpkt_recv_time -= offset; + p->lastpkt_recv_time += offset; } else { p->reachable_bits = 0; p->lastpkt_recv_time = G.cur_time; } filter_datapoints(p); /* recalc p->filter_xxx */ - p->next_action_time -= offset; VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); } @@ -815,11 +814,14 @@ step_time(double offset) for (item = G.ntp_peers; item != NULL; item = item->link) { peer_t *pp = (peer_t *) item->data; reset_peer_stats(pp, offset); + //bb_error_msg("offset:%f pp->next_action_time:%f -> %f", + // offset, pp->next_action_time, pp->next_action_time + offset); + pp->next_action_time += offset; } /* Globals: */ - G.cur_time -= offset; - G.last_update_recv_time -= offset; - G.last_script_run -= offset; + G.cur_time += offset; + G.last_update_recv_time += offset; + G.last_script_run += offset; } -- cgit v1.2.3-55-g6feb From 51fa147c9bab41cc1f7bf5b2e3bbeddf0fdaf5ca Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Jun 2010 00:57:57 +0200 Subject: conspy: code shrink function old new delta conspy_main 1385 1380 -5 screen_dump 215 202 -13 Signed-off-by: Denys Vlasenko --- miscutils/conspy.c | 49 ++++++++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 21 deletions(-) diff --git a/miscutils/conspy.c b/miscutils/conspy.c index b443c9133..b5adce930 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -9,9 +9,9 @@ * * Licensed under GPLv2 or later, see file License in this tarball for details. * - * example : conspy num shared access to console num - * or conspy -d num screenshot of console num - * or conspy -cs num poor man's GNU screen like + * example: conspy num shared access to console num + * or conspy -d num screenshot of console num + * or conspy -cs num poor man's GNU screen like */ //applet:IF_CONSPY(APPLET(conspy, _BB_DIR_BIN, _BB_SUID_DROP)) @@ -28,7 +28,7 @@ //config: or conspy -cs num poor man's GNU screen like //usage:#define conspy_trivial_usage -//usage: "[-vcsndf] [-x ROW] [-y LINE] [CONSOLE_NO]" +//usage: "[-vcsndf] [-x ROW] [-y LINE] [CONSOLE_NO]" //usage:#define conspy_full_usage "\n\n" //usage: "A text-mode VNC like program for Linux virtual consoles." //usage: "\nTo exit, quickly press ESC 3 times." @@ -50,10 +50,10 @@ struct screen_info { unsigned char lines, rows, cursor_x, cursor_y; }; -#define CHAR(x) ((x)[0]) -#define ATTR(x) ((x)[1]) +#define CHAR(x) ((uint8_t)((x)[0])) +#define ATTR(x) ((uint8_t)((x)[1])) #define NEXT(x) ((x)+=2) -#define DATA(x) (* (short *) (x)) +#define DATA(x) (*(uint16_t*)(x)) struct globals { char* data; @@ -102,7 +102,7 @@ static void screen_read_close(void) unsigned y = i - G.y; // if will catch i < G.y too if (CHAR(data) < ' ') - CHAR(data) = ' '; + *data = ' '; // CHAR(data) = ' '; if (y >= G.height || x >= G.width) DATA(data) = 0; } @@ -151,8 +151,15 @@ static void screen_char(char *data) putchar(CHAR(data)); } -#define clrscr() printf("\033[1;1H" "\033[0J") -#define curoff() printf("\033[?25l") +static void clrscr(void) +{ + printf("\033[1;1H" "\033[0J"); +} + +static void curoff(void) +{ + printf("\033[?25l"); +} static void curon(void) { @@ -180,10 +187,10 @@ static void screen_dump(void) if (tty_row >= G.width) continue; space_cnt++; - if (BW && (CHAR(data) | ' ') == ' ') + if (BW && CHAR(data) == ' ') continue; while (linefeed_cnt != 0) { - bb_putchar('\r'); + //bb_putchar('\r'); - tty driver does it for us bb_putchar('\n'); linefeed_cnt--; } @@ -229,12 +236,11 @@ static void cleanup(int code) static void get_initial_data(const char* vcsa_name) { - int size; G.vcsa_fd = xopen(vcsa_name, O_RDONLY); xread(G.vcsa_fd, &G.info, 4); - G.size = size = G.info.rows * G.info.lines * 2; + G.size = G.info.rows * G.info.lines * 2; G.width = G.height = UINT_MAX; - G.data = xzalloc(2 * size); + G.data = xzalloc(2 * G.size); screen_read_close(); } @@ -280,11 +286,11 @@ static NOINLINE void start_shell_in_child(const char* tty_name) } } -int conspy_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE; +int conspy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int conspy_main(int argc UNUSED_PARAM, char **argv) { - char vcsa_name[sizeof("/dev/vcsa") + 2]; - char tty_name[sizeof("/dev/tty") + 2]; + char vcsa_name[sizeof("/dev/vcsaNN")]; + char tty_name[sizeof("/dev/ttyNN")]; #define keybuf bb_common_bufsiz1 struct termios termbuf; unsigned opts; @@ -339,7 +345,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) tcgetattr(G.kbd_fd, &G.term_orig); termbuf = G.term_orig; termbuf.c_iflag &= ~(BRKINT|INLCR|ICRNL|IXON|IXOFF|IUCLC|IXANY|IMAXBEL); - termbuf.c_oflag &= ~(OPOST); + //termbuf.c_oflag &= ~(OPOST); - no, we still want \n -> \r\n termbuf.c_lflag &= ~(ISIG|ICANON|ECHO); termbuf.c_cc[VMIN] = 1; termbuf.c_cc[VTIME] = 0; @@ -354,7 +360,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) old = G.data + G.current; G.current = G.size - G.current; data = G.data + G.current; - + // Close & re-open vcsa in case they have // swapped virtual consoles G.vcsa_fd = xopen(vcsa_name, O_RDONLY); @@ -448,7 +454,8 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) // Do exit processing for (i = 0; i < bytes_read; i++) { - if (k[i] != '\033') G.escape_count = 0; + if (k[i] != '\033') + G.escape_count = 0; else if (++G.escape_count >= 3) cleanup(0); } -- cgit v1.2.3-55-g6feb From 2b46fd49b14b2ac30e0c767c65ac2b29f6922a45 Mon Sep 17 00:00:00 2001 From: Ladislav Michl Date: Fri, 25 Jun 2010 01:33:00 +0200 Subject: tar: optional support for --to-command function old new delta data_extract_to_command - 430 +430 dec2env - 44 +44 tar_main 778 819 +41 str2env - 37 +37 tar_var - 32 +32 xputenv - 22 +22 tar_longopts 257 270 +13 ------------------------------------------------------------------------------ (add/remove: 6/0 grow/shrink: 2/0 up/down: 619/0) Total: 619 bytes Signed-off-by: Ladislav Michl Signed-off-by: Denys Vlasenko --- archival/Config.src | 9 ++ archival/libunarchive/Kbuild.src | 1 + archival/libunarchive/data_extract_to_command.c | 137 ++++++++++++++++++++++++ archival/tar.c | 12 +++ include/unarchive.h | 4 + 5 files changed, 163 insertions(+) create mode 100644 archival/libunarchive/data_extract_to_command.c diff --git a/archival/Config.src b/archival/Config.src index 3dbd3aea1..f64b3347b 100644 --- a/archival/Config.src +++ b/archival/Config.src @@ -280,6 +280,15 @@ config FEATURE_TAR_LONG_OPTIONS help Enable use of long options, increases size by about 400 Bytes +config FEATURE_TAR_TO_COMMAND + bool "Support for writing to an external program" + default y + depends on TAR && FEATURE_TAR_LONG_OPTIONS + help + If you enable this option you'll be able to instruct tar to send + the contents of each extracted file to the standard input of an + external program. + config FEATURE_TAR_UNAME_GNAME bool "Enable use of user and group names" default y diff --git a/archival/libunarchive/Kbuild.src b/archival/libunarchive/Kbuild.src index 81854558b..6ad1d7a65 100644 --- a/archival/libunarchive/Kbuild.src +++ b/archival/libunarchive/Kbuild.src @@ -53,6 +53,7 @@ lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2 lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o +lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o ifneq ($(lib-y),) lib-y += $(COMMON_FILES) diff --git a/archival/libunarchive/data_extract_to_command.c b/archival/libunarchive/data_extract_to_command.c new file mode 100644 index 000000000..983c5301d --- /dev/null +++ b/archival/libunarchive/data_extract_to_command.c @@ -0,0 +1,137 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + */ + +#include "libbb.h" +#include "unarchive.h" + +enum { + //TAR_FILETYPE, + TAR_MODE, + TAR_FILENAME, + TAR_REALNAME, +#if ENABLE_FEATURE_TAR_UNAME_GNAME + TAR_UNAME, + TAR_GNAME, +#endif + TAR_SIZE, + TAR_UID, + TAR_GID, + TAR_MAX, +}; + +static const char *const tar_var[] = { + // "FILETYPE", + "MODE", + "FILENAME", + "REALNAME", +#if ENABLE_FEATURE_TAR_UNAME_GNAME + "UNAME", + "GNAME", +#endif + "SIZE", + "UID", + "GID", +}; + +static void xputenv(char *str) +{ + if (putenv(str)) + bb_error_msg_and_die(bb_msg_memory_exhausted); +} + +static void str2env(char *env[], int idx, const char *str) +{ + env[idx] = xasprintf("TAR_%s=%s", tar_var[idx], str); + xputenv(env[idx]); +} + +static void dec2env(char *env[], int idx, unsigned long long val) +{ + env[idx] = xasprintf("TAR_%s=%llu", tar_var[idx], val); + xputenv(env[idx]); +} + +static void oct2env(char *env[], int idx, unsigned long val) +{ + env[idx] = xasprintf("TAR_%s=%lo", tar_var[idx], val); + xputenv(env[idx]); +} + +void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) +{ + file_header_t *file_header = archive_handle->file_header; + +#if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */ + char *sctx = archive_handle->tar__next_file_sctx; + if (!sctx) + sctx = archive_handle->tar__global_sctx; + if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ + setfscreatecon(sctx); + free(archive_handle->tar__next_file_sctx); + archive_handle->tar__next_file_sctx = NULL; + } +#endif + + if ((file_header->mode & S_IFMT) == S_IFREG) { + pid_t pid; + int p[2], status; + char *tar_env[TAR_MAX]; + + memset(tar_env, 0, sizeof(tar_env)); + + xpipe(p); + pid = BB_MMU ? fork() : vfork(); + switch (pid) { + case -1: + bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); + case 0: + /* Child */ + /* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */ + oct2env(tar_env, TAR_MODE, file_header->mode); + str2env(tar_env, TAR_FILENAME, file_header->name); + str2env(tar_env, TAR_REALNAME, file_header->name); +#if ENABLE_FEATURE_TAR_UNAME_GNAME + str2env(tar_env, TAR_UNAME, file_header->tar__uname); + str2env(tar_env, TAR_GNAME, file_header->tar__gname); +#endif + dec2env(tar_env, TAR_SIZE, file_header->size); + dec2env(tar_env, TAR_UID, file_header->uid); + dec2env(tar_env, TAR_GID, file_header->gid); + close(p[1]); + xdup2(p[0], STDIN_FILENO); + signal(SIGPIPE, SIG_DFL); + execl("/bin/sh", "/bin/sh" + 5, "-c", archive_handle->tar__to_command, NULL); + bb_perror_msg_and_die("can't execute '%s'", "/bin/sh"); + } + close(p[0]); + /* Our caller is expected to do signal(SIGPIPE, SIG_IGN) + * so that we don't die if child don't read all the input: */ + bb_copyfd_exact_size(archive_handle->src_fd, p[1], file_header->size); + close(p[1]); + + if (safe_waitpid(pid, &status, 0) == -1) + bb_perror_msg_and_die("waitpid"); + if (WIFEXITED(status) && WEXITSTATUS(status)) + bb_error_msg_and_die("'%s' returned status %d", + archive_handle->tar__to_command, WEXITSTATUS(status)); + if (WIFSIGNALED(status)) + bb_error_msg_and_die("'%s' terminated on signal %d", + archive_handle->tar__to_command, WTERMSIG(status)); + + if (!BB_MMU) { + int i; + for (i = 0; i < TAR_MAX; i++) { + if (tar_env[i]) + bb_unsetenv_and_free(tar_env[i]); + } + } + } + +#if 0 /* ENABLE_FEATURE_TAR_SELINUX */ + if (sctx) + /* reset the context after creating an entry */ + setfscreatecon(NULL); +#endif +} diff --git a/archival/tar.c b/archival/tar.c index 3a940128b..344c9dea4 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -750,6 +750,7 @@ enum { IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,) // 16th bit IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,) #if ENABLE_FEATURE_TAR_LONG_OPTIONS + IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,) OPTBIT_NUMERIC_OWNER, OPTBIT_NOPRESERVE_PERM, OPTBIT_OVERWRITE, @@ -772,6 +773,7 @@ enum { OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0, // z OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0, // Z OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m + OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0, // to-command OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite @@ -812,6 +814,9 @@ static const char tar_longopts[] ALIGN1 = # endif # if ENABLE_FEATURE_TAR_NOPRESERVE_TIME "touch\0" No_argument "m" +# endif +# if ENABLE_FEATURE_TAR_TO_COMMAND + "to-command\0" Required_argument "\xfb" # endif /* use numeric uid/gid from tar header, not textual */ "numeric-owner\0" No_argument "\xfc" @@ -904,6 +909,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) , &tar_filename // -f filename IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X + IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM , &excludes // --exclude #endif @@ -922,6 +928,12 @@ int tar_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_2STDOUT) tar_handle->action_data = data_extract_to_stdout; + if (opt & OPT_2COMMAND) { + putenv((char*)"TAR_FILETYPE=f"); + signal(SIGPIPE, SIG_IGN); + tar_handle->action_data = data_extract_to_command; + } + if (opt & OPT_KEEP_OLD) tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD; diff --git a/include/unarchive.h b/include/unarchive.h index 8009de282..f3aa05d09 100644 --- a/include/unarchive.h +++ b/include/unarchive.h @@ -75,6 +75,9 @@ typedef struct archive_handle_t { char* tar__longname; char* tar__linkname; # endif +#if ENABLE_FEATURE_TAR_TO_COMMAND + char* tar__to_command; +#endif # if ENABLE_FEATURE_TAR_SELINUX char* tar__global_sctx; char* tar__next_file_sctx; @@ -128,6 +131,7 @@ extern void unpack_ar_archive(archive_handle_t *ar_archive) FAST_FUNC; extern void data_skip(archive_handle_t *archive_handle) FAST_FUNC; extern void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC; extern void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC; +extern void data_extract_to_command(archive_handle_t *archive_handle) FAST_FUNC; extern void header_skip(const file_header_t *file_header) FAST_FUNC; extern void header_list(const file_header_t *file_header) FAST_FUNC; -- cgit v1.2.3-55-g6feb From 41ddd9f60604cd994eeb37eb5708e9d3d5c8484b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Jun 2010 01:46:53 +0200 Subject: *: make exec failure message more consistent Signed-off-by: Denys Vlasenko --- console-tools/openvt.c | 2 +- coreutils/chroot.c | 4 ++-- coreutils/env.c | 6 +++--- coreutils/nice.c | 5 ++--- coreutils/nohup.c | 5 +++-- debianutils/start_stop_daemon.c | 2 +- libbb/run_shell.c | 2 +- libbb/vfork_daemon_rexec.c | 2 +- mailutils/mail.c | 4 ++-- mailutils/mime.c | 4 ++-- miscutils/chrt.c | 6 +++--- miscutils/ionice.c | 6 +++--- miscutils/setsid.c | 5 +++-- miscutils/taskset.c | 6 +++--- miscutils/time.c | 2 +- miscutils/timeout.c | 2 +- networking/httpd.c | 2 +- networking/ifupdown.c | 2 +- networking/inetd.c | 2 +- networking/nc_bloaty.c | 2 +- networking/tcpudp.c | 2 +- printutils/lpd.c | 4 ++-- runit/chpst.c | 2 +- selinux/runcon.c | 1 - 24 files changed, 40 insertions(+), 40 deletions(-) diff --git a/console-tools/openvt.c b/console-tools/openvt.c index 7bd6072a4..6f58916e7 100644 --- a/console-tools/openvt.c +++ b/console-tools/openvt.c @@ -98,7 +98,7 @@ static NOINLINE void vfork_child(char **argv) //bb_error_msg("VT's sid %d", tcgetsid(0)); //bb_error_msg("VT's pgrp %d", tcgetpgrp(0)); BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("exec %s", argv[0]); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } } diff --git a/coreutils/chroot.c b/coreutils/chroot.c index f7228a61a..bc0b1f82c 100644 --- a/coreutils/chroot.c +++ b/coreutils/chroot.c @@ -30,6 +30,6 @@ int chroot_main(int argc UNUSED_PARAM, char **argv) argv[1] = (char *) "-i"; } - BB_EXECVP(*argv, argv); - bb_perror_msg_and_die("can't execute '%s'", *argv); + BB_EXECVP(argv[0], argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } diff --git a/coreutils/env.c b/coreutils/env.c index 9635d2b22..c6ba04d35 100644 --- a/coreutils/env.c +++ b/coreutils/env.c @@ -76,11 +76,11 @@ int env_main(int argc UNUSED_PARAM, char **argv) ++argv; } - if (*argv) { - BB_EXECVP(*argv, argv); + if (argv[0]) { + BB_EXECVP(argv[0], argv); /* SUSv3-mandated exit codes. */ xfunc_error_retval = (errno == ENOENT) ? 127 : 126; - bb_simple_perror_msg_and_die(*argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } if (environ) { /* clearenv() may set environ == NULL! */ diff --git a/coreutils/nice.c b/coreutils/nice.c index d24a95b45..0f70f1079 100644 --- a/coreutils/nice.c +++ b/coreutils/nice.c @@ -47,9 +47,8 @@ int nice_main(int argc, char **argv) } } - BB_EXECVP(*argv, argv); /* Now exec the desired program. */ - + BB_EXECVP(argv[0], argv); /* The exec failed... */ xfunc_error_retval = (errno == ENOENT) ? 127 : 126; /* SUSv3 */ - bb_simple_perror_msg_and_die(*argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } diff --git a/coreutils/nohup.c b/coreutils/nohup.c index 4f6385f8e..1027ada1c 100644 --- a/coreutils/nohup.c +++ b/coreutils/nohup.c @@ -75,6 +75,7 @@ int nohup_main(int argc UNUSED_PARAM, char **argv) signal(SIGHUP, SIG_IGN); - BB_EXECVP(argv[1], argv+1); - bb_simple_perror_msg_and_die(argv[1]); + argv++; + BB_EXECVP(argv[0], argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 0a0802575..3ded758bf 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -448,5 +448,5 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) } #endif execvp(startas, argv); - bb_perror_msg_and_die("can't start %s", startas); + bb_perror_msg_and_die("can't execute '%s'", startas); } diff --git a/libbb/run_shell.c b/libbb/run_shell.c index 6f98bd695..4608a24a9 100644 --- a/libbb/run_shell.c +++ b/libbb/run_shell.c @@ -86,5 +86,5 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, freecon(current_sid); #endif execv(shell, (char **) args); - bb_perror_msg_and_die("can't run '%s'", shell); + bb_perror_msg_and_die("can't execute '%s'", shell); } diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 07024f5f0..082f0f63e 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -249,7 +249,7 @@ void FAST_FUNC re_exec(char **argv) * "we have (already) re-execed, don't do it again" flag */ argv[0][0] |= 0x80; execv(bb_busybox_exec_path, argv); - bb_perror_msg_and_die("exec %s", bb_busybox_exec_path); + bb_perror_msg_and_die("can't execute '%s'", bb_busybox_exec_path); } pid_t FAST_FUNC fork_or_rexec(char **argv) diff --git a/mailutils/mail.c b/mailutils/mail.c index 64a5b996f..49e72c32b 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c @@ -67,8 +67,8 @@ void FAST_FUNC launch_helper(const char **argv) if (!G.helper_pid) { // child: try to execute connection helper // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec - BB_EXECVP(*argv, (char **)argv); - _exit(127); + BB_EXECVP(argv[0], (char **)argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } // parent diff --git a/mailutils/mime.c b/mailutils/mime.c index ee147802e..654b8731c 100644 --- a/mailutils/mime.c +++ b/mailutils/mime.c @@ -288,8 +288,8 @@ static int parse(const char *boundary, char **argv) xsetenv("CHARSET", charset); xsetenv("ENCODING", encoding); xsetenv("FILENAME", filename); - BB_EXECVP(*argv, argv); - _exit(EXIT_FAILURE); + BB_EXECVP(argv[0], argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } // parent dumps to fd[1] close(fd[0]); diff --git a/miscutils/chrt.c b/miscutils/chrt.c index cc5660be7..e2b7f8ae0 100644 --- a/miscutils/chrt.c +++ b/miscutils/chrt.c @@ -115,9 +115,9 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) if (sched_setscheduler(pid, policy, &sp) < 0) bb_perror_msg_and_die("can't %cet pid %d's policy", 's', pid); - if (!*argv) /* "-p [...]" */ + if (!argv[0]) /* "-p [...]" */ goto print_rt_info; - BB_EXECVP(*argv, argv); - bb_simple_perror_msg_and_die(*argv); + BB_EXECVP(argv[0], argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } diff --git a/miscutils/ionice.c b/miscutils/ionice.c index 361c141b8..8393cd8b2 100644 --- a/miscutils/ionice.c +++ b/miscutils/ionice.c @@ -89,9 +89,9 @@ int ionice_main(int argc UNUSED_PARAM, char **argv) pri |= (ioclass << IOPRIO_CLASS_SHIFT); if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1) bb_perror_msg_and_die("ioprio_%cet", 's'); - if (*argv) { - BB_EXECVP(*argv, argv); - bb_simple_perror_msg_and_die(*argv); + if (argv[0]) { + BB_EXECVP(argv[0], argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } } diff --git a/miscutils/setsid.c b/miscutils/setsid.c index fd3283e30..60ee062e3 100644 --- a/miscutils/setsid.c +++ b/miscutils/setsid.c @@ -44,6 +44,7 @@ int setsid_main(int argc UNUSED_PARAM, char **argv) setsid(); } - BB_EXECVP(argv[1], argv + 1); - bb_simple_perror_msg_and_die(argv[1]); + argv++; + BB_EXECVP(argv[0], argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } diff --git a/miscutils/taskset.c b/miscutils/taskset.c index a0bbf0aa1..2891003df 100644 --- a/miscutils/taskset.c +++ b/miscutils/taskset.c @@ -129,9 +129,9 @@ int taskset_main(int argc UNUSED_PARAM, char **argv) if (sched_setaffinity(pid, sizeof(mask), &mask)) bb_perror_msg_and_die("can't %cet pid %d's affinity", 's', pid); - if (!*argv) /* "-p [...ignored...]" */ + if (!argv[0]) /* "-p [...ignored...]" */ goto print_aff; /* print new affinity and exit */ - BB_EXECVP(*argv, argv); - bb_simple_perror_msg_and_die(*argv); + BB_EXECVP(argv[0], argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } diff --git a/miscutils/time.c b/miscutils/time.c index 6946c863f..f5d1e15fb 100644 --- a/miscutils/time.c +++ b/miscutils/time.c @@ -380,7 +380,7 @@ static void run_command(char *const *cmd, resource_t *resp) versus merely warnings if the cast is left off. */ BB_EXECVP(cmd[0], cmd); xfunc_error_retval = (errno == ENOENT ? 127 : 126); - bb_error_msg_and_die("can't run '%s'", cmd[0]); + bb_perror_msg_and_die("can't execute '%s'", cmd[0]); } /* Have signals kill the child but not self (if possible). */ diff --git a/miscutils/timeout.c b/miscutils/timeout.c index 83ae56e69..273d26953 100644 --- a/miscutils/timeout.c +++ b/miscutils/timeout.c @@ -111,5 +111,5 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) argv[1] = sv2; #endif BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("exec '%s'", argv[0]); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } diff --git a/networking/httpd.c b/networking/httpd.c index 6dbc219e7..bab7b99cb 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -1474,7 +1474,7 @@ static void send_cgi_and_exit( * in the current directory */ execv(argv[0], argv); if (verbose) - bb_perror_msg("exec %s", argv[0]); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); error_execing_cgi: /* send to stdout * (we are CGI here, our stdout is pumped to the net) */ diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 2f3dd1d7b..714d2a107 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c @@ -1053,7 +1053,7 @@ static int popen2(FILE **in, FILE **out, char *command, char *param) xmove_fd(infd.rd, 0); xmove_fd(outfd.wr, 1); BB_EXECVP(command, argv); - _exit(127); + bb_perror_msg_and_die("can't execute '%s'", command); } /* parent */ close(infd.rd); diff --git a/networking/inetd.c b/networking/inetd.c index 7aa6b7b19..6d21e18f5 100644 --- a/networking/inetd.c +++ b/networking/inetd.c @@ -1380,7 +1380,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) sigaction_set(SIGPIPE, &saved_pipe_handler); restore_sigmask(&omask); BB_EXECVP(sep->se_program, sep->se_argv); - bb_perror_msg("exec %s", sep->se_program); + bb_perror_msg_and_die("can't execute '%s'", sep->se_program); do_exit1: /* eat packet in udp case */ if (sep->se_socktype != SOCK_STREAM) diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index e14d512ed..8d27e9682 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c @@ -230,7 +230,7 @@ static int doexec(char **proggie) /* dup2(0, 2); - do we *really* want this? NO! * exec'ed prog can do it yourself, if needed */ execvp(proggie[0], proggie); - bb_perror_msg_and_die("exec"); + bb_perror_msg_and_die("can't execute '%s'", proggie[0]); } /* connect_w_timeout: diff --git a/networking/tcpudp.c b/networking/tcpudp.c index b32fad624..4e4756738 100644 --- a/networking/tcpudp.c +++ b/networking/tcpudp.c @@ -504,7 +504,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) #else BB_EXECVP(argv[0], argv); #endif - bb_perror_msg_and_die("exec '%s'", argv[0]); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } /* diff --git a/printutils/lpd.c b/printutils/lpd.c index 43c22948f..15f1ba20b 100644 --- a/printutils/lpd.c +++ b/printutils/lpd.c @@ -181,8 +181,8 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[]) // this call reopens stdio fds to "/dev/null" // (no daemonization is done) bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL); - BB_EXECVP(*argv, argv); - exit(127); + BB_EXECVP(argv[0], argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } // validate input. diff --git a/runit/chpst.c b/runit/chpst.c index 1a68eb755..028a28d6c 100644 --- a/runit/chpst.c +++ b/runit/chpst.c @@ -383,5 +383,5 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) close(STDERR_FILENO); BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("exec %s", argv[0]); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } diff --git a/selinux/runcon.c b/selinux/runcon.c index 4afd1116e..f8ca9a6aa 100644 --- a/selinux/runcon.c +++ b/selinux/runcon.c @@ -133,6 +133,5 @@ int runcon_main(int argc UNUSED_PARAM, char **argv) context_str(con)); execvp(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); } -- cgit v1.2.3-55-g6feb From e69c5e2429f78b695d2ee26bd0d3bbef17da4c07 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Jun 2010 12:58:17 +0200 Subject: build system: make gen_build_files.sh run before autoconf.h generation Signed-off-by: Denys Vlasenko --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 483842f06..87779d791 100644 --- a/Makefile +++ b/Makefile @@ -509,7 +509,7 @@ include $(srctree)/Makefile.flags # with it and forgot to run make oldconfig. # If kconfig.d is missing then we are probarly in a cleaned tree so # we execute the config step to be sure to catch updated Kconfig files -include/autoconf.h: .kconfig.d .config +include/autoconf.h: .kconfig.d .config gen_build_files $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig else -- cgit v1.2.3-55-g6feb From 1d72d439405fdf4b51eb9e22c5c7a469695ae29c Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Jun 2010 13:30:59 +0200 Subject: gen_build_files.sh is an order prerequisite only for autoconf.h Signed-off-by: Denys Vlasenko --- Makefile | 2 +- scripts/gen_build_files.sh | 48 +++++++++++++++++++--------------------------- 2 files changed, 21 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index 87779d791..590512191 100644 --- a/Makefile +++ b/Makefile @@ -509,7 +509,7 @@ include $(srctree)/Makefile.flags # with it and forgot to run make oldconfig. # If kconfig.d is missing then we are probarly in a cleaned tree so # we execute the config step to be sure to catch updated Kconfig files -include/autoconf.h: .kconfig.d .config gen_build_files +include/autoconf.h: .kconfig.d .config | gen_build_files $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig else diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index 647c7daf7..a98f509ce 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh @@ -11,20 +11,19 @@ srctree="$1" src="$srctree/include/applets.src.h" dst="include/applets.h" s=`sed -n 's@^//applet:@@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` -echo "/* DO NOT EDIT. This file is generated from applets.src.h */" >"$dst.$$.tmp" +old=`cat "$dst" 2>/dev/null` # Why "IFS='' read -r REPLY"?? # This atrocity is needed to read lines without mangling. # IFS='' prevents whitespace trimming, # -r suppresses backslash handling. +new=`echo "/* DO NOT EDIT. This file is generated from applets.src.h */" while IFS='' read -r REPLY; do test x"$REPLY" = x"INSERT" && REPLY="$s" printf "%s\n" "$REPLY" -done <"$src" >>"$dst.$$.tmp" -if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then - rm -- "$dst.$$.tmp" -else +done <"$src"` +if test x"$new" != x"$old"; then echo " GEN $dst" - mv -- "$dst.$$.tmp" "$dst" + printf "%s\n" "$new" >"$dst" fi # (Re)generate include/usage.h @@ -35,20 +34,15 @@ dst="include/usage.h" # with space or tab # (note: we need to use \\\\ because of ``) s=`sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\\\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\\\@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` -echo "/* DO NOT EDIT. This file is generated from usage.src.h */" >"$dst.$$.tmp" -# Why "IFS='' read -r REPLY"?? -# This atrocity is needed to read lines without mangling. -# IFS='' prevents whitespace trimming, -# -r suppresses backslash handling. +old=`cat "$dst" 2>/dev/null` +new=`echo "/* DO NOT EDIT. This file is generated from usage.src.h */" while IFS='' read -r REPLY; do test x"$REPLY" = x"INSERT" && REPLY="$s" printf "%s\n" "$REPLY" -done <"$src" >>"$dst.$$.tmp" -if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then - rm -- "$dst.$$.tmp" -else +done <"$src"` +if test x"$new" != x"$old"; then echo " GEN $dst" - mv -- "$dst.$$.tmp" "$dst" + printf "%s\n" "$new" >"$dst" fi # (Re)generate */Kbuild and */Config.in @@ -61,16 +55,15 @@ find -type d | while read -r d; do s=`sed -n 's@^//kbuild:@@p' -- "$srctree/$d"/*.c` - echo "# DO NOT EDIT. This file is generated from Kbuild.src" >"$dst.$$.tmp" + old=`cat "$dst" 2>/dev/null` + new=`echo "# DO NOT EDIT. This file is generated from Kbuild.src" while IFS='' read -r REPLY; do test x"$REPLY" = x"INSERT" && REPLY="$s" printf "%s\n" "$REPLY" - done <"$src" >>"$dst.$$.tmp" - if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then - rm -- "$dst.$$.tmp" - else + done <"$src"` + if test x"$new" != x"$old"; then echo " GEN $dst" - mv -- "$dst.$$.tmp" "$dst" + printf "%s\n" "$new" >"$dst" fi fi @@ -81,16 +74,15 @@ find -type d | while read -r d; do s=`sed -n 's@^//config:@@p' -- "$srctree/$d"/*.c` - echo "# DO NOT EDIT. This file is generated from Config.src" >"$dst.$$.tmp" + old=`cat "$dst" 2>/dev/null` + new=`echo "# DO NOT EDIT. This file is generated from Config.src" while IFS='' read -r REPLY; do test x"$REPLY" = x"INSERT" && REPLY="$s" printf "%s\n" "$REPLY" - done <"$src" >>"$dst.$$.tmp" - if test -f "$dst" && cmp -s "$dst.$$.tmp" "$dst"; then - rm -- "$dst.$$.tmp" - else + done <"$src"` + if test x"$new" != x"$old"; then echo " GEN $dst" - mv -- "$dst.$$.tmp" "$dst" + printf "%s\n" "$new" >"$dst" fi fi done -- cgit v1.2.3-55-g6feb From 8d444494ef82809f83f75b142c66e0aff0aa9668 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Jun 2010 13:56:28 +0200 Subject: another fix to gen_build_files / autoconf.h dependency Signed-off-by: Denys Vlasenko --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 590512191..9a8277648 100644 --- a/Makefile +++ b/Makefile @@ -360,7 +360,7 @@ scripts/basic/%: scripts_basic ; # This target generates Kbuild's and Config.in's from *.c files PHONY += gen_build_files -gen_build_files: +gen_build_files: $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) $(Q)$(srctree)/scripts/gen_build_files.sh $(srctree) $(objtree) # bbox: we have helpers in applets/ @@ -509,7 +509,7 @@ include $(srctree)/Makefile.flags # with it and forgot to run make oldconfig. # If kconfig.d is missing then we are probarly in a cleaned tree so # we execute the config step to be sure to catch updated Kconfig files -include/autoconf.h: .kconfig.d .config | gen_build_files +include/autoconf.h: .kconfig.d .config $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) | gen_build_files $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig else -- cgit v1.2.3-55-g6feb From 918f444f9012ca22d696020dff116844400d37d2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 25 Jun 2010 14:40:25 +0200 Subject: conspy: make "conspy 0" use vcsa0 but "conspy" (no param) use vcsa Signed-off-by: Denys Vlasenko --- miscutils/conspy.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/miscutils/conspy.c b/miscutils/conspy.c index b5adce930..11758c603 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -222,7 +222,6 @@ static void cleanup(int code) fflush_all(); tcsetattr(G.kbd_fd, TCSANOW, &G.term_orig); if (ENABLE_FEATURE_CLEAN_UP) { - free(ptr_to_globals); close(G.kbd_fd); } // Reset attributes @@ -309,6 +308,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) applet_long_options = getopt_longopts; #endif INIT_G(); + strcpy(vcsa_name, "/dev/vcsa"); opt_complementary = "x+:y+"; // numeric params opts = getopt32(argv, "vcsndfx:y:", &G.x, &G.y); @@ -316,8 +316,8 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) ttynum = 0; if (argv[0]) { ttynum = xatou_range(argv[0], 0, 63); + sprintf(vcsa_name + sizeof("/dev/vcsa")-1, "%u", ttynum); } - sprintf(vcsa_name, "/dev/vcsa%u", ttynum); sprintf(tty_name, "%s%u", "/dev/tty", ttynum); if (opts & FLAG(c)) { if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v)) @@ -329,19 +329,16 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) } get_initial_data(vcsa_name); - G.kbd_fd = xopen(CURRENT_TTY, O_RDONLY); if (opts & FLAG(d)) { screen_dump(); bb_putchar('\n'); - if (ENABLE_FEATURE_CLEAN_UP) { - free(ptr_to_globals); - close(G.kbd_fd); - } return 0; } bb_signals(BB_FATAL_SIGS, cleanup); + // All characters must be passed through to us unaltered + G.kbd_fd = xopen(CURRENT_TTY, O_RDONLY); tcgetattr(G.kbd_fd, &G.term_orig); termbuf = G.term_orig; termbuf.c_iflag &= ~(BRKINT|INLCR|ICRNL|IXON|IXOFF|IUCLC|IXANY|IMAXBEL); -- cgit v1.2.3-55-g6feb From 1fcbff2fac490f5665fc1ed13ddad766a8879f3b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 26 Jun 2010 02:40:08 +0200 Subject: build system: do not rebuild ash and hush on any change to any .c file Signed-off-by: Denys Vlasenko --- applets/Kbuild.src | 2 +- applets/applet_tables.c | 24 ++++++++++++++++++++++-- libbb/appletlib.c | 2 +- shell/ash.c | 4 +--- shell/hush.c | 4 +--- 5 files changed, 26 insertions(+), 10 deletions(-) diff --git a/applets/Kbuild.src b/applets/Kbuild.src index e3bac9681..31fee8d1e 100644 --- a/applets/Kbuild.src +++ b/applets/Kbuild.src @@ -38,7 +38,7 @@ include/usage_compressed.h: applets/usage $(srctree_slash)applets/usage_compress $(call cmd,gen_usage_compressed) quiet_cmd_gen_applet_tables = GEN include/applet_tables.h - cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h + cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h include/NUM_APPLETS.h include/applet_tables.h: applets/applet_tables $(call cmd,gen_applet_tables) diff --git a/applets/applet_tables.c b/applets/applet_tables.c index e48be4682..338dc20f9 100644 --- a/applets/applet_tables.c +++ b/applets/applet_tables.c @@ -79,7 +79,7 @@ int main(int argc, char **argv) } printf("\n"); - printf("#ifndef SKIP_definitions\n"); + //printf("#ifndef SKIP_definitions\n"); printf("const char applet_names[] ALIGN1 = \"\"\n"); for (i = 0; i < NUM_APPLETS; i++) { printf("\"%s\" \"\\0\"\n", applets[i].name); @@ -123,9 +123,29 @@ int main(int argc, char **argv) } printf("};\n"); #endif - printf("#endif /* SKIP_definitions */\n"); + //printf("#endif /* SKIP_definitions */\n"); printf("\n"); printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN); + if (argv[2]) { + char line_old[80]; + char line_new[80]; + FILE *fp; + + line_old[0] = 0; + fp = fopen(argv[2], "r"); + if (fp) { + fgets(line_old, sizeof(line_old), fp); + fclose(fp); + } + sprintf(line_new, "#define NUM_APPLETS %u\n", NUM_APPLETS); + if (strcmp(line_old, line_new) != 0) { + fp = fopen(argv[2], "w"); + if (!fp) + return 1; + fputs(line_new, fp); + } + } + return 0; } diff --git a/libbb/appletlib.c b/libbb/appletlib.c index f3d530184..58f1a9490 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -61,7 +61,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; #else # define usage_messages 0 -#endif /* SHOW_USAGE */ +#endif #if ENABLE_FEATURE_COMPRESS_USAGE diff --git a/shell/ash.c b/shell/ash.c index 1f8f90a09..cfd8154ef 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -50,9 +50,7 @@ # define CLEAR_RANDOM_T(rnd) ((void)0) #endif -#define SKIP_definitions 1 -#include "applet_tables.h" -#undef SKIP_definitions +#include "NUM_APPLETS.h" #if NUM_APPLETS == 1 /* STANDALONE does not make sense, and won't compile */ # undef CONFIG_FEATURE_SH_STANDALONE diff --git a/shell/hush.c b/shell/hush.c index e64c923b4..29ff3c442 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -128,9 +128,7 @@ # define USE_FOR_MMU(...) #endif -#define SKIP_definitions 1 -#include "applet_tables.h" -#undef SKIP_definitions +#include "NUM_APPLETS.h" #if NUM_APPLETS == 1 /* STANDALONE does not make sense, and won't compile */ # undef CONFIG_FEATURE_SH_STANDALONE -- cgit v1.2.3-55-g6feb From 63144be7eae8757b0e0d81ff6fa8adb0b26ff7c1 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 26 Jun 2010 04:00:52 +0200 Subject: universal parser: do not leak parser->data Signed-off-by: Denys Vlasenko --- libbb/parse_config.c | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/libbb/parse_config.c b/libbb/parse_config.c index c511d97fb..b7c3a00e0 100644 --- a/libbb/parse_config.c +++ b/libbb/parse_config.c @@ -128,8 +128,8 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const int ntokens, mintokens; int t, len; - ntokens = flags & 0xFF; - mintokens = (flags & 0xFF00) >> 8; + ntokens = (uint8_t)flags; + mintokens = (uint8_t)(flags >> 8); if (parser == NULL) return 0; @@ -159,7 +159,8 @@ again: parser->data = xstrdup(line); /* Tokenize the line */ - for (t = 0; *line && *line != delims[0] && t < ntokens; t++) { + t = 0; + do { /* Pin token */ tokens[t] = line; @@ -179,10 +180,10 @@ again: } /* Token not terminated? */ - if (line[0] == delims[0]) + if (*line == delims[0]) *line = '\0'; - else if (line[0] != '\0') - *(line++) = '\0'; + else if (*line != '\0') + *line++ = '\0'; #if 0 /* unused so far */ if (flags & PARSE_ESCAPE) { @@ -201,17 +202,20 @@ again: *to = '\0'; } #endif - /* Skip possible delimiters */ if (flags & PARSE_COLLAPSE) line += strspn(line, delims + 1); - } + + t++; + } while (*line && *line != delims[0] && t < ntokens); if (t < mintokens) { bb_error_msg("bad line %u: %d tokens found, %d needed", parser->lineno, t, mintokens); if (flags & PARSE_MIN_DIE) xfunc_die(); + if (flags & PARSE_KEEP_COPY) + free(parser->data); goto again; } -- cgit v1.2.3-55-g6feb From 894fa0ad62924bcfc2d37e045e36d25ad5784888 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 26 Jun 2010 05:01:16 +0200 Subject: fix breakage in compressed file detection Signed-off-by: Denys Vlasenko --- archival/rpm2cpio.c | 4 ++-- libbb/read_printf.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index 1c67dcc6e..1f67fa887 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c @@ -75,7 +75,7 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) } magic; IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd); - xread(rpm_fd, magic.b16, sizeof(magic.b16)); + xread(rpm_fd, magic.b16, sizeof(magic.b16[0])); if (magic.b16[0] == GZIP_MAGIC) { unpack = unpack_gz_stream; } else @@ -89,7 +89,7 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) ) { /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ /* More info at: http://tukaani.org/xz/xz-file-format.txt */ - xread(rpm_fd, magic.b32, sizeof(magic.b32)); + xread(rpm_fd, magic.b32, sizeof(magic.b32[0])); if (magic.b32[0] != XZ_MAGIC2) goto no_magic; /* unpack_xz_stream wants fd at position 0 */ diff --git a/libbb/read_printf.c b/libbb/read_printf.c index 53f528f5a..3aee075c6 100644 --- a/libbb/read_printf.c +++ b/libbb/read_printf.c @@ -265,7 +265,7 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) /* .gz and .bz2 both have 2-byte signature, and their * unpack_XXX_stream wants this header skipped. */ - xread(fd, magic.b16, sizeof(magic.b16)); + xread(fd, magic.b16, sizeof(magic.b16[0])); if (ENABLE_FEATURE_SEAMLESS_GZ && magic.b16[0] == GZIP_MAGIC ) { @@ -292,7 +292,7 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ /* More info at: http://tukaani.org/xz/xz-file-format.txt */ offset = -6; - xread(fd, magic.b32, sizeof(magic.b32)); + xread(fd, magic.b32, sizeof(magic.b32[0])); if (magic.b32[0] == XZ_MAGIC2) { # if BB_MMU xformer = unpack_xz_stream; -- cgit v1.2.3-55-g6feb From d0a8a0d31243f2ac798531ced2cca45ddf1fea42 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 26 Jun 2010 18:11:44 +0200 Subject: tar: fix --to-command wrt short writes function old new delta bb_copyfd_exact_size 51 98 +47 bb_full_fd_action 362 394 +32 get_header_tar 1546 1558 +12 data_extract_to_command 430 439 +9 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/0 up/down: 100/0) Total: 100 bytes Signed-off-by: Denys Vlasenko --- archival/libunarchive/data_extract_to_command.c | 2 +- libbb/copyfd.c | 21 ++++++++++++++++----- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/archival/libunarchive/data_extract_to_command.c b/archival/libunarchive/data_extract_to_command.c index 983c5301d..53a7217c2 100644 --- a/archival/libunarchive/data_extract_to_command.c +++ b/archival/libunarchive/data_extract_to_command.c @@ -108,7 +108,7 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) close(p[0]); /* Our caller is expected to do signal(SIGPIPE, SIG_IGN) * so that we don't die if child don't read all the input: */ - bb_copyfd_exact_size(archive_handle->src_fd, p[1], file_header->size); + bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size); close(p[1]); if (safe_waitpid(pid, &status, 0) == -1) diff --git a/libbb/copyfd.c b/libbb/copyfd.c index f42eb7623..2538d496d 100644 --- a/libbb/copyfd.c +++ b/libbb/copyfd.c @@ -9,8 +9,10 @@ #include "libbb.h" -/* Used by NOFORK applets (e.g. cat) - must not use xmalloc */ - +/* Used by NOFORK applets (e.g. cat) - must not use xmalloc. + * size < 0 means "ignore write errors", used by tar --to-command + * size = 0 means "copy till EOF" + */ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) { int status = -1; @@ -21,6 +23,12 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) #else char *buffer; int buffer_size; + bool continue_on_write_error = 0; + + if (size < 0) { + size = -size; + continue_on_write_error = 1; + } if (size > 0 && size <= 4 * 1024) goto use_small_buf; @@ -63,8 +71,11 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) if (dst_fd >= 0) { ssize_t wr = full_write(dst_fd, buffer, rd); if (wr < rd) { - bb_perror_msg(bb_msg_write_error); - break; + if (!continue_on_write_error) { + bb_perror_msg(bb_msg_write_error); + break; + } + dst_fd = -1; } } total += rd; @@ -108,7 +119,7 @@ off_t FAST_FUNC bb_copyfd_size(int fd1, int fd2, off_t size) void FAST_FUNC bb_copyfd_exact_size(int fd1, int fd2, off_t size) { off_t sz = bb_copyfd_size(fd1, fd2, size); - if (sz == size) + if (sz == (size >= 0 ? size : -size)) return; if (sz != -1) bb_error_msg_and_die("short read"); -- cgit v1.2.3-55-g6feb From 52827e3ebcd80f634f990030ee697254a0ae517d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 26 Jun 2010 18:21:36 +0200 Subject: *: tar-related cleanups: move struct to unarchive.h; move help to tar.c Signed-off-by: Denys Vlasenko --- archival/libunarchive/get_header_tar.c | 40 +++--------- archival/tar.c | 107 +++++++++++++++++++++------------ include/unarchive.h | 33 ++++++++++ include/usage.src.h | 48 --------------- procps/smemcap.c | 43 +++---------- 5 files changed, 118 insertions(+), 153 deletions(-) diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c index fcddcb834..01c10433e 100644 --- a/archival/libunarchive/get_header_tar.c +++ b/archival/libunarchive/get_header_tar.c @@ -118,34 +118,10 @@ static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, uns } #endif -void BUG_tar_header_size(void); char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; - struct { - /* ustar header, Posix 1003.1 */ - char name[100]; /* 0-99 */ - char mode[8]; /* 100-107 */ - char uid[8]; /* 108-115 */ - char gid[8]; /* 116-123 */ - char size[12]; /* 124-135 */ - char mtime[12]; /* 136-147 */ - char chksum[8]; /* 148-155 */ - char typeflag; /* 156-156 */ - char linkname[100]; /* 157-256 */ - /* POSIX: "ustar" NUL "00" */ - /* GNU tar: "ustar " NUL */ - /* Normally it's defined as magic[6] followed by - * version[2], but we put them together to simplify code - */ - char magic[8]; /* 257-264 */ - char uname[32]; /* 265-296 */ - char gname[32]; /* 297-328 */ - char devmajor[8]; /* 329-336 */ - char devminor[8]; /* 337-344 */ - char prefix[155]; /* 345-499 */ - char padding[12]; /* 500-512 */ - } tar; + struct tar_header_t tar; char *cp; int i, sum_u, sum; #if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY @@ -162,9 +138,6 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) # define p_linkname 0 #endif - if (sizeof(tar) != 512) - BUG_tar_header_size(); - #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX again: #endif @@ -230,18 +203,21 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) * we can switch to get_header_tar_gz/bz2/lzma(). * Needs seekable fd. I wish recv(MSG_PEEK) works * on any fd... */ -#if ENABLE_FEATURE_SEAMLESS_GZ +# if ENABLE_FEATURE_SEAMLESS_GZ if (tar.name[0] == 0x1f && tar.name[1] == (char)0x8b) { /* gzip */ get_header_ptr = get_header_tar_gz; } else -#endif -#if ENABLE_FEATURE_SEAMLESS_BZ2 +# endif +# if ENABLE_FEATURE_SEAMLESS_BZ2 if (tar.name[0] == 'B' && tar.name[1] == 'Z' && tar.name[2] == 'h' && isdigit(tar.name[3]) ) { /* bzip2 */ get_header_ptr = get_header_tar_bz2; } else -#endif +# endif +# if ENABLE_FEATURE_SEAMLESS_XZ + //TODO +# endif goto err; /* Two different causes for lseek() != 0: * unseekable fd (would like to support that too, but...), diff --git a/archival/tar.c b/archival/tar.c index 344c9dea4..f49fb129e 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -48,37 +48,6 @@ #if ENABLE_FEATURE_TAR_CREATE -/* Tar file constants */ - -#define TAR_BLOCK_SIZE 512 - -/* POSIX tar Header Block, from POSIX 1003.1-1990 */ -#define NAME_SIZE 100 -#define NAME_SIZE_STR "100" -typedef struct TarHeader { /* byte offset */ - char name[NAME_SIZE]; /* 0-99 */ - char mode[8]; /* 100-107 */ - char uid[8]; /* 108-115 */ - char gid[8]; /* 116-123 */ - char size[12]; /* 124-135 */ - char mtime[12]; /* 136-147 */ - char chksum[8]; /* 148-155 */ - char typeflag; /* 156-156 */ - char linkname[NAME_SIZE]; /* 157-256 */ - /* POSIX: "ustar" NUL "00" */ - /* GNU tar: "ustar " NUL */ - /* Normally it's defined as magic[6] followed by - * version[2], but we put them together to save code. - */ - char magic[8]; /* 257-264 */ - char uname[32]; /* 265-296 */ - char gname[32]; /* 297-328 */ - char devmajor[8]; /* 329-336 */ - char devminor[8]; /* 337-344 */ - char prefix[155]; /* 345-499 */ - char padding[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */ -} TarHeader; - /* ** writeTarFile(), writeFileToTarball(), and writeTarHeader() are ** the only functions that deal with the HardLinkInfo structure. @@ -193,7 +162,7 @@ static void putOctal(char *cp, int len, off_t value) } #define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b)) -static void chksum_and_xwrite(int fd, struct TarHeader* hp) +static void chksum_and_xwrite(int fd, struct tar_header_t* hp) { /* POSIX says that checksum is done on unsigned bytes * (Sun and HP-UX gets it wrong... more details in @@ -235,7 +204,7 @@ static void writeLongname(int fd, int type, const char *name, int dir) "00000000000", "00000000000", }; - struct TarHeader header; + struct tar_header_t header; int size; dir = !!dir; /* normalize: 0/1 */ @@ -262,17 +231,13 @@ static void writeLongname(int fd, int type, const char *name, int dir) #endif /* Write out a tar header for the specified file/directory/whatever */ -void BUG_tar_header_size(void); static int writeTarHeader(struct TarBallInfo *tbInfo, const char *header_name, const char *fileName, struct stat *statbuf) { - struct TarHeader header; - - if (sizeof(header) != 512) - BUG_tar_header_size(); - - memset(&header, 0, sizeof(struct TarHeader)); + struct tar_header_t header; + memset(&header, 0, sizeof(header)); + strncpy(header.name, header_name, sizeof(header.name)); /* POSIX says to mask mode with 07777. */ @@ -738,6 +703,68 @@ static void handle_SIGCHLD(int status) } #endif +//usage:#define tar_trivial_usage +//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" IF_FEATURE_SEAMLESS_GZ("z") +//usage: IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a") +//usage: IF_FEATURE_SEAMLESS_Z("Z") IF_FEATURE_TAR_NOPRESERVE_TIME("m") "vO] " +//usage: IF_FEATURE_TAR_FROM("[-X FILE] ") +//usage: "[-f TARFILE] [-C DIR] [FILE]..." +//usage:#define tar_full_usage "\n\n" +//usage: IF_FEATURE_TAR_CREATE("Create, extract, ") +//usage: IF_NOT_FEATURE_TAR_CREATE("Extract ") +//usage: "or list files from a tar file\n" +//usage: "\nOperation:" +//usage: IF_FEATURE_TAR_CREATE( +//usage: "\n c Create" +//usage: ) +//usage: "\n x Extract" +//usage: "\n t List" +//usage: "\nOptions:" +//usage: "\n f Name of TARFILE ('-' for stdin/out)" +//usage: "\n C Change to DIR before operation" +//usage: "\n v Verbose" +//usage: IF_FEATURE_SEAMLESS_GZ( +//usage: "\n z (De)compress using gzip" +//usage: ) +//usage: IF_FEATURE_SEAMLESS_BZ2( +//usage: "\n j (De)compress using bzip2" +//usage: ) +//usage: IF_FEATURE_SEAMLESS_LZMA( +//usage: "\n a (De)compress using lzma" +//usage: ) +//usage: IF_FEATURE_SEAMLESS_Z( +//usage: "\n Z (De)compress using compress" +//usage: ) +//usage: "\n O Extract to stdout" +//usage: IF_FEATURE_TAR_CREATE( +//usage: "\n h Follow symlinks" +//usage: ) +//usage: IF_FEATURE_TAR_NOPRESERVE_TIME( +//usage: "\n m Don't restore mtime" +//usage: ) +//usage: IF_FEATURE_TAR_FROM( +//usage: IF_FEATURE_TAR_LONG_OPTIONS( +//usage: "\n exclude File to exclude" +//usage: ) +//usage: "\n X File with names to exclude" +//usage: "\n T File with names to include" +//usage: ) +//usage: +//usage:#define tar_example_usage +//usage: "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" +//usage: "$ tar -cf /tmp/tarball.tar /usr/local\n" + +// Supported but aren't in --help: +// o no-same-owner +// p same-permissions +// k keep-old +// numeric-owner +// no-same-permissions +// overwrite +//IF_FEATURE_TAR_TO_COMMAND( +// to-command +//) + enum { OPTBIT_KEEP_OLD = 8, IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,) diff --git a/include/unarchive.h b/include/unarchive.h index f3aa05d09..b4cf16082 100644 --- a/include/unarchive.h +++ b/include/unarchive.h @@ -113,6 +113,39 @@ typedef struct archive_handle_t { #define ARCHIVE_O_TRUNC (1 << 8) +/* POSIX tar Header Block, from POSIX 1003.1-1990 */ +#define TAR_BLOCK_SIZE 512 +#define NAME_SIZE 100 +#define NAME_SIZE_STR "100" +typedef struct tar_header_t { /* byte offset */ + char name[NAME_SIZE]; /* 0-99 */ + char mode[8]; /* 100-107 */ + char uid[8]; /* 108-115 */ + char gid[8]; /* 116-123 */ + char size[12]; /* 124-135 */ + char mtime[12]; /* 136-147 */ + char chksum[8]; /* 148-155 */ + char typeflag; /* 156-156 */ + char linkname[NAME_SIZE]; /* 157-256 */ + /* POSIX: "ustar" NUL "00" */ + /* GNU tar: "ustar " NUL */ + /* Normally it's defined as magic[6] followed by + * version[2], but we put them together to save code. + */ + char magic[8]; /* 257-264 */ + char uname[32]; /* 265-296 */ + char gname[32]; /* 297-328 */ + char devmajor[8]; /* 329-336 */ + char devminor[8]; /* 337-344 */ + char prefix[155]; /* 345-499 */ + char padding[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */ +} tar_header_t; +struct BUG_tar_header { + char c[sizeof(tar_header_t) == TAR_BLOCK_SIZE ? 1 : -1]; +}; + + + /* Info struct unpackers can fill out to inform users of thing like * timestamps of unpacked files */ typedef struct unpack_info_t { diff --git a/include/usage.src.h b/include/usage.src.h index f30edbc54..f84bb93c7 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -4273,54 +4273,6 @@ INSERT #define tac_full_usage "\n\n" \ "Concatenate FILEs and print them in reverse" -#define tar_trivial_usage \ - "-[" IF_FEATURE_TAR_CREATE("c") "xt" IF_FEATURE_SEAMLESS_GZ("z") \ - IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a") \ - IF_FEATURE_SEAMLESS_Z("Z") IF_FEATURE_TAR_NOPRESERVE_TIME("m") "vO] " \ - IF_FEATURE_TAR_FROM("[-X FILE] ") \ - "[-f TARFILE] [-C DIR] [FILE]..." -#define tar_full_usage "\n\n" \ - IF_FEATURE_TAR_CREATE("Create, extract, ") \ - IF_NOT_FEATURE_TAR_CREATE("Extract ") \ - "or list files from a tar file\n" \ - "\nOptions:" \ - IF_FEATURE_TAR_CREATE( \ - "\n c Create" \ - ) \ - "\n x Extract" \ - "\n t List" \ - "\nArchive format selection:" \ - IF_FEATURE_SEAMLESS_GZ( \ - "\n z Filter the archive through gzip" \ - ) \ - IF_FEATURE_SEAMLESS_BZ2( \ - "\n j Filter the archive through bzip2" \ - ) \ - IF_FEATURE_SEAMLESS_LZMA( \ - "\n a Filter the archive through lzma" \ - ) \ - IF_FEATURE_SEAMLESS_Z( \ - "\n Z Filter the archive through compress" \ - ) \ - IF_FEATURE_TAR_NOPRESERVE_TIME( \ - "\n m Do not restore mtime" \ - ) \ - "\nFile selection:" \ - "\n f Name of TARFILE or \"-\" for stdin" \ - "\n O Extract to stdout" \ - IF_FEATURE_TAR_FROM( \ - IF_FEATURE_TAR_LONG_OPTIONS( \ - "\n exclude File to exclude" \ - ) \ - "\n X File with names to exclude" \ - ) \ - "\n C Change to DIR before operation" \ - "\n v Verbose" \ - -#define tar_example_usage \ - "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" \ - "$ tar -cf /tmp/tarball.tar /usr/local\n" - #define taskset_trivial_usage \ "[-p] [MASK] [PID | PROG ARGS]" #define taskset_full_usage "\n\n" \ diff --git a/procps/smemcap.c b/procps/smemcap.c index cdcc891a1..06cf93c85 100644 --- a/procps/smemcap.c +++ b/procps/smemcap.c @@ -20,42 +20,19 @@ //config: a memory usage statistic tool. #include "libbb.h" - -struct tar_header { - char name[100]; /* 0-99 */ - char mode[8]; /* 100-107 */ - char uid[8]; /* 108-115 */ - char gid[8]; /* 116-123 */ - char size[12]; /* 124-135 */ - char mtime[12]; /* 136-147 */ - char chksum[8]; /* 148-155 */ - char typeflag; /* 156-156 */ - char linkname[100]; /* 157-256 */ - /* POSIX: "ustar" NUL "00" */ - /* GNU tar: "ustar " NUL */ - /* Normally it's defined as magic[6] followed by - * version[2], but we put them together to save code. - */ - char magic[8]; /* 257-264 */ - char uname[32]; /* 265-296 */ - char gname[32]; /* 297-328 */ - char devmajor[8]; /* 329-336 */ - char devminor[8]; /* 337-344 */ - char prefix[155]; /* 345-499 */ - char padding[12]; /* 500-512 (pad to exactly TAR_512) */ -}; +#include "unarchive.h" struct fileblock { struct fileblock *next; - char data[512]; + char data[TAR_BLOCK_SIZE]; }; static void writeheader(const char *path, struct stat *sb, int type) { - struct tar_header header; + struct tar_header_t header; int i, sum; - memset(&header, 0, 512); + memset(&header, 0, TAR_BLOCK_SIZE); strcpy(header.name, path); sprintf(header.mode, "%o", sb->st_mode & 0777); /* careful to not overflow fields! */ @@ -73,11 +50,11 @@ static void writeheader(const char *path, struct stat *sb, int type) * digits, followed by a NUL like the other fields... */ header.chksum[7] = ' '; sum = ' ' * 7; - for (i = 0; i < 512; i++) + for (i = 0; i < TAR_BLOCK_SIZE; i++) sum += ((unsigned char*)&header)[i]; sprintf(header.chksum, "%06o", sum); - xwrite(STDOUT_FILENO, &header, 512); + xwrite(STDOUT_FILENO, &header, TAR_BLOCK_SIZE); } static void archivefile(const char *path) @@ -94,10 +71,10 @@ static void archivefile(const char *path) cur = xzalloc(sizeof(*cur)); *prev = cur; prev = &cur->next; - r = full_read(fd, cur->data, 512); + r = full_read(fd, cur->data, TAR_BLOCK_SIZE); if (r > 0) size += r; - } while (r == 512); + } while (r == TAR_BLOCK_SIZE); /* write archive header */ fstat(fd, &s); @@ -106,8 +83,8 @@ static void archivefile(const char *path) writeheader(path, &s, '0'); /* dump file contents */ - for (cur = start; (int)size > 0; size -= 512) { - xwrite(STDOUT_FILENO, cur->data, 512); + for (cur = start; (int)size > 0; size -= TAR_BLOCK_SIZE) { + xwrite(STDOUT_FILENO, cur->data, TAR_BLOCK_SIZE); start = cur; cur = cur->next; free(start); -- cgit v1.2.3-55-g6feb From b768aeb164d361d1ca2c8f6c091e93442f072656 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 26 Jun 2010 18:22:41 +0200 Subject: tar: make typical extraction less memory-hungry Signed-off-by: Denys Vlasenko --- archival/libunarchive/get_header_tar.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c index 01c10433e..21bbc9715 100644 --- a/archival/libunarchive/get_header_tar.c +++ b/archival/libunarchive/get_header_tar.c @@ -436,9 +436,11 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */ if (cp) *cp = '\0'; - //archive_handle->ah_flags |= ARCHIVE_EXTRACT_QUIET; // why?? archive_handle->action_data(archive_handle); - llist_add_to(&(archive_handle->passed), file_header->name); + if (archive_handle->accept || archive_handle->reject) + llist_add_to(&archive_handle->passed, file_header->name); + else /* Caller isn't interested in list of unpacked files */ + free(file_header->name); } else { data_skip(archive_handle); free(file_header->name); @@ -446,7 +448,8 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) archive_handle->offset += file_header->size; free(file_header->link_target); - /* Do not free(file_header->name)! (why?) */ + /* Do not free(file_header->name)! + * It might be inserted in archive_handle->passed - see above */ #if ENABLE_FEATURE_TAR_UNAME_GNAME free(file_header->tar__uname); free(file_header->tar__gname); -- cgit v1.2.3-55-g6feb From fd33e17a2bf4c09bb12ac09a645cfd0f0f914fec Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 26 Jun 2010 22:55:44 +0200 Subject: ash: fix obscure case of replacing + globbing + backslashes function old new delta subevalvar 1152 1178 +26 readtoken1 3267 3275 +8 redirect 1284 1286 +2 expandarg 957 958 +1 expdir 4 - -4 evalcommand 1219 1209 -10 expmeta 481 469 -12 ------------------------------------------------------------------------------ (add/remove: 0/1 grow/shrink: 4/2 up/down: 37/-26) Total: 11 bytes Signed-off-by: Denys Vlasenko --- shell/ash.c | 42 +++++++++++----------- .../ash-quoting/dollar_repl_slash_bash1.right | 10 ++++++ .../ash-quoting/dollar_repl_slash_bash1.tests | 21 +++++++++++ 3 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right create mode 100755 shell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests diff --git a/shell/ash.c b/shell/ash.c index cfd8154ef..0337a5535 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6184,8 +6184,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, char *startp; char *loc; char *rmesc, *rmescend; - IF_ASH_BASH_COMPAT(char *repl = NULL;) - IF_ASH_BASH_COMPAT(char null = '\0';) + IF_ASH_BASH_COMPAT(const char *repl = NULL;) IF_ASH_BASH_COMPAT(int pos, len, orig_len;) int saveherefd = herefd; int amount, workloc, resetloc; @@ -6306,7 +6305,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, if (!repl) { repl = parse_sub_pattern(str, varflags & VSQUOTE); if (!repl) - repl = &null; + repl = nullstr; } /* If there's no pattern to match, return the expansion unmolested */ @@ -6357,8 +6356,12 @@ subevalvar(char *p, char *str, int strloc, int subtype, idx = loc; } - for (loc = repl; *loc; loc++) { + for (loc = (char*)repl; *loc; loc++) { char *restart_detect = stackblock(); + if (quotes && *loc == '\\') { + STPUTC(CTLESC, expdest); + len++; + } STPUTC(*loc, expdest); if (stackblock() != restart_detect) goto restart; @@ -6368,6 +6371,10 @@ subevalvar(char *p, char *str, int strloc, int subtype, if (subtype == VSREPLACE) { while (*idx) { char *restart_detect = stackblock(); + if (quotes && *idx == '\\') { + STPUTC(CTLESC, expdest); + len++; + } STPUTC(*idx, expdest); if (stackblock() != restart_detect) goto restart; @@ -6381,11 +6388,10 @@ subevalvar(char *p, char *str, int strloc, int subtype, /* We've put the replaced text into a buffer at workloc, now * move it to the right place and adjust the stack. */ - startp = stackblock() + startloc; STPUTC('\0', expdest); - memmove(startp, stackblock() + workloc, len); - startp[len++] = '\0'; - amount = expdest - ((char *)stackblock() + startloc + len - 1); + startp = (char *)stackblock() + startloc; + memmove(startp, (char *)stackblock() + workloc, len + 1); + amount = expdest - (startp + len); STADJUST(-amount, expdest); return startp; } @@ -6685,7 +6691,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) */ STPUTC('\0', expdest); patloc = expdest - (char *)stackblock(); - if (0 == subevalvar(p, /* str: */ NULL, patloc, subtype, + if (NULL == subevalvar(p, /* str: */ NULL, patloc, subtype, startloc, varflags, //TODO: | EXP_REDIR too? All other such places do it too /* quotes: */ flags & (EXP_FULL | EXP_CASE), @@ -6848,13 +6854,11 @@ addfname(const char *name) exparg.lastp = &sp->next; } -static char *expdir; - /* * Do metacharacter (i.e. *, ?, [...]) expansion. */ static void -expmeta(char *enddir, char *name) +expmeta(char *expdir, char *enddir, char *name) { char *p; const char *cp; @@ -6953,7 +6957,7 @@ expmeta(char *enddir, char *name) for (p = enddir, cp = dp->d_name; (*p++ = *cp++) != '\0';) continue; p[-1] = '/'; - expmeta(p, endname); + expmeta(expdir, p, endname); } } } @@ -7035,6 +7039,7 @@ expandmeta(struct strlist *str /*, int flag*/) /* TODO - EXP_REDIR */ while (str) { + char *expdir; struct strlist **savelastp; struct strlist *sp; char *p; @@ -7051,8 +7056,7 @@ expandmeta(struct strlist *str /*, int flag*/) int i = strlen(str->text); expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ } - - expmeta(expdir, p); + expmeta(expdir, expdir, p); free(expdir); if (p != str->text) free(p); @@ -9101,19 +9105,15 @@ evalcommand(union node *cmd, int flags) /* Print the command if xflag is set. */ if (xflag) { int n; - const char *p = " %s"; + const char *p = " %s" + 1; - p++; fdprintf(preverrout_fd, p, expandstr(ps4val())); - sp = varlist.list; for (n = 0; n < 2; n++) { while (sp) { fdprintf(preverrout_fd, p, sp->text); sp = sp->next; - if (*p == '%') { - p--; - } + p = " %s"; } sp = arglist.list; } diff --git a/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right new file mode 100644 index 000000000..b212c246c --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.right @@ -0,0 +1,10 @@ +192\.168\.0\.1 +192\.168\.0\.1[ +192\.168\.0\.1[ +192\\.168\\.0\\.1[ +192\.168\.0\.1[ +192\.168\.0\.1 +192\.168\.0\.1[ +192\.168\.0\.1[ +192\\.168\\.0\\.1[ +192\.168\.0\.1[ diff --git a/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests new file mode 100755 index 000000000..3fa2f186d --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_slash_bash1.tests @@ -0,0 +1,21 @@ +# The bug here was triggered by: +# * performin pathname expansion because we see [ +# * replace operator did not escape \ in replace string + +IP=192.168.0.1 + +rm -f '192.168.0.1[' +echo "${IP//./\\.}" +echo "${IP//./\\.}"'[' # bug was here +echo "${IP//./\\.}[" # bug was here +echo "${IP//./\\\\.}[" # bug was here +echo "192\.168\.0\.1[" + +echo >'192.168.0.1[' +echo "${IP//./\\.}" +echo "${IP//./\\.}"'[' # bug was here +echo "${IP//./\\.}[" # bug was here +echo "${IP//./\\\\.}[" # bug was here +echo "192\.168\.0\.1[" + +rm -f '192.168.0.1[' -- cgit v1.2.3-55-g6feb From 1eaf7e76bfff22646baf7d815650106e64ba0691 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 26 Jun 2010 23:08:59 +0200 Subject: libbb/copyfd.c: fix the case of copy buffer <= 4kb Signed-off-by: Denys Vlasenko --- libbb/copyfd.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libbb/copyfd.c b/libbb/copyfd.c index 2538d496d..82622c06f 100644 --- a/libbb/copyfd.c +++ b/libbb/copyfd.c @@ -17,19 +17,21 @@ static off_t bb_full_fd_action(int src_fd, int dst_fd, off_t size) { int status = -1; off_t total = 0; + bool continue_on_write_error = 0; #if CONFIG_FEATURE_COPYBUF_KB <= 4 char buffer[CONFIG_FEATURE_COPYBUF_KB * 1024]; enum { buffer_size = sizeof(buffer) }; #else char *buffer; int buffer_size; - bool continue_on_write_error = 0; +#endif if (size < 0) { size = -size; continue_on_write_error = 1; } +#if CONFIG_FEATURE_COPYBUF_KB > 4 if (size > 0 && size <= 4 * 1024) goto use_small_buf; /* We want page-aligned buffer, just in case kernel is clever -- cgit v1.2.3-55-g6feb From f6464000cab81639e76b45b861d828d3931a0b77 Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Sat, 26 Jun 2010 13:41:35 +0300 Subject: modinfo: needs DEFAULT_MODULES_DIR and DEFAULT_DEPMOD_FILE Signed-off-by: Lauri Kasanen Signed-off-by: Denys Vlasenko --- modutils/Config.src | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modutils/Config.src b/modutils/Config.src index 2ced9b308..a7dcb3ab3 100644 --- a/modutils/Config.src +++ b/modutils/Config.src @@ -228,7 +228,7 @@ config FEATURE_MODUTILS_SYMBOLS config DEFAULT_MODULES_DIR string "Default directory containing modules" default "/lib/modules" - depends on DEPMOD || MODPROBE || MODPROBE_SMALL + depends on DEPMOD || MODPROBE || MODPROBE_SMALL || MODINFO help Directory that contains kernel modules. Defaults to "/lib/modules" @@ -236,7 +236,7 @@ config DEFAULT_MODULES_DIR config DEFAULT_DEPMOD_FILE string "Default name of modules.dep" default "modules.dep" - depends on DEPMOD || MODPROBE || MODPROBE_SMALL + depends on DEPMOD || MODPROBE || MODPROBE_SMALL || MODINFO help Filename that contains kernel modules dependencies. Defaults to "modules.dep" -- cgit v1.2.3-55-g6feb From 1b14cdb27ca5e8104a824424731be430c8592dd6 Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Sun, 27 Jun 2010 00:35:49 +0200 Subject: modinfo: support relative paths in modules.dep function old new delta modinfo 272 329 +57 modinfo_main 325 344 +19 Signed-off-by: Lauri Kasanen Signed-off-by: Denys Vlasenko --- modutils/modinfo.c | 35 ++++++++++++++++++++++++----------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/modutils/modinfo.c b/modutils/modinfo.c index 321ad78f4..454a1b366 100644 --- a/modutils/modinfo.c +++ b/modutils/modinfo.c @@ -43,7 +43,8 @@ static int display(const char *data, const char *pattern, int flag) return printf("%s%c", data, (option_mask32 & OPT_0) ? '\0' : '\n'); } -static void modinfo(const char *path, struct modinfo_env *env) +static void modinfo(const char *path, const char *version, + struct modinfo_env *env) { static const char *const shortcuts[] = { "filename", @@ -62,10 +63,20 @@ static void modinfo(const char *path, struct modinfo_env *env) if (tags & 1) { /* filename */ display(path, shortcuts[0], 1 != tags); } + len = MAXINT(ssize_t); the_module = xmalloc_open_zipped_read_close(path, &len); - if (!the_module) - return; + if (!the_module) { + if (path[0] == '/') + return; + /* Newer depmod puts relative paths in modules.dep */ + path = xasprintf("%s/%s/%s", CONFIG_DEFAULT_MODULES_DIR, version, path); + the_module = xmalloc_open_zipped_read_close(path, &len); + free((char*)path); + if (!the_module) + return; + } + if (field) tags |= OPT_F; for (j = 1; (1< Date: Sun, 27 Jun 2010 03:23:31 +0200 Subject: *: s/"/bin/sh"/DEFAULT_SHELL, run_shell() API fix, remove unneeded strdup function old new delta run_shell 157 166 +9 su_main 477 470 -7 sulogin_main 515 503 -12 Signed-off-by: Ladislav Michl Signed-off-by: Denys Vlasenko --- archival/libunarchive/data_extract_to_command.c | 4 +- include/libbb.h | 7 ++- libbb/run_shell.c | 18 ++++---- libbb/setup_environment.c | 4 +- loginutils/login.c | 12 +++--- loginutils/su.c | 57 ++++++++++++++----------- loginutils/sulogin.c | 8 ++-- runit/svlogd.c | 2 +- 8 files changed, 58 insertions(+), 54 deletions(-) diff --git a/archival/libunarchive/data_extract_to_command.c b/archival/libunarchive/data_extract_to_command.c index 53a7217c2..eb09439bc 100644 --- a/archival/libunarchive/data_extract_to_command.c +++ b/archival/libunarchive/data_extract_to_command.c @@ -102,8 +102,8 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) close(p[1]); xdup2(p[0], STDIN_FILENO); signal(SIGPIPE, SIG_DFL); - execl("/bin/sh", "/bin/sh" + 5, "-c", archive_handle->tar__to_command, NULL); - bb_perror_msg_and_die("can't execute '%s'", "/bin/sh"); + execl(DEFAULT_SHELL, DEFAULT_SHELL_SHORT_NAME, "-c", archive_handle->tar__to_command, NULL); + bb_perror_msg_and_die("can't execute '%s'", DEFAULT_SHELL); } close(p[0]); /* Our caller is expected to do signal(SIGPIPE, SIG_IGN) diff --git a/include/libbb.h b/include/libbb.h index 58719a85b..53b768d88 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1157,7 +1157,6 @@ char *bb_simplify_abs_path_inplace(char *path) FAST_FUNC; extern void bb_do_delay(int seconds) FAST_FUNC; extern void change_identity(const struct passwd *pw) FAST_FUNC; extern void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) NORETURN FAST_FUNC; -extern void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) FAST_FUNC; #if ENABLE_SELINUX extern void renew_current_security_context(void) FAST_FUNC; extern void set_current_security_context(security_context_t sid) FAST_FUNC; @@ -1593,12 +1592,12 @@ extern struct globals *const ptr_to_globals; * use bb_default_login_shell and following defines. * If you change LIBBB_DEFAULT_LOGIN_SHELL, * don't forget to change increment constant. */ -#define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh" +#define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh" extern const char bb_default_login_shell[]; /* "/bin/sh" */ -#define DEFAULT_SHELL (bb_default_login_shell+1) +#define DEFAULT_SHELL (bb_default_login_shell+1) /* "sh" */ -#define DEFAULT_SHELL_SHORT_NAME (bb_default_login_shell+6) +#define DEFAULT_SHELL_SHORT_NAME (bb_default_login_shell+6) #if ENABLE_FEATURE_DEVFS # define CURRENT_VC "/dev/vc/0" diff --git a/libbb/run_shell.c b/libbb/run_shell.c index 4608a24a9..4d92c3caa 100644 --- a/libbb/run_shell.c +++ b/libbb/run_shell.c @@ -49,15 +49,14 @@ void FAST_FUNC set_current_security_context(security_context_t sid) #endif -/* Run SHELL, or DEFAULT_SHELL if SHELL is empty. - If COMMAND is nonzero, pass it to the shell with the -c option. - If ADDITIONAL_ARGS is nonzero, pass it to the shell as more - arguments. */ - +/* Run SHELL, or DEFAULT_SHELL if SHELL is "" or NULL. + * If COMMAND is nonzero, pass it to the shell with the -c option. + * If ADDITIONAL_ARGS is nonzero, pass it to the shell as more + * arguments. */ void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) { const char **args; - int argno = 1; + int argno; int additional_args_cnt = 0; for (args = additional_args; args && *args; args++) @@ -65,11 +64,13 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, args = xmalloc(sizeof(char*) * (4 + additional_args_cnt)); - args[0] = bb_get_last_path_component_nostrip(xstrdup(shell)); + if (!shell || !shell[0]) + shell = DEFAULT_SHELL; + args[0] = bb_get_last_path_component_nostrip(shell); if (loginshell) args[0] = xasprintf("-%s", args[0]); - + argno = 1; if (command) { args[argno++] = "-c"; args[argno++] = command; @@ -79,6 +80,7 @@ void FAST_FUNC run_shell(const char *shell, int loginshell, const char *command, args[argno++] = *additional_args; } args[argno] = NULL; + #if ENABLE_SELINUX if (current_sid) setexeccon(current_sid); diff --git a/libbb/setup_environment.c b/libbb/setup_environment.c index 13e60d8e4..a95fbc5bf 100644 --- a/libbb/setup_environment.c +++ b/libbb/setup_environment.c @@ -43,7 +43,7 @@ void FAST_FUNC setup_environment(const char *shell, int flags, const struct pass const char *term; /* Leave TERM unchanged. Set HOME, SHELL, USER, LOGNAME, PATH. - Unset all other environment variables. */ + * Unset all other environment variables. */ term = getenv("TERM"); clearenv(); if (term) @@ -57,7 +57,7 @@ void FAST_FUNC setup_environment(const char *shell, int flags, const struct pass //xsetenv("SHELL", shell); } else if (flags & SETUP_ENV_CHANGEENV) { /* Set HOME, SHELL, and if not becoming a super-user, - USER and LOGNAME. */ + * USER and LOGNAME. */ if (pw->pw_uid) { shortcut: xsetenv("USER", pw->pw_name); diff --git a/loginutils/login.c b/loginutils/login.c index 078cd68ed..88ed0af78 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -201,7 +201,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) }; char *fromhost; char username[USERNAME_SIZE]; - const char *tmp; + const char *shell; int run_by_root; unsigned opt; int count = 0; @@ -389,10 +389,10 @@ int login_main(int argc UNUSED_PARAM, char **argv) run_login_script(pw, full_tty); change_identity(pw); - tmp = pw->pw_shell; - if (!tmp || !*tmp) - tmp = DEFAULT_SHELL; - setup_environment(tmp, + shell = pw->pw_shell; + if (!shell || !shell[0]) + shell = DEFAULT_SHELL; + setup_environment(shell, (!(opt & LOGIN_OPT_p) * SETUP_ENV_CLEARENV) + SETUP_ENV_CHANGEENV, pw); @@ -427,7 +427,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) signal(SIGINT, SIG_DFL); /* Exec login shell with no additional parameters */ - run_shell(tmp, 1, NULL, NULL); + run_shell(shell, 1, NULL, NULL); /* return EXIT_FAILURE; - not reached */ } diff --git a/loginutils/su.c b/loginutils/su.c index af25655fd..9bae37551 100644 --- a/loginutils/su.c +++ b/loginutils/su.c @@ -10,23 +10,27 @@ #if ENABLE_FEATURE_SU_CHECKS_SHELLS /* Return 1 if SHELL is a restricted shell (one not returned by - getusershell), else 0, meaning it is a standard shell. */ + * getusershell), else 0, meaning it is a standard shell. */ static int restricted_shell(const char *shell) { char *line; + int result = 1; /*setusershell(); - getusershell does it itself*/ while ((line = getusershell()) != NULL) { - if (/* *line != '#' && */ strcmp(line, shell) == 0) - return 0; + if (/* *line != '#' && */ strcmp(line, shell) == 0) { + result = 0; + break; + } } - endusershell(); - return 1; + if (ENABLE_FEATURE_CLEAN_UP) + endusershell(); + return result; } #endif #define SU_OPT_mp (3) -#define SU_OPT_l (4) +#define SU_OPT_l (4) int su_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int su_main(int argc UNUSED_PARAM, char **argv) @@ -38,7 +42,8 @@ int su_main(int argc UNUSED_PARAM, char **argv) struct passwd *pw; uid_t cur_uid = getuid(); const char *tty; - char *old_user; + char user_buf[64]; + const char *old_user; flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); //argc -= optind; @@ -56,21 +61,18 @@ int su_main(int argc UNUSED_PARAM, char **argv) } if (ENABLE_FEATURE_SU_SYSLOG) { - /* The utmp entry (via getlogin) is probably the best way to identify - * the user, especially if someone su's from a su-shell. + /* The utmp entry (via getlogin) is probably the best way to + * identify the user, especially if someone su's from a su-shell. * But getlogin can fail -- usually due to lack of utmp entry. * in this case resort to getpwuid. */ - const char *user; #if ENABLE_FEATURE_UTMP - char user_buf[64]; - user = user_buf; + old_user = user_buf; if (getlogin_r(user_buf, sizeof(user_buf)) != 0) #endif { pw = getpwuid(cur_uid); - user = pw ? pw->pw_name : ""; + old_user = pw ? xstrdup(pw->pw_name) : ""; } - old_user = xstrdup(user); tty = xmalloc_ttyname(2); if (!tty) { tty = "none"; @@ -80,13 +82,7 @@ int su_main(int argc UNUSED_PARAM, char **argv) pw = xgetpwnam(opt_username); - /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER - is a username that is retrieved via NIS (YP), but that doesn't have - a default shell listed. */ - if (!pw->pw_shell || !pw->pw_shell[0]) - pw->pw_shell = (char *)DEFAULT_SHELL; - - if ((cur_uid == 0) || correct_password(pw)) { + if (cur_uid == 0 || correct_password(pw)) { if (ENABLE_FEATURE_SU_SYSLOG) syslog(LOG_NOTICE, "%c %s %s:%s", '+', tty, old_user, opt_username); @@ -99,21 +95,30 @@ int su_main(int argc UNUSED_PARAM, char **argv) if (ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_SU_SYSLOG) { closelog(); - free(old_user); } - if (!opt_shell && (flags & SU_OPT_mp)) + if (!opt_shell && (flags & SU_OPT_mp)) { + /* -s SHELL is not given, but "preserve env" opt is */ opt_shell = getenv("SHELL"); + } + + /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER + * is a username that is retrieved via NIS (YP), that doesn't have + * a default shell listed. */ + if (!pw->pw_shell || !pw->pw_shell[0]) + pw->pw_shell = (char *)DEFAULT_SHELL; #if ENABLE_FEATURE_SU_CHECKS_SHELLS if (opt_shell && cur_uid != 0 && restricted_shell(pw->pw_shell)) { /* The user being su'd to has a nonstandard shell, and so is - probably a uucp account or has restricted access. Don't - compromise the account by allowing access with a standard - shell. */ + * probably a uucp account or has restricted access. Don't + * compromise the account by allowing access with a standard + * shell. */ bb_error_msg("using restricted shell"); opt_shell = NULL; } + /* else: user can run whatever he wants via "su -s PROG USER". + * This is safe since PROG is run under user's uid/gid. */ #endif if (!opt_shell) opt_shell = pw->pw_shell; diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c index 6e3d3b019..3516013f1 100644 --- a/loginutils/sulogin.c +++ b/loginutils/sulogin.c @@ -101,11 +101,9 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv) shell = getenv("SUSHELL"); if (!shell) shell = getenv("sushell"); - if (!shell) { - shell = "/bin/sh"; - if (pwd->pw_shell[0]) - shell = pwd->pw_shell; - } + if (!shell) + shell = pwd->pw_shell; + /* Exec login shell with no additional parameters. Never returns. */ run_shell(shell, 1, NULL, NULL); diff --git a/runit/svlogd.c b/runit/svlogd.c index fc8b4abb9..9fe81b900 100644 --- a/runit/svlogd.c +++ b/runit/svlogd.c @@ -354,7 +354,7 @@ static void processorstart(struct logdir *ld) xmove_fd(fd, 5); // getenv("SHELL")? - execl("/bin/sh", "/bin/sh" + 5, "-c", ld->processor, (char*) NULL); + execl(DEFAULT_SHELL, DEFAULT_SHELL_SHORT_NAME, "-c", ld->processor, (char*) NULL); bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name); } ld->fnsave[26] = sv_ch; /* ...restore */ -- cgit v1.2.3-55-g6feb From 77cc2c5738d780b97b56af49510ed64d61ad2e2d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 27 Jun 2010 04:22:02 +0200 Subject: nc: introduce CONFIG_NC_110_COMPAT option. Signed-off-by: Denys Vlasenko --- include/usage.src.h | 78 ------------------------------------------- networking/Config.src | 23 ------------- networking/nc.c | 89 +++++++++++++++++++++++++++++++++++++++++++++++--- networking/nc_bloaty.c | 40 +++++++++++++++++++++-- 4 files changed, 122 insertions(+), 108 deletions(-) diff --git a/include/usage.src.h b/include/usage.src.h index f84bb93c7..6d17ab571 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -2954,84 +2954,6 @@ INSERT " or\n" \ "$ nameif -c /etc/my_mactab_file\n" \ -#if !ENABLE_DESKTOP - -#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA -#define NC_OPTIONS_STR "\n\nOptions:" -#else -#define NC_OPTIONS_STR -#endif - -#define nc_trivial_usage \ - IF_NC_EXTRA("[-iN] [-wN] ")IF_NC_SERVER("[-l] [-p PORT] ") \ - "["IF_NC_EXTRA("-f FILENAME|")"IPADDR PORT]"IF_NC_EXTRA(" [-e PROG]") -#define nc_full_usage "\n\n" \ - "Open a pipe to IP:port" IF_NC_EXTRA(" or file") \ - NC_OPTIONS_STR \ - IF_NC_EXTRA( \ - "\n -e PROG Run PROG after connect" \ - "\n -i SEC Delay interval for lines sent" \ - "\n -w SEC Timeout for connect" \ - "\n -f FILE Use file (ala /dev/ttyS0) instead of network" \ - ) \ - IF_NC_SERVER( \ - "\n -l Listen mode, for inbound connects" \ - IF_NC_EXTRA( \ - "\n (use -l twice with -e for persistent server)") \ - "\n -p PORT Local port" \ - ) - -#define nc_notes_usage "" \ - IF_NC_EXTRA( \ - "To use netcat as a terminal emulator on a serial port:\n\n" \ - "$ stty 115200 -F /dev/ttyS0\n" \ - "$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n" \ - ) - -#define nc_example_usage \ - "$ nc foobar.somedomain.com 25\n" \ - "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" \ - "help\n" \ - "214-Commands supported:\n" \ - "214- HELO EHLO MAIL RCPT DATA AUTH\n" \ - "214 NOOP QUIT RSET HELP\n" \ - "quit\n" \ - "221 foobar closing connection\n" - -#else /* DESKTOP nc - much more compatible with nc 1.10 */ - -#define nc_trivial_usage \ - "[OPTIONS] HOST PORT - connect" \ - IF_NC_SERVER("\n" \ - "nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen") -#define nc_full_usage "\n\n" \ - "Options:" \ - "\n -e PROG Run PROG after connect (must be last)" \ - IF_NC_SERVER( \ - "\n -l Listen mode, for inbound connects" \ - ) \ - "\n -n Don't do DNS resolution" \ - "\n -s ADDR Local address" \ - "\n -p PORT Local port" \ - "\n -u UDP mode" \ - "\n -v Verbose" \ - "\n -w SEC Timeout for connects and final net reads" \ - IF_NC_EXTRA( \ - "\n -i SEC Delay interval for lines sent" /* ", ports scanned" */ \ - "\n -o FILE Hex dump traffic" \ - "\n -z Zero-I/O mode (scanning)" \ - ) \ -/* "\n -r Randomize local and remote ports" */ -/* "\n -g gateway Source-routing hop point[s], up to 8" */ -/* "\n -G num Source-routing pointer: 4, 8, 12, ..." */ -/* "\nport numbers can be individual or ranges: lo-hi [inclusive]" */ - -/* -e PROG can take ARGS too: "nc ... -e ls -l", but we don't document it - * in help text: nc 1.10 does not allow that. We don't want to entice - * users to use this incompatibility */ - -#endif - #define netstat_trivial_usage \ "[-laentuwxr"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]" #define netstat_full_usage "\n\n" \ diff --git a/networking/Config.src b/networking/Config.src index ebad9e598..449436247 100644 --- a/networking/Config.src +++ b/networking/Config.src @@ -623,29 +623,6 @@ config FEATURE_NAMEIF_EXTENDED new_interface_name mac=00:80:C8:38:91:B5 new_interface_name 00:80:C8:38:91:B5 -config NC - bool "nc" - default y - help - A simple Unix utility which reads and writes data across network - connections. - -config NC_SERVER - bool "Netcat server options (-l)" - default y - depends on NC - help - Allow netcat to act as a server. - -config NC_EXTRA - bool "Netcat extensions (-eiw and filename)" - default y - depends on NC - help - Add -e (support for executing the rest of the command line after - making or receiving a successful connection), -i (delay interval for - lines sent), -w (timeout for initial connection). - config NETSTAT bool "netstat" default y diff --git a/networking/nc.c b/networking/nc.c index 243c47976..5fd8bd759 100644 --- a/networking/nc.c +++ b/networking/nc.c @@ -9,10 +9,89 @@ #include "libbb.h" -#if ENABLE_DESKTOP -#include "nc_bloaty.c" +//config:config NC +//config: bool "nc" +//config: default y +//config: help +//config: A simple Unix utility which reads and writes data across network +//config: connections. +//config: +//config:config NC_SERVER +//config: bool "Netcat server options (-l)" +//config: default y +//config: depends on NC +//config: help +//config: Allow netcat to act as a server. +//config: +//config:config NC_EXTRA +//config: bool "Netcat extensions (-eiw and filename)" +//config: default y +//config: depends on NC +//config: help +//config: Add -e (support for executing the rest of the command line after +//config: making or receiving a successful connection), -i (delay interval for +//config: lines sent), -w (timeout for initial connection). +//config: +//config:config NC_110_COMPAT +//config: bool "Netcat 1.10 compatibility (+2.5k)" +//config: default y +//config: depends on NC +//config: help +//config: This option makes nc closely follow original nc-1.10. +//config: The code is about 2.5k bigger. It enables +//config: -s ADDR, -n, -u, -v, -o FILE, -z options, but loses +//config: busybox-specific extensions: -f FILE and -ll. + +#if ENABLE_NC_110_COMPAT +# include "nc_bloaty.c" #else +//usage:#if !ENABLE_NC_110_COMPAT +//usage: +//usage:#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA +//usage:#define NC_OPTIONS_STR "\n\nOptions:" +//usage:#else +//usage:#define NC_OPTIONS_STR +//usage:#endif +//usage: +//usage:#define nc_trivial_usage +//usage: IF_NC_EXTRA("[-iN] [-wN] ")IF_NC_SERVER("[-l] [-p PORT] ") +//usage: "["IF_NC_EXTRA("-f FILE|")"IPADDR PORT]"IF_NC_EXTRA(" [-e PROG]") +//usage:#define nc_full_usage "\n\n" +//usage: "Open a pipe to IP:PORT" IF_NC_EXTRA(" or FILE") +//usage: NC_OPTIONS_STR +//usage: IF_NC_EXTRA( +//usage: "\n -e PROG Run PROG after connect" +//usage: IF_NC_SERVER( +//usage: "\n -l Listen mode, for inbound connects" +//usage: IF_NC_EXTRA( +//usage: "\n (use -l twice with -e for persistent server)") +//usage: "\n -p PORT Local port" +//usage: ) +//usage: "\n -w SEC Timeout for connect" +//usage: "\n -i SEC Delay interval for lines sent" +//usage: "\n -f FILE Use file (ala /dev/ttyS0) instead of network" +//usage: ) +//usage: +//usage:#define nc_notes_usage "" +//usage: IF_NC_EXTRA( +//usage: "To use netcat as a terminal emulator on a serial port:\n\n" +//usage: "$ stty 115200 -F /dev/ttyS0\n" +//usage: "$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n" +//usage: ) +//usage: +//usage:#define nc_example_usage +//usage: "$ nc foobar.somedomain.com 25\n" +//usage: "220 foobar ESMTP Exim 3.12 #1 Sat, 15 Apr 2000 00:03:02 -0600\n" +//usage: "help\n" +//usage: "214-Commands supported:\n" +//usage: "214- HELO EHLO MAIL RCPT DATA AUTH\n" +//usage: "214 NOOP QUIT RSET HELP\n" +//usage: "quit\n" +//usage: "221 foobar closing connection\n" +//usage: +//usage:#endif + /* Lots of small differences in features * when compared to "standard" nc */ @@ -39,7 +118,7 @@ int nc_main(int argc, char **argv) if (ENABLE_NC_SERVER || ENABLE_NC_EXTRA) { /* getopt32 is _almost_ usable: - ** it cannot handle "... -e prog -prog-opt" */ + ** it cannot handle "... -e PROG -prog-opt" */ while ((opt = getopt(argc, argv, "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0 ) { @@ -57,7 +136,7 @@ int nc_main(int argc, char **argv) /* We cannot just 'break'. We should let getopt finish. ** Or else we won't be able to find where ** 'host' and 'port' params are - ** (think "nc -w 60 host port -e prog"). */ + ** (think "nc -w 60 host port -e PROG"). */ IF_NC_EXTRA( char **p; // +2: one for progname (optarg) and one for NULL @@ -70,7 +149,7 @@ int nc_main(int argc, char **argv) ) /* optind points to argv[arvc] (NULL) now. ** FIXME: we assume that getopt will not count options - ** possibly present on "-e prog args" and will not + ** possibly present on "-e PROG ARGS" and will not ** include them into final value of optind ** which is to be used ... */ } else bb_show_usage(); diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index 8d27e9682..c44133b5d 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c @@ -36,9 +36,9 @@ * - source routing * - multiple DNS checks * Functionalty which is different from nc 1.10: - * - Prog in '-e prog' can have prog's parameters and options. + * - Prog in '-e PROG' can have prog's parameters and options. * Because of this -e option must be last. - * - nc doesn't redirect stderr to the network socket for the -e prog. + * - nc doesn't redirect stderr to the network socket for the -e PROG. * - numeric addresses are printed in (), not [] (IPv6 looks better), * port numbers are inside (): (1.2.3.4:5678) * - network read errors are reported on verbose levels > 1 @@ -50,6 +50,42 @@ /* done in nc.c: #include "libbb.h" */ +//usage:#if ENABLE_NC_110_COMPAT +//usage: +//usage:#define nc_trivial_usage +//usage: "[OPTIONS] HOST PORT - connect" +//usage: IF_NC_SERVER("\n" +//usage: "nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen") +//usage:#define nc_full_usage "\n\n" +//usage: "Options:" +//usage: "\n -e PROG Run PROG after connect (must be last)" +//usage: IF_NC_SERVER( +//usage: "\n -l Listen mode, for inbound connects" +//usage: ) +//usage: "\n -p PORT Local port" +//usage: "\n -s ADDR Local address" +//usage: "\n -w SEC Timeout for connects and final net reads" +//usage: IF_NC_EXTRA( +//usage: "\n -i SEC Delay interval for lines sent" /* ", ports scanned" */ +//usage: ) +//usage: "\n -n Don't do DNS resolution" +//usage: "\n -u UDP mode" +//usage: "\n -v Verbose" +//usage: IF_NC_EXTRA( +//usage: "\n -o FILE Hex dump traffic" +//usage: "\n -z Zero-I/O mode (scanning)" +//usage: ) +//usage:#endif + +/* "\n -r Randomize local and remote ports" */ +/* "\n -g gateway Source-routing hop point[s], up to 8" */ +/* "\n -G num Source-routing pointer: 4, 8, 12, ..." */ +/* "\nport numbers can be individual or ranges: lo-hi [inclusive]" */ + +/* -e PROG can take ARGS too: "nc ... -e ls -l", but we don't document it + * in help text: nc 1.10 does not allow that. We don't want to entice + * users to use this incompatibility */ + enum { SLEAZE_PORT = 31337, /* for UDP-scan RTT trick, change if ya want */ BIGSIZ = 8192, /* big buffers */ -- cgit v1.2.3-55-g6feb From fa1b3705a336f2ff4b6b841e12ae1edaba742d18 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 27 Jun 2010 16:47:40 +0200 Subject: mount: fix a case when sometimes error message is not printed Signed-off-by: Denys Vlasenko --- util-linux/mount.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/util-linux/mount.c b/util-linux/mount.c index aed6f798b..9107e4308 100644 --- a/util-linux/mount.c +++ b/util-linux/mount.c @@ -1718,9 +1718,9 @@ static int singlemount(struct mntent *mp, int ignore_busy) // If we know the fstype (or don't need to), jump straight // to the actual mount. - if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) + if (mp->mnt_type || (vfsflags & (MS_REMOUNT | MS_BIND | MS_MOVE))) { rc = mount_it_now(mp, vfsflags, filteropts); - else { + } else { // Loop through filesystem types until mount succeeds // or we run out @@ -1756,7 +1756,7 @@ static int singlemount(struct mntent *mp, int ignore_busy) if (errno == EBUSY && ignore_busy) return 0; - if (rc < 0) + if (rc != 0) bb_perror_msg("mounting %s on %s failed", mp->mnt_fsname, mp->mnt_dir); return rc; } -- cgit v1.2.3-55-g6feb From 31c3dad85142eac32d441f0f1140eda9884d7774 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 27 Jun 2010 16:57:55 +0200 Subject: remove recently added erroneous _and_die() Signed-off-by: Denys Vlasenko --- networking/httpd.c | 2 +- networking/inetd.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/networking/httpd.c b/networking/httpd.c index bab7b99cb..8ad7e88b1 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -1474,7 +1474,7 @@ static void send_cgi_and_exit( * in the current directory */ execv(argv[0], argv); if (verbose) - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + bb_perror_msg("can't execute '%s'", argv[0]); error_execing_cgi: /* send to stdout * (we are CGI here, our stdout is pumped to the net) */ diff --git a/networking/inetd.c b/networking/inetd.c index 6d21e18f5..2b0e0069e 100644 --- a/networking/inetd.c +++ b/networking/inetd.c @@ -1380,7 +1380,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) sigaction_set(SIGPIPE, &saved_pipe_handler); restore_sigmask(&omask); BB_EXECVP(sep->se_program, sep->se_argv); - bb_perror_msg_and_die("can't execute '%s'", sep->se_program); + bb_perror_msg("can't execute '%s'", sep->se_program); do_exit1: /* eat packet in udp case */ if (sep->se_socktype != SOCK_STREAM) -- cgit v1.2.3-55-g6feb From 1a3b0710f5424fd71a7c44eade5d4398c44ae431 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 27 Jun 2010 20:42:17 +0200 Subject: conspy: significant output minimization; blink attribute support Signed-off-by: Denys Vlasenko --- miscutils/conspy.c | 198 ++++++++++++++++++++++++++++++++++------------------- 1 file changed, 126 insertions(+), 72 deletions(-) diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 11758c603..11105f0b8 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -8,10 +8,6 @@ * http://ace-host.stuart.id.au/russell/files/conspy.c * * Licensed under GPLv2 or later, see file License in this tarball for details. - * - * example: conspy num shared access to console num - * or conspy -d num screenshot of console num - * or conspy -cs num poor man's GNU screen like */ //applet:IF_CONSPY(APPLET(conspy, _BB_DIR_BIN, _BB_SUID_DROP)) @@ -23,12 +19,12 @@ //config: default n //config: help //config: A text-mode VNC like program for Linux virtual terminals. -//config: example : conspy num shared access to console num -//config: or conspy -d num screenshot of console num -//config: or conspy -cs num poor man's GNU screen like +//config: example: conspy NUM shared access to console num +//config: or conspy -nd NUM screenshot of console num +//config: or conspy -cs NUM poor man's GNU screen like //usage:#define conspy_trivial_usage -//usage: "[-vcsndf] [-x ROW] [-y LINE] [CONSOLE_NO]" +//usage: "[-vcsndf] [-x COL] [-y LINE] [CONSOLE_NO]" //usage:#define conspy_full_usage "\n\n" //usage: "A text-mode VNC like program for Linux virtual consoles." //usage: "\nTo exit, quickly press ESC 3 times." @@ -40,14 +36,14 @@ //usage: "\n -n Black & white" //usage: "\n -d Dump console to stdout" //usage: "\n -f Follow cursor" -//usage: "\n -x ROW Starting row" +//usage: "\n -x COL Starting column" //usage: "\n -y LINE Starting line" #include "libbb.h" #include struct screen_info { - unsigned char lines, rows, cursor_x, cursor_y; + unsigned char lines, cols, cursor_x, cursor_y; }; #define CHAR(x) ((uint8_t)((x)[0])) @@ -62,20 +58,29 @@ struct globals { int kbd_fd; unsigned width; unsigned height; - uint8_t last_attr; + unsigned col; + unsigned line; int ioerror_count; int key_count; int escape_count; int nokeys; int current; int vcsa_fd; - struct screen_info info; + uint16_t last_attr; + uint8_t last_bold; + uint8_t last_blink; + uint8_t last_fg; + uint8_t last_bg; + char attrbuf[sizeof("\033[0;1;5;30;40m")]; + smallint curoff; + struct screen_info remote; struct termios term_orig; }; #define G (*ptr_to_globals) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ + strcpy((char*)&G.last_attr, "\xff\xff\xff\xff\xff\xff" "\033["); \ } while (0) enum { @@ -96,8 +101,8 @@ static void screen_read_close(void) xread(G.vcsa_fd, data, G.size); G.last_attr = 0; - for (i = 0; i < G.info.lines; i++) { - for (j = 0; j < G.info.rows; j++, NEXT(data)) { + for (i = 0; i < G.remote.lines; i++) { + for (j = 0; j < G.remote.cols; j++, NEXT(data)) { unsigned x = j - G.x; // if will catch j < G.x too unsigned y = i - G.y; // if will catch i < G.y too @@ -140,51 +145,101 @@ static void screen_char(char *data) // text 8th bit // converting RGB color bit triad to BGR: static const char color[8] = "04261537"; + char *ptr; + uint8_t fg, bold, bg, blink; G.last_attr = attr; - printf("\033[%c;4%c;3%cm", - (attr & 8) ? '1' : '0', // bold text / reset all - color[(attr >> 4) & 7], // bkgd color - color[attr & 7] // text color - ); + + //attr >>= 1; // for framebuffer console + ptr = G.attrbuf + sizeof("\033[")-1; + fg = (attr & 0x07); + bold = (attr & 0x08); + bg = (attr & 0x70); + blink = (attr & 0x80); + if (G.last_bold > bold || G.last_blink > blink) { + G.last_bold = G.last_blink = 0; + G.last_bg = 0xff; + *ptr++ = '0'; + *ptr++ = ';'; + } + if (G.last_bold != bold) { + G.last_bold = bold; + *ptr++ = '1'; + *ptr++ = ';'; + } + if (G.last_blink != blink) { + G.last_blink = blink; + *ptr++ = '5'; + *ptr++ = ';'; + } + if (G.last_fg != fg) { + G.last_fg = fg; + *ptr++ = '3'; + *ptr++ = color[fg]; + *ptr++ = ';'; + } + if (G.last_bg != bg) { + G.last_bg = bg; + *ptr++ = '4'; + *ptr++ = color[bg >> 4]; + *ptr++ = ';'; + } + if (ptr != G.attrbuf + sizeof("\033[")-1) { + ptr[-1] = 'm'; + *ptr = '\0'; + fputs(G.attrbuf, stdout); + } } putchar(CHAR(data)); + G.col++; } static void clrscr(void) { - printf("\033[1;1H" "\033[0J"); + // Home, clear till end of src, cursor on + fputs("\033[1;1H" "\033[J" "\033[?25h", stdout); + G.curoff = G.col = G.line = 0; } static void curoff(void) { - printf("\033[?25l"); + if (!G.curoff) { + G.curoff = 1; + fputs("\033[?25l", stdout); + } } static void curon(void) { - printf("\033[?25h"); + if (G.curoff) { + G.curoff = 0; + fputs("\033[?25h", stdout); + } } -static void gotoxy(int row, int line) +static void gotoxy(int col, int line) { - printf("\033[%u;%uH", line + 1, row + 1); + if (G.col != col || G.line != line) { + G.col = col; + G.line = line; + printf("\033[%u;%uH", line + 1, col + 1); + } } static void screen_dump(void) { int linefeed_cnt; - int line, row; - int linecnt = G.info.lines - G.y; - char *data = G.data + G.current + (2 * G.y * G.info.rows); + int line, col; + int linecnt = G.remote.lines - G.y; + char *data = G.data + G.current + (2 * G.y * G.remote.cols); linefeed_cnt = 0; for (line = 0; line < linecnt && line < G.height; line++) { int space_cnt = 0; - for (row = 0; row < G.info.rows; row++, NEXT(data)) { - unsigned tty_row = row - G.x; // if will catch row < G.x too + for (col = 0; col < G.remote.cols; col++, NEXT(data)) { + unsigned tty_col = col - G.x; // if will catch col < G.x too - if (tty_row >= G.width) + if (tty_col >= G.width) continue; space_cnt++; if (BW && CHAR(data) == ' ') @@ -204,8 +259,8 @@ static void screen_dump(void) static void curmove(void) { - unsigned cx = G.info.cursor_x - G.x; - unsigned cy = G.info.cursor_y - G.y; + unsigned cx = G.remote.cursor_x - G.x; + unsigned cy = G.remote.cursor_y - G.y; if (cx >= G.width || cy >= G.height) { curoff(); @@ -226,7 +281,7 @@ static void cleanup(int code) } // Reset attributes if (!BW) - printf("\033[0m"); + fputs("\033[0m", stdout); bb_putchar('\n'); if (code > 1) kill_myself_with_sig(code); // does not return @@ -236,8 +291,8 @@ static void cleanup(int code) static void get_initial_data(const char* vcsa_name) { G.vcsa_fd = xopen(vcsa_name, O_RDONLY); - xread(G.vcsa_fd, &G.info, 4); - G.size = G.info.rows * G.info.lines * 2; + xread(G.vcsa_fd, &G.remote, 4); + G.size = G.remote.cols * G.remote.lines * 2; G.width = G.height = UINT_MAX; G.data = xzalloc(2 * G.size); screen_read_close(); @@ -354,34 +409,30 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) int i, j; char *data, *old; - old = G.data + G.current; - G.current = G.size - G.current; - data = G.data + G.current; - // Close & re-open vcsa in case they have // swapped virtual consoles G.vcsa_fd = xopen(vcsa_name, O_RDONLY); - xread(G.vcsa_fd, &G.info, 4); - if (G.size != (G.info.rows * G.info.lines * 2)) { + xread(G.vcsa_fd, &G.remote, 4); + if (G.size != (G.remote.cols * G.remote.lines * 2)) { cleanup(1); } i = G.width; j = G.height; get_terminal_width_height(G.kbd_fd, &G.width, &G.height); if ((option_mask32 & FLAG(f))) { - int nx = G.info.cursor_x - G.width + 1; - int ny = G.info.cursor_y - G.height + 1; + int nx = G.remote.cursor_x - G.width + 1; + int ny = G.remote.cursor_y - G.height + 1; - if (G.info.cursor_x < G.x) { - G.x = G.info.cursor_x; + if (G.remote.cursor_x < G.x) { + G.x = G.remote.cursor_x; i = 0; // force refresh } if (nx > G.x) { G.x = nx; i = 0; // force refresh } - if (G.info.cursor_y < G.y) { - G.y = G.info.cursor_y; + if (G.remote.cursor_y < G.y) { + G.y = G.remote.cursor_y; i = 0; // force refresh } if (ny > G.y) { @@ -391,40 +442,43 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) } // Scan console data and redraw our tty where needed + old = G.data + G.current; + G.current = G.size - G.current; + data = G.data + G.current; screen_read_close(); if (i != G.width || j != G.height) { clrscr(); screen_dump(); - } - else for (i = 0; i < G.info.lines; i++) { - char *last = last; - char *first = NULL; - int iy = i - G.y; - - if (iy >= (int) G.height) - break; - for (j = 0; j < G.info.rows; j++) { - last = data; - if (DATA(data) != DATA(old) && iy >= 0) { + } else { + // For each remote line + old += G.y * G.remote.cols * 2; + data += G.y * G.remote.cols * 2; + for (i = G.y; i < G.remote.lines; i++) { + char *first = NULL; // first char which needs updating + char *last = last; // last char which needs updating + unsigned iy = i - G.y; + + if (iy >= G.height) + break; + old += G.x * 2; + data += G.x * 2; + for (j = G.x; j < G.remote.cols; j++, NEXT(old), NEXT(data)) { unsigned jx = j - G.x; - last = NULL; - if (first == NULL && jx < G.width) { - first = data; - gotoxy(jx, iy); + if (jx < G.width && DATA(data) != DATA(old)) { + last = data; + if (!first) { + first = data; + gotoxy(jx, iy); + } } } - NEXT(old); - NEXT(data); + if (first) { + // Rewrite updated data on the local screen + for (; first <= last; NEXT(first)) + screen_char(first); + } } - if (first == NULL) - continue; - if (last == NULL) - last = data; - - // Write the data to the screen - for (; first < last; NEXT(first)) - screen_char(first); } curmove(); -- cgit v1.2.3-55-g6feb From 7d1201c5d7014365fb7e3d9da58f5e3fe0a1edc8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 28 Jun 2010 04:17:06 +0200 Subject: nc: better comments. no code changes Signed-off-by: Denys Vlasenko --- networking/nc_bloaty.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index c44133b5d..aebb9cb8c 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c @@ -36,16 +36,18 @@ * - source routing * - multiple DNS checks * Functionalty which is different from nc 1.10: - * - Prog in '-e PROG' can have prog's parameters and options. + * - PROG in '-e PROG' can have ARGS (and options). * Because of this -e option must be last. - * - nc doesn't redirect stderr to the network socket for the -e PROG. +//TODO: remove -e incompatibility? + * - we don't redirect stderr to the network socket for the -e PROG. + * (PROG can do it itself if needed, but sometimes it is NOT wanted!) * - numeric addresses are printed in (), not [] (IPv6 looks better), * port numbers are inside (): (1.2.3.4:5678) * - network read errors are reported on verbose levels > 1 * (nc 1.10 treats them as EOF) * - TCP connects from wrong ip/ports (if peer ip:port is specified * on the command line, but accept() says that it came from different addr) - * are closed, but nc doesn't exit - continues to listen/accept. + * are closed, but we don't exit - we continue to listen/accept. */ /* done in nc.c: #include "libbb.h" */ -- cgit v1.2.3-55-g6feb From ff37799dfe0e6e8fb9b971a2aeb4076d8a3784ec Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Mon, 28 Jun 2010 15:50:22 +0200 Subject: conspy: code shrink function old new delta conspy_main 1446 1444 -2 screen_read_close 114 108 -6 screen_char 299 293 -6 Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- include/usage.src.h | 10 ----- init/bootchartd.c | 31 +++++++------ miscutils/conspy.c | 123 +++++++++++++++++++++++++++------------------------- 3 files changed, 78 insertions(+), 86 deletions(-) diff --git a/include/usage.src.h b/include/usage.src.h index 6d17ab571..53ee7943a 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -163,16 +163,6 @@ INSERT #define blkid_full_usage "\n\n" \ "Print UUIDs of all filesystems" -#define bootchartd_trivial_usage \ - "start [PROG ARGS]|stop|init" -#define bootchartd_full_usage "\n\n" \ - "Create /var/log/bootchart.tgz with boot chart data\n" \ - "\nOptions:" \ - "\nstart: start background logging; with PROG, run PROG, then kill logging with USR1" \ - "\nstop: send USR1 to all bootchartd processes" \ - "\ninit: start background logging; stop when getty/xdm is seen (for init scripts)" \ - "\nUnder PID 1: as init, then exec $bootchart_init, /init, /sbin/init" \ - #define brctl_trivial_usage \ "COMMAND [BRIDGE [INTERFACE]]" #define brctl_full_usage "\n\n" \ diff --git a/init/bootchartd.c b/init/bootchartd.c index f7de13e2f..4e15da4e8 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -156,7 +156,7 @@ static int dump_procs(FILE *fp, int look_for_login_process) continue; p++; strchrnul(p, ')')[0] = '\0'; - /* If is gdm, kdm or a getty? */ + /* Is it gdm, kdm or a getty? */ if (((p[0] == 'g' || p[0] == 'k' || p[0] == 'x') && p[1] == 'd' && p[2] == 'm') || strstr(p, "getty") ) { @@ -258,13 +258,12 @@ static void finalize(char *tempdir, const char *prog) fprintf(header_fp, "profile.process = %s\n", prog); fputs("version = "BC_VERSION_STR"\n", header_fp); - if (ENABLE_FEATURE_BOOTCHARTD_BLOATED_HEADER) { char *hostname; char *kcmdline; time_t t; struct tm tm_time; - /* x2 for possible localized data */ + /* x2 for possible localized weekday/month names */ char date_buf[sizeof("Mon Jun 21 05:29:03 CEST 2010") * 2]; struct utsname unamebuf; @@ -313,16 +312,16 @@ static void finalize(char *tempdir, const char *prog) */ } -/* Usage: - * bootchartd start [PROG ARGS]: start logging in background, USR1 stops it. - * With PROG, runs PROG, then kills background logging. - * bootchartd stop: same as "killall -USR1 bootchartd" - * bootchartd init: start logging in background - * Stop when getty/gdm is seen (if AUTO_STOP_LOGGER = yes). - * Meant to be used from init scripts. - * bootchartd (pid==1): as init, but then execs $bootchart_init, /init, /sbin/init - * Meant to be used as kernel's init process. - */ +//usage:#define bootchartd_trivial_usage +//usage: "start [PROG ARGS]|stop|init" +//usage:#define bootchartd_full_usage "\n\n" +//usage: "Create /var/log/bootchart.tgz with boot chart data\n" +//usage: "\nOptions:" +//usage: "\nstart: start background logging; with PROG, run PROG, then kill logging with USR1" +//usage: "\nstop: send USR1 to all bootchartd processes" +//usage: "\ninit: start background logging; stop when getty/xdm is seen (for init scripts)" +//usage: "\nUnder PID 1: as init, then exec $bootchart_init, /init, /sbin/init" + int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bootchartd_main(int argc UNUSED_PARAM, char **argv) { @@ -358,7 +357,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) cmd = CMD_PID1; } - /* Here we are in START or INIT state */ + /* Here we are in START, INIT or CMD_PID1 state */ /* Read config file: */ sample_period_us = 200 * 1000; @@ -422,7 +421,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) execl(bootchart_init, bootchart_init, NULL); execl("/init", "init", NULL); execl("/sbin/init", "init", NULL); - bb_perror_msg_and_die("can't exec '%s'", "/sbin/init"); + bb_perror_msg_and_die("can't execute '%s'", "/sbin/init"); } if (cmd == CMD_START && argv[2]) { /* "start PROG ARGS" */ @@ -432,7 +431,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) if (pid == 0) { /* child */ argv += 2; execvp(argv[0], argv); - bb_perror_msg_and_die("can't exec '%s'", argv[0]); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); } /* parent */ waitpid(pid, NULL, 0); diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 11105f0b8..6f2f0255c 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -56,31 +56,33 @@ struct globals { int size; int x, y; int kbd_fd; - unsigned width; - unsigned height; - unsigned col; - unsigned line; + int vcsa_fd; int ioerror_count; int key_count; int escape_count; int nokeys; int current; - int vcsa_fd; - uint16_t last_attr; - uint8_t last_bold; - uint8_t last_blink; - uint8_t last_fg; - uint8_t last_bg; - char attrbuf[sizeof("\033[0;1;5;30;40m")]; + // cached local tty parameters + unsigned width; + unsigned height; + unsigned col; + unsigned line; smallint curoff; + uint8_t last_attr; + uint8_t force_attr_change; + char attrbuf[sizeof("\033[0;1;5;30;40m")]; + // remote console struct screen_info remote; + // saved local tty terminfo struct termios term_orig; }; #define G (*ptr_to_globals) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ - strcpy((char*)&G.last_attr, "\xff\xff\xff\xff\xff\xff" "\033["); \ + G.attrbuf[0] = '\033'; \ + G.attrbuf[1] = '['; \ + G.force_attr_change = 0xff; \ } while (0) enum { @@ -100,7 +102,6 @@ static void screen_read_close(void) char *data = G.data + G.current; xread(G.vcsa_fd, data, G.size); - G.last_attr = 0; for (i = 0; i < G.remote.lines; i++) { for (j = 0; j < G.remote.cols; j++, NEXT(data)) { unsigned x = j - G.x; // if will catch j < G.x too @@ -117,9 +118,12 @@ static void screen_read_close(void) static void screen_char(char *data) { - uint8_t attr = ATTR(data); + if (!BW) { + uint8_t attr = ATTR(data); + //uint8_t attr = ATTR(data) >> 1; // for framebuffer console + uint8_t attr_diff = (G.last_attr ^ attr) | G.force_attr_change; - if (!BW && G.last_attr != attr) { + if (attr_diff) { // Attribute layout for VGA compatible text videobuffer: // blinking text // |red bkgd @@ -143,51 +147,49 @@ static void screen_char(char *data) // green text // blue text // text 8th bit - // converting RGB color bit triad to BGR: - static const char color[8] = "04261537"; - char *ptr; - uint8_t fg, bold, bg, blink; - - G.last_attr = attr; - - //attr >>= 1; // for framebuffer console - ptr = G.attrbuf + sizeof("\033[")-1; - fg = (attr & 0x07); - bold = (attr & 0x08); - bg = (attr & 0x70); - blink = (attr & 0x80); - if (G.last_bold > bold || G.last_blink > blink) { - G.last_bold = G.last_blink = 0; - G.last_bg = 0xff; - *ptr++ = '0'; - *ptr++ = ';'; - } - if (G.last_bold != bold) { - G.last_bold = bold; - *ptr++ = '1'; - *ptr++ = ';'; - } - if (G.last_blink != blink) { - G.last_blink = blink; - *ptr++ = '5'; - *ptr++ = ';'; - } - if (G.last_fg != fg) { - G.last_fg = fg; - *ptr++ = '3'; - *ptr++ = color[fg]; - *ptr++ = ';'; - } - if (G.last_bg != bg) { - G.last_bg = bg; - *ptr++ = '4'; - *ptr++ = color[bg >> 4]; - *ptr++ = ';'; - } - if (ptr != G.attrbuf + sizeof("\033[")-1) { - ptr[-1] = 'm'; - *ptr = '\0'; - fputs(G.attrbuf, stdout); + // converting RGB color bit triad to BGR: + static const char color[8] = "04261537"; + const uint8_t fg_mask = 0x07, bold_mask = 0x08; + const uint8_t bg_mask = 0x70, blink_mask = 0x80; + char *ptr; + + ptr = G.attrbuf + 2; /* skip "ESC [" */ + + // (G.last_attr & ~attr) has 1 only where + // G.last_attr has 1 but attr has 0. + // Here we check whether we have transition + // bold->non-bold or blink->non-blink: + if ((G.last_attr & ~attr) & (bold_mask | blink_mask)) { + *ptr++ = '0'; // "reset all attrs" + *ptr++ = ';'; + // must set fg & bg, maybe need to set bold or blink: + attr_diff = attr | ~(bold_mask | blink_mask); + } + G.force_attr_change = 0; + G.last_attr = attr; + if (attr_diff & bold_mask) { + *ptr++ = '1'; + *ptr++ = ';'; + } + if (attr_diff & blink_mask) { + *ptr++ = '5'; + *ptr++ = ';'; + } + if (attr_diff & fg_mask) { + *ptr++ = '3'; + *ptr++ = color[attr & fg_mask]; + *ptr++ = ';'; + } + if (attr_diff & bg_mask) { + *ptr++ = '4'; + *ptr++ = color[(attr & bg_mask) >> 4]; + *ptr++ = ';'; + } + if (ptr != G.attrbuf + 2) { + ptr[-1] = 'm'; + *ptr = '\0'; + fputs(G.attrbuf, stdout); + } } } putchar(CHAR(data)); @@ -402,6 +404,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) termbuf.c_cc[VMIN] = 1; termbuf.c_cc[VTIME] = 0; tcsetattr(G.kbd_fd, TCSANOW, &termbuf); + poll_timeout_ms = 250; while (1) { struct pollfd pfd; -- cgit v1.2.3-55-g6feb From c03fb3cd7d6b41706a4ade372c5df9c6b951a51c Mon Sep 17 00:00:00 2001 From: Keisuke Yasui Date: Mon, 28 Jun 2010 16:04:00 +0200 Subject: bootchartd: fix sample period calculations Signed-off-by: Keisuke Yasui Signed-off-by: Denys Vlasenko --- init/bootchartd.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/init/bootchartd.c b/init/bootchartd.c index 4e15da4e8..42b98c827 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -197,7 +197,7 @@ static char *make_tempdir(void) return tempdir; } -static void do_logging(int sample_period_us) +static void do_logging(unsigned sample_period_us) { //# Enable process accounting if configured //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then @@ -210,7 +210,7 @@ static void do_logging(int sample_period_us) //FILE *proc_netdev = xfopen("proc_netdev.log", "w"); FILE *proc_ps = xfopen("proc_ps.log", "w"); int look_for_login_process = (getppid() == 1); - unsigned count = 60*1000*1000 / (200*1000); /* ~1 minute */ + unsigned count = 60*1000*1000 / sample_period_us; /* ~1 minute */ while (--count && !bb_got_signal) { char *p; @@ -235,8 +235,8 @@ static void do_logging(int sample_period_us) /* dump_procs saw a getty or {g,k,x}dm * stop logging in 2 seconds: */ - if (count > 2*1000*1000 / (200*1000)) - count = 2*1000*1000 / (200*1000); + if (count > 2*1000*1000 / sample_period_us) + count = 2*1000*1000 / sample_period_us; } fflush_all(); wait_more: @@ -325,7 +325,7 @@ static void finalize(char *tempdir, const char *prog) int bootchartd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bootchartd_main(int argc UNUSED_PARAM, char **argv) { - int sample_period_us; + unsigned sample_period_us; pid_t parent_pid, logger_pid; smallint cmd; enum { @@ -372,6 +372,8 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) } config_close(parser); } + if ((int)sample_period_us <= 0) + sample_period_us = 1; /* prevent division by 0 */ /* Create logger child: */ logger_pid = fork_or_rexec(argv); -- cgit v1.2.3-55-g6feb From fa5ea17b5f6457d888a30afeff87420b7fe0348a Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Wed, 30 Jun 2010 07:05:31 +0200 Subject: conspy: code shrink function old new delta screen_read_close 114 187 +73 set_cursor - 53 +53 cleanup 93 91 -2 screen_dump 202 197 -5 curon 34 - -34 screen_char 351 308 -43 conspy_main 1444 1264 -180 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 1/4 up/down: 126/-264) Total: -138 bytes Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- miscutils/conspy.c | 211 +++++++++++++++++++++++++---------------------------- 1 file changed, 101 insertions(+), 110 deletions(-) diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 6f2f0255c..565922ca0 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -46,9 +46,9 @@ struct screen_info { unsigned char lines, cols, cursor_x, cursor_y; }; -#define CHAR(x) ((uint8_t)((x)[0])) -#define ATTR(x) ((uint8_t)((x)[1])) -#define NEXT(x) ((x)+=2) +#define CHAR(x) (*(uint8_t*)(x)) +#define ATTR(x) (((uint8_t*)(x))[1]) +#define NEXT(x) ((x) += 2) #define DATA(x) (*(uint16_t*)(x)) struct globals { @@ -56,25 +56,25 @@ struct globals { int size; int x, y; int kbd_fd; - int vcsa_fd; int ioerror_count; int key_count; int escape_count; int nokeys; int current; + int first_line_offset; + int last_attr; // cached local tty parameters unsigned width; unsigned height; unsigned col; unsigned line; - smallint curoff; - uint8_t last_attr; - uint8_t force_attr_change; + smallint curoff; // unknown:0 cursor on:-1 cursor off:1 char attrbuf[sizeof("\033[0;1;5;30;40m")]; // remote console struct screen_info remote; // saved local tty terminfo struct termios term_orig; + char vcsa_name[sizeof("/dev/vcsaNN")]; }; #define G (*ptr_to_globals) @@ -82,7 +82,8 @@ struct globals { SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ G.attrbuf[0] = '\033'; \ G.attrbuf[1] = '['; \ - G.force_attr_change = 0xff; \ + G.width = G.height = UINT_MAX; \ + G.last_attr--; \ } while (0) enum { @@ -96,24 +97,80 @@ enum { #define FLAG(x) (1 << FLAG_##x) #define BW (option_mask32 & FLAG(n)) +static void clrscr(void) +{ + // Home, clear till end of screen + fputs("\033[1;1H" "\033[J", stdout); + G.col = G.line = 0; +} + +static void set_cursor(int state) +{ + if (G.curoff != state) { + G.curoff = state; + fputs("\033[?25", stdout); + bb_putchar("h?l"[1 + state]); + } +} + +static void gotoxy(int col, int line) +{ + if (G.col != col || G.line != line) { + G.col = col; + G.line = line; + printf("\033[%u;%uH", line + 1, col + 1); + } +} + +static void cleanup(int code) +{ + set_cursor(-1); // cursor on + tcsetattr(G.kbd_fd, TCSANOW, &G.term_orig); + if (ENABLE_FEATURE_CLEAN_UP) { + close(G.kbd_fd); + } + // Reset attributes + if (!BW) + fputs("\033[0m", stdout); + bb_putchar('\n'); + if (code > 1) + kill_myself_with_sig(code); + exit(code); +} + static void screen_read_close(void) { unsigned i, j; - char *data = G.data + G.current; - - xread(G.vcsa_fd, data, G.size); + int vcsa_fd; + char *data; + + // Close & re-open vcsa in case they have swapped virtual consoles + vcsa_fd = xopen(G.vcsa_name, O_RDONLY); + xread(vcsa_fd, &G.remote, 4); + i = G.remote.cols * 2; + G.first_line_offset = G.y * i; + i *= G.remote.lines; + if (G.data == NULL) { + G.size = i; + G.data = xzalloc(2 * i); + } + else if (G.size != i) { + cleanup(1); + } + data = G.data + G.current; + xread(vcsa_fd, data, G.size); + close(vcsa_fd); for (i = 0; i < G.remote.lines; i++) { for (j = 0; j < G.remote.cols; j++, NEXT(data)) { unsigned x = j - G.x; // if will catch j < G.x too unsigned y = i - G.y; // if will catch i < G.y too if (CHAR(data) < ' ') - *data = ' '; // CHAR(data) = ' '; + CHAR(data) = ' '; if (y >= G.height || x >= G.width) DATA(data) = 0; } } - close(G.vcsa_fd); } static void screen_char(char *data) @@ -121,7 +178,7 @@ static void screen_char(char *data) if (!BW) { uint8_t attr = ATTR(data); //uint8_t attr = ATTR(data) >> 1; // for framebuffer console - uint8_t attr_diff = (G.last_attr ^ attr) | G.force_attr_change; + uint8_t attr_diff = G.last_attr ^ attr; if (attr_diff) { // Attribute layout for VGA compatible text videobuffer: @@ -153,19 +210,20 @@ static void screen_char(char *data) const uint8_t bg_mask = 0x70, blink_mask = 0x80; char *ptr; - ptr = G.attrbuf + 2; /* skip "ESC [" */ + ptr = G.attrbuf + 2; // skip "ESC [" // (G.last_attr & ~attr) has 1 only where // G.last_attr has 1 but attr has 0. // Here we check whether we have transition // bold->non-bold or blink->non-blink: - if ((G.last_attr & ~attr) & (bold_mask | blink_mask)) { + if (G.last_attr < 0 // initial value + || ((G.last_attr & ~attr) & (bold_mask | blink_mask)) != 0 + ) { *ptr++ = '0'; // "reset all attrs" *ptr++ = ';'; // must set fg & bg, maybe need to set bold or blink: attr_diff = attr | ~(bold_mask | blink_mask); } - G.force_attr_change = 0; G.last_attr = attr; if (attr_diff & bold_mask) { *ptr++ = '1'; @@ -196,44 +254,12 @@ static void screen_char(char *data) G.col++; } -static void clrscr(void) -{ - // Home, clear till end of src, cursor on - fputs("\033[1;1H" "\033[J" "\033[?25h", stdout); - G.curoff = G.col = G.line = 0; -} - -static void curoff(void) -{ - if (!G.curoff) { - G.curoff = 1; - fputs("\033[?25l", stdout); - } -} - -static void curon(void) -{ - if (G.curoff) { - G.curoff = 0; - fputs("\033[?25h", stdout); - } -} - -static void gotoxy(int col, int line) -{ - if (G.col != col || G.line != line) { - G.col = col; - G.line = line; - printf("\033[%u;%uH", line + 1, col + 1); - } -} - static void screen_dump(void) { int linefeed_cnt; int line, col; int linecnt = G.remote.lines - G.y; - char *data = G.data + G.current + (2 * G.y * G.remote.cols); + char *data = G.data + G.current + G.first_line_offset; linefeed_cnt = 0; for (line = 0; line < linecnt && line < G.height; line++) { @@ -263,41 +289,13 @@ static void curmove(void) { unsigned cx = G.remote.cursor_x - G.x; unsigned cy = G.remote.cursor_y - G.y; + int cursor = 1; - if (cx >= G.width || cy >= G.height) { - curoff(); - } else { - curon(); + if (cx < G.width && cy < G.height) { gotoxy(cx, cy); + cursor = -1; } - fflush_all(); -} - -static void cleanup(int code) -{ - curon(); - fflush_all(); - tcsetattr(G.kbd_fd, TCSANOW, &G.term_orig); - if (ENABLE_FEATURE_CLEAN_UP) { - close(G.kbd_fd); - } - // Reset attributes - if (!BW) - fputs("\033[0m", stdout); - bb_putchar('\n'); - if (code > 1) - kill_myself_with_sig(code); // does not return - exit(code); -} - -static void get_initial_data(const char* vcsa_name) -{ - G.vcsa_fd = xopen(vcsa_name, O_RDONLY); - xread(G.vcsa_fd, &G.remote, 4); - G.size = G.remote.cols * G.remote.lines * 2; - G.width = G.height = UINT_MAX; - G.data = xzalloc(2 * G.size); - screen_read_close(); + set_cursor(cursor); } static void create_cdev_if_doesnt_exist(const char* name, dev_t dev) @@ -345,7 +343,6 @@ static NOINLINE void start_shell_in_child(const char* tty_name) int conspy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int conspy_main(int argc UNUSED_PARAM, char **argv) { - char vcsa_name[sizeof("/dev/vcsaNN")]; char tty_name[sizeof("/dev/ttyNN")]; #define keybuf bb_common_bufsiz1 struct termios termbuf; @@ -365,7 +362,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) applet_long_options = getopt_longopts; #endif INIT_G(); - strcpy(vcsa_name, "/dev/vcsa"); + strcpy(G.vcsa_name, "/dev/vcsa"); opt_complementary = "x+:y+"; // numeric params opts = getopt32(argv, "vcsndfx:y:", &G.x, &G.y); @@ -373,19 +370,19 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) ttynum = 0; if (argv[0]) { ttynum = xatou_range(argv[0], 0, 63); - sprintf(vcsa_name + sizeof("/dev/vcsa")-1, "%u", ttynum); + sprintf(G.vcsa_name + sizeof("/dev/vcsa")-1, "%u", ttynum); } sprintf(tty_name, "%s%u", "/dev/tty", ttynum); if (opts & FLAG(c)) { if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v)) create_cdev_if_doesnt_exist(tty_name, makedev(4, ttynum)); - create_cdev_if_doesnt_exist(vcsa_name, makedev(7, 128 + ttynum)); + create_cdev_if_doesnt_exist(G.vcsa_name, makedev(7, 128 + ttynum)); } if ((opts & FLAG(s)) && ttynum) { start_shell_in_child(tty_name); } - get_initial_data(vcsa_name); + screen_read_close(); if (opts & FLAG(d)) { screen_dump(); bb_putchar('\n'); @@ -412,17 +409,11 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) int i, j; char *data, *old; - // Close & re-open vcsa in case they have - // swapped virtual consoles - G.vcsa_fd = xopen(vcsa_name, O_RDONLY); - xread(G.vcsa_fd, &G.remote, 4); - if (G.size != (G.remote.cols * G.remote.lines * 2)) { - cleanup(1); - } + // in the first loop G.width = G.height = 0: refresh i = G.width; j = G.height; get_terminal_width_height(G.kbd_fd, &G.width, &G.height); - if ((option_mask32 & FLAG(f))) { + if (option_mask32 & FLAG(f)) { int nx = G.remote.cursor_x - G.width + 1; int ny = G.remote.cursor_y - G.height + 1; @@ -454,8 +445,8 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) screen_dump(); } else { // For each remote line - old += G.y * G.remote.cols * 2; - data += G.y * G.remote.cols * 2; + old += G.first_line_offset; + data += G.first_line_offset; for (i = G.y; i < G.remote.lines; i++) { char *first = NULL; // first char which needs updating char *last = last; // last char which needs updating @@ -463,10 +454,8 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) if (iy >= G.height) break; - old += G.x * 2; - data += G.x * 2; - for (j = G.x; j < G.remote.cols; j++, NEXT(old), NEXT(data)) { - unsigned jx = j - G.x; + for (j = 0; j < G.remote.cols; j++, NEXT(old), NEXT(data)) { + unsigned jx = j - G.x; // if will catch j >= G.x too if (jx < G.width && DATA(data) != DATA(old)) { last = data; @@ -486,6 +475,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) curmove(); // Wait for local user keypresses + fflush_all(); pfd.fd = G.kbd_fd; pfd.events = POLLIN; bytes_read = 0; @@ -532,15 +522,16 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) else if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE) G.key_count = 0; // scan code mode else { - for (i = 0; i < G.key_count && result != -1; i++) - result = ioctl(handle, TIOCSTI, keybuf + i); - G.key_count -= i; + char *p = keybuf; + for (; G.key_count != 0 && result != -1; p++, G.key_count--) { + result = ioctl(handle, TIOCSTI, p); + // If there is an application on console which reacts + // to keypresses, we need to make our first sleep + // shorter to quickly redraw whatever it printed there. + poll_timeout_ms = 20; + } if (G.key_count) - memmove(keybuf, keybuf + i, G.key_count); - // If there is an application on console which reacts - // to keypresses, we need to make our first sleep - // shorter to quickly redraw whatever it printed there. - poll_timeout_ms = 20; + memmove(keybuf, p, G.key_count); } // Close & re-open tty in case they have // swapped virtual consoles @@ -553,5 +544,5 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) else if (errno != EIO || ++G.ioerror_count > 4) cleanup(1); } - } + } /* while (1) */ } -- cgit v1.2.3-55-g6feb From 620e863ba24fe9e0126d1540e89a531264021a77 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 30 Jun 2010 19:43:44 +0200 Subject: bzip2 decompression: simple code shrink function old new delta unpack_bz2_stream_prime 60 55 -5 get_header_tar 1508 1496 -12 Signed-off-by: Denys Vlasenko --- archival/libunarchive/decompress_bunzip2.c | 6 +++--- archival/libunarchive/get_header_tar.c | 9 ++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libunarchive/decompress_bunzip2.c index cd8df086e..bdbd39ac2 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libunarchive/decompress_bunzip2.c @@ -692,9 +692,9 @@ unpack_bz2_stream(int src_fd, int dst_fd) IF_DESKTOP(long long) int FAST_FUNC unpack_bz2_stream_prime(int src_fd, int dst_fd) { - unsigned char magic[2]; - xread(src_fd, magic, 2); - if (magic[0] != 'B' || magic[1] != 'Z') { + uint16_t magic2; + xread(src_fd, &magic2, 2); + if (magic2 != BZIP2_MAGIC) { bb_error_msg_and_die("invalid magic"); } return unpack_bz2_stream(src_fd, dst_fd); diff --git a/archival/libunarchive/get_header_tar.c b/archival/libunarchive/get_header_tar.c index 21bbc9715..d5c92359c 100644 --- a/archival/libunarchive/get_header_tar.c +++ b/archival/libunarchive/get_header_tar.c @@ -196,27 +196,30 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) ) { #if ENABLE_FEATURE_TAR_AUTODETECT char FAST_FUNC (*get_header_ptr)(archive_handle_t *); + uint16_t magic2; autodetect: + magic2 = *(uint16_t*)tar.name; /* tar gz/bz autodetect: check for gz/bz2 magic. * If we see the magic, and it is the very first block, * we can switch to get_header_tar_gz/bz2/lzma(). * Needs seekable fd. I wish recv(MSG_PEEK) works * on any fd... */ # if ENABLE_FEATURE_SEAMLESS_GZ - if (tar.name[0] == 0x1f && tar.name[1] == (char)0x8b) { /* gzip */ + if (magic2 == GZIP_MAGIC) { get_header_ptr = get_header_tar_gz; } else # endif # if ENABLE_FEATURE_SEAMLESS_BZ2 - if (tar.name[0] == 'B' && tar.name[1] == 'Z' + if (magic2 == BZIP2_MAGIC && tar.name[2] == 'h' && isdigit(tar.name[3]) ) { /* bzip2 */ get_header_ptr = get_header_tar_bz2; } else # endif # if ENABLE_FEATURE_SEAMLESS_XZ - //TODO + //TODO: if (magic2 == XZ_MAGIC1)... + //else # endif goto err; /* Two different causes for lseek() != 0: -- cgit v1.2.3-55-g6feb From 45f66167fe96de219aac91d842f3e64d857340f6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 1 Jul 2010 05:12:28 +0200 Subject: xz compression detection: avoid the need to seek function old new delta unpack_unxz 12 67 +55 unpack_xz_stream 2357 2373 +16 xmalloc_read 197 199 +2 setup_unzip_on_fd 118 99 -19 rpm2cpio_main 222 203 -19 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/2 up/down: 73/-38) Total: 35 bytes Signed-off-by: Denys Vlasenko --- archival/bbunzip.c | 9 +++++++++ archival/libunarchive/decompress_unxz.c | 4 +++- archival/rpm2cpio.c | 4 ++-- include/unarchive.h | 23 ++++++++++++++--------- libbb/read_printf.c | 4 ++-- 5 files changed, 30 insertions(+), 14 deletions(-) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index b243afb2e..832a7bbf3 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -373,6 +373,15 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) static IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM) { + struct { + uint32_t v1; + uint16_t v2; + } magic; + xread(STDIN_FILENO, &magic, 6); + if (magic.v1 != XZ_MAGIC1a || magic.v2 != XZ_MAGIC2a) { + bb_error_msg("invalid magic"); + return -1; + } return unpack_xz_stream(STDIN_FILENO, STDOUT_FILENO); } int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libunarchive/decompress_unxz.c index 5d7513a2e..721acd907 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libunarchive/decompress_unxz.c @@ -56,9 +56,11 @@ unpack_xz_stream(int src_fd, int dst_fd) if (!crc32_table) crc32_table = crc32_filltable(NULL, /*endian:*/ 0); - membuf = xmalloc(2 * BUFSIZ); memset(&iobuf, 0, sizeof(iobuf)); + /* Preload XZ file signature */ + membuf = (void*) strcpy(xmalloc(2 * BUFSIZ), HEADER_MAGIC); iobuf.in = membuf; + iobuf.in_size = HEADER_MAGIC_SIZE; iobuf.out = membuf + BUFSIZ; iobuf.out_size = BUFSIZ; diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index 1f67fa887..b23d5afa9 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c @@ -92,8 +92,8 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) xread(rpm_fd, magic.b32, sizeof(magic.b32[0])); if (magic.b32[0] != XZ_MAGIC2) goto no_magic; - /* unpack_xz_stream wants fd at position 0 */ - xlseek(rpm_fd, -6, SEEK_CUR); + /* unpack_xz_stream wants fd at position 6, no need to seek */ + //xlseek(rpm_fd, -6, SEEK_CUR); unpack = unpack_xz_stream; } else { no_magic: diff --git a/include/unarchive.h b/include/unarchive.h index b4cf16082..3b8e1575a 100644 --- a/include/unarchive.h +++ b/include/unarchive.h @@ -7,16 +7,21 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN enum { #if BB_BIG_ENDIAN COMPRESS_MAGIC = 0x1f9d, - GZIP_MAGIC = 0x1f8b, - BZIP2_MAGIC = ('B'<<8) + 'Z', - XZ_MAGIC1 = (0xfd<<8) + '7', - XZ_MAGIC2 = ((((('z'<<8) + 'X')<<8) + 'Z')<<8) + 0, + GZIP_MAGIC = 0x1f8b, + BZIP2_MAGIC = 'B' * 256 + 'Z', + XZ_MAGIC1 = 0xfd * 256 + '7', + XZ_MAGIC2 = (('z' * 256 + 'X') * 256 + 'Z') * 256 + 0, + /* Different form: 32 bits, then 16 bits: */ + XZ_MAGIC1a = ((0xfd * 256 + '7') * 256 + 'z') * 256 + 'X', + XZ_MAGIC2a = 'Z' * 256 + 0, #else COMPRESS_MAGIC = 0x9d1f, - GZIP_MAGIC = 0x8b1f, - BZIP2_MAGIC = ('Z'<<8) + 'B', - XZ_MAGIC1 = ('7'<<8) + 0xfd, - XZ_MAGIC2 = (((((0<<8) + 'Z')<<8) + 'X')<<8) + 'z', + GZIP_MAGIC = 0x8b1f, + BZIP2_MAGIC = 'Z' * 256 + 'B', + XZ_MAGIC1 = '7' * 256 + 0xfd, + XZ_MAGIC2 = ((0 * 256 + 'Z') * 256 + 'X') * 256 + 'z', + XZ_MAGIC1a = (('X' * 256 + 'z') * 256 + '7') * 256 + 0xfd, + XZ_MAGIC2a = 0 * 256 + 'Z', #endif }; @@ -196,7 +201,7 @@ typedef struct inflate_unzip_result { } inflate_unzip_result; IF_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC; -/* xz unpacker takes .xz stream from offset 0 */ +/* xz unpacker takes .xz stream from offset 6 */ IF_DESKTOP(long long) int unpack_xz_stream(int src_fd, int dst_fd) FAST_FUNC; /* lzma unpacker takes .lzma stream from offset 0 */ IF_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; diff --git a/libbb/read_printf.c b/libbb/read_printf.c index 3aee075c6..6780b94ef 100644 --- a/libbb/read_printf.c +++ b/libbb/read_printf.c @@ -296,8 +296,8 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) if (magic.b32[0] == XZ_MAGIC2) { # if BB_MMU xformer = unpack_xz_stream; - /* unpack_xz_stream wants fd at position 0 */ - xlseek(fd, offset, SEEK_CUR); + /* unpack_xz_stream wants fd at position 6, no need to seek */ + //xlseek(fd, offset, SEEK_CUR); # else xformer_prog = "unxz"; # endif -- cgit v1.2.3-55-g6feb From 81199672bed1446fa6b584728c92ecfb11bc530b Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Thu, 1 Jul 2010 07:18:41 +0200 Subject: conspy: stop losing some keyboard keys. 11 bytes shrink. Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- miscutils/conspy.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 565922ca0..3f341ce18 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -517,21 +517,23 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) G.key_count += bytes_read; handle = xopen(tty_name, O_WRONLY); result = ioctl(handle, KDGKBMODE, &kbd_mode); - if (result == -1) - /* nothing */; - else if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE) - G.key_count = 0; // scan code mode - else { + if (result >= 0) { char *p = keybuf; - for (; G.key_count != 0 && result != -1; p++, G.key_count--) { + + if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE) { + G.key_count = 0; // scan code mode + } + for (; G.key_count != 0; p++, G.key_count--) { result = ioctl(handle, TIOCSTI, p); + if (result < 0) { + memmove(keybuf, p, G.key_count); + break; + } // If there is an application on console which reacts // to keypresses, we need to make our first sleep // shorter to quickly redraw whatever it printed there. poll_timeout_ms = 20; } - if (G.key_count) - memmove(keybuf, p, G.key_count); } // Close & re-open tty in case they have // swapped virtual consoles @@ -539,7 +541,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) // We sometimes get spurious IO errors on the TTY // as programs close and re-open it - if (result != -1) + if (result >= 0) G.ioerror_count = 0; else if (errno != EIO || ++G.ioerror_count > 4) cleanup(1); -- cgit v1.2.3-55-g6feb From cd0f6b0c939e5098410ddb171db8c4a26cf8d623 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 1 Jul 2010 10:38:10 +0200 Subject: consolidate xz format comment. no code changes Signed-off-by: Denys Vlasenko --- archival/rpm2cpio.c | 2 -- include/unarchive.h | 2 ++ libbb/read_printf.c | 2 -- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index b23d5afa9..5bc50b88f 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c @@ -87,8 +87,6 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) if (ENABLE_FEATURE_SEAMLESS_XZ && magic.b16[0] == XZ_MAGIC1 ) { - /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ - /* More info at: http://tukaani.org/xz/xz-file-format.txt */ xread(rpm_fd, magic.b32, sizeof(magic.b32[0])); if (magic.b32[0] != XZ_MAGIC2) goto no_magic; diff --git a/include/unarchive.h b/include/unarchive.h index 3b8e1575a..b55af6d9d 100644 --- a/include/unarchive.h +++ b/include/unarchive.h @@ -9,6 +9,8 @@ enum { COMPRESS_MAGIC = 0x1f9d, GZIP_MAGIC = 0x1f8b, BZIP2_MAGIC = 'B' * 256 + 'Z', + /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ + /* More info at: http://tukaani.org/xz/xz-file-format.txt */ XZ_MAGIC1 = 0xfd * 256 + '7', XZ_MAGIC2 = (('z' * 256 + 'X') * 256 + 'Z') * 256 + 0, /* Different form: 32 bits, then 16 bits: */ diff --git a/libbb/read_printf.c b/libbb/read_printf.c index 6780b94ef..1b215f97a 100644 --- a/libbb/read_printf.c +++ b/libbb/read_printf.c @@ -289,8 +289,6 @@ void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) if (ENABLE_FEATURE_SEAMLESS_XZ && magic.b16[0] == XZ_MAGIC1 ) { - /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ - /* More info at: http://tukaani.org/xz/xz-file-format.txt */ offset = -6; xread(fd, magic.b32, sizeof(magic.b32[0])); if (magic.b32[0] == XZ_MAGIC2) { -- cgit v1.2.3-55-g6feb From 922f6f51dba8ba710cac0679635ed811b2139a53 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 1 Jul 2010 16:42:27 +0200 Subject: chrt: code shrink function old new delta show_min_max 80 60 -20 packed_usage 26929 26896 -33 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-53) Total: -53 bytes Signed-off-by: Denys Vlasenko --- include/usage.src.h | 74 ++++++++++++++++++++++++++--------------------------- miscutils/chrt.c | 20 ++++++++------- 2 files changed, 48 insertions(+), 46 deletions(-) diff --git a/include/usage.src.h b/include/usage.src.h index 53ee7943a..94a3256b1 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -434,7 +434,7 @@ INSERT " [-/ DIR] [-n NICE] [-m BYTES] [-d BYTES] [-o N]\n" \ " [-p N] [-f BYTES] [-c BYTES] PROG ARGS" #define chpst_full_usage "\n\n" \ - "Change the process state and run PROG\n" \ + "Change the process state, run PROG\n" \ "\nOptions:" \ "\n -u USER[:GRP] Set uid and gid" \ "\n -U USER[:GRP] Set $UID and $GID in environment" \ @@ -457,17 +457,17 @@ INSERT #define setuidgid_trivial_usage \ "USER PROG ARGS" #define setuidgid_full_usage "\n\n" \ - "Set uid and gid to USER's uid and gid, removing all supplementary\n" \ - "groups and run PROG" + "Set uid and gid to USER's uid and gid, drop supplementary group ids,\n" \ + "run PROG" #define envuidgid_trivial_usage \ "USER PROG ARGS" #define envuidgid_full_usage "\n\n" \ - "Set $UID to USER's uid and $GID to USER's gid and run PROG" + "Set $UID to USER's uid and $GID to USER's gid, run PROG" #define envdir_trivial_usage \ "DIR PROG ARGS" #define envdir_full_usage "\n\n" \ "Set various environment variables as specified by files\n" \ - "in the directory dir and run PROG" + "in the directory DIR, run PROG" #define softlimit_trivial_usage \ "[-a BYTES] [-m BYTES] [-d BYTES] [-s BYTES] [-l BYTES]\n" \ " [-f BYTES] [-c BYTES] [-r BYTES] [-o N] [-p N] [-t N]\n" \ @@ -538,24 +538,49 @@ INSERT #define bbconfig_trivial_usage \ "" #define bbconfig_full_usage "\n\n" \ - "Print the config file which built busybox" + "Print the config file used by busybox build" #define chrt_trivial_usage \ "[OPTIONS] [PRIO] [PID | PROG ARGS]" #define chrt_full_usage "\n\n" \ - "Manipulate real-time attributes of a process\n" \ + "Change scheduling priority and class for a process\n" \ "\nOptions:" \ "\n -p Operate on PID" \ - "\n -r Set SCHED_RR scheduling" \ - "\n -f Set SCHED_FIFO scheduling" \ - "\n -o Set SCHED_OTHER scheduling" \ - "\n -m Show min and max priorities" \ + "\n -r Set SCHED_RR class" \ + "\n -f Set SCHED_FIFO class" \ + "\n -o Set SCHED_OTHER class" \ + "\n -m Show min/max priorities" \ #define chrt_example_usage \ "$ chrt -r 4 sleep 900; x=$!\n" \ "$ chrt -f -p 3 $x\n" \ "You need CAP_SYS_NICE privileges to set scheduling attributes of a process" +#define nice_trivial_usage \ + "[-n ADJUST] [PROG ARGS]" +#define nice_full_usage "\n\n" \ + "Change scheduling priority, run PROG\n" \ + "\nOptions:" \ + "\n -n ADJUST Adjust priority by ADJUST" \ + +#define renice_trivial_usage \ + "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]" +#define renice_full_usage "\n\n" \ + "Change scheduling priority for a running process\n" \ + "\nOptions:" \ + "\n -n Adjust current nice value (smaller is faster)" \ + "\n -p Process id(s) (default)" \ + "\n -g Process group id(s)" \ + "\n -u Process user name(s) and/or id(s)" \ + +#define ionice_trivial_usage \ + "[-c 1-3] [-n 0-7] [-p PID] [PROG]" +#define ionice_full_usage "\n\n" \ + "Change I/O priority and class\n" \ + "\nOptions:" \ + "\n -c Class. 1:realtime 2:best-effort 3:idle" \ + "\n -n Priority" \ + #define cp_trivial_usage \ "[OPTIONS] SOURCE DEST" #define cp_full_usage "\n\n" \ @@ -1299,7 +1324,7 @@ INSERT #define flock_trivial_usage \ "[-sxun] FD|{FILE [-c] PROG ARGS}" #define flock_full_usage "\n\n" \ - "[Un]lock file descriptor, or lock FILE and run PROG\n" \ + "[Un]lock file descriptor, or lock FILE, run PROG\n" \ "\nOptions:" \ "\n -s Shared lock" \ "\n -x Exclusive lock (default)" \ @@ -2038,14 +2063,6 @@ INSERT "\n -Z Set security context" \ ) -#define ionice_trivial_usage \ - "[-c 1-3] [-n 0-7] [-p PID] [PROG]" -#define ionice_full_usage "\n\n" \ - "Change I/O scheduling class and priority\n" \ - "\nOptions:" \ - "\n -c Class. 1:realtime 2:best-effort 3:idle" \ - "\n -n Priority" \ - /* would need to make the " | " optional depending on more than one selected: */ #define ip_trivial_usage \ "[OPTIONS] {" \ @@ -2965,13 +2982,6 @@ INSERT "\n -p Display PID/Program name for sockets" \ ) -#define nice_trivial_usage \ - "[-n ADJUST] [PROG ARGS]" -#define nice_full_usage "\n\n" \ - "Run PROG with modified scheduling priority\n" \ - "\nOptions:" \ - "\n -n ADJUST Adjust priority by ADJUST" \ - #define nmeter_trivial_usage \ "format_string" #define nmeter_full_usage "\n\n" \ @@ -3425,16 +3435,6 @@ INSERT "\n" \ "\nOther options are silently ignored" \ -#define renice_trivial_usage \ - "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]" -#define renice_full_usage "\n\n" \ - "Change priority of running processes\n" \ - "\nOptions:" \ - "\n -n Adjust current nice value (smaller is faster)" \ - "\n -p Process id(s) (default)" \ - "\n -g Process group id(s)" \ - "\n -u Process user name(s) and/or id(s)" \ - #define scriptreplay_trivial_usage \ "timingfile [typescript [divisor]]" #define scriptreplay_full_usage "\n\n" \ diff --git a/miscutils/chrt.c b/miscutils/chrt.c index e2b7f8ae0..3d0da58ca 100644 --- a/miscutils/chrt.c +++ b/miscutils/chrt.c @@ -5,33 +5,35 @@ * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include #include "libbb.h" #ifndef _POSIX_PRIORITY_SCHEDULING #warning your system may be foobared #endif + static const struct { int policy; - char name[12]; + char name[sizeof("SCHED_OTHER")]; } policies[] = { {SCHED_OTHER, "SCHED_OTHER"}, {SCHED_FIFO, "SCHED_FIFO"}, {SCHED_RR, "SCHED_RR"} }; +//TODO: add +// -b, SCHED_BATCH +// -i, SCHED_IDLE + static void show_min_max(int pol) { - const char *fmt = "%s min/max priority\t: %d/%d\n\0%s not supported?\n"; + const char *fmt = "%s min/max priority\t: %u/%u\n"; int max, min; + max = sched_get_priority_max(pol); min = sched_get_priority_min(pol); - if (max >= 0 && min >= 0) - printf(fmt, policies[pol].name, min, max); - else { - fmt += 29; - printf(fmt, policies[pol].name); - } + if ((max|min) < 0) + fmt = "%s not supported\n"; + printf(fmt, policies[pol].name, min, max); } #define OPT_m (1<<0) -- cgit v1.2.3-55-g6feb From 5c296de390b1329a6243d12a86ef9c4726ace22a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 3 Jul 2010 14:28:35 +0200 Subject: fix compile breakage with "make -j" Signed-off-by: Denys Vlasenko --- Makefile | 2 ++ libbb/Kbuild.src | 2 ++ libbb/appletlib.c | 2 +- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 9a8277648..ef7c532b7 100644 --- a/Makefile +++ b/Makefile @@ -512,6 +512,8 @@ include $(srctree)/Makefile.flags include/autoconf.h: .kconfig.d .config $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) | gen_build_files $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig +include/usage.h: gen_build_files + else # Dummy target needed, because used as prerequisite include/autoconf.h: ; diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 29c136ccb..cb1f8e954 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -4,6 +4,8 @@ # # Licensed under the GPL v2, see the file LICENSE in this tarball. +libbb/appletlib.o: include/usage_compressed.h + lib-y:= INSERT diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 58f1a9490..6f058bcc8 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -65,7 +65,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; #if ENABLE_FEATURE_COMPRESS_USAGE -static const char packed_usage[] = { PACKED_USAGE }; +static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; # include "unarchive.h" static const char *unpack_usage_messages(void) { -- cgit v1.2.3-55-g6feb From 7c1b2b5420d4208864b8bc6e07e90792aed94981 Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Sun, 4 Jul 2010 00:04:03 +0200 Subject: losetup: use LOOP_foo defines Signed-off-by: Lauri Kasanen Signed-off-by: Denys Vlasenko --- include/libbb.h | 12 ++++++------ util-linux/losetup.c | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 53b768d88..e26001705 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1606,18 +1606,18 @@ extern const char bb_default_login_shell[]; # define VC_3 "/dev/vc/3" # define VC_4 "/dev/vc/4" # define VC_5 "/dev/vc/5" -#if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) +# if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) /* Yes, this sucks, but both SH (including sh64) and H8 have a SCI(F) for their respective serial ports .. as such, we can't use the common device paths for these. -- PFM */ # define SC_0 "/dev/ttsc/0" # define SC_1 "/dev/ttsc/1" # define SC_FORMAT "/dev/ttsc/%d" -#else +# else # define SC_0 "/dev/tts/0" # define SC_1 "/dev/tts/1" # define SC_FORMAT "/dev/tts/%d" -#endif +# endif # define VC_FORMAT "/dev/vc/%d" # define LOOP_FORMAT "/dev/loop/%d" # define LOOP_NAMESIZE (sizeof("/dev/loop/") + sizeof(int)*3 + 1) @@ -1630,15 +1630,15 @@ extern const char bb_default_login_shell[]; # define VC_3 "/dev/tty3" # define VC_4 "/dev/tty4" # define VC_5 "/dev/tty5" -#if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) +# if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) # define SC_0 "/dev/ttySC0" # define SC_1 "/dev/ttySC1" # define SC_FORMAT "/dev/ttySC%d" -#else +# else # define SC_0 "/dev/ttyS0" # define SC_1 "/dev/ttyS1" # define SC_FORMAT "/dev/ttyS%d" -#endif +# endif # define VC_FORMAT "/dev/tty%d" # define LOOP_FORMAT "/dev/loop%d" # define LOOP_NAMESIZE (sizeof("/dev/loop") + sizeof(int)*3 + 1) diff --git a/util-linux/losetup.c b/util-linux/losetup.c index 0f5914c88..3873be399 100644 --- a/util-linux/losetup.c +++ b/util-linux/losetup.c @@ -65,9 +65,9 @@ int losetup_main(int argc UNUSED_PARAM, char **argv) n = 0; while (1) { char *s; - char dev[sizeof(LOOP_NAME) + sizeof(int)*3]; + char dev[LOOP_NAMESIZE]; - sprintf(dev, LOOP_NAME"%u", n); + sprintf(dev, LOOP_FORMAT, n); s = query_loop(dev); n++; if (!s) { -- cgit v1.2.3-55-g6feb From 21e8e8da6483c80a6054b06e48341968a7dccdd5 Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Sun, 4 Jul 2010 00:57:03 +0200 Subject: libbb: introduce and use BB_EXECVP_or_die() function old new delta BB_EXECVP_or_die - 47 +47 time_main 1042 1043 +1 chrt_main 371 364 -7 ionice_main 292 282 -10 setsid_main 69 56 -13 nohup_main 236 223 -13 cttyhack_main 266 253 -13 chroot_main 94 81 -13 chpst_main 746 733 -13 timeout_main 297 279 -18 taskset_main 541 522 -19 vfork_child 67 45 -22 parse 975 953 -22 lpd_main 770 748 -22 launch_helper 192 170 -22 tcpudpsvd_main 1810 1782 -28 nice_main 190 156 -34 env_main 242 206 -36 run_command 221 174 -47 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/17 up/down: 48/-352) Total: -304 bytes Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- console-tools/openvt.c | 3 +-- coreutils/chroot.c | 3 +-- coreutils/env.c | 5 +---- coreutils/nice.c | 5 +---- coreutils/nohup.c | 3 +-- include/libbb.h | 1 + libbb/execable.c | 8 ++++++++ libbb/vfork_daemon_rexec.c | 34 ---------------------------------- libbb/xfuncs.c | 34 ++++++++++++++++++++++++++++++++++ mailutils/mail.c | 3 +-- mailutils/mime.c | 3 +-- miscutils/chrt.c | 3 +-- miscutils/ionice.c | 3 +-- miscutils/setsid.c | 3 +-- miscutils/taskset.c | 3 +-- miscutils/time.c | 15 ++++++--------- miscutils/timeout.c | 3 +-- networking/ifupdown.c | 3 +-- networking/tcpudp.c | 4 ++-- printutils/lpd.c | 3 +-- runit/chpst.c | 3 +-- shell/cttyhack.c | 3 +-- 22 files changed, 67 insertions(+), 81 deletions(-) diff --git a/console-tools/openvt.c b/console-tools/openvt.c index 6f58916e7..e3ea71bc5 100644 --- a/console-tools/openvt.c +++ b/console-tools/openvt.c @@ -97,8 +97,7 @@ static NOINLINE void vfork_child(char **argv) //bb_error_msg("our pgrp %d", getpgrp()); //bb_error_msg("VT's sid %d", tcgetsid(0)); //bb_error_msg("VT's pgrp %d", tcgetpgrp(0)); - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } } diff --git a/coreutils/chroot.c b/coreutils/chroot.c index bc0b1f82c..046c2fabf 100644 --- a/coreutils/chroot.c +++ b/coreutils/chroot.c @@ -30,6 +30,5 @@ int chroot_main(int argc UNUSED_PARAM, char **argv) argv[1] = (char *) "-i"; } - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/coreutils/env.c b/coreutils/env.c index c6ba04d35..d4eab191b 100644 --- a/coreutils/env.c +++ b/coreutils/env.c @@ -77,10 +77,7 @@ int env_main(int argc UNUSED_PARAM, char **argv) } if (argv[0]) { - BB_EXECVP(argv[0], argv); - /* SUSv3-mandated exit codes. */ - xfunc_error_retval = (errno == ENOENT) ? 127 : 126; - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } if (environ) { /* clearenv() may set environ == NULL! */ diff --git a/coreutils/nice.c b/coreutils/nice.c index 0f70f1079..ff3eb1140 100644 --- a/coreutils/nice.c +++ b/coreutils/nice.c @@ -47,8 +47,5 @@ int nice_main(int argc, char **argv) } } - BB_EXECVP(argv[0], argv); - /* The exec failed... */ - xfunc_error_retval = (errno == ENOENT) ? 127 : 126; /* SUSv3 */ - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/coreutils/nohup.c b/coreutils/nohup.c index 1027ada1c..3dc531409 100644 --- a/coreutils/nohup.c +++ b/coreutils/nohup.c @@ -76,6 +76,5 @@ int nohup_main(int argc UNUSED_PARAM, char **argv) signal(SIGHUP, SIG_IGN); argv++; - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/include/libbb.h b/include/libbb.h index e26001705..4b6699f2f 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -839,6 +839,7 @@ int bb_execvp(const char *file, char *const argv[]) FAST_FUNC; #define BB_EXECVP(prog,cmd) execvp(prog,cmd) #define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__) #endif +int BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC; /* NOMMU friendy fork+exec: */ pid_t spawn(char **argv) FAST_FUNC; diff --git a/libbb/execable.c b/libbb/execable.c index 5c7ac16a2..82241cd81 100644 --- a/libbb/execable.c +++ b/libbb/execable.c @@ -76,3 +76,11 @@ int FAST_FUNC bb_execvp(const char *file, char *const argv[]) argv); } #endif + +int FAST_FUNC BB_EXECVP_or_die(char **argv) +{ + BB_EXECVP(argv[0], argv); + /* SUSv3-mandated exit codes */ + xfunc_error_retval = (errno == ENOENT) ? 127 : 126; + bb_perror_msg_and_die("can't execute '%s'", argv[0]); +} diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 082f0f63e..8102ea2dc 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -67,40 +67,6 @@ pid_t FAST_FUNC xspawn(char **argv) return pid; } -pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options) -{ - pid_t r; - - do - r = waitpid(pid, wstat, options); - while ((r == -1) && (errno == EINTR)); - return r; -} - -pid_t FAST_FUNC wait_any_nohang(int *wstat) -{ - return safe_waitpid(-1, wstat, WNOHANG); -} - -// Wait for the specified child PID to exit, returning child's error return. -int FAST_FUNC wait4pid(pid_t pid) -{ - int status; - - if (pid <= 0) { - /*errno = ECHILD; -- wrong. */ - /* we expect errno to be already set from failed [v]fork/exec */ - return -1; - } - if (safe_waitpid(pid, &status, 0) == -1) - return -1; - if (WIFEXITED(status)) - return WEXITSTATUS(status); - if (WIFSIGNALED(status)) - return WTERMSIG(status) + 0x180; - return 0; -} - #if ENABLE_FEATURE_PREFER_APPLETS void FAST_FUNC save_nofork_data(struct nofork_save_area *save) { diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 65437211d..275dd4b62 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -268,3 +268,37 @@ int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) { return tcsetattr(STDIN_FILENO, TCSANOW, tp); } + +pid_t FAST_FUNC safe_waitpid(pid_t pid, int *wstat, int options) +{ + pid_t r; + + do + r = waitpid(pid, wstat, options); + while ((r == -1) && (errno == EINTR)); + return r; +} + +pid_t FAST_FUNC wait_any_nohang(int *wstat) +{ + return safe_waitpid(-1, wstat, WNOHANG); +} + +// Wait for the specified child PID to exit, returning child's error return. +int FAST_FUNC wait4pid(pid_t pid) +{ + int status; + + if (pid <= 0) { + /*errno = ECHILD; -- wrong. */ + /* we expect errno to be already set from failed [v]fork/exec */ + return -1; + } + if (safe_waitpid(pid, &status, 0) == -1) + return -1; + if (WIFEXITED(status)) + return WEXITSTATUS(status); + if (WIFSIGNALED(status)) + return WTERMSIG(status) + 0x180; + return 0; +} diff --git a/mailutils/mail.c b/mailutils/mail.c index 49e72c32b..5eb99e13d 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c @@ -67,8 +67,7 @@ void FAST_FUNC launch_helper(const char **argv) if (!G.helper_pid) { // child: try to execute connection helper // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec - BB_EXECVP(argv[0], (char **)argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die((char**)argv); } // parent diff --git a/mailutils/mime.c b/mailutils/mime.c index 654b8731c..5eb8ef6f2 100644 --- a/mailutils/mime.c +++ b/mailutils/mime.c @@ -288,8 +288,7 @@ static int parse(const char *boundary, char **argv) xsetenv("CHARSET", charset); xsetenv("ENCODING", encoding); xsetenv("FILENAME", filename); - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } // parent dumps to fd[1] close(fd[0]); diff --git a/miscutils/chrt.c b/miscutils/chrt.c index 3d0da58ca..d5f87c4d7 100644 --- a/miscutils/chrt.c +++ b/miscutils/chrt.c @@ -120,6 +120,5 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) if (!argv[0]) /* "-p [...]" */ goto print_rt_info; - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/miscutils/ionice.c b/miscutils/ionice.c index 8393cd8b2..52e51b908 100644 --- a/miscutils/ionice.c +++ b/miscutils/ionice.c @@ -90,8 +90,7 @@ int ionice_main(int argc UNUSED_PARAM, char **argv) if (ioprio_set(IOPRIO_WHO_PROCESS, pid, pri) == -1) bb_perror_msg_and_die("ioprio_%cet", 's'); if (argv[0]) { - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } } diff --git a/miscutils/setsid.c b/miscutils/setsid.c index 60ee062e3..c573fae34 100644 --- a/miscutils/setsid.c +++ b/miscutils/setsid.c @@ -45,6 +45,5 @@ int setsid_main(int argc UNUSED_PARAM, char **argv) } argv++; - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/miscutils/taskset.c b/miscutils/taskset.c index 2891003df..08198d5d4 100644 --- a/miscutils/taskset.c +++ b/miscutils/taskset.c @@ -132,6 +132,5 @@ int taskset_main(int argc UNUSED_PARAM, char **argv) if (!argv[0]) /* "-p [...ignored...]" */ goto print_aff; /* print new affinity and exit */ - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/miscutils/time.c b/miscutils/time.c index f5d1e15fb..5cfbcef8e 100644 --- a/miscutils/time.c +++ b/miscutils/time.c @@ -367,20 +367,17 @@ static void summarize(const char *fmt, char **command, resource_t *resp) Put the statistics in *RESP. */ static void run_command(char *const *cmd, resource_t *resp) { - pid_t pid; /* Pid of child. */ + pid_t pid; void (*interrupt_signal)(int); void (*quit_signal)(int); resp->elapsed_ms = monotonic_ms(); - pid = vfork(); /* Run CMD as child process. */ + pid = vfork(); if (pid < 0) - bb_perror_msg_and_die("fork"); - if (pid == 0) { /* If child. */ - /* Don't cast execvp arguments; that causes errors on some systems, - versus merely warnings if the cast is left off. */ - BB_EXECVP(cmd[0], cmd); - xfunc_error_retval = (errno == ENOENT ? 127 : 126); - bb_perror_msg_and_die("can't execute '%s'", cmd[0]); + bb_perror_msg_and_die("vfork"); + if (pid == 0) { + /* Child */ + BB_EXECVP_or_die((char**)cmd); } /* Have signals kill the child but not self (if possible). */ diff --git a/miscutils/timeout.c b/miscutils/timeout.c index 273d26953..f6e655acc 100644 --- a/miscutils/timeout.c +++ b/miscutils/timeout.c @@ -110,6 +110,5 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) argv[0] = sv1; argv[1] = sv2; #endif - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 714d2a107..1bab2c5cb 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c @@ -1052,8 +1052,7 @@ static int popen2(FILE **in, FILE **out, char *command, char *param) close(outfd.rd); xmove_fd(infd.rd, 0); xmove_fd(outfd.wr, 1); - BB_EXECVP(command, argv); - bb_perror_msg_and_die("can't execute '%s'", command); + BB_EXECVP_or_die(argv); } /* parent */ close(infd.rd); diff --git a/networking/tcpudp.c b/networking/tcpudp.c index 4e4756738..53e622b56 100644 --- a/networking/tcpudp.c +++ b/networking/tcpudp.c @@ -501,10 +501,10 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) #ifdef SSLSVD strcpy(id, utoa(pid)); ssl_io(0, argv); + bb_perror_msg_and_die("can't execute '%s'", argv[0]); #else - BB_EXECVP(argv[0], argv); + BB_EXECVP_or_die(argv); #endif - bb_perror_msg_and_die("can't execute '%s'", argv[0]); } /* diff --git a/printutils/lpd.c b/printutils/lpd.c index 15f1ba20b..d91491f1b 100644 --- a/printutils/lpd.c +++ b/printutils/lpd.c @@ -181,8 +181,7 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[]) // this call reopens stdio fds to "/dev/null" // (no daemonization is done) bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO | DAEMON_ONLY_SANITIZE, NULL); - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } // validate input. diff --git a/runit/chpst.c b/runit/chpst.c index 028a28d6c..ad0811294 100644 --- a/runit/chpst.c +++ b/runit/chpst.c @@ -382,6 +382,5 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_2) close(STDERR_FILENO); - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/shell/cttyhack.c b/shell/cttyhack.c index bde2acdc9..67736ad62 100644 --- a/shell/cttyhack.c +++ b/shell/cttyhack.c @@ -81,6 +81,5 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv) } } - BB_EXECVP(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } -- cgit v1.2.3-55-g6feb From fd744519d1e848c4760c23805bf993396b19c8b2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 4 Jul 2010 03:55:43 +0200 Subject: ip a: fix SEGV if "dev IFACE" is not specified Signed-off-by: Denys Vlasenko --- networking/libiproute/ipaddress.c | 47 +++++++++++++++++++-------------------- 1 file changed, 23 insertions(+), 24 deletions(-) diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c index a603053e1..381293412 100644 --- a/networking/libiproute/ipaddress.c +++ b/networking/libiproute/ipaddress.c @@ -444,28 +444,28 @@ int ipaddr_list_or_flush(char **argv, int flush) while (*argv) { const smalluint key = index_in_strings(option, *argv); if (key == 0) { /* to */ - NEXT_ARG(); - get_prefix(&G_filter.pfx, *argv, G_filter.family); - if (G_filter.family == AF_UNSPEC) { - G_filter.family = G_filter.pfx.family; - } + NEXT_ARG(); + get_prefix(&G_filter.pfx, *argv, G_filter.family); + if (G_filter.family == AF_UNSPEC) { + G_filter.family = G_filter.pfx.family; + } } else if (key == 1) { /* scope */ - uint32_t scope = 0; - NEXT_ARG(); - G_filter.scopemask = -1; - if (rtnl_rtscope_a2n(&scope, *argv)) { - if (strcmp(*argv, "all") != 0) { - invarg(*argv, "scope"); - } - scope = RT_SCOPE_NOWHERE; - G_filter.scopemask = 0; + uint32_t scope = 0; + NEXT_ARG(); + G_filter.scopemask = -1; + if (rtnl_rtscope_a2n(&scope, *argv)) { + if (strcmp(*argv, "all") != 0) { + invarg(*argv, "scope"); } - G_filter.scope = scope; + scope = RT_SCOPE_NOWHERE; + G_filter.scopemask = 0; + } + G_filter.scope = scope; } else if (key == 2) { /* up */ - G_filter.up = 1; + G_filter.up = 1; } else if (key == 3) { /* label */ - NEXT_ARG(); - G_filter.label = *argv; + NEXT_ARG(); + G_filter.label = *argv; } else { if (key == 4) /* dev */ NEXT_ARG(); @@ -681,7 +681,7 @@ static int ipaddr_modify(int cmd, char **argv) } else if (arg == 7) { /* label */ NEXT_ARG(); l = *argv; - addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l)+1); + addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1); } else { if (arg == 8) /* local */ NEXT_ARG(); @@ -698,11 +698,10 @@ static int ipaddr_modify(int cmd, char **argv) argv++; } - // d cannot be null here, NEXT_ARG() of "dev" ensures that - //if (d == NULL) { - // bb_error_msg(bb_msg_requires_arg, "\"dev\""); - // return -1; - //} + if (!d) { + /* There was no "dev IFACE", but we need that */ + bb_error_msg_and_die("need \"dev IFACE\""); + } if (l && strncmp(d, l, strlen(d)) != 0) { bb_error_msg_and_die("\"dev\" (%s) must match \"label\" (%s)", d, l); } -- cgit v1.2.3-55-g6feb From 243d1757d798a0cd43f51eb1db75cc1e81c65732 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 4 Jul 2010 04:26:55 +0200 Subject: remove some dead assignments, add a TODO comment Signed-off-by: Denys Vlasenko --- archival/libunarchive/data_extract_all.c | 1 + editors/vi.c | 1 - networking/udhcp/dhcprelay.c | 3 +-- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/archival/libunarchive/data_extract_all.c b/archival/libunarchive/data_extract_all.c index c4ffe7ef8..00e67d405 100644 --- a/archival/libunarchive/data_extract_all.c +++ b/archival/libunarchive/data_extract_all.c @@ -127,6 +127,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) break; case S_IFLNK: /* Symlink */ +//TODO: what if file_header->link_target == NULL (say, corrupted tarball?) res = symlink(file_header->link_target, file_header->name); if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) diff --git a/editors/vi.c b/editors/vi.c index 9b050e115..0f412c362 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -2385,7 +2385,6 @@ static int file_write(char *fn, char *first, char *last) status_line_bold("No current filename"); return -2; } - charcnt = 0; /* By popular request we do not open file with O_TRUNC, * but instead ftruncate() it _after_ successful write. * Might reduce amount of data lost on power fail etc. diff --git a/networking/udhcp/dhcprelay.c b/networking/udhcp/dhcprelay.c index e14325dca..d194a989b 100644 --- a/networking/udhcp/dhcprelay.c +++ b/networking/udhcp/dhcprelay.c @@ -175,7 +175,6 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) { int res, type; - struct xid_item *item; /* check packet_type */ type = get_dhcp_packet_type(p); @@ -187,7 +186,7 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in } /* create new xid entry */ - item = xid_add(p->xid, client_addr, client); + xid_add(p->xid, client_addr, client); /* forward request to LAN (server) */ errno = 0; -- cgit v1.2.3-55-g6feb From 926031b7640bf5aad2ffcd54b096911743a47d97 Mon Sep 17 00:00:00 2001 From: Pascal Bellard Date: Sun, 4 Jul 2010 15:32:38 +0200 Subject: *: introduce and use xfork() and xvfork() function old new delta launch_helper 170 169 -1 setup_heredoc 312 302 -10 handle_dir_common 367 354 -13 expand_vars_to_list 2456 2443 -13 open_transformer 89 74 -15 data_extract_to_command 439 423 -16 do_ipaddr 1406 1389 -17 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/7 up/down: 0/-85) Total: -85 bytes Signed-off-by: Pascal Bellard Signed-off-by: Denys Vlasenko --- archival/libunarchive/data_extract_to_command.c | 7 ++----- archival/libunarchive/open_transformer.c | 14 ++------------ archival/tar.c | 4 +--- debianutils/start_stop_daemon.c | 4 +--- e2fsprogs/old_e2fsprogs/fsck.c | 2 +- include/libbb.h | 21 +++++++++++++++++---- init/bootchartd.c | 4 +--- libbb/vfork_daemon_rexec.c | 16 +--------------- libbb/xfuncs_printf.c | 11 +++++++++++ mailutils/mail.c | 4 +--- miscutils/conspy.c | 5 +---- miscutils/crontab.c | 8 ++------ miscutils/time.c | 4 +--- miscutils/timeout.c | 4 +--- networking/ftpd.c | 5 +---- networking/ifupdown.c | 8 +++----- networking/inetd.c | 2 +- networking/nc.c | 6 ++---- scripts/basic/docproc.c | 2 +- shell/hush.c | 15 ++++----------- util-linux/script.c | 5 +---- 21 files changed, 56 insertions(+), 95 deletions(-) diff --git a/archival/libunarchive/data_extract_to_command.c b/archival/libunarchive/data_extract_to_command.c index eb09439bc..95f5bc864 100644 --- a/archival/libunarchive/data_extract_to_command.c +++ b/archival/libunarchive/data_extract_to_command.c @@ -82,11 +82,8 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) memset(tar_env, 0, sizeof(tar_env)); xpipe(p); - pid = BB_MMU ? fork() : vfork(); - switch (pid) { - case -1: - bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); - case 0: + pid = BB_MMU ? xfork() : xvfork(); + if (pid == 0) { /* Child */ /* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */ oct2env(tar_env, TAR_MODE, file_header->mode); diff --git a/archival/libunarchive/open_transformer.c b/archival/libunarchive/open_transformer.c index 47c13e6f4..cba049f1f 100644 --- a/archival/libunarchive/open_transformer.c +++ b/archival/libunarchive/open_transformer.c @@ -19,19 +19,9 @@ void FAST_FUNC open_transformer(int fd, int pid; xpiped_pair(fd_pipe); - -#if BB_MMU - pid = fork(); - if (pid == -1) - bb_perror_msg_and_die("vfork" + 1); -#else - pid = vfork(); - if (pid == -1) - bb_perror_msg_and_die("vfork"); -#endif - + pid = BB_MMU ? xfork() : xvfork(); if (pid == 0) { - /* child process */ + /* Child */ close(fd_pipe.rd); /* we don't want to read from the parent */ // FIXME: error check? #if BB_MMU diff --git a/archival/tar.c b/archival/tar.c index f49fb129e..9dd74536e 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -514,9 +514,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) (void) &zip_exec; # endif - gzipPid = vfork(); - if (gzipPid < 0) - bb_perror_msg_and_die("vfork"); + gzipPid = xvfork(); if (gzipPid == 0) { /* child */ diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 3ded758bf..665f38fbd 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -409,9 +409,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) /* DAEMON_DEVNULL_STDIO is superfluous - * it's always done by bb_daemonize() */ #else - pid_t pid = vfork(); - if (pid < 0) /* error */ - bb_perror_msg_and_die("vfork"); + pid_t pid = xvfork(); if (pid != 0) { /* parent */ /* why _exit? the child may have changed the stack, diff --git a/e2fsprogs/old_e2fsprogs/fsck.c b/e2fsprogs/old_e2fsprogs/fsck.c index dc029b65a..2a66d728a 100644 --- a/e2fsprogs/old_e2fsprogs/fsck.c +++ b/e2fsprogs/old_e2fsprogs/fsck.c @@ -612,7 +612,7 @@ static int execute(const char *type, const char *device, const char *mntpt, if (noexecute) pid = -1; else if ((pid = fork()) < 0) { - perror("fork"); + perror("vfork"+1); return errno; } else if (pid == 0) { if (!interactive) diff --git a/include/libbb.h b/include/libbb.h index 4b6699f2f..e2a8322b8 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -841,6 +841,19 @@ int bb_execvp(const char *file, char *const argv[]) FAST_FUNC; #endif int BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC; +/* xvfork() can't be a _function_, return after vfork mangles stack + * in the parent. It must be a macro. */ +#define xvfork() \ +({ \ + pid_t bb__xvfork_pid = vfork(); \ + if (bb__xvfork_pid < 0) \ + bb_perror_msg_and_die("vfork"); \ + bb__xvfork_pid; \ +}) +#if BB_MMU +pid_t xfork(void) FAST_FUNC; +#endif + /* NOMMU friendy fork+exec: */ pid_t spawn(char **argv) FAST_FUNC; pid_t xspawn(char **argv) FAST_FUNC; @@ -886,7 +899,7 @@ int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char ** * Both of the above will redirect fd 0,1,2 to /dev/null and drop ctty * (will do setsid()). * - * fork_or_rexec(argv) = bare-bones "fork" on MMU, + * fork_or_rexec(argv) = bare-bones fork on MMU, * "vfork + re-exec ourself" on NOMMU. No fd redirection, no setsid(). * On MMU ignores argv. * @@ -902,19 +915,19 @@ enum { DAEMON_ONLY_SANITIZE = 8, /* internal use */ }; #if BB_MMU - pid_t fork_or_rexec(void) FAST_FUNC; enum { re_execed = 0 }; -# define fork_or_rexec(argv) fork_or_rexec() +# define fork_or_rexec(argv) xfork() # define bb_daemonize_or_rexec(flags, argv) bb_daemonize_or_rexec(flags) # define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) #else + extern bool re_execed; void re_exec(char **argv) NORETURN FAST_FUNC; pid_t fork_or_rexec(char **argv) FAST_FUNC; - extern bool re_execed; int BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC; int BUG_daemon_is_unavailable_on_nommu(void) FAST_FUNC; void BUG_bb_daemonize_is_unavailable_on_nommu(void) FAST_FUNC; # define fork() BUG_fork_is_unavailable_on_nommu() +# define xfork() BUG_fork_is_unavailable_on_nommu() # define daemon(a,b) BUG_daemon_is_unavailable_on_nommu() # define bb_daemonize(a) BUG_bb_daemonize_is_unavailable_on_nommu() #endif diff --git a/init/bootchartd.c b/init/bootchartd.c index 42b98c827..b3e08af92 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -427,9 +427,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) } if (cmd == CMD_START && argv[2]) { /* "start PROG ARGS" */ - pid_t pid = vfork(); - if (pid < 0) - bb_perror_msg_and_die("vfork"); + pid_t pid = xvfork(); if (pid == 0) { /* child */ argv += 2; execvp(argv[0], argv); diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 8102ea2dc..5c2c529c9 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -224,26 +224,12 @@ pid_t FAST_FUNC fork_or_rexec(char **argv) /* Maybe we are already re-execed and come here again? */ if (re_execed) return 0; - pid = vfork(); - if (pid < 0) /* wtf? */ - bb_perror_msg_and_die("vfork"); + pid = xvfork(); if (pid) /* parent */ return pid; /* child - re-exec ourself */ re_exec(argv); } -#else -/* Dance around (void)...*/ -#undef fork_or_rexec -pid_t FAST_FUNC fork_or_rexec(void) -{ - pid_t pid; - pid = fork(); - if (pid < 0) /* wtf? */ - bb_perror_msg_and_die("fork"); - return pid; -} -#define fork_or_rexec(argv) fork_or_rexec() #endif /* Due to a #define in libbb.h on MMU systems we actually have 1 argument - diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c index f021493b1..7069a7c8e 100644 --- a/libbb/xfuncs_printf.c +++ b/libbb/xfuncs_printf.c @@ -589,3 +589,14 @@ void FAST_FUNC generate_uuid(uint8_t *buf) /* variant = 10x */ buf[4 + 2 + 2] = (buf[4 + 2 + 2] & 0x3f) | 0x80; } + +#if BB_MMU +pid_t FAST_FUNC xfork(void) +{ + pid_t pid; + pid = fork(); + if (pid < 0) /* wtf? */ + bb_perror_msg_and_die("vfork"+1); + return pid; +} +#endif diff --git a/mailutils/mail.c b/mailutils/mail.c index 5eb99e13d..bcd358302 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c @@ -54,9 +54,7 @@ void FAST_FUNC launch_helper(const char **argv) + (1 << SIGALRM) , signal_handler); - G.helper_pid = vfork(); - if (G.helper_pid < 0) - bb_perror_msg_and_die("vfork"); + G.helper_pid = xvfork(); i = (!G.helper_pid) * 2; // for parent:0, for child:2 close(pipes[i + 1]); // 1 or 3 - closing one write end diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 3f341ce18..509a0f271 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -309,10 +309,7 @@ static void create_cdev_if_doesnt_exist(const char* name, dev_t dev) static NOINLINE void start_shell_in_child(const char* tty_name) { - int pid = vfork(); - if (pid < 0) { - bb_perror_msg_and_die("vfork"); - } + int pid = xvfork(); if (pid == 0) { struct termios termchild; char *shell = getenv("SHELL"); diff --git a/miscutils/crontab.c b/miscutils/crontab.c index 5557bc491..b8a5abc64 100644 --- a/miscutils/crontab.c +++ b/miscutils/crontab.c @@ -20,10 +20,8 @@ static void edit_file(const struct passwd *pas, const char *file) { const char *ptr; - int pid = vfork(); + int pid = xvfork(); - if (pid < 0) /* failure */ - bb_perror_msg_and_die("vfork"); if (pid) { /* parent */ wait4pid(pid); return; @@ -51,9 +49,7 @@ static int open_as_user(const struct passwd *pas, const char *file) pid_t pid; char c; - pid = vfork(); - if (pid < 0) /* ERROR */ - bb_perror_msg_and_die("vfork"); + pid = xvfork(); if (pid) { /* PARENT */ if (wait4pid(pid) == 0) { /* exitcode 0: child says it can read */ diff --git a/miscutils/time.c b/miscutils/time.c index 5cfbcef8e..9facc3657 100644 --- a/miscutils/time.c +++ b/miscutils/time.c @@ -372,9 +372,7 @@ static void run_command(char *const *cmd, resource_t *resp) void (*quit_signal)(int); resp->elapsed_ms = monotonic_ms(); - pid = vfork(); - if (pid < 0) - bb_perror_msg_and_die("vfork"); + pid = xvfork(); if (pid == 0) { /* Child */ BB_EXECVP_or_die((char**)cmd); diff --git a/miscutils/timeout.c b/miscutils/timeout.c index f6e655acc..48b8d8fc0 100644 --- a/miscutils/timeout.c +++ b/miscutils/timeout.c @@ -71,9 +71,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) sv1 = argv[optind]; sv2 = argv[optind + 1]; #endif - pid = vfork(); - if (pid < 0) - bb_perror_msg_and_die("vfork"); + pid = xvfork(); if (pid == 0) { /* Child: spawn grandchild and exit */ parent = getppid(); diff --git a/networking/ftpd.c b/networking/ftpd.c index c63b9319e..e8cae0a36 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c @@ -632,10 +632,7 @@ popen_ls(const char *opt) xpiped_pair(outfd); /*fflush_all(); - so far we dont use stdio on output */ - pid = BB_MMU ? fork() : vfork(); - if (pid < 0) - bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); - + pid = BB_MMU ? xfork() : xvfork(); if (pid == 0) { /* child */ #if !BB_MMU diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 1bab2c5cb..69c56e879 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c @@ -1041,12 +1041,10 @@ static int popen2(FILE **in, FILE **out, char *command, char *param) xpiped_pair(outfd); fflush_all(); - pid = vfork(); + pid = xvfork(); - switch (pid) { - case -1: /* failure */ - bb_perror_msg_and_die("vfork"); - case 0: /* child */ + if (pid == 0) { + /* Child */ /* NB: close _first_, then move fds! */ close(infd.wr); close(outfd.rd); diff --git a/networking/inetd.c b/networking/inetd.c index 2b0e0069e..7030062b6 100644 --- a/networking/inetd.c +++ b/networking/inetd.c @@ -1271,7 +1271,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) pid = vfork(); if (pid < 0) { /* fork error */ - bb_perror_msg("fork"); + bb_perror_msg("vfork"+1); sleep(1); restore_sigmask(&omask); maybe_close(accepted_fd); diff --git a/networking/nc.c b/networking/nc.c index 5fd8bd759..0dacaf117 100644 --- a/networking/nc.c +++ b/networking/nc.c @@ -216,10 +216,8 @@ int nc_main(int argc, char **argv) if (execparam) { pid_t pid; /* With more than one -l, repeatedly act as server */ - if (do_listen > 1 && (pid = vfork()) != 0) { - /* parent or error */ - if (pid < 0) - bb_perror_msg_and_die("vfork"); + if (do_listen > 1 && (pid = xvfork()) != 0) { + /* parent */ /* prevent zombies */ signal(SIGCHLD, SIG_IGN); close(cfd); diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c index ef5181226..50ef37157 100644 --- a/scripts/basic/docproc.c +++ b/scripts/basic/docproc.c @@ -86,7 +86,7 @@ void exec_kernel_doc(char **svec) fflush(stdout); switch(pid=fork()) { case -1: - perror("fork"); + perror("vfork"+1); exit(1); case 0: rflen = strlen(getenv("SRCTREE")); diff --git a/shell/hush.c b/shell/hush.c index 29ff3c442..831443e2e 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -3208,15 +3208,11 @@ static void setup_heredoc(struct redir_struct *redir) #if !BB_MMU to_free = NULL; #endif - pid = vfork(); - if (pid < 0) - bb_perror_msg_and_die("vfork"); + pid = xvfork(); if (pid == 0) { /* child */ disable_restore_tty_pgrp_on_exit(); - pid = BB_MMU ? fork() : vfork(); - if (pid < 0) - bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); + pid = BB_MMU ? xfork() : xvfork(); if (pid != 0) _exit(0); /* grandchild */ @@ -4450,7 +4446,7 @@ static NOINLINE int run_pipe(struct pipe *pi) argv_expanded = NULL; if (command->pid < 0) { /* [v]fork failed */ /* Clearly indicate, was it fork or vfork */ - bb_perror_msg(BB_MMU ? "fork" : "vfork"); + bb_perror_msg(BB_MMU ? "vfork"+1 : "vfork"); } else { pi->alive_cmds++; #if ENABLE_HUSH_JOB @@ -5586,10 +5582,7 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p) # endif xpipe(channel); - pid = BB_MMU ? fork() : vfork(); - if (pid < 0) - bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork"); - + pid = BB_MMU ? xfork() : xvfork(); if (pid == 0) { /* child */ disable_restore_tty_pgrp_on_exit(); /* Process substitution is not considered to be usual diff --git a/util-linux/script.c b/util-linux/script.c index d9a62fbfe..c23117cf3 100644 --- a/util-linux/script.c +++ b/util-linux/script.c @@ -88,10 +88,7 @@ int script_main(int argc UNUSED_PARAM, char **argv) /* TODO: SIGWINCH? pass window size changes down to slave? */ - child_pid = vfork(); - if (child_pid < 0) { - bb_perror_msg_and_die("vfork"); - } + child_pid = xvfork(); if (child_pid) { /* parent */ -- cgit v1.2.3-55-g6feb From 7e1bb4bc5c1e2724a00bb4ef18925c8ed6f44886 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 4 Jul 2010 17:16:44 +0200 Subject: libbb: reduce number of *error_msg[_and_die].c files by four No code changes. Signed-off-by: Denys Vlasenko --- libbb/Kbuild.src | 4 ---- libbb/error_msg.c | 19 ------------------- libbb/error_msg_and_die.c | 20 -------------------- libbb/herror_msg.c | 11 ++++++++++- libbb/herror_msg_and_die.c | 20 -------------------- libbb/perror_msg.c | 17 ++++++++++++++++- libbb/perror_msg_and_die.c | 26 -------------------------- libbb/verror_msg.c | 23 ++++++++++++++++++++--- 8 files changed, 46 insertions(+), 94 deletions(-) delete mode 100644 libbb/error_msg.c delete mode 100644 libbb/error_msg_and_die.c delete mode 100644 libbb/herror_msg_and_die.c delete mode 100644 libbb/perror_msg_and_die.c diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index cb1f8e954..5c567000a 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -32,8 +32,6 @@ lib-y += create_icmp_socket.o lib-y += default_error_retval.o lib-y += device_open.o lib-y += dump.o -lib-y += error_msg.o -lib-y += error_msg_and_die.o lib-y += execable.o lib-y += fclose_nonstdin.o lib-y += fflush_stdout_and_exit.o @@ -48,7 +46,6 @@ lib-y += getopt32.o lib-y += getpty.o lib-y += get_volsize.o lib-y += herror_msg.o -lib-y += herror_msg_and_die.o lib-y += human_readable.o lib-y += inet_common.o lib-y += info_msg.o @@ -72,7 +69,6 @@ lib-y += obscure.o lib-y += parse_mode.o lib-y += parse_config.o lib-y += perror_msg.o -lib-y += perror_msg_and_die.o lib-y += perror_nomsg.o lib-y += perror_nomsg_and_die.o lib-y += pidfile.o diff --git a/libbb/error_msg.c b/libbb/error_msg.c deleted file mode 100644 index 802fd5715..000000000 --- a/libbb/error_msg.c +++ /dev/null @@ -1,19 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) 1999-2004 by Erik Andersen - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" - -void FAST_FUNC bb_error_msg(const char *s, ...) -{ - va_list p; - - va_start(p, s); - bb_verror_msg(s, p, NULL); - va_end(p); -} diff --git a/libbb/error_msg_and_die.c b/libbb/error_msg_and_die.c deleted file mode 100644 index 243433b2d..000000000 --- a/libbb/error_msg_and_die.c +++ /dev/null @@ -1,20 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) 1999-2004 by Erik Andersen - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" - -void FAST_FUNC bb_error_msg_and_die(const char *s, ...) -{ - va_list p; - - va_start(p, s); - bb_verror_msg(s, p, NULL); - va_end(p); - xfunc_die(); -} diff --git a/libbb/herror_msg.c b/libbb/herror_msg.c index 7e4f64045..ca9274cf7 100644 --- a/libbb/herror_msg.c +++ b/libbb/herror_msg.c @@ -6,7 +6,6 @@ * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include "libbb.h" void FAST_FUNC bb_herror_msg(const char *s, ...) @@ -17,3 +16,13 @@ void FAST_FUNC bb_herror_msg(const char *s, ...) bb_verror_msg(s, p, hstrerror(h_errno)); va_end(p); } + +void FAST_FUNC bb_herror_msg_and_die(const char *s, ...) +{ + va_list p; + + va_start(p, s); + bb_verror_msg(s, p, hstrerror(h_errno)); + va_end(p); + xfunc_die(); +} diff --git a/libbb/herror_msg_and_die.c b/libbb/herror_msg_and_die.c deleted file mode 100644 index 230fe645a..000000000 --- a/libbb/herror_msg_and_die.c +++ /dev/null @@ -1,20 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) 1999-2004 by Erik Andersen - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" - -void FAST_FUNC bb_herror_msg_and_die(const char *s, ...) -{ - va_list p; - - va_start(p, s); - bb_verror_msg(s, p, hstrerror(h_errno)); - va_end(p); - xfunc_die(); -} diff --git a/libbb/perror_msg.c b/libbb/perror_msg.c index 6c8e1b51e..cbba805fb 100644 --- a/libbb/perror_msg.c +++ b/libbb/perror_msg.c @@ -6,7 +6,6 @@ * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include "libbb.h" void FAST_FUNC bb_perror_msg(const char *s, ...) @@ -19,7 +18,23 @@ void FAST_FUNC bb_perror_msg(const char *s, ...) va_end(p); } +void FAST_FUNC bb_perror_msg_and_die(const char *s, ...) +{ + va_list p; + + va_start(p, s); + /* Guard against ": Success" */ + bb_verror_msg(s, p, errno ? strerror(errno) : NULL); + va_end(p); + xfunc_die(); +} + void FAST_FUNC bb_simple_perror_msg(const char *s) { bb_perror_msg("%s", s); } + +void FAST_FUNC bb_simple_perror_msg_and_die(const char *s) +{ + bb_perror_msg_and_die("%s", s); +} diff --git a/libbb/perror_msg_and_die.c b/libbb/perror_msg_and_die.c deleted file mode 100644 index 15615fa22..000000000 --- a/libbb/perror_msg_and_die.c +++ /dev/null @@ -1,26 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) 1999-2004 by Erik Andersen - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" - -void FAST_FUNC bb_perror_msg_and_die(const char *s, ...) -{ - va_list p; - - va_start(p, s); - /* Guard against ": Success" */ - bb_verror_msg(s, p, errno ? strerror(errno) : NULL); - va_end(p); - xfunc_die(); -} - -void FAST_FUNC bb_simple_perror_msg_and_die(const char *s) -{ - bb_perror_msg_and_die("%s", s); -} diff --git a/libbb/verror_msg.c b/libbb/verror_msg.c index 613432906..c5fbc380c 100644 --- a/libbb/verror_msg.c +++ b/libbb/verror_msg.c @@ -76,12 +76,9 @@ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) free(msg); } - #ifdef VERSION_WITH_WRITEV - /* Code size is approximately the same, but currently it's the only user * of writev in entire bbox. __libc_writev in uclibc is ~50 bytes. */ - void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) { int strerr_len, msgeol_len; @@ -139,3 +136,23 @@ void FAST_FUNC bb_verror_msg(const char *s, va_list p, const char* strerr) free(msgc); } #endif + + +void FAST_FUNC bb_error_msg_and_die(const char *s, ...) +{ + va_list p; + + va_start(p, s); + bb_verror_msg(s, p, NULL); + va_end(p); + xfunc_die(); +} + +void FAST_FUNC bb_error_msg(const char *s, ...) +{ + va_list p; + + va_start(p, s); + bb_verror_msg(s, p, NULL); + va_end(p); +} -- cgit v1.2.3-55-g6feb From 08f0b784fd4351929090c877605762d664e70098 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 4 Jul 2010 23:34:02 +0200 Subject: Yet another attempt to stamp out "make -j" problems Signed-off-by: Denys Vlasenko --- applets/usage_compressed | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/applets/usage_compressed b/applets/usage_compressed index bfd5aa873..9ddf16d38 100755 --- a/applets/usage_compressed +++ b/applets/usage_compressed @@ -9,7 +9,7 @@ test -x "$loc/usage" || exit 1 test "$SED" || SED=sed test "$DD" || DD=dd -exec >"$target" +exec >"$target.$$" echo '#define UNPACKED_USAGE "" \' "$loc/usage" | od -v -t x1 \ @@ -39,3 +39,9 @@ echo '#define PACKED_USAGE \' -e 's/\(..\)/0x\1,/g' \ -e 's/$/ \\/' echo '' + +if cmp -s "$target.$$" "$target" 2>/dev/null; then + rm -- "$target.$$" +else + mv -- "$target.$$" "$target" +fi -- cgit v1.2.3-55-g6feb From 9297dbc9d285e823af59c443e0123cb99577569a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 5 Jul 2010 21:37:12 +0200 Subject: randomconfig fixes Signed-off-by: Denys Vlasenko --- applets/applets.c | 2 -- archival/bbunzip.c | 2 +- archival/libunarchive/Kbuild.src | 1 + libbb/appletlib.c | 6 +++++- shell/hush.c | 18 +++++++++++++----- testsuite/ash.tests | 1 - testsuite/cal.tests | 1 - testsuite/cpio.tests | 2 +- testsuite/date/date-works-1 | 2 ++ testsuite/expand.tests | 7 ++++--- testsuite/fold.tests | 7 ++++--- testsuite/ls.tests | 8 ++++---- testsuite/mount.tests | 1 - testsuite/unexpand.tests | 6 ++++-- 14 files changed, 39 insertions(+), 25 deletions(-) diff --git a/applets/applets.c b/applets/applets.c index 133a21575..6a3996272 100644 --- a/applets/applets.c +++ b/applets/applets.c @@ -6,8 +6,6 @@ * * Licensed under GPLv2, see file License in this tarball for details. */ - -#include #include "busybox.h" #if ENABLE_BUILD_LIBBUSYBOX diff --git a/archival/bbunzip.c b/archival/bbunzip.c index 832a7bbf3..c1259ac46 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -387,7 +387,7 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unxz_main(int argc UNUSED_PARAM, char **argv) { - int opts = getopt32(argv, "cfvdt"); + IF_XZ(int opts =) getopt32(argv, "cfvdt"); # if ENABLE_XZ /* xz without -d or -t? */ if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) diff --git a/archival/libunarchive/Kbuild.src b/archival/libunarchive/Kbuild.src index 6ad1d7a65..a8549570e 100644 --- a/archival/libunarchive/Kbuild.src +++ b/archival/libunarchive/Kbuild.src @@ -38,6 +38,7 @@ INSERT lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o lib-$(CONFIG_UNLZMA) += decompress_unlzma.o +lib-$(CONFIG_UNXZ) += decompress_unxz.o lib-$(CONFIG_CPIO) += get_header_cpio.o lib-$(CONFIG_DPKG) += $(DPKG_FILES) lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 6f058bcc8..4924a97c1 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -195,7 +195,11 @@ void lbb_prepare(const char *applet #if ENABLE_FEATURE_INDIVIDUAL /* Redundant for busybox (run_applet_and_exit covers that case) * but needed for "individual applet" mode */ - if (argv[1] && !argv[2] && strcmp(argv[1], "--help") == 0) { + if (argv[1] + && !argv[2] + && strcmp(argv[1], "--help") == 0 + && strncmp(applet, "busybox", 7) != 0 + ) { /* Special case. POSIX says "test --help" * should be no different from e.g. "test --foo". */ if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) diff --git a/shell/hush.c b/shell/hush.c index 831443e2e..31ca22a2e 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -117,6 +117,10 @@ * and therefore waitpid will return the same result as last time) */ #define ENABLE_HUSH_FAST 0 +/* TODO: implement simplified code for users which do not need ${var%...} ops + * So far ${var%...} ops are always enabled: + */ +#define ENABLE_HUSH_DOLLAR_OPS 1 #if BUILD_AS_NOMMU @@ -2681,7 +2685,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char } } } else if (exp_op == ':') { -#if ENABLE_HUSH_BASH_COMPAT +#if ENABLE_HUSH_BASH_COMPAT && ENABLE_SH_MATH_SUPPORT /* It's ${var:N[:M]} bashism. * Note that in encoded form it has TWO parts: * var:NM @@ -5820,7 +5824,7 @@ static int parse_group(o_string *dest, struct parse_context *ctx, /* command remains "open", available for possible redirects */ } -#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT +#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS /* Subroutines for copying $(...) and `...` things */ static void add_till_backquote(o_string *dest, struct in_str *input); /* '...' */ @@ -5921,9 +5925,9 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign { int ch; char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG; -#if ENABLE_HUSH_BASH_COMPAT +# if ENABLE_HUSH_BASH_COMPAT char end_char2 = end_ch >> 8; -#endif +# endif end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); while (1) { @@ -5976,7 +5980,7 @@ static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsign } return ch; } -#endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT */ +#endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS */ /* Return code: 0 for OK, 1 for syntax error */ #if BB_MMU @@ -6082,7 +6086,11 @@ static int parse_dollar(o_string *as_string, again: if (!BB_MMU) pos = dest->length; +#if ENABLE_HUSH_DOLLAR_OPS last_ch = add_till_closing_bracket(dest, input, end_ch); +#else +#error Simple code to only allow ${var} is not implemented +#endif if (as_string) { o_addstr(as_string, dest->data + pos); o_addchr(as_string, last_ch); diff --git a/testsuite/ash.tests b/testsuite/ash.tests index dd626e6d1..2eeb746e4 100755 --- a/testsuite/ash.tests +++ b/testsuite/ash.tests @@ -6,7 +6,6 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh - test -f "$bindir/.config" && . "$bindir/.config" test x"CONFIG_SCRIPT" = x"y" || exit 0 diff --git a/testsuite/cal.tests b/testsuite/cal.tests index 30985688b..db693ee59 100755 --- a/testsuite/cal.tests +++ b/testsuite/cal.tests @@ -3,7 +3,6 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh - test -f "$bindir/.config" && . "$bindir/.config" # testing "test name" "command" "expected result" "file input" "stdin" diff --git a/testsuite/cpio.tests b/testsuite/cpio.tests index 5b397b01c..7aee774a1 100755 --- a/testsuite/cpio.tests +++ b/testsuite/cpio.tests @@ -99,7 +99,7 @@ SKIP= # chown on a link was affecting file, dropping its suid/sgid bits rm -rf cpio.testdir -optional FEATURE_CPIO_O +optional FEATURE_CPIO_O FEATURE_STAT_FORMAT mkdir cpio.testdir touch cpio.testdir/file chmod 6755 cpio.testdir/file # sets suid/sgid bits diff --git a/testsuite/date/date-works-1 b/testsuite/date/date-works-1 index 1b3e47ab0..e745d3841 100644 --- a/testsuite/date/date-works-1 +++ b/testsuite/date/date-works-1 @@ -1,3 +1,5 @@ +unset LANG + dt=`busybox date -d 1:2 +%T` test x"$dt" = x"01:02:00" diff --git a/testsuite/expand.tests b/testsuite/expand.tests index 357a9ad6b..2d92344d4 100755 --- a/testsuite/expand.tests +++ b/testsuite/expand.tests @@ -3,6 +3,7 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh +test -f "$bindir/.config" && . "$bindir/.config" # testing "test name" "options" "expected result" "file input" "stdin" @@ -12,13 +13,13 @@ testing "expand" \ "" \ "\t12345678\t12345678\n" -optional UNICODE_SUPPORT +test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ +&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ +&& test "$CONFIG_LAST_SUPPORTED_WCHAR" -gt "916" \ testing "expand with unicode characher 0x394" \ "expand" \ "Δ 12345ΔΔΔ 12345678\n" \ "" \ "Δ\t12345ΔΔΔ\t12345678\n" -SKIP= - exit $FAILCOUNT diff --git a/testsuite/fold.tests b/testsuite/fold.tests index 0197d024d..e5700cc2b 100755 --- a/testsuite/fold.tests +++ b/testsuite/fold.tests @@ -3,6 +3,7 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh +test -f "$bindir/.config" && . "$bindir/.config" # testing "test name" "options" "expected result" "file input" "stdin" @@ -28,9 +29,10 @@ be preserved is here:>\0< - they must be preserved " \ -optional UNICODE_SUPPORT # The text was taken from English and Ukrainian wikipedia pages -testing "fold -sw66 with unicode input" "fold -sw66" \ +test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ +&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ +&& testing "fold -sw66 with unicode input" "fold -sw66" \ "\ The Andromeda Galaxy (pronounced /ænˈdrɒmədə/, also known as \n\ Messier 31, M31, or NGC224; often referred to as the Great \n\ @@ -56,6 +58,5 @@ Way. спіральна галактика, що знаходиться на відстані приблизно у 2,5 \ мільйони світлових років від нашої планети у сузір'ї Андромеди. \ На початку ХХІ ст. в центрі галактики виявлено чорну дірку." -SKIP= exit $FAILCOUNT diff --git a/testsuite/ls.tests b/testsuite/ls.tests index 0680762fc..dc842123d 100755 --- a/testsuite/ls.tests +++ b/testsuite/ls.tests @@ -3,10 +3,9 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh - test -f "$bindir/.config" && . "$bindir/.config" -rm -rf ls.testdir >/dev/null +rm -rf ls.testdir 2>/dev/null mkdir ls.testdir || exit 1 # testing "test name" "command" "expected result" "file input" "stdin" @@ -15,9 +14,10 @@ mkdir ls.testdir || exit 1 # I suspect we might fail to skip exactly correct number of bytes # over broked unicode sequences. test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ -&& test x"$CONFIG_LOCALE_SUPPORT" != x"y" \ +&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ && test x"$CONFIG_SUBST_WCHAR" = x"63" \ && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"767" \ +&& test x"$CONFIG_FEATURE_LS_SORTFILES" = x"y" \ && testing "ls unicode test with codepoints limited to 767" \ "(cd ls.testdir && sh ../ls.mk_uni_tests) && ls -1 ls.testdir" \ '0001_1__Some_correct_UTF-8_text___________________________________________| @@ -134,7 +134,7 @@ test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ # Currently fails on "0080_4.2.2__U-000007FF_=_e0_9f_bf" line test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ -&& test x"$CONFIG_LOCALE_SUPPORT" != x"y" \ +&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ && test x"$CONFIG_SUBST_WCHAR" = x"63" \ && test x"$CONFIG_LAST_SUPPORTED_WCHAR" = x"0" \ && testing "ls unicode test with unlimited codepoints" \ diff --git a/testsuite/mount.tests b/testsuite/mount.tests index 3c7405fbd..ce1a6006b 100755 --- a/testsuite/mount.tests +++ b/testsuite/mount.tests @@ -3,7 +3,6 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh - test -f "$bindir/.config" && . "$bindir/.config" test "`id -u`" = 0 || { diff --git a/testsuite/unexpand.tests b/testsuite/unexpand.tests index a48e3214e..0727884f7 100755 --- a/testsuite/unexpand.tests +++ b/testsuite/unexpand.tests @@ -3,6 +3,7 @@ # Licensed under GPL v2, see file LICENSE for details. . ./testing.sh +test -f "$bindir/.config" && . "$bindir/.config" # testing "test name" "options" "expected result" "file input" "stdin" @@ -30,9 +31,10 @@ testing "unexpand case 7" "unexpand" \ testing "unexpand case 8" "unexpand" \ "a b\n" "" "a b\n" \ -optional UNICODE_SUPPORT +test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ +&& test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ +&& test "$CONFIG_LAST_SUPPORTED_WCHAR" -gt "916" \ testing "unexpand with unicode characher 0x394" "unexpand" \ "1ΔΔΔ5\t99999\n" "" "1ΔΔΔ5 99999\n" -SKIP= exit $FAILCOUNT -- cgit v1.2.3-55-g6feb From ee1f19b9425a8a0d5b9cc5c037b18278df07ee3e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Jul 2010 02:20:00 +0200 Subject: [un]expand: fix testsuite Signed-off-by: Denys Vlasenko --- testsuite/expand.tests | 3 +-- testsuite/unexpand.tests | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/testsuite/expand.tests b/testsuite/expand.tests index 2d92344d4..631ab4db3 100755 --- a/testsuite/expand.tests +++ b/testsuite/expand.tests @@ -15,8 +15,7 @@ testing "expand" \ test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ && test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ -&& test "$CONFIG_LAST_SUPPORTED_WCHAR" -gt "916" \ -testing "expand with unicode characher 0x394" \ +&& testing "expand with unicode characher 0x394" \ "expand" \ "Δ 12345ΔΔΔ 12345678\n" \ "" \ diff --git a/testsuite/unexpand.tests b/testsuite/unexpand.tests index 0727884f7..8dbe3eb27 100755 --- a/testsuite/unexpand.tests +++ b/testsuite/unexpand.tests @@ -33,8 +33,7 @@ testing "unexpand case 8" "unexpand" \ test x"$CONFIG_UNICODE_SUPPORT" = x"y" \ && test x"$CONFIG_UNICODE_USING_LOCALE" != x"y" \ -&& test "$CONFIG_LAST_SUPPORTED_WCHAR" -gt "916" \ -testing "unexpand with unicode characher 0x394" "unexpand" \ +&& testing "unexpand with unicode characher 0x394" "unexpand" \ "1ΔΔΔ5\t99999\n" "" "1ΔΔΔ5 99999\n" exit $FAILCOUNT -- cgit v1.2.3-55-g6feb From 3e5fa43b2faba827e44f184818534b476ec0ed09 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Jul 2010 02:26:35 +0200 Subject: scripts/randomtest: update to pass testsuite with Rob's toolchain Signed-off-by: Denys Vlasenko --- scripts/randomtest | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/scripts/randomtest b/scripts/randomtest index 8d0d79e64..a102593d3 100755 --- a/scripts/randomtest +++ b/scripts/randomtest @@ -43,6 +43,10 @@ mv .config.new .config echo '# CONFIG_DEBUG_PESSIMIZE is not set' >>.config echo '# CONFIG_WERROR is not set' >>.config echo "CONFIG_CROSS_COMPILER_PREFIX=\"${CROSS_COMPILER_PREFIX}\"" >>.config +echo '# CONFIG_SELINUX is not set' >>.config +echo '# CONFIG_EFENCE is not set' >>.config +echo '# CONFIG_DMALLOC is not set' >>.config +echo '# CONFIG_RFKILL is not set' >>.config # If glibc, don't build static if test x"$LIBC" = x"glibc"; then @@ -53,18 +57,21 @@ if test x"$LIBC" = x"glibc"; then echo '# CONFIG_STATIC is not set' >>.config fi -# If glibc, build static, and remove some things +# If uclibc, build static, and remove some things # likely to not work on uclibc. if test x"$LIBC" = x"uclibc"; then cat .config \ | grep -v CONFIG_STATIC \ | grep -v CONFIG_BUILD_LIBBUSYBOX \ - | grep -v CONFIG_TASKSET \ - | grep -v CONFIG_UNICODE_SUPPORT \ | grep -v CONFIG_PIE \ + \ + | grep -v CONFIG_FEATURE_2_4_MODULES \ >.config.new mv .config.new .config echo 'CONFIG_STATIC=y' >>.config + echo '# CONFIG_BUILD_LIBBUSYBOX is not set' >>.config + echo '# CONFIG_PIE is not set' >>.config + echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config fi # If STATIC, remove some things. @@ -75,6 +82,7 @@ if grep -q "^CONFIG_STATIC=y" .config; then | grep -v CONFIG_PAM \ >.config.new mv .config.new .config + echo '# CONFIG_PAM is not set' >>.config fi # Regenerate .config with default answers for yanked-off options -- cgit v1.2.3-55-g6feb From b2d95147c989448f23cc59c63b83e2d89f0bd9cd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Jul 2010 04:16:50 +0200 Subject: bump version to 1.17.0 Signed-off-by: Denys Vlasenko --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index ef7c532b7..83a9128a6 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 1 PATCHLEVEL = 17 SUBLEVEL = 0 -EXTRAVERSION = .git +EXTRAVERSION = NAME = Unnamed # *DOCUMENTATION* -- cgit v1.2.3-55-g6feb From 89a1cace3b8de66f4df63cbec5c50bae67bf1104 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Jul 2010 15:47:35 +0200 Subject: Start 1.18.0 development cycle Signed-off-by: Denys Vlasenko --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 83a9128a6..2d6a3b2a0 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 1 -PATCHLEVEL = 17 +PATCHLEVEL = 18 SUBLEVEL = 0 -EXTRAVERSION = +EXTRAVERSION = .git NAME = Unnamed # *DOCUMENTATION* -- cgit v1.2.3-55-g6feb From 7a2aa87c7555a678e92d00c860e25b83305ee064 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Jul 2010 15:49:01 +0200 Subject: bootchartd: fix labels in config system. no code changes Signed-off-by: Denys Vlasenko --- init/bootchartd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/init/bootchartd.c b/init/bootchartd.c index b3e08af92..dae2fe6e9 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -18,7 +18,7 @@ //config: and stopped using bootchartd stop. //config: //config:config FEATURE_BOOTCHARTD_BLOATED_HEADER -//config: bool "bootchartd" +//config: bool "Compatible, bloated header" //config: default y //config: depends on BOOTCHARTD //config: help @@ -35,7 +35,7 @@ //config: makes bootchartd applet to dump a subset of it. //config: //config:config FEATURE_BOOTCHARTD_CONFIG_FILE -//config: bool "bootchartd" +//config: bool "Support bootchartd.conf" //config: default y //config: depends on BOOTCHARTD //config: help -- cgit v1.2.3-55-g6feb From 8f65b0cf31837e3400e1f54f6826198d8ca81b42 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Jul 2010 18:46:02 +0200 Subject: whitespace fixes Signed-off-by: Denys Vlasenko --- archival/tar.c | 2 +- coreutils/realpath.c | 2 +- util-linux/fdisk.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/archival/tar.c b/archival/tar.c index 9dd74536e..5ddff7fa5 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -237,7 +237,7 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, struct tar_header_t header; memset(&header, 0, sizeof(header)); - + strncpy(header.name, header_name, sizeof(header.name)); /* POSIX says to mask mode with 07777. */ diff --git a/coreutils/realpath.c b/coreutils/realpath.c index 90a71ed7d..3bc40ee04 100644 --- a/coreutils/realpath.c +++ b/coreutils/realpath.c @@ -23,7 +23,7 @@ int realpath_main(int argc UNUSED_PARAM, char **argv) do { char *resolved_path = xmalloc_realpath(*argv); - if (resolved_path != NULL) { + if (resolved_path != NULL) { puts(resolved_path); free(resolved_path); } else { diff --git a/util-linux/fdisk.c b/util-linux/fdisk.c index 7227a829e..aa718c787 100644 --- a/util-linux/fdisk.c +++ b/util-linux/fdisk.c @@ -2805,7 +2805,7 @@ list_devs_in_proc_partititons(void) &ma, &mi, &sz, ptname) != 4) continue; for (s = ptname; *s; s++) - continue; + continue; /* note: excluding '0': e.g. mmcblk0 is not a partition name! */ if (s[-1] >= '1' && s[-1] <= '9') continue; -- cgit v1.2.3-55-g6feb From d3c2b71ffae3f408e8e0e51b50a9f98e1b8b85e3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 6 Jul 2010 18:47:00 +0200 Subject: crond: code shrink function old new delta ForkJob 513 457 -56 Signed-off-by: Denys Vlasenko --- miscutils/crond.c | 127 ++++++++++++++++++++++++++++-------------------------- 1 file changed, 65 insertions(+), 62 deletions(-) diff --git a/miscutils/crond.c b/miscutils/crond.c index 4a3103cb9..49ecf745e 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c @@ -54,8 +54,8 @@ typedef struct CronLine { pid_t cl_Pid; /* running pid, 0, or armed (-1) */ #if ENABLE_FEATURE_CROND_CALL_SENDMAIL int cl_MailPos; /* 'empty file' size */ - smallint cl_MailFlag; /* running pid is for mail */ char *cl_MailTo; /* whom to mail results */ + smallint cl_MailFlag; /* running pid is for mail */ #endif /* ordered by size, not in natural order. makes code smaller: */ char cl_Dow[7]; /* 0-6, beginning sunday */ @@ -166,6 +166,9 @@ static void crondlog(const char *ctl, ...) int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int crond_main(int argc UNUSED_PARAM, char **argv) { + time_t t2; + int rescan; + int sleep_time; unsigned opts; INIT_G(); @@ -195,62 +198,62 @@ int crond_main(int argc UNUSED_PARAM, char **argv) xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", LogLevel); SynchronizeDir(); + write_pidfile("/var/run/crond.pid"); /* main loop - synchronize to 1 second after the minute, minimum sleep * of 1 second. */ - { - time_t t1 = time(NULL); - int rescan = 60; - int sleep_time = 60; + t2 = time(NULL); + rescan = 60; + sleep_time = 60; + for (;;) { + time_t t1; + long dt; - write_pidfile("/var/run/crond.pid"); - for (;;) { - time_t t2; - long dt; + t1 = t2; + sleep((sleep_time + 1) - (time(NULL) % sleep_time)); - sleep((sleep_time + 1) - (time(NULL) % sleep_time)); + t2 = time(NULL); + dt = (long)t2 - (long)t1; - t2 = time(NULL); - dt = (long)t2 - (long)t1; - - /* - * The file 'cron.update' is checked to determine new cron - * jobs. The directory is rescanned once an hour to deal - * with any screwups. - * - * check for disparity. Disparities over an hour either way - * result in resynchronization. A reverse-indexed disparity - * less then an hour causes us to effectively sleep until we - * match the original time (i.e. no re-execution of jobs that - * have just been run). A forward-indexed disparity less then - * an hour causes intermediate jobs to be run, but only once - * in the worst case. - * - * when running jobs, the inequality used is greater but not - * equal to t1, and less then or equal to t2. - */ - if (--rescan == 0) { - rescan = 60; - SynchronizeDir(); - } - CheckUpdates(); - if (DebugOpt) - crondlog(LVL5 "wakeup dt=%ld", dt); - if (dt < -60 * 60 || dt > 60 * 60) { - crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); - } else if (dt > 0) { - TestJobs(t1, t2); - RunJobs(); - sleep(5); - if (CheckJobs() > 0) { - sleep_time = 10; - } else { - sleep_time = 60; - } + /* + * The file 'cron.update' is checked to determine new cron + * jobs. The directory is rescanned once an hour to deal + * with any screwups. + * + * Check for time jump. Disparities over an hour either way + * result in resynchronization. A negative disparity + * less than an hour causes us to effectively sleep until we + * match the original time (i.e. no re-execution of jobs that + * have just been run). A positive disparity less than + * an hour causes intermediate jobs to be run, but only once + * in the worst case. + * + * When running jobs, the inequality used is greater but not + * equal to t1, and less then or equal to t2. + */ + if (--rescan == 0) { + rescan = 60; + SynchronizeDir(); + } + CheckUpdates(); + if (DebugOpt) + crondlog(LVL5 "wakeup dt=%ld", dt); + if (dt < -60 * 60 || dt > 60 * 60) { + crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); + /* and we do not run any jobs in this case */ + } else if (dt > 0) { + /* Usual case: time advances forwad, as expected */ + TestJobs(t1, t2); + RunJobs(); + sleep(5); + if (CheckJobs() > 0) { + sleep_time = 10; + } else { + sleep_time = 60; } - t1 = t2; - } /* for (;;) */ - } + } + /* else: time jumped back, do not run any jobs */ + } /* for (;;) */ return 0; /* not reached */ } @@ -277,7 +280,7 @@ static void SetEnv(struct passwd *pas) safe_setenv(&env_var_user, "USER", pas->pw_name); safe_setenv(&env_var_home, "HOME", pas->pw_dir); /* if we want to set user's shell instead: */ - /*safe_setenv(env_var_user, "SHELL", pas->pw_shell);*/ + /*safe_setenv(env_var_shell, "SHELL", pas->pw_shell);*/ #else xsetenv("USER", pas->pw_name); xsetenv("HOME", pas->pw_dir); @@ -597,10 +600,10 @@ static void SynchronizeDir(void) } /* - * DeleteFile() - delete user database + * DeleteFile() - delete user database * - * Note: multiple entries for same user may exist if we were unable to - * completely delete a database due to running processes. + * Note: multiple entries for same user may exist if we were unable to + * completely delete a database due to running processes. */ static void DeleteFile(const char *userName) { @@ -806,14 +809,14 @@ ForkJob(const char *user, CronLine *line, int mailFd, if (mail_filename) { unlink(mail_filename); } - } else if (mail_filename) { - /* PARENT, FORK SUCCESS - * rename mail-file based on pid of process - */ - char mailFile2[128]; - - snprintf(mailFile2, sizeof(mailFile2), "%s/cron.%s.%d", TMPDIR, user, pid); - rename(mail_filename, mailFile2); // TODO: xrename? + } else { + /* PARENT, FORK SUCCESS */ + if (mail_filename) { + /* rename mail-file based on pid of process */ + char *mailFile2 = xasprintf("%s/cron.%s.%d", TMPDIR, user, (int)pid); + rename(mail_filename, mailFile2); // TODO: xrename? + free(mailFile2); + } } /* -- cgit v1.2.3-55-g6feb From 1d36f24bcb22d06b007f162802cbc5a251f3e612 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 8 Jul 2010 02:29:47 +0200 Subject: make usage_compressed.h generation _always_ update mtime Signed-off-by: Denys Vlasenko --- applets/usage_compressed | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/applets/usage_compressed b/applets/usage_compressed index 9ddf16d38..e1fd0d94d 100755 --- a/applets/usage_compressed +++ b/applets/usage_compressed @@ -40,8 +40,4 @@ echo '#define PACKED_USAGE \' -e 's/$/ \\/' echo '' -if cmp -s "$target.$$" "$target" 2>/dev/null; then - rm -- "$target.$$" -else - mv -- "$target.$$" "$target" -fi +mv -- "$target.$$" "$target" -- cgit v1.2.3-55-g6feb From 9388b4e72051b031b84a1345cc763757dbd9a699 Mon Sep 17 00:00:00 2001 From: Maksym Kryzhanovskyy Date: Thu, 8 Jul 2010 02:47:25 +0200 Subject: ifplugd: code shrink function old new delta detect_link 122 221 +99 api_modes - 7 +7 maybe_up_new_iface 27 33 +6 ifplugd_main 1143 1089 -54 detect_link_auto 117 - -117 ------------------------------------------------------------------------------ (add/remove: 1/1 grow/shrink: 2/1 up/down: 112/-171) Total: -59 bytes Signed-off-by: Maksym Kryzhanovskyy Signed-off-by: Denys Vlasenko --- networking/ifplugd.c | 95 +++++++++++++++++++--------------------------------- 1 file changed, 35 insertions(+), 60 deletions(-) diff --git a/networking/ifplugd.c b/networking/ifplugd.c index 8cb07db5d..eb7442881 100644 --- a/networking/ifplugd.c +++ b/networking/ifplugd.c @@ -79,6 +79,7 @@ enum { // api mode API_WLAN = 'w', API_IFF = 'i', }; +static const char api_modes[] ALIGN1 = "aempwi"; enum { // interface status IFSTATUS_ERR = -1, @@ -95,6 +96,7 @@ struct globals { smallint iface_last_status; smallint iface_prev_status; smallint iface_exists; + smallint api_method_num; /* Used in getopt32, must have sizeof == sizeof(int) */ unsigned poll_time; @@ -107,7 +109,6 @@ struct globals { const char *extra_arg; smallint (*detect_link_func)(void); - smallint (*cached_detect_link_func)(void); }; #define G (*ptr_to_globals) #define INIT_G() do { \ @@ -239,8 +240,8 @@ static void maybe_up_new_iface(void) G.iface, buf, driver_info.driver, driver_info.version); } #endif - - G.cached_detect_link_func = NULL; + if (G.api_method_num == 0) + G.detect_link_func = NULL; } static smallint detect_link_mii(void) @@ -348,7 +349,7 @@ static smallint detect_link_wlan(void) return IFSTATUS_UP; } -static smallint detect_link_auto(void) +static smallint detect_link(void) { static const struct { const char *name; @@ -360,32 +361,6 @@ static smallint detect_link_auto(void) { "wireless extension", &detect_link_wlan }, { "IFF_RUNNING" , &detect_link_iff }, }; - int i; - smallint iface_status; - smallint sv_logmode; - - if (G.cached_detect_link_func) { - iface_status = G.cached_detect_link_func(); - if (iface_status != IFSTATUS_ERR) - return iface_status; - } - - sv_logmode = logmode; - for (i = 0; i < ARRAY_SIZE(method); i++) { - logmode = LOGMODE_NONE; - iface_status = method[i].func(); - logmode = sv_logmode; - if (iface_status != IFSTATUS_ERR) { - G.cached_detect_link_func = method[i].func; - bb_error_msg("using %s detection mode", method[i].name); - break; - } - } - return iface_status; -} - -static smallint detect_link(void) -{ smallint status; if (!G.iface_exists) @@ -398,20 +373,38 @@ static smallint detect_link(void) if (!(option_mask32 & FLAG_NO_AUTO)) up_iface(); + if (!G.detect_link_func) { + if (G.api_method_num == 0) { + int i; + smallint sv_logmode; + + sv_logmode = logmode; + for (i = 0; i < ARRAY_SIZE(method); i++) { + logmode = LOGMODE_NONE; + status = method[i].func(); + logmode = sv_logmode; + if (status != IFSTATUS_ERR) { + G.detect_link_func = method[i].func; + bb_error_msg("using %s detection mode", method[i].name); + goto _2; + } + } + goto _1; + } + G.detect_link_func = method[G.api_method_num - 1].func; + } + status = G.detect_link_func(); + _1: if (status == IFSTATUS_ERR) { if (option_mask32 & FLAG_IGNORE_FAIL) status = IFSTATUS_DOWN; - if (option_mask32 & FLAG_IGNORE_FAIL_POSITIVE) + else if (option_mask32 & FLAG_IGNORE_FAIL_POSITIVE) status = IFSTATUS_UP; + else if (G.api_method_num == 0) + bb_error_msg("can't detect link status"); } - - if (status == IFSTATUS_ERR - && G.detect_link_func == detect_link_auto - ) { - bb_error_msg("can't detect link status"); - } - + _2: if (status != G.iface_last_status) { G.iface_prev_status = G.iface_last_status; G.iface_last_status = status; @@ -523,6 +516,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv) const char *iface_status_str; struct pollfd netlink_pollfd[1]; unsigned opts; + const char *api_mode_found; #if ENABLE_FEATURE_PIDFILE char *pidfile_name; pid_t pid_from_pidfile; @@ -551,29 +545,10 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv) if (pid_from_pidfile > 0 && kill(pid_from_pidfile, 0) == 0) bb_error_msg_and_die("daemon already running"); #endif - - switch (G.api_mode[0]) { - case API_AUTO: - G.detect_link_func = detect_link_auto; - break; - case API_ETHTOOL: - G.detect_link_func = detect_link_ethtool; - break; - case API_MII: - G.detect_link_func = detect_link_mii; - break; - case API_PRIVATE: - G.detect_link_func = detect_link_priv; - break; - case API_WLAN: - G.detect_link_func = detect_link_wlan; - break; - case API_IFF: - G.detect_link_func = detect_link_iff; - break; - default: + api_mode_found = strchr(api_modes, G.api_mode[0]); + if (!api_mode_found) bb_error_msg_and_die("unknown API mode '%s'", G.api_mode); - } + G.api_method_num = api_mode_found - api_modes; if (!(opts & FLAG_NO_DAEMON)) bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); -- cgit v1.2.3-55-g6feb From 4a09aefae2523bf242039e45c9f85bd1f35b72ad Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 8 Jul 2010 04:07:15 +0200 Subject: crond: reorder functions to follow usual order: "main last" Signed-off-by: Denys Vlasenko --- miscutils/crond.c | 452 ++++++++++++++++++++++++++---------------------------- 1 file changed, 221 insertions(+), 231 deletions(-) diff --git a/miscutils/crond.c b/miscutils/crond.c index 49ecf745e..06d72ced9 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c @@ -17,25 +17,25 @@ /* glibc frees previous setenv'ed value when we do next setenv() * of the same variable. uclibc does not do this! */ #if (defined(__GLIBC__) && !defined(__UCLIBC__)) /* || OTHER_SAFE_LIBC... */ -#define SETENV_LEAKS 0 +# define SETENV_LEAKS 0 #else -#define SETENV_LEAKS 1 +# define SETENV_LEAKS 1 #endif #define TMPDIR CONFIG_FEATURE_CROND_DIR #define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" #ifndef SENDMAIL -#define SENDMAIL "sendmail" +# define SENDMAIL "sendmail" #endif #ifndef SENDMAIL_ARGS -#define SENDMAIL_ARGS "-ti", NULL +# define SENDMAIL_ARGS "-ti", NULL #endif #ifndef CRONUPDATE -#define CRONUPDATE "cron.update" +# define CRONUPDATE "cron.update" #endif #ifndef MAXLINES -#define MAXLINES 256 /* max lines in non-root crontabs */ +# define MAXLINES 256 /* max lines in non-root crontabs */ #endif @@ -108,20 +108,6 @@ struct globals { } while (0) -static void CheckUpdates(void); -static void SynchronizeDir(void); -static int TestJobs(time_t t1, time_t t2); -static void RunJobs(void); -static int CheckJobs(void); -static void RunJob(const char *user, CronLine *line); -#if ENABLE_FEATURE_CROND_CALL_SENDMAIL -static void EndJob(const char *user, CronLine *line); -#else -#define EndJob(user, line) ((line)->cl_Pid = 0) -#endif -static void DeleteFile(const char *userName); - - /* 0 is the most verbose, default 8 */ #define LVL5 "\x05" #define LVL7 "\x07" @@ -163,101 +149,6 @@ static void crondlog(const char *ctl, ...) exit(20); } -int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int crond_main(int argc UNUSED_PARAM, char **argv) -{ - time_t t2; - int rescan; - int sleep_time; - unsigned opts; - - INIT_G(); - - /* "-b after -f is ignored", and so on for every pair a-b */ - opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") - ":l+:d+"; /* -l and -d have numeric param */ - opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), - &LogLevel, &LogFile, &CDir - IF_FEATURE_CROND_D(,&LogLevel)); - /* both -d N and -l N set the same variable: LogLevel */ - - if (!(opts & OPT_f)) { - /* close stdin, stdout, stderr. - * close unused descriptors - don't need them. */ - bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); - } - - if (!(opts & OPT_d) && LogFile == NULL) { - /* logging to syslog */ - openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); - logmode = LOGMODE_SYSLOG; - } - - xchdir(CDir); - //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ - xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ - crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", LogLevel); - SynchronizeDir(); - write_pidfile("/var/run/crond.pid"); - - /* main loop - synchronize to 1 second after the minute, minimum sleep - * of 1 second. */ - t2 = time(NULL); - rescan = 60; - sleep_time = 60; - for (;;) { - time_t t1; - long dt; - - t1 = t2; - sleep((sleep_time + 1) - (time(NULL) % sleep_time)); - - t2 = time(NULL); - dt = (long)t2 - (long)t1; - - /* - * The file 'cron.update' is checked to determine new cron - * jobs. The directory is rescanned once an hour to deal - * with any screwups. - * - * Check for time jump. Disparities over an hour either way - * result in resynchronization. A negative disparity - * less than an hour causes us to effectively sleep until we - * match the original time (i.e. no re-execution of jobs that - * have just been run). A positive disparity less than - * an hour causes intermediate jobs to be run, but only once - * in the worst case. - * - * When running jobs, the inequality used is greater but not - * equal to t1, and less then or equal to t2. - */ - if (--rescan == 0) { - rescan = 60; - SynchronizeDir(); - } - CheckUpdates(); - if (DebugOpt) - crondlog(LVL5 "wakeup dt=%ld", dt); - if (dt < -60 * 60 || dt > 60 * 60) { - crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); - /* and we do not run any jobs in this case */ - } else if (dt > 0) { - /* Usual case: time advances forwad, as expected */ - TestJobs(t1, t2); - RunJobs(); - sleep(5); - if (CheckJobs() > 0) { - sleep_time = 10; - } else { - sleep_time = 60; - } - } - /* else: time jumped back, do not run any jobs */ - } /* for (;;) */ - - return 0; /* not reached */ -} - #if SETENV_LEAKS /* We set environment *before* vfork (because we want to use vfork), * so we cannot use setenv() - repeated calls to setenv() may leak memory! @@ -452,6 +343,48 @@ static void FixDayDow(CronLine *line) } } +/* + * DeleteFile() - delete user database + * + * Note: multiple entries for same user may exist if we were unable to + * completely delete a database due to running processes. + */ +static void DeleteFile(const char *userName) +{ + CronFile **pfile = &FileBase; + CronFile *file; + + while ((file = *pfile) != NULL) { + if (strcmp(userName, file->cf_User) == 0) { + CronLine **pline = &file->cf_LineBase; + CronLine *line; + + file->cf_Running = 0; + file->cf_Deleted = 1; + + while ((line = *pline) != NULL) { + if (line->cl_Pid > 0) { + file->cf_Running = 1; + pline = &line->cl_Next; + } else { + *pline = line->cl_Next; + free(line->cl_Shell); + free(line); + } + } + if (file->cf_Running == 0) { + *pfile = file->cf_Next; + free(file->cf_User); + free(file); + } else { + pfile = &file->cf_Next; + } + } else { + pfile = &file->cf_Next; + } + } +} + static void SynchronizeFile(const char *fileName) { struct parser_t *parser; @@ -600,51 +533,7 @@ static void SynchronizeDir(void) } /* - * DeleteFile() - delete user database - * - * Note: multiple entries for same user may exist if we were unable to - * completely delete a database due to running processes. - */ -static void DeleteFile(const char *userName) -{ - CronFile **pfile = &FileBase; - CronFile *file; - - while ((file = *pfile) != NULL) { - if (strcmp(userName, file->cf_User) == 0) { - CronLine **pline = &file->cf_LineBase; - CronLine *line; - - file->cf_Running = 0; - file->cf_Deleted = 1; - - while ((line = *pline) != NULL) { - if (line->cl_Pid > 0) { - file->cf_Running = 1; - pline = &line->cl_Next; - } else { - *pline = line->cl_Next; - free(line->cl_Shell); - free(line); - } - } - if (file->cf_Running == 0) { - *pfile = file->cf_Next; - free(file->cf_User); - free(file); - } else { - pfile = &file->cf_Next; - } - } else { - pfile = &file->cf_Next; - } - } -} - -/* - * TestJobs() - * - * determine which jobs need to be run. Under normal conditions, the + * Determine which jobs need to be run. Under normal conditions, the * period is about a minute (one scan). Worst case it will be one * hour (60 scans). */ @@ -695,35 +584,63 @@ static int TestJobs(time_t t1, time_t t2) return nJobs; } -static void RunJobs(void) +#if ENABLE_FEATURE_CROND_CALL_SENDMAIL +static void +ForkJob(const char *user, CronLine *line, int mailFd, + const char *prog, const char *cmd, const char *arg, + const char *mail_filename); +/* + * EndJob - called when job terminates and when mail terminates + */ +static void EndJob(const char *user, CronLine *line) { - CronFile *file; - CronLine *line; + int mailFd; + char mailFile[128]; + struct stat sbuf; - for (file = FileBase; file; file = file->cf_Next) { - if (!file->cf_Ready) - continue; + /* No job */ + if (line->cl_Pid <= 0) { + line->cl_Pid = 0; + return; + } - file->cf_Ready = 0; - for (line = file->cf_LineBase; line; line = line->cl_Next) { - if (line->cl_Pid >= 0) - continue; + /* + * End of job and no mail file + * End of sendmail job + */ + snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, line->cl_Pid); + line->cl_Pid = 0; - RunJob(file->cf_User, line); - crondlog(LVL8 "USER %s pid %3d cmd %s", - file->cf_User, (int)line->cl_Pid, line->cl_Shell); - if (line->cl_Pid < 0) { - file->cf_Ready = 1; - } else if (line->cl_Pid > 0) { - file->cf_Running = 1; - } - } + if (line->cl_MailFlag == 0) { + return; } + line->cl_MailFlag = 0; + + /* + * End of primary job - check for mail file. If size has increased and + * the file is still valid, we sendmail it. + */ + mailFd = open(mailFile, O_RDONLY); + unlink(mailFile); + if (mailFd < 0) { + return; + } + + if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid + || sbuf.st_nlink != 0 || sbuf.st_size == line->cl_MailPos + || !S_ISREG(sbuf.st_mode) + ) { + close(mailFd); + return; + } + if (line->cl_MailTo) + ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL); } +#else +# define EndJob(user, line) ((line)->cl_Pid = 0) +#endif /* - * CheckJobs() - check for job completion - * * Check for job completion, return number of jobs still running after * all done. */ @@ -855,55 +772,7 @@ static void RunJob(const char *user, CronLine *line) ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile); } -/* - * EndJob - called when job terminates and when mail terminates - */ -static void EndJob(const char *user, CronLine *line) -{ - int mailFd; - char mailFile[128]; - struct stat sbuf; - - /* No job */ - if (line->cl_Pid <= 0) { - line->cl_Pid = 0; - return; - } - - /* - * End of job and no mail file - * End of sendmail job - */ - snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, line->cl_Pid); - line->cl_Pid = 0; - - if (line->cl_MailFlag == 0) { - return; - } - line->cl_MailFlag = 0; - - /* - * End of primary job - check for mail file. If size has increased and - * the file is still valid, we sendmail it. - */ - mailFd = open(mailFile, O_RDONLY); - unlink(mailFile); - if (mailFd < 0) { - return; - } - - if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid - || sbuf.st_nlink != 0 || sbuf.st_size == line->cl_MailPos - || !S_ISREG(sbuf.st_mode) - ) { - close(mailFd); - return; - } - if (line->cl_MailTo) - ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL); -} - -#else /* crond without sendmail */ +#else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ static void RunJob(const char *user, CronLine *line) { @@ -943,4 +812,125 @@ static void RunJob(const char *user, CronLine *line) line->cl_Pid = pid; } -#endif /* ENABLE_FEATURE_CROND_CALL_SENDMAIL */ +#endif /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ + +static void RunJobs(void) +{ + CronFile *file; + CronLine *line; + + for (file = FileBase; file; file = file->cf_Next) { + if (!file->cf_Ready) + continue; + + file->cf_Ready = 0; + for (line = file->cf_LineBase; line; line = line->cl_Next) { + if (line->cl_Pid >= 0) + continue; + + RunJob(file->cf_User, line); + crondlog(LVL8 "USER %s pid %3d cmd %s", + file->cf_User, (int)line->cl_Pid, line->cl_Shell); + if (line->cl_Pid < 0) { + file->cf_Ready = 1; + } else if (line->cl_Pid > 0) { + file->cf_Running = 1; + } + } + } +} + +int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int crond_main(int argc UNUSED_PARAM, char **argv) +{ + time_t t2; + int rescan; + int sleep_time; + unsigned opts; + + INIT_G(); + + /* "-b after -f is ignored", and so on for every pair a-b */ + opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") + ":l+:d+"; /* -l and -d have numeric param */ + opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), + &LogLevel, &LogFile, &CDir + IF_FEATURE_CROND_D(,&LogLevel)); + /* both -d N and -l N set the same variable: LogLevel */ + + if (!(opts & OPT_f)) { + /* close stdin, stdout, stderr. + * close unused descriptors - don't need them. */ + bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); + } + + if (!(opts & OPT_d) && LogFile == NULL) { + /* logging to syslog */ + openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); + logmode = LOGMODE_SYSLOG; + } + + xchdir(CDir); + //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ + xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ + crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", LogLevel); + SynchronizeDir(); + write_pidfile("/var/run/crond.pid"); + + /* main loop - synchronize to 1 second after the minute, minimum sleep + * of 1 second. */ + t2 = time(NULL); + rescan = 60; + sleep_time = 60; + for (;;) { + time_t t1; + long dt; + + t1 = t2; + sleep((sleep_time + 1) - (time(NULL) % sleep_time)); + + t2 = time(NULL); + dt = (long)t2 - (long)t1; + + /* + * The file 'cron.update' is checked to determine new cron + * jobs. The directory is rescanned once an hour to deal + * with any screwups. + * + * Check for time jump. Disparities over an hour either way + * result in resynchronization. A negative disparity + * less than an hour causes us to effectively sleep until we + * match the original time (i.e. no re-execution of jobs that + * have just been run). A positive disparity less than + * an hour causes intermediate jobs to be run, but only once + * in the worst case. + * + * When running jobs, the inequality used is greater but not + * equal to t1, and less then or equal to t2. + */ + if (--rescan == 0) { + rescan = 60; + SynchronizeDir(); + } + CheckUpdates(); + if (DebugOpt) + crondlog(LVL5 "wakeup dt=%ld", dt); + if (dt < -60 * 60 || dt > 60 * 60) { + crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); + /* and we do not run any jobs in this case */ + } else if (dt > 0) { + /* Usual case: time advances forwad, as expected */ + TestJobs(t1, t2); + RunJobs(); + sleep(5); + if (CheckJobs() > 0) { + sleep_time = 10; + } else { + sleep_time = 60; + } + } + /* else: time jumped back, do not run any jobs */ + } /* for (;;) */ + + return 0; /* not reached */ +} -- cgit v1.2.3-55-g6feb From dfc870fab711b3ee85341f8cd8e7c8e0799d2da7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 8 Jul 2010 04:07:54 +0200 Subject: crond: check mtime on crontab dir every minute, and reread if changed function old new delta crond_main 1417 1460 +43 Signed-off-by: Denys Vlasenko --- miscutils/crond.c | 75 ++++++++++++++++++++++++++----------------------------- 1 file changed, 36 insertions(+), 39 deletions(-) diff --git a/miscutils/crond.c b/miscutils/crond.c index 06d72ced9..481830f4d 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c @@ -87,6 +87,7 @@ enum { struct globals { unsigned LogLevel; /* = 8; */ + time_t CDir_mtime; const char *LogFile; const char *CDir; /* = CRONTABS; */ CronFile *FileBase; @@ -96,15 +97,9 @@ struct globals { #endif } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) -#define LogLevel (G.LogLevel ) -#define LogFile (G.LogFile ) -#define CDir (G.CDir ) -#define FileBase (G.FileBase ) -#define env_var_user (G.env_var_user ) -#define env_var_home (G.env_var_home ) #define INIT_G() do { \ - LogLevel = 8; \ - CDir = CRONTABS; \ + G.LogLevel = 8; \ + G.CDir = CRONTABS; \ } while (0) @@ -124,12 +119,12 @@ static void crondlog(const char *ctl, ...) int level = (ctl[0] & 0x1f); va_start(va, ctl); - if (level >= (int)LogLevel) { + if (level >= (int)G.LogLevel) { /* Debug mode: all to (non-redirected) stderr, */ /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */ - if (!DebugOpt && LogFile) { + if (!DebugOpt && G.LogFile) { /* Otherwise (log to file): we reopen log file at every write: */ - int logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0666); + int logfd = open3_or_warn(G.LogFile, O_WRONLY | O_CREAT | O_APPEND, 0666); if (logfd >= 0) xmove_fd(logfd, STDERR_FILENO); } @@ -168,10 +163,10 @@ static void safe_setenv(char **pvar_val, const char *var, const char *val) static void SetEnv(struct passwd *pas) { #if SETENV_LEAKS - safe_setenv(&env_var_user, "USER", pas->pw_name); - safe_setenv(&env_var_home, "HOME", pas->pw_dir); + safe_setenv(&G.env_var_user, "USER", pas->pw_name); + safe_setenv(&G.env_var_home, "HOME", pas->pw_dir); /* if we want to set user's shell instead: */ - /*safe_setenv(env_var_shell, "SHELL", pas->pw_shell);*/ + /*safe_setenv(G.env_var_shell, "SHELL", pas->pw_shell);*/ #else xsetenv("USER", pas->pw_name); xsetenv("HOME", pas->pw_dir); @@ -308,7 +303,7 @@ static void ParseField(char *user, char *ary, int modvalue, int off, return; } - if (DebugOpt && (LogLevel <= 5)) { /* like LVL5 */ + if (DebugOpt && (G.LogLevel <= 5)) { /* like LVL5 */ /* can't use crondlog, it inserts '\n' */ int i; for (i = 0; i < modvalue; ++i) @@ -351,7 +346,7 @@ static void FixDayDow(CronLine *line) */ static void DeleteFile(const char *userName) { - CronFile **pfile = &FileBase; + CronFile **pfile = &G.FileBase; CronFile *file; while ((file = *pfile) != NULL) { @@ -462,8 +457,8 @@ static void SynchronizeFile(const char *fileName) } *pline = NULL; - file->cf_Next = FileBase; - FileBase = file; + file->cf_Next = G.FileBase; + G.FileBase = file; if (maxLines == 0) { crondlog(WARN9 "user %s: too many lines", fileName); @@ -493,7 +488,7 @@ static void SynchronizeDir(void) CronFile *file; /* Attempt to delete the database. */ again: - for (file = FileBase; file; file = file->cf_Next) { + for (file = G.FileBase; file; file = file->cf_Next) { if (!file->cf_Deleted) { DeleteFile(file->cf_User); goto again; @@ -509,8 +504,8 @@ static void SynchronizeDir(void) * scan directory and add associated users */ unlink(CRONUPDATE); - if (chdir(CDir) < 0) { - crondlog(DIE9 "chdir(%s)", CDir); + if (chdir(G.CDir) < 0) { + crondlog(DIE9 "chdir(%s)", G.CDir); } { DIR *dir = opendir("."); @@ -537,9 +532,8 @@ static void SynchronizeDir(void) * period is about a minute (one scan). Worst case it will be one * hour (60 scans). */ -static int TestJobs(time_t t1, time_t t2) +static void TestJobs(time_t t1, time_t t2) { - int nJobs = 0; time_t t; /* Find jobs > t1 and <= t2 */ @@ -553,7 +547,7 @@ static int TestJobs(time_t t1, time_t t2) continue; ptm = localtime(&t); - for (file = FileBase; file; file = file->cf_Next) { + for (file = G.FileBase; file; file = file->cf_Next) { if (DebugOpt) crondlog(LVL5 "file %s:", file->cf_User); if (file->cf_Deleted) @@ -575,13 +569,11 @@ static int TestJobs(time_t t1, time_t t2) } else if (line->cl_Pid == 0) { line->cl_Pid = -1; file->cf_Ready = 1; - ++nJobs; } } } } } - return nJobs; } #if ENABLE_FEATURE_CROND_CALL_SENDMAIL @@ -650,7 +642,7 @@ static int CheckJobs(void) CronLine *line; int nStillRunning = 0; - for (file = FileBase; file; file = file->cf_Next) { + for (file = G.FileBase; file; file = file->cf_Next) { if (file->cf_Running) { file->cf_Running = 0; @@ -819,7 +811,7 @@ static void RunJobs(void) CronFile *file; CronLine *line; - for (file = FileBase; file; file = file->cf_Next) { + for (file = G.FileBase; file; file = file->cf_Next) { if (!file->cf_Ready) continue; @@ -854,9 +846,9 @@ int crond_main(int argc UNUSED_PARAM, char **argv) opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") ":l+:d+"; /* -l and -d have numeric param */ opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), - &LogLevel, &LogFile, &CDir - IF_FEATURE_CROND_D(,&LogLevel)); - /* both -d N and -l N set the same variable: LogLevel */ + &G.LogLevel, &G.LogFile, &G.CDir + IF_FEATURE_CROND_D(,&G.LogLevel)); + /* both -d N and -l N set the same variable: G.LogLevel */ if (!(opts & OPT_f)) { /* close stdin, stdout, stderr. @@ -864,30 +856,32 @@ int crond_main(int argc UNUSED_PARAM, char **argv) bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); } - if (!(opts & OPT_d) && LogFile == NULL) { + if (!(opts & OPT_d) && G.LogFile == NULL) { /* logging to syslog */ openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); logmode = LOGMODE_SYSLOG; } - xchdir(CDir); + xchdir(G.CDir); //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ - crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", LogLevel); + crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", G.LogLevel); SynchronizeDir(); write_pidfile("/var/run/crond.pid"); - /* main loop - synchronize to 1 second after the minute, minimum sleep - * of 1 second. */ + /* Main loop */ t2 = time(NULL); rescan = 60; sleep_time = 60; for (;;) { + struct stat sbuf; time_t t1; long dt; t1 = t2; - sleep((sleep_time + 1) - (time(NULL) % sleep_time)); + + /* Synchronize to 1 minute, minimum 1 second */ + sleep(sleep_time - (time(NULL) % sleep_time) + 1); t2 = time(NULL); dt = (long)t2 - (long)t1; @@ -908,6 +902,10 @@ int crond_main(int argc UNUSED_PARAM, char **argv) * When running jobs, the inequality used is greater but not * equal to t1, and less then or equal to t2. */ + if (stat(G.CDir, &sbuf) == 0 && G.CDir_mtime != sbuf.st_mtime) { + G.CDir_mtime = sbuf.st_mtime; + rescan = 1; + } if (--rescan == 0) { rescan = 60; SynchronizeDir(); @@ -919,10 +917,9 @@ int crond_main(int argc UNUSED_PARAM, char **argv) crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); /* and we do not run any jobs in this case */ } else if (dt > 0) { - /* Usual case: time advances forwad, as expected */ + /* Usual case: time advances forward, as expected */ TestJobs(t1, t2); RunJobs(); - sleep(5); if (CheckJobs() > 0) { sleep_time = 10; } else { -- cgit v1.2.3-55-g6feb From 45963c873c4eb8d95ba327c9e21d5188d14f1fa4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 8 Jul 2010 15:37:10 +0200 Subject: crond: rename HumpBack names. Note two TODOs/FIXMEs Signed-off-by: Denys Vlasenko --- miscutils/crond.c | 633 +++++++++++++++++++++++++++--------------------------- 1 file changed, 322 insertions(+), 311 deletions(-) diff --git a/miscutils/crond.c b/miscutils/crond.c index 481830f4d..28722563c 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c @@ -40,33 +40,33 @@ typedef struct CronFile { - struct CronFile *cf_Next; - struct CronLine *cf_LineBase; - char *cf_User; /* username */ - smallint cf_Ready; /* bool: one or more jobs ready */ - smallint cf_Running; /* bool: one or more jobs running */ - smallint cf_Deleted; /* marked for deletion, ignore */ + struct CronFile *cf_next; + struct CronLine *cf_lines; + char *cf_username; + smallint cf_wants_starting; /* bool: one or more jobs ready */ + smallint cf_has_running; /* bool: one or more jobs running */ + smallint cf_deleted; /* marked for deletion (but still has running jobs) */ } CronFile; typedef struct CronLine { - struct CronLine *cl_Next; - char *cl_Shell; /* shell command */ - pid_t cl_Pid; /* running pid, 0, or armed (-1) */ + struct CronLine *cl_next; + char *cl_cmd; /* shell command */ + pid_t cl_pid; /* >0:running, <0:needs to be started in this minute, 0:dormant */ #if ENABLE_FEATURE_CROND_CALL_SENDMAIL - int cl_MailPos; /* 'empty file' size */ - char *cl_MailTo; /* whom to mail results */ - smallint cl_MailFlag; /* running pid is for mail */ + int cl_empty_mail_size; /* size of mail header only */ + char *cl_mailto; /* whom to mail results, may be NULL */ + smallint cl_mail_result; /* mail file is created, need to send it on completion */ #endif /* ordered by size, not in natural order. makes code smaller: */ - char cl_Dow[7]; /* 0-6, beginning sunday */ - char cl_Mons[12]; /* 0-11 */ - char cl_Hrs[24]; /* 0-23 */ - char cl_Days[32]; /* 1-31 */ - char cl_Mins[60]; /* 0-59 */ + char cl_Dow[7]; /* 0-6, beginning sunday */ + char cl_Mons[12]; /* 0-11 */ + char cl_Hrs[24]; /* 0-23 */ + char cl_Days[32]; /* 1-31 */ + char cl_Mins[60]; /* 0-59 */ } CronLine; -#define DaemonUid 0 +#define DAEMON_UID 0 enum { @@ -79,18 +79,18 @@ enum { OPT_d = (1 << 6) * ENABLE_FEATURE_CROND_D, }; #if ENABLE_FEATURE_CROND_D -#define DebugOpt (option_mask32 & OPT_d) +# define DebugOpt (option_mask32 & OPT_d) #else -#define DebugOpt 0 +# define DebugOpt 0 #endif struct globals { - unsigned LogLevel; /* = 8; */ - time_t CDir_mtime; - const char *LogFile; - const char *CDir; /* = CRONTABS; */ - CronFile *FileBase; + unsigned log_level; /* = 8; */ + time_t crontab_dir_mtime; + const char *log_filename; + const char *crontab_dir_name; /* = CRONTABS; */ + CronFile *cron_files; #if SETENV_LEAKS char *env_var_user; char *env_var_home; @@ -98,8 +98,8 @@ struct globals { } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { \ - G.LogLevel = 8; \ - G.CDir = CRONTABS; \ + G.log_level = 8; \ + G.crontab_dir_name = CRONTABS; \ } while (0) @@ -119,12 +119,12 @@ static void crondlog(const char *ctl, ...) int level = (ctl[0] & 0x1f); va_start(va, ctl); - if (level >= (int)G.LogLevel) { + if (level >= (int)G.log_level) { /* Debug mode: all to (non-redirected) stderr, */ /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */ - if (!DebugOpt && G.LogFile) { + if (!DebugOpt && G.log_filename) { /* Otherwise (log to file): we reopen log file at every write: */ - int logfd = open3_or_warn(G.LogFile, O_WRONLY | O_CREAT | O_APPEND, 0666); + int logfd = open3_or_warn(G.log_filename, O_WRONLY | O_CREAT | O_APPEND, 0666); if (logfd >= 0) xmove_fd(logfd, STDERR_FILENO); } @@ -144,49 +144,6 @@ static void crondlog(const char *ctl, ...) exit(20); } -#if SETENV_LEAKS -/* We set environment *before* vfork (because we want to use vfork), - * so we cannot use setenv() - repeated calls to setenv() may leak memory! - * Using putenv(), and freeing memory after unsetenv() won't leak */ -static void safe_setenv(char **pvar_val, const char *var, const char *val) -{ - char *var_val = *pvar_val; - - if (var_val) { - bb_unsetenv_and_free(var_val); - } - *pvar_val = xasprintf("%s=%s", var, val); - putenv(*pvar_val); -} -#endif - -static void SetEnv(struct passwd *pas) -{ -#if SETENV_LEAKS - safe_setenv(&G.env_var_user, "USER", pas->pw_name); - safe_setenv(&G.env_var_home, "HOME", pas->pw_dir); - /* if we want to set user's shell instead: */ - /*safe_setenv(G.env_var_shell, "SHELL", pas->pw_shell);*/ -#else - xsetenv("USER", pas->pw_name); - xsetenv("HOME", pas->pw_dir); -#endif - /* currently, we use constant one: */ - /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */ -} - -static void ChangeUser(struct passwd *pas) -{ - /* careful: we're after vfork! */ - change_identity(pas); /* - initgroups, setgid, setuid */ - if (chdir(pas->pw_dir) < 0) { - crondlog(WARN9 "chdir(%s)", pas->pw_dir); - if (chdir(TMPDIR) < 0) { - crondlog(DIE9 "chdir(%s)", TMPDIR); /* exits */ - } - } -} - static const char DowAry[] ALIGN1 = "sun""mon""tue""wed""thu""fri""sat" /* "Sun""Mon""Tue""Wed""Thu""Fri""Sat" */ @@ -303,7 +260,7 @@ static void ParseField(char *user, char *ary, int modvalue, int off, return; } - if (DebugOpt && (G.LogLevel <= 5)) { /* like LVL5 */ + if (DebugOpt && (G.log_level <= 5)) { /* like LVL5 */ /* can't use crondlog, it inserts '\n' */ int i; for (i = 0; i < modvalue; ++i) @@ -339,48 +296,57 @@ static void FixDayDow(CronLine *line) } /* - * DeleteFile() - delete user database + * delete_cronfile() - delete user database * * Note: multiple entries for same user may exist if we were unable to * completely delete a database due to running processes. */ -static void DeleteFile(const char *userName) +//FIXME: we will start a new job even if the old job is running +//if crontab was reloaded: crond thinks that "new" job is different from "old" +//even if they are in fact completely the same. Example +//Crontab was: +// 0-59 * * * job1 +// 0-59 * * * long_running_job2 +//User edits crontab to: +// 0-59 * * * job1_updated +// 0-59 * * * long_running_job2 +//Bug: crond can now start another long_running_job2 even if old one +//is still running. +static void delete_cronfile(const char *userName) { - CronFile **pfile = &G.FileBase; + CronFile **pfile = &G.cron_files; CronFile *file; while ((file = *pfile) != NULL) { - if (strcmp(userName, file->cf_User) == 0) { - CronLine **pline = &file->cf_LineBase; + if (strcmp(userName, file->cf_username) == 0) { + CronLine **pline = &file->cf_lines; CronLine *line; - file->cf_Running = 0; - file->cf_Deleted = 1; + file->cf_has_running = 0; + file->cf_deleted = 1; while ((line = *pline) != NULL) { - if (line->cl_Pid > 0) { - file->cf_Running = 1; - pline = &line->cl_Next; + if (line->cl_pid > 0) { + file->cf_has_running = 1; + pline = &line->cl_next; } else { - *pline = line->cl_Next; - free(line->cl_Shell); + *pline = line->cl_next; + free(line->cl_cmd); free(line); } } - if (file->cf_Running == 0) { - *pfile = file->cf_Next; - free(file->cf_User); + if (file->cf_has_running == 0) { + *pfile = file->cf_next; + free(file->cf_username); free(file); - } else { - pfile = &file->cf_Next; + continue; } - } else { - pfile = &file->cf_Next; } + pfile = &file->cf_next; } } -static void SynchronizeFile(const char *fileName) +static void load_crontab(const char *fileName) { struct parser_t *parser; struct stat sbuf; @@ -390,23 +356,26 @@ static void SynchronizeFile(const char *fileName) char *mailTo = NULL; #endif - if (!fileName) + delete_cronfile(fileName); + + if (!getpwnam(fileName)) { + crondlog(LVL7 "ignoring file '%s' (no such user)", fileName); return; + } - DeleteFile(fileName); parser = config_open(fileName); if (!parser) return; maxLines = (strcmp(fileName, "root") == 0) ? 65535 : MAXLINES; - if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DaemonUid) { + if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DAEMON_UID) { CronFile *file = xzalloc(sizeof(CronFile)); CronLine **pline; int n; - file->cf_User = xstrdup(fileName); - pline = &file->cf_LineBase; + file->cf_username = xstrdup(fileName); + pline = &file->cf_lines; while (1) { CronLine *line; @@ -433,11 +402,11 @@ static void SynchronizeFile(const char *fileName) continue; *pline = line = xzalloc(sizeof(*line)); /* parse date ranges */ - ParseField(file->cf_User, line->cl_Mins, 60, 0, NULL, tokens[0]); - ParseField(file->cf_User, line->cl_Hrs, 24, 0, NULL, tokens[1]); - ParseField(file->cf_User, line->cl_Days, 32, 0, NULL, tokens[2]); - ParseField(file->cf_User, line->cl_Mons, 12, -1, MonAry, tokens[3]); - ParseField(file->cf_User, line->cl_Dow, 7, 0, DowAry, tokens[4]); + ParseField(file->cf_username, line->cl_Mins, 60, 0, NULL, tokens[0]); + ParseField(file->cf_username, line->cl_Hrs, 24, 0, NULL, tokens[1]); + ParseField(file->cf_username, line->cl_Days, 32, 0, NULL, tokens[2]); + ParseField(file->cf_username, line->cl_Mons, 12, -1, MonAry, tokens[3]); + ParseField(file->cf_username, line->cl_Dow, 7, 0, DowAry, tokens[4]); /* * fix days and dow - if one is not "*" and the other * is "*", the other is set to 0, and vise-versa @@ -445,20 +414,20 @@ static void SynchronizeFile(const char *fileName) FixDayDow(line); #if ENABLE_FEATURE_CROND_CALL_SENDMAIL /* copy mailto (can be NULL) */ - line->cl_MailTo = xstrdup(mailTo); + line->cl_mailto = xstrdup(mailTo); #endif /* copy command */ - line->cl_Shell = xstrdup(tokens[5]); + line->cl_cmd = xstrdup(tokens[5]); if (DebugOpt) { crondlog(LVL5 " command:%s", tokens[5]); } - pline = &line->cl_Next; + pline = &line->cl_next; //bb_error_msg("M[%s]F[%s][%s][%s][%s][%s][%s]", mailTo, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]); } *pline = NULL; - file->cf_Next = G.FileBase; - G.FileBase = file; + file->cf_next = G.cron_files; + G.cron_files = file; if (maxLines == 0) { crondlog(WARN9 "user %s: too many lines", fileName); @@ -467,7 +436,7 @@ static void SynchronizeFile(const char *fileName) config_close(parser); } -static void CheckUpdates(void) +static void process_cron_update_file(void) { FILE *fi; char buf[256]; @@ -477,36 +446,34 @@ static void CheckUpdates(void) unlink(CRONUPDATE); while (fgets(buf, sizeof(buf), fi) != NULL) { /* use first word only */ - SynchronizeFile(strtok(buf, " \t\r\n")); + skip_non_whitespace(buf)[0] = '\0'; + load_crontab(buf); } fclose(fi); } } -static void SynchronizeDir(void) +static void rescan_crontab_dir(void) { CronFile *file; - /* Attempt to delete the database. */ + + /* Delete all files until we only have ones with running jobs (or none) */ again: - for (file = G.FileBase; file; file = file->cf_Next) { - if (!file->cf_Deleted) { - DeleteFile(file->cf_User); + for (file = G.cron_files; file; file = file->cf_next) { + if (!file->cf_deleted) { + delete_cronfile(file->cf_username); goto again; } } - /* - * Remove cron update file - * - * Re-chdir, in case directory was renamed & deleted, or otherwise - * screwed up. - * - * scan directory and add associated users - */ + /* Remove cron update file */ unlink(CRONUPDATE); - if (chdir(G.CDir) < 0) { - crondlog(DIE9 "chdir(%s)", G.CDir); + /* Re-chdir, in case directory was renamed & deleted */ + if (chdir(G.crontab_dir_name) < 0) { + crondlog(DIE9 "chdir(%s)", G.crontab_dir_name); } + + /* Scan directory and add associated users */ { DIR *dir = opendir("."); struct dirent *den; @@ -517,162 +484,62 @@ static void SynchronizeDir(void) if (strchr(den->d_name, '.') != NULL) { continue; } - if (getpwnam(den->d_name)) { - SynchronizeFile(den->d_name); - } else { - crondlog(LVL7 "ignoring %s", den->d_name); - } + load_crontab(den->d_name); } closedir(dir); } } -/* - * Determine which jobs need to be run. Under normal conditions, the - * period is about a minute (one scan). Worst case it will be one - * hour (60 scans). - */ -static void TestJobs(time_t t1, time_t t2) +#if SETENV_LEAKS +/* We set environment *before* vfork (because we want to use vfork), + * so we cannot use setenv() - repeated calls to setenv() may leak memory! + * Using putenv(), and freeing memory after unsetenv() won't leak */ +static void safe_setenv(char **pvar_val, const char *var, const char *val) { - time_t t; - - /* Find jobs > t1 and <= t2 */ - - for (t = t1 - t1 % 60; t <= t2; t += 60) { - struct tm *ptm; - CronFile *file; - CronLine *line; - - if (t <= t1) - continue; + char *var_val = *pvar_val; - ptm = localtime(&t); - for (file = G.FileBase; file; file = file->cf_Next) { - if (DebugOpt) - crondlog(LVL5 "file %s:", file->cf_User); - if (file->cf_Deleted) - continue; - for (line = file->cf_LineBase; line; line = line->cl_Next) { - if (DebugOpt) - crondlog(LVL5 " line %s", line->cl_Shell); - if (line->cl_Mins[ptm->tm_min] && line->cl_Hrs[ptm->tm_hour] - && (line->cl_Days[ptm->tm_mday] || line->cl_Dow[ptm->tm_wday]) - && line->cl_Mons[ptm->tm_mon] - ) { - if (DebugOpt) { - crondlog(LVL5 " job: %d %s", - (int)line->cl_Pid, line->cl_Shell); - } - if (line->cl_Pid > 0) { - crondlog(LVL8 "user %s: process already running: %s", - file->cf_User, line->cl_Shell); - } else if (line->cl_Pid == 0) { - line->cl_Pid = -1; - file->cf_Ready = 1; - } - } - } - } + if (var_val) { + bb_unsetenv_and_free(var_val); } + *pvar_val = xasprintf("%s=%s", var, val); + putenv(*pvar_val); } +#endif -#if ENABLE_FEATURE_CROND_CALL_SENDMAIL -static void -ForkJob(const char *user, CronLine *line, int mailFd, - const char *prog, const char *cmd, const char *arg, - const char *mail_filename); -/* - * EndJob - called when job terminates and when mail terminates - */ -static void EndJob(const char *user, CronLine *line) +static void set_env_vars(struct passwd *pas) { - int mailFd; - char mailFile[128]; - struct stat sbuf; - - /* No job */ - if (line->cl_Pid <= 0) { - line->cl_Pid = 0; - return; - } - - /* - * End of job and no mail file - * End of sendmail job - */ - snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, line->cl_Pid); - line->cl_Pid = 0; - - if (line->cl_MailFlag == 0) { - return; - } - line->cl_MailFlag = 0; - - /* - * End of primary job - check for mail file. If size has increased and - * the file is still valid, we sendmail it. - */ - mailFd = open(mailFile, O_RDONLY); - unlink(mailFile); - if (mailFd < 0) { - return; - } - - if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid - || sbuf.st_nlink != 0 || sbuf.st_size == line->cl_MailPos - || !S_ISREG(sbuf.st_mode) - ) { - close(mailFd); - return; - } - if (line->cl_MailTo) - ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL); -} +#if SETENV_LEAKS + safe_setenv(&G.env_var_user, "USER", pas->pw_name); + safe_setenv(&G.env_var_home, "HOME", pas->pw_dir); + /* if we want to set user's shell instead: */ + /*safe_setenv(G.env_var_shell, "SHELL", pas->pw_shell);*/ #else -# define EndJob(user, line) ((line)->cl_Pid = 0) + xsetenv("USER", pas->pw_name); + xsetenv("HOME", pas->pw_dir); #endif + /* currently, we use constant one: */ + /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */ +} -/* - * Check for job completion, return number of jobs still running after - * all done. - */ -static int CheckJobs(void) +static void change_user(struct passwd *pas) { - CronFile *file; - CronLine *line; - int nStillRunning = 0; - - for (file = G.FileBase; file; file = file->cf_Next) { - if (file->cf_Running) { - file->cf_Running = 0; - - for (line = file->cf_LineBase; line; line = line->cl_Next) { - int status, r; - if (line->cl_Pid <= 0) - continue; - - r = waitpid(line->cl_Pid, &status, WNOHANG); - if (r < 0 || r == line->cl_Pid) { - EndJob(file->cf_User, line); - if (line->cl_Pid) { - file->cf_Running = 1; - } - } else if (r == 0) { - file->cf_Running = 1; - } - } + /* careful: we're after vfork! */ + change_identity(pas); /* - initgroups, setgid, setuid */ + if (chdir(pas->pw_dir) < 0) { + crondlog(WARN9 "chdir(%s)", pas->pw_dir); + if (chdir(TMPDIR) < 0) { + crondlog(DIE9 "chdir(%s)", TMPDIR); /* exits */ } - nStillRunning += file->cf_Running; } - return nStillRunning; } -#if ENABLE_FEATURE_CROND_CALL_SENDMAIL - // TODO: sendmail should be _run-time_ option, not compile-time! +#if ENABLE_FEATURE_CROND_CALL_SENDMAIL +//TODO: return pid (and stop passing line); +// stop passing mail_filename here but process it in caller static void -ForkJob(const char *user, CronLine *line, int mailFd, +fork_job(const char *user, CronLine *line, int mailFd, const char *prog, const char *cmd, const char *arg, const char *mail_filename) { @@ -685,13 +552,13 @@ ForkJob(const char *user, CronLine *line, int mailFd, crondlog(WARN9 "can't get uid for %s", user); goto err; } - SetEnv(pas); + set_env_vars(pas); pid = vfork(); if (pid == 0) { /* CHILD */ - /* change running state to the user in question */ - ChangeUser(pas); + /* initgroups, setgid, setuid, and chdir to home or TMPDIR */ + change_user(pas); if (DebugOpt) { crondlog(LVL5 "child running %s", prog); } @@ -709,12 +576,12 @@ ForkJob(const char *user, CronLine *line, int mailFd, _exit(EXIT_SUCCESS); } - line->cl_Pid = pid; + line->cl_pid = pid; if (pid < 0) { /* FORK FAILED */ crondlog(ERR20 "can't vfork"); err: - line->cl_Pid = 0; + line->cl_pid = 0; if (mail_filename) { unlink(mail_filename); } @@ -737,62 +604,108 @@ ForkJob(const char *user, CronLine *line, int mailFd, } } -static void RunJob(const char *user, CronLine *line) +static void start_one_job(const char *user, CronLine *line) { char mailFile[128]; int mailFd = -1; - line->cl_Pid = 0; - line->cl_MailFlag = 0; + line->cl_pid = 0; + line->cl_mail_result = 0; - if (line->cl_MailTo) { - /* open mail file - owner root so nobody can screw with it. */ + if (line->cl_mailto) { + /* Open mail file (owner is root so nobody can screw with it) */ snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, getpid()); mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600); if (mailFd >= 0) { - line->cl_MailFlag = 1; - fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", line->cl_MailTo, - line->cl_Shell); - line->cl_MailPos = lseek(mailFd, 0, SEEK_CUR); + line->cl_mail_result = 1; + fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", line->cl_mailto, + line->cl_cmd); + line->cl_empty_mail_size = lseek(mailFd, 0, SEEK_CUR); } else { crondlog(ERR20 "can't create mail file %s for user %s, " "discarding output", mailFile, user); } } - ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile); + fork_job(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_cmd, mailFile); +} + +/* + * process_finished_job - called when job terminates and when mail terminates + */ +static void process_finished_job(const char *user, CronLine *line) +{ + pid_t pid; + int mailFd; + char mailFile[128]; + struct stat sbuf; + + pid = line->cl_pid; + line->cl_pid = 0; + if (pid <= 0) { + /* No job */ + return; + } + if (line->cl_mail_result == 0) { + /* End of job and no mail file, or end of sendmail job */ + return; + } + line->cl_mail_result = 0; + + /* + * End of primary job - check for mail file. + * If size has changed and the file is still valid, we send it. + */ + snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, (int)pid); + mailFd = open(mailFile, O_RDONLY); + unlink(mailFile); + if (mailFd < 0) { + return; + } + + if (fstat(mailFd, &sbuf) < 0 + || sbuf.st_uid != DAEMON_UID + || sbuf.st_nlink != 0 + || sbuf.st_size == line->cl_empty_mail_size + || !S_ISREG(sbuf.st_mode) + ) { + close(mailFd); + return; + } + /* if (line->cl_mailto) - always true if cl_mail_result was true */ + fork_job(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL); } #else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ -static void RunJob(const char *user, CronLine *line) +static void start_one_job(const char *user, CronLine *line) { struct passwd *pas; pid_t pid; - /* prepare things before vfork */ pas = getpwnam(user); if (!pas) { crondlog(WARN9 "can't get uid for %s", user); goto err; } - SetEnv(pas); - /* fork as the user in question and run program */ + /* Prepare things before vfork */ + set_env_vars(pas); + + /* Fork as the user in question and run program */ pid = vfork(); if (pid == 0) { /* CHILD */ - /* change running state to the user in question */ - ChangeUser(pas); + /* initgroups, setgid, setuid, and chdir to home or TMPDIR */ + change_user(pas); if (DebugOpt) { crondlog(LVL5 "child running %s", DEFAULT_SHELL); } /* crond 3.0pl1-100 puts tasks in separate process groups */ bb_setpgrp(); - execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, (char *) NULL); - crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, - DEFAULT_SHELL, "-c", line->cl_Shell); + execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_cmd, (char *) NULL); + crondlog(ERR20 "can't execute '%s' for user %s", DEFAULT_SHELL, user); _exit(EXIT_SUCCESS); } if (pid < 0) { @@ -801,35 +714,130 @@ static void RunJob(const char *user, CronLine *line) err: pid = 0; } - line->cl_Pid = pid; + line->cl_pid = pid; } +#define process_finished_job(user, line) ((line)->cl_pid = 0) + #endif /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ -static void RunJobs(void) +/* + * Determine which jobs need to be run. Under normal conditions, the + * period is about a minute (one scan). Worst case it will be one + * hour (60 scans). + */ +static void flag_starting_jobs(time_t t1, time_t t2) +{ + time_t t; + + /* Find jobs > t1 and <= t2 */ + + for (t = t1 - t1 % 60; t <= t2; t += 60) { + struct tm *ptm; + CronFile *file; + CronLine *line; + + if (t <= t1) + continue; + + ptm = localtime(&t); + for (file = G.cron_files; file; file = file->cf_next) { + if (DebugOpt) + crondlog(LVL5 "file %s:", file->cf_username); + if (file->cf_deleted) + continue; + for (line = file->cf_lines; line; line = line->cl_next) { + if (DebugOpt) + crondlog(LVL5 " line %s", line->cl_cmd); + if (line->cl_Mins[ptm->tm_min] + && line->cl_Hrs[ptm->tm_hour] + && (line->cl_Days[ptm->tm_mday] || line->cl_Dow[ptm->tm_wday]) + && line->cl_Mons[ptm->tm_mon] + ) { + if (DebugOpt) { + crondlog(LVL5 " job: %d %s", + (int)line->cl_pid, line->cl_cmd); + } + if (line->cl_pid > 0) { + crondlog(LVL8 "user %s: process already running: %s", + file->cf_username, line->cl_cmd); + } else if (line->cl_pid == 0) { + line->cl_pid = -1; + file->cf_wants_starting = 1; + } + } + } + } + } +} + +static void start_jobs(void) { CronFile *file; CronLine *line; - for (file = G.FileBase; file; file = file->cf_Next) { - if (!file->cf_Ready) + for (file = G.cron_files; file; file = file->cf_next) { + if (!file->cf_wants_starting) continue; - file->cf_Ready = 0; - for (line = file->cf_LineBase; line; line = line->cl_Next) { - if (line->cl_Pid >= 0) + file->cf_wants_starting = 0; + for (line = file->cf_lines; line; line = line->cl_next) { + pid_t pid; + if (line->cl_pid >= 0) continue; - RunJob(file->cf_User, line); + start_one_job(file->cf_username, line); + pid = line->cl_pid; crondlog(LVL8 "USER %s pid %3d cmd %s", - file->cf_User, (int)line->cl_Pid, line->cl_Shell); - if (line->cl_Pid < 0) { - file->cf_Ready = 1; - } else if (line->cl_Pid > 0) { - file->cf_Running = 1; + file->cf_username, (int)pid, line->cl_cmd); + if (pid < 0) { + file->cf_wants_starting = 1; + } + if (pid > 0) { + file->cf_has_running = 1; + } + } + } +} + +/* + * Check for job completion, return number of jobs still running after + * all done. + */ +static int check_completions(void) +{ + CronFile *file; + CronLine *line; + int num_still_running = 0; + + for (file = G.cron_files; file; file = file->cf_next) { + if (!file->cf_has_running) + continue; + + file->cf_has_running = 0; + for (line = file->cf_lines; line; line = line->cl_next) { + int r; + + if (line->cl_pid <= 0) + continue; + + r = waitpid(line->cl_pid, NULL, WNOHANG); + if (r < 0 || r == line->cl_pid) { + process_finished_job(file->cf_username, line); + if (line->cl_pid == 0) { + /* sendmail was not started for it */ + continue; + } + /* else: sendmail was started, job is still running, fall thru */ } + /* else: r == 0: "process is still running" */ + file->cf_has_running = 1; } +//FIXME: if !file->cf_has_running && file->deleted: delete it! +//otherwise deleted entries will stay forever, right? + num_still_running += file->cf_has_running; } + return num_still_running; } int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -846,9 +854,9 @@ int crond_main(int argc UNUSED_PARAM, char **argv) opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") ":l+:d+"; /* -l and -d have numeric param */ opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), - &G.LogLevel, &G.LogFile, &G.CDir - IF_FEATURE_CROND_D(,&G.LogLevel)); - /* both -d N and -l N set the same variable: G.LogLevel */ + &G.log_level, &G.log_filename, &G.crontab_dir_name + IF_FEATURE_CROND_D(,&G.log_level)); + /* both -d N and -l N set the same variable: G.log_level */ if (!(opts & OPT_f)) { /* close stdin, stdout, stderr. @@ -856,17 +864,17 @@ int crond_main(int argc UNUSED_PARAM, char **argv) bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); } - if (!(opts & OPT_d) && G.LogFile == NULL) { + if (!(opts & OPT_d) && G.log_filename == NULL) { /* logging to syslog */ openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); logmode = LOGMODE_SYSLOG; } - xchdir(G.CDir); + xchdir(G.crontab_dir_name); //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ - crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", G.LogLevel); - SynchronizeDir(); + crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", G.log_level); + rescan_crontab_dir(); write_pidfile("/var/run/crond.pid"); /* Main loop */ @@ -902,15 +910,17 @@ int crond_main(int argc UNUSED_PARAM, char **argv) * When running jobs, the inequality used is greater but not * equal to t1, and less then or equal to t2. */ - if (stat(G.CDir, &sbuf) == 0 && G.CDir_mtime != sbuf.st_mtime) { - G.CDir_mtime = sbuf.st_mtime; + if (stat(G.crontab_dir_name, &sbuf) != 0) + sbuf.st_mtime = 0; /* force update (once) if dir was deleted */ + if (G.crontab_dir_mtime != sbuf.st_mtime) { + G.crontab_dir_mtime = sbuf.st_mtime; rescan = 1; } if (--rescan == 0) { rescan = 60; - SynchronizeDir(); + rescan_crontab_dir(); } - CheckUpdates(); + process_cron_update_file(); if (DebugOpt) crondlog(LVL5 "wakeup dt=%ld", dt); if (dt < -60 * 60 || dt > 60 * 60) { @@ -918,9 +928,10 @@ int crond_main(int argc UNUSED_PARAM, char **argv) /* and we do not run any jobs in this case */ } else if (dt > 0) { /* Usual case: time advances forward, as expected */ - TestJobs(t1, t2); - RunJobs(); - if (CheckJobs() > 0) { + flag_starting_jobs(t1, t2); + start_jobs(); + if (check_completions() > 0) { + /* some jobs are still running */ sleep_time = 10; } else { sleep_time = 60; -- cgit v1.2.3-55-g6feb From 1f0ab1dc6427e9340f50551d9e4f2212d03ec845 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 8 Jul 2010 16:12:10 +0200 Subject: crond: code shrink function old new delta crond_main 1431 1472 +41 fork_job 457 389 -68 Signed-off-by: Denys Vlasenko --- miscutils/crond.c | 67 +++++++++++++++++++++++++------------------------------ 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/miscutils/crond.c b/miscutils/crond.c index 28722563c..a459c6a8c 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c @@ -29,7 +29,7 @@ # define SENDMAIL "sendmail" #endif #ifndef SENDMAIL_ARGS -# define SENDMAIL_ARGS "-ti", NULL +# define SENDMAIL_ARGS "-ti" #endif #ifndef CRONUPDATE # define CRONUPDATE "cron.update" @@ -53,9 +53,8 @@ typedef struct CronLine { char *cl_cmd; /* shell command */ pid_t cl_pid; /* >0:running, <0:needs to be started in this minute, 0:dormant */ #if ENABLE_FEATURE_CROND_CALL_SENDMAIL - int cl_empty_mail_size; /* size of mail header only */ + int cl_empty_mail_size; /* size of mail header only, 0 if no mailfile */ char *cl_mailto; /* whom to mail results, may be NULL */ - smallint cl_mail_result; /* mail file is created, need to send it on completion */ #endif /* ordered by size, not in natural order. makes code smaller: */ char cl_Dow[7]; /* 0-6, beginning sunday */ @@ -536,13 +535,11 @@ static void change_user(struct passwd *pas) // TODO: sendmail should be _run-time_ option, not compile-time! #if ENABLE_FEATURE_CROND_CALL_SENDMAIL -//TODO: return pid (and stop passing line); -// stop passing mail_filename here but process it in caller -static void -fork_job(const char *user, CronLine *line, int mailFd, - const char *prog, const char *cmd, const char *arg, - const char *mail_filename) -{ +static pid_t +fork_job(const char *user, int mailFd, + const char *prog, + const char *shell_cmd /* if NULL, we run sendmail */ +) { struct passwd *pas; pid_t pid; @@ -563,37 +560,25 @@ fork_job(const char *user, CronLine *line, int mailFd, crondlog(LVL5 "child running %s", prog); } if (mailFd >= 0) { - xmove_fd(mailFd, mail_filename ? 1 : 0); + xmove_fd(mailFd, shell_cmd ? 1 : 0); dup2(1, 2); } /* crond 3.0pl1-100 puts tasks in separate process groups */ bb_setpgrp(); - execlp(prog, prog, cmd, arg, (char *) NULL); - crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, prog, cmd, arg); - if (mail_filename) { - fdprintf(1, "Exec failed: %s -c %s\n", prog, arg); + execlp(prog, prog, (shell_cmd ? "-c" : SENDMAIL_ARGS), shell_cmd, (char *) NULL); + crondlog(ERR20 "can't execute '%s' for user %s", prog, user); + if (shell_cmd) { + fdprintf(1, "Exec failed: %s -c %s\n", prog, shell_cmd); } _exit(EXIT_SUCCESS); } - line->cl_pid = pid; if (pid < 0) { /* FORK FAILED */ crondlog(ERR20 "can't vfork"); err: - line->cl_pid = 0; - if (mail_filename) { - unlink(mail_filename); - } - } else { - /* PARENT, FORK SUCCESS */ - if (mail_filename) { - /* rename mail-file based on pid of process */ - char *mailFile2 = xasprintf("%s/cron.%s.%d", TMPDIR, user, (int)pid); - rename(mail_filename, mailFile2); // TODO: xrename? - free(mailFile2); - } - } + pid = 0; + } /* else: PARENT, FORK SUCCESS */ /* * Close the mail file descriptor.. we can't just leave it open in @@ -602,6 +587,7 @@ fork_job(const char *user, CronLine *line, int mailFd, if (mailFd >= 0) { close(mailFd); } + return pid; } static void start_one_job(const char *user, CronLine *line) @@ -610,7 +596,7 @@ static void start_one_job(const char *user, CronLine *line) int mailFd = -1; line->cl_pid = 0; - line->cl_mail_result = 0; + line->cl_empty_mail_size = 0; if (line->cl_mailto) { /* Open mail file (owner is root so nobody can screw with it) */ @@ -618,7 +604,6 @@ static void start_one_job(const char *user, CronLine *line) mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600); if (mailFd >= 0) { - line->cl_mail_result = 1; fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", line->cl_mailto, line->cl_cmd); line->cl_empty_mail_size = lseek(mailFd, 0, SEEK_CUR); @@ -628,7 +613,17 @@ static void start_one_job(const char *user, CronLine *line) } } - fork_job(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_cmd, mailFile); + line->cl_pid = fork_job(user, mailFd, DEFAULT_SHELL, line->cl_cmd); + if (mailFd >= 0) { + if (line->cl_pid <= 0) { + unlink(mailFile); + } else { + /* rename mail-file based on pid of process */ + char *mailFile2 = xasprintf("%s/cron.%s.%d", TMPDIR, user, (int)line->cl_pid); + rename(mailFile, mailFile2); // TODO: xrename? + free(mailFile2); + } + } } /* @@ -647,11 +642,10 @@ static void process_finished_job(const char *user, CronLine *line) /* No job */ return; } - if (line->cl_mail_result == 0) { + if (line->cl_empty_mail_size <= 0) { /* End of job and no mail file, or end of sendmail job */ return; } - line->cl_mail_result = 0; /* * End of primary job - check for mail file. @@ -673,8 +667,9 @@ static void process_finished_job(const char *user, CronLine *line) close(mailFd); return; } - /* if (line->cl_mailto) - always true if cl_mail_result was true */ - fork_job(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL); + line->cl_empty_mail_size = 0; + /* if (line->cl_mailto) - always true if cl_empty_mail_size was nonzero */ + line->cl_pid = fork_job(user, mailFd, SENDMAIL, NULL); } #else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ -- cgit v1.2.3-55-g6feb From 1883cb174619cfc90ca86da08598f470d3a11315 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 9 Jul 2010 01:25:36 +0200 Subject: fix make O=dir build Signed-off-by: Denys Vlasenko --- scripts/Makefile.build | 7 ++++++- scripts/gen_build_files.sh | 7 ++++++- scripts/test_make_O | 11 +++++++++++ 3 files changed, 23 insertions(+), 2 deletions(-) create mode 100755 scripts/test_make_O diff --git a/scripts/Makefile.build b/scripts/Makefile.build index f343818b1..5685b5bcc 100644 --- a/scripts/Makefile.build +++ b/scripts/Makefile.build @@ -13,8 +13,13 @@ __build: include scripts/Kbuild.include # The filename Kbuild has precedence over Makefile +# bbox: we also try to include Kbuild file in obj tree first kbuild-dir := $(if $(filter /%,$(src)),$(src),$(srctree)/$(src)) -include $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, $(kbuild-dir)/Makefile) +include $(if $(wildcard $(src)/Kbuild), $(src)/Kbuild, \ + $(if $(wildcard $(kbuild-dir)/Kbuild), $(kbuild-dir)/Kbuild, \ + $(kbuild-dir)/Makefile \ + ) \ + ) include scripts/Makefile.lib diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index a98f509ce..968158758 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh @@ -4,6 +4,8 @@ test $# -ge 2 || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; } # cd to objtree cd -- "$2" || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; } +# In separate objtree build, include/ might not exist yet +mkdir include 2>/dev/null srctree="$1" @@ -46,10 +48,12 @@ if test x"$new" != x"$old"; then fi # (Re)generate */Kbuild and */Config.in -find -type d | while read -r d; do +{ cd -- "$srctree" && find -type d; } | while read -r d; do d="${d#./}" + src="$srctree/$d/Kbuild.src" dst="$d/Kbuild" + mkdir -p -- "$d" 2>/dev/null if test -f "$src"; then #echo " CHK $dst" @@ -69,6 +73,7 @@ find -type d | while read -r d; do src="$srctree/$d/Config.src" dst="$d/Config.in" + mkdir -p -- "$d" 2>/dev/null if test -f "$src"; then #echo " CHK $dst" diff --git a/scripts/test_make_O b/scripts/test_make_O new file mode 100755 index 000000000..a0ee6a868 --- /dev/null +++ b/scripts/test_make_O @@ -0,0 +1,11 @@ +#!/bin/sh + +b=`basename $PWD` +test "${b#busybox}" != "$b" || { echo "Must be run in busybox tree"; exit 1; } + +rm -rf ../testdir_make_O.$$ +mkdir ../testdir_make_O.$$ +odir=`cd ../testdir_make_O.$$ && pwd` +test -d "$odir" || exit 1 + +make O="$odir" $MAKEOPTS "$@" defconfig busybox 2>&1 | tee test_make_O.log -- cgit v1.2.3-55-g6feb From 61f5f7823c4f217dd9bad2f1df547f81b9338c76 Mon Sep 17 00:00:00 2001 From: Matheus Izvekov Date: Fri, 9 Jul 2010 19:40:00 +0200 Subject: diff: fix "diff dir1 dir2/". Closes bug 2203 Signed-off-by: Matheus Izvekov Signed-off-by: Denys Vlasenko --- editors/diff.c | 6 ++++-- testsuite/diff.tests | 31 +++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 4 deletions(-) diff --git a/editors/diff.c b/editors/diff.c index 07594e8d8..8d91b83bf 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -760,9 +760,11 @@ static int FAST_FUNC add_to_dirlist(const char *filename, void *userdata, int depth UNUSED_PARAM) { struct dlist *const l = userdata; + const char *file = filename + l->len; l->dl = xrealloc_vector(l->dl, 6, l->e); - /* + 1 skips "/" after dirname */ - l->dl[l->e] = xstrdup(filename + l->len + 1); + while(*file == '/') + file++; + l->dl[l->e] = xstrdup(file); l->e++; return TRUE; } diff --git a/testsuite/diff.tests b/testsuite/diff.tests index 06d5a4fd7..27a4b33a7 100755 --- a/testsuite/diff.tests +++ b/testsuite/diff.tests @@ -4,7 +4,7 @@ . ./testing.sh -# testing "test name" "options" "expected result" "file input" "stdin" +# testing "test name" "commands" "expected result" "file input" "stdin" # diff outputs date/time in the header, which should not be analysed # NB: sed has tab character in s command! @@ -100,9 +100,11 @@ testing "diff always takes context from old file" \ "abc\na c\ndef\n" \ "a c\n" -# testing "test name" "options" "expected result" "file input" "stdin" +# testing "test name" "commands" "expected result" "file input" "stdin" +# clean up rm -rf diff1 diff2 + mkdir diff1 diff2 diff2/subdir echo qwe >diff1/- echo asd >diff2/subdir/- @@ -187,4 +189,29 @@ SKIP= # clean up rm -rf diff1 diff2 +# NOT using directory structure from prev test... +mkdir diff1 diff2 +echo qwe >diff1/- +echo rty >diff2/- +optional FEATURE_DIFF_DIR +testing "diff diff1 diff2/" \ + "diff -ur diff1 diff2/ | $TRIM_TAB; diff -ur .///diff1 diff2//// | $TRIM_TAB" \ +"\ +--- diff1/- ++++ diff2/- +@@ -1 +1 @@ +-qwe ++rty +--- .///diff1/- ++++ diff2////- +@@ -1 +1 @@ +-qwe ++rty +" \ + "" "" +SKIP= + +# clean up +rm -rf diff1 diff2 + exit $FAILCOUNT -- cgit v1.2.3-55-g6feb From 32a6baeefaf040fb04fee7be3ea7c6e60b95f5bd Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 9 Jul 2010 19:44:38 +0200 Subject: diff: cosmetic change on top of last commit Signed-off-by: Denys Vlasenko --- editors/diff.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/editors/diff.c b/editors/diff.c index 8d91b83bf..3e2048330 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -761,9 +761,9 @@ static int FAST_FUNC add_to_dirlist(const char *filename, { struct dlist *const l = userdata; const char *file = filename + l->len; - l->dl = xrealloc_vector(l->dl, 6, l->e); while(*file == '/') file++; + l->dl = xrealloc_vector(l->dl, 6, l->e); l->dl[l->e] = xstrdup(file); l->e++; return TRUE; -- cgit v1.2.3-55-g6feb From a48a29f921d9d50598784047b40c97c6850bb8ec Mon Sep 17 00:00:00 2001 From: Lauri Kasanen Date: Thu, 8 Jul 2010 11:22:30 +0300 Subject: Modprobe: Make -l open the right file Before: modprobe -l modules.dep not found No size change, just moved the chdir. Signed-off-by: Lauri Kasanen Signed-off-by: Denys Vlasenko --- modutils/modprobe.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/modutils/modprobe.c b/modutils/modprobe.c index b4de65b1f..0a9424293 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -483,6 +483,11 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS); argv += optind; + /* Goto modules location */ + xchdir(CONFIG_DEFAULT_MODULES_DIR); + uname(&uts); + xchdir(uts.release); + if (opt & MODPROBE_OPT_LIST_ONLY) { char name[MODULE_NAME_LEN]; char *colon, *tokens[2]; @@ -524,11 +529,6 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) return EXIT_SUCCESS; } - /* Goto modules location */ - xchdir(CONFIG_DEFAULT_MODULES_DIR); - uname(&uts); - xchdir(uts.release); - /* Retrieve module names of already loaded modules */ { char *s; -- cgit v1.2.3-55-g6feb From 75703eb8d5bd0d8d9ef0a8abaf25b421ca668ab5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 10 Jul 2010 16:25:47 +0200 Subject: diff: make diff -r much less eager to recurse into directories function old new delta skip_dir 44 120 +76 diff_main 1175 1185 +10 Signed-off-by: Denys Vlasenko --- editors/diff.c | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/editors/diff.c b/editors/diff.c index 3e2048330..a3ca2b660 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -121,6 +121,7 @@ typedef struct FILE_and_pos_t { struct globals { smallint exit_status; int opt_U_context; + const char *other_dir; char *label[2]; struct stat stb[2]; }; @@ -761,7 +762,7 @@ static int FAST_FUNC add_to_dirlist(const char *filename, { struct dlist *const l = userdata; const char *file = filename + l->len; - while(*file == '/') + while (*file == '/') file++; l->dl = xrealloc_vector(l->dl, 6, l->e); l->dl[l->e] = xstrdup(file); @@ -780,6 +781,25 @@ static int FAST_FUNC skip_dir(const char *filename, add_to_dirlist(filename, sb, userdata, depth); return SKIP; } + if (!(option_mask32 & FLAG(N))) { + /* -r without -N: no need to recurse into dirs + * which do not exist on the "other side". + * Testcase: diff -r /tmp / + * (it would recurse deep into /proc without this code) */ + struct dlist *const l = userdata; + filename += l->len; + if (filename[0]) { + struct stat osb; + char *othername = concat_path_file(G.other_dir, filename); + int r = stat(othername, &osb); + free(othername); + if (r != 0 || !S_ISDIR(osb.st_mode)) { + /* other dir doesn't have similarly named + * directory, don't recurse */ + return SKIP; + } + } + } return TRUE; } @@ -793,6 +813,7 @@ static void diffdir(char *p[2], const char *s_start) /*list[i].s = list[i].e = 0; - memset did it */ /*list[i].dl = NULL; */ + G.other_dir = p[1 - i]; /* We need to trim root directory prefix. * Using list.len to specify its length, * add_to_dirlist will remove it. */ -- cgit v1.2.3-55-g6feb From 729f39dd17b66f9771433d5442776c298208c09a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 10 Jul 2010 19:52:13 +0200 Subject: remove unzip doc: we don't have 100% proof it's ok to distribute Signed-off-by: Denys Vlasenko --- archival/unzip_doc.txt.bz2 | Bin 11359 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 archival/unzip_doc.txt.bz2 diff --git a/archival/unzip_doc.txt.bz2 b/archival/unzip_doc.txt.bz2 deleted file mode 100644 index ab77d10da..000000000 Binary files a/archival/unzip_doc.txt.bz2 and /dev/null differ -- cgit v1.2.3-55-g6feb From 69d69e2cb898f77827d2cf2c06a7f6fcd5157567 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 11 Jul 2010 23:20:15 +0200 Subject: crond: mention other cronds' behavior in comment. no code changes Signed-off-by: Denys Vlasenko --- miscutils/crond.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/miscutils/crond.c b/miscutils/crond.c index a459c6a8c..66110bb85 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c @@ -304,13 +304,15 @@ static void FixDayDow(CronLine *line) //if crontab was reloaded: crond thinks that "new" job is different from "old" //even if they are in fact completely the same. Example //Crontab was: -// 0-59 * * * job1 -// 0-59 * * * long_running_job2 +// 0-59 * * * * job1 +// 0-59 * * * * long_running_job2 //User edits crontab to: -// 0-59 * * * job1_updated -// 0-59 * * * long_running_job2 +// 0-59 * * * * job1_updated +// 0-59 * * * * long_running_job2 //Bug: crond can now start another long_running_job2 even if old one //is still running. +//OTOH most other versions of cron do not wait for job termination anyway, +//they end up with multiple copies of jobs if they don't terminate soon enough. static void delete_cronfile(const char *userName) { CronFile **pfile = &G.cron_files; -- cgit v1.2.3-55-g6feb From d8b989f22dbb21642ada9696ad7e8358464e20cc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 12 Jul 2010 03:14:17 +0200 Subject: more: style fix. no code changes Signed-off-by: Denys Vlasenko --- util-linux/more.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util-linux/more.c b/util-linux/more.c index 55694e434..9216b6137 100644 --- a/util-linux/more.c +++ b/util-linux/more.c @@ -31,7 +31,7 @@ struct globals { #define setTermSettings(fd, argp) do { \ if (ENABLE_FEATURE_USE_TERMIOS) tcsetattr(fd, TCSANOW, argp); \ - } while(0) + } while (0) #define getTermSettings(fd, argp) tcgetattr(fd, argp) static void gotsig(int sig UNUSED_PARAM) @@ -46,7 +46,7 @@ static void gotsig(int sig UNUSED_PARAM) int more_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int more_main(int argc UNUSED_PARAM, char **argv) { - int c = c; /* for gcc */ + int c = c; /* for compiler */ int lines; int input = 0; int spaces = 0; -- cgit v1.2.3-55-g6feb From c5bbd5d08543bbd18ebdeee2b0c3c35ac7e15729 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 12 Jul 2010 03:27:09 +0200 Subject: wget: fix progress display function old new delta progress_meter 187 199 +12 Signed-off-by: Denys Vlasenko --- networking/wget.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/networking/wget.c b/networking/wget.c index f55b68a38..1f35f8b03 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -50,7 +50,7 @@ static void progress_meter(int flag) } bb_progress_update(&G.pmt, G.curfile, G.beg_range, G.transferred, - G.chunked ? 0 : G.content_len + G.beg_range); + G.chunked ? 0 : G.beg_range + G.transferred + G.content_len); if (flag == 0) { /* last call to progress_meter */ -- cgit v1.2.3-55-g6feb From 04a5d5ad15899161b0ea0e53e0551d12d0401ca3 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 12 Jul 2010 03:43:39 +0200 Subject: mktemp: fix "mktemp /path/to/tempfile.XXXXXX" function old new delta mktemp_main 152 167 +15 Signed-off-by: Denys Vlasenko --- debianutils/mktemp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/debianutils/mktemp.c b/debianutils/mktemp.c index c40211476..2c4e19670 100644 --- a/debianutils/mktemp.c +++ b/debianutils/mktemp.c @@ -50,7 +50,8 @@ int mktemp_main(int argc UNUSED_PARAM, char **argv) opts = getopt32(argv, "dqtp:", &path); chp = argv[optind] ? argv[optind] : xstrdup("tmp.XXXXXX"); - chp = concat_path_file(path, chp); + if (chp[0] != '/' || (opts & 8)) + chp = concat_path_file(path, chp); if (opts & 1) { /* -d */ if (mkdtemp(chp) == NULL) -- cgit v1.2.3-55-g6feb From 6af732b9ae841b05a70242004811d25476fa7b54 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 12 Jul 2010 06:20:11 +0200 Subject: acpid: old kernel headers compat Signed-off-by: Denys Vlasenko --- util-linux/acpid.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/util-linux/acpid.c b/util-linux/acpid.c index 342930964..11a9f624a 100644 --- a/util-linux/acpid.c +++ b/util-linux/acpid.c @@ -9,9 +9,25 @@ #include "libbb.h" #include +#ifndef EV_SW +# define EV_SW 0x05 +#endif +#ifndef EV_KEY +# define EV_KEY 0x01 +#endif +#ifndef SW_LID +# define SW_LID 0x00 +#endif #ifndef SW_RFKILL_ALL -# define SW_RFKILL_ALL 3 +# define SW_RFKILL_ALL 0x03 #endif +#ifndef KEY_POWER +# define KEY_POWER 116 /* SC System Power Down */ +#endif +#ifndef KEY_SLEEP +# define KEY_SLEEP 142 /* SC System Sleep */ +#endif + /* * acpid listens to ACPI events coming either in textual form -- cgit v1.2.3-55-g6feb From a95ce93e578958ad84c51d8cc01d18afed9bc6f2 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 13 Jul 2010 12:13:04 +0200 Subject: top: add tie breaking for topmem mode Signed-off-by: Denys Vlasenko --- procps/top.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/procps/top.c b/procps/top.c index 04dd82633..ec8437442 100644 --- a/procps/top.c +++ b/procps/top.c @@ -686,10 +686,10 @@ static int topmem_sort(char *a, char *b) n = offsetof(topmem_status_t, vsz) + (sort_field * sizeof(mem_t)); l = *(mem_t*)(a + n); r = *(mem_t*)(b + n); -// if (l == r) { -// l = a->mapped_rw; -// r = b->mapped_rw; -// } + if (l == r) { + l = ((topmem_status_t*)a)->dirty; + r = ((topmem_status_t*)b)->dirty; + } /* We want to avoid unsigned->signed and truncation errors */ /* l>r: -1, l=r: 0, l r) ? -1 : (l != r); -- cgit v1.2.3-55-g6feb From 0e450669d455e4f8dab97c26b4009a9700cd677b Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Jul 2010 07:10:47 +0200 Subject: util-linux: move VOLUMEID to a submenu Signed-off-by: Denys Vlasenko --- util-linux/Config.src | 435 +++++++++++++++++++++++++------------------------- 1 file changed, 220 insertions(+), 215 deletions(-) diff --git a/util-linux/Config.src b/util-linux/Config.src index 3c3e05ec4..91d1fc2ce 100644 --- a/util-linux/Config.src +++ b/util-linux/Config.src @@ -470,221 +470,6 @@ config FEATURE_USE_TERMIOS will be unable to determine the current screen size, and will be unable to move the cursor. -config VOLUMEID - bool #No description makes it a hidden option - default n - -config FEATURE_VOLUMEID_EXT - bool "Ext filesystem" - default y - depends on VOLUMEID - help - TODO - -config FEATURE_VOLUMEID_BTRFS - bool "btrfs filesystem" - default y - depends on VOLUMEID - help - TODO - -config FEATURE_VOLUMEID_REISERFS - bool "Reiser filesystem" - default y - depends on VOLUMEID - help - TODO - -config FEATURE_VOLUMEID_FAT - bool "fat filesystem" - default y - depends on VOLUMEID - help - TODO - -config FEATURE_VOLUMEID_HFS - bool "hfs filesystem" - default y - depends on VOLUMEID - help - TODO - -config FEATURE_VOLUMEID_JFS - bool "jfs filesystem" - default y - depends on VOLUMEID - help - TODO - -### config FEATURE_VOLUMEID_UFS -### bool "ufs filesystem" -### default y -### depends on VOLUMEID -### help -### TODO - -config FEATURE_VOLUMEID_XFS - bool "xfs filesystem" - default y - depends on VOLUMEID - help - TODO - -config FEATURE_VOLUMEID_NTFS - bool "ntfs filesystem" - default y - depends on VOLUMEID - help - TODO - -config FEATURE_VOLUMEID_ISO9660 - bool "iso9660 filesystem" - default y - depends on VOLUMEID - help - TODO - -config FEATURE_VOLUMEID_UDF - bool "udf filesystem" - default y - depends on VOLUMEID - help - TODO - -config FEATURE_VOLUMEID_LUKS - bool "luks filesystem" - default y - depends on VOLUMEID - help - TODO - -config FEATURE_VOLUMEID_LINUXSWAP - bool "linux swap filesystem" - default y - depends on VOLUMEID - help - TODO - -### config FEATURE_VOLUMEID_LVM -### bool "lvm" -### default y -### depends on VOLUMEID -### help -### TODO - -config FEATURE_VOLUMEID_CRAMFS - bool "cramfs filesystem" - default y - depends on VOLUMEID - help - TODO - -### config FEATURE_VOLUMEID_HPFS -### bool "hpfs filesystem" -### default y -### depends on VOLUMEID -### help -### TODO - -config FEATURE_VOLUMEID_ROMFS - bool "romfs filesystem" - default y - depends on VOLUMEID - help - TODO - -config FEATURE_VOLUMEID_SYSV - bool "sysv filesystem" - default y - depends on VOLUMEID - help - TODO - -### config FEATURE_VOLUMEID_MINIX -### bool "minix filesystem" -### default y -### depends on VOLUMEID -### help -### TODO - -### These only detect partition tables - not used (yet?) -### config FEATURE_VOLUMEID_MAC -### bool "mac filesystem" -### default y -### depends on VOLUMEID -### help -### TODO -### -### config FEATURE_VOLUMEID_MSDOS -### bool "msdos filesystem" -### default y -### depends on VOLUMEID -### help -### TODO - -config FEATURE_VOLUMEID_OCFS2 - bool "ocfs2 filesystem" - default y - depends on VOLUMEID - help - TODO - -### config FEATURE_VOLUMEID_HIGHPOINTRAID -### bool "highpoint raid" -### default y -### depends on VOLUMEID -### help -### TODO - -### config FEATURE_VOLUMEID_ISWRAID -### bool "intel raid" -### default y -### depends on VOLUMEID -### help -### TODO - -### config FEATURE_VOLUMEID_LSIRAID -### bool "lsi raid" -### default y -### depends on VOLUMEID -### help -### TODO - -### config FEATURE_VOLUMEID_VIARAID -### bool "via raid" -### default y -### depends on VOLUMEID -### help -### TODO - -### config FEATURE_VOLUMEID_SILICONRAID -### bool "silicon raid" -### default y -### depends on VOLUMEID -### help -### TODO - -### config FEATURE_VOLUMEID_NVIDIARAID -### bool "nvidia raid" -### default y -### depends on VOLUMEID -### help -### TODO - -### config FEATURE_VOLUMEID_PROMISERAID -### bool "promise raid" -### default y -### depends on VOLUMEID -### help -### TODO - -config FEATURE_VOLUMEID_LINUXRAID - bool "linuxraid" - default y - depends on VOLUMEID - help - TODO - config MOUNT bool "mount" default y @@ -937,4 +722,224 @@ config FEATURE_MTAB_SUPPORT About the only reason to use this is if you've removed /proc from your kernel. +config VOLUMEID + bool #No description makes it a hidden option + default n + +menu "Filesystem/Volume identification" + depends on VOLUMEID + +config FEATURE_VOLUMEID_EXT + bool "Ext filesystem" + default y + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_BTRFS + bool "btrfs filesystem" + default y + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_REISERFS + bool "Reiser filesystem" + default y + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_FAT + bool "fat filesystem" + default y + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_HFS + bool "hfs filesystem" + default y + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_JFS + bool "jfs filesystem" + default y + depends on VOLUMEID + help + TODO + +### config FEATURE_VOLUMEID_UFS +### bool "ufs filesystem" +### default y +### depends on VOLUMEID +### help +### TODO + +config FEATURE_VOLUMEID_XFS + bool "xfs filesystem" + default y + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_NTFS + bool "ntfs filesystem" + default y + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_ISO9660 + bool "iso9660 filesystem" + default y + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_UDF + bool "udf filesystem" + default y + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_LUKS + bool "luks filesystem" + default y + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_LINUXSWAP + bool "linux swap filesystem" + default y + depends on VOLUMEID + help + TODO + +### config FEATURE_VOLUMEID_LVM +### bool "lvm" +### default y +### depends on VOLUMEID +### help +### TODO + +config FEATURE_VOLUMEID_CRAMFS + bool "cramfs filesystem" + default y + depends on VOLUMEID + help + TODO + +### config FEATURE_VOLUMEID_HPFS +### bool "hpfs filesystem" +### default y +### depends on VOLUMEID +### help +### TODO + +config FEATURE_VOLUMEID_ROMFS + bool "romfs filesystem" + default y + depends on VOLUMEID + help + TODO + +config FEATURE_VOLUMEID_SYSV + bool "sysv filesystem" + default y + depends on VOLUMEID + help + TODO + +### config FEATURE_VOLUMEID_MINIX +### bool "minix filesystem" +### default y +### depends on VOLUMEID +### help +### TODO + +### These only detect partition tables - not used (yet?) +### config FEATURE_VOLUMEID_MAC +### bool "mac filesystem" +### default y +### depends on VOLUMEID +### help +### TODO +### +### config FEATURE_VOLUMEID_MSDOS +### bool "msdos filesystem" +### default y +### depends on VOLUMEID +### help +### TODO + +config FEATURE_VOLUMEID_OCFS2 + bool "ocfs2 filesystem" + default y + depends on VOLUMEID + help + TODO + +### config FEATURE_VOLUMEID_HIGHPOINTRAID +### bool "highpoint raid" +### default y +### depends on VOLUMEID +### help +### TODO + +### config FEATURE_VOLUMEID_ISWRAID +### bool "intel raid" +### default y +### depends on VOLUMEID +### help +### TODO + +### config FEATURE_VOLUMEID_LSIRAID +### bool "lsi raid" +### default y +### depends on VOLUMEID +### help +### TODO + +### config FEATURE_VOLUMEID_VIARAID +### bool "via raid" +### default y +### depends on VOLUMEID +### help +### TODO + +### config FEATURE_VOLUMEID_SILICONRAID +### bool "silicon raid" +### default y +### depends on VOLUMEID +### help +### TODO + +### config FEATURE_VOLUMEID_NVIDIARAID +### bool "nvidia raid" +### default y +### depends on VOLUMEID +### help +### TODO + +### config FEATURE_VOLUMEID_PROMISERAID +### bool "promise raid" +### default y +### depends on VOLUMEID +### help +### TODO + +config FEATURE_VOLUMEID_LINUXRAID + bool "linuxraid" + default y + depends on VOLUMEID + help + TODO + +endmenu + endmenu -- cgit v1.2.3-55-g6feb From 6ac37da4256a248b8b8046d3b356a3b9c4831c97 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Jul 2010 08:33:20 +0200 Subject: build system: disable some applets by default Signed-off-by: Denys Vlasenko --- Config.in | 1 + miscutils/Config.src | 14 +++++++------- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Config.in b/Config.in index fc02a2d93..eebc9774d 100644 --- a/Config.in +++ b/Config.in @@ -138,6 +138,7 @@ config UNICODE_USING_LOCALE help With this option on, Unicode support is implemented using libc routines. Otherwise, internal implementation is used. + Internal implementation is smaller. config FEATURE_CHECK_UNICODE_IN_ENV bool "Check $LANG environment variable" diff --git a/miscutils/Config.src b/miscutils/Config.src index 012132e7b..2f7c50271 100644 --- a/miscutils/Config.src +++ b/miscutils/Config.src @@ -276,28 +276,28 @@ config FBSPLASH config FLASHCP bool "flashcp" - default y + default n # doesn't build on Ubuntu 8.04 help The flashcp binary, inspired by mtd-utils as of git head 5eceb74f7. This utility is used to copy images into a MTD device. config FLASH_LOCK bool "flash_lock" - default y + default n # doesn't build on Ubuntu 8.04 help The flash_lock binary from mtd-utils as of git head 5ec0c10d0. This utility locks part or all of the flash device. config FLASH_UNLOCK bool "flash_unlock" - default y + default n # doesn't build on Ubuntu 8.04 help The flash_unlock binary from mtd-utils as of git head 5ec0c10d0. This utility unlocks part or all of the flash device. config FLASH_ERASEALL bool "flash_eraseall" - default y + default n # doesn't build on Ubuntu 8.04 help The flash_eraseall binary from mtd-utils as of git head c4c6a59eb. This utility is used to erase the whole MTD device. @@ -311,7 +311,7 @@ config IONICE config INOTIFYD bool "inotifyd" - default y + default n # doesn't build on Knoppix 5 help Simple inotify daemon. Reports filesystem changes. Requires kernel >= 2.6.13 @@ -549,7 +549,7 @@ config READAHEAD config RFKILL bool "rfkill" - default n + default n # doesn't build on Ubuntu 9.04 help Enable/disable wireless devices. @@ -588,7 +588,7 @@ config STRINGS config TASKSET bool "taskset" - default y + default n # doesn't build on some non-x86 targets (m68k) help Retrieve or set a processes's CPU affinity. This requires sched_{g,s}etaffinity support in your libc. -- cgit v1.2.3-55-g6feb From 889550b36b057fb8ad5c825c7a17e46fde4ebbf6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 14 Jul 2010 19:01:25 +0200 Subject: hush: make pun_pipe loop clearer; fix "cmd | var=`cmd` | cmd" handling function old new delta free_strings - 38 +38 pseudo_exec_argv 161 171 +10 free_pipe 227 205 -22 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/1 up/down: 48/-22) Total: 26 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 42 ++++++++++++++++++++++++++---------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/shell/hush.c b/shell/hush.c index 31ca22a2e..8a467be80 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -3713,11 +3713,17 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, { char **new_env; - /* Case when we are here: ... | var=val | ... */ - if (!argv[assignment_cnt]) + new_env = expand_assignments(argv, assignment_cnt); + + if (!argv[assignment_cnt]) { + /* Case when we are here: ... | var=val | ... + * (note that we do not exit early, i.e., do not optimize out + * expand_assignments(): think about ... | var=`sleep 1` | ... + */ + free_strings(new_env); _exit(EXIT_SUCCESS); + } - new_env = expand_assignments(argv, assignment_cnt); #if BB_MMU set_vars_and_save_old(new_env); free(new_env); /* optional */ @@ -3727,6 +3733,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, nommu_save->new_env = new_env; nommu_save->old_vars = set_vars_and_save_old(new_env); #endif + if (argv_expanded) { argv = argv_expanded; } else { @@ -4145,8 +4152,9 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe) static NOINLINE int run_pipe(struct pipe *pi) { static const char *const null_ptr = NULL; - int i; - int nextin; + + int cmd_no; + int next_infd; struct command *command; char **argv_expanded; char **argv; @@ -4160,7 +4168,7 @@ static NOINLINE int run_pipe(struct pipe *pi) IF_HUSH_JOB(pi->pgrp = -1;) pi->stopped_cmds = 0; - command = &(pi->cmds[0]); + command = &pi->cmds[0]; argv_expanded = NULL; if (pi->num_cmds != 1 @@ -4358,9 +4366,10 @@ static NOINLINE int run_pipe(struct pipe *pi) /* Going to fork a child per each pipe member */ pi->alive_cmds = 0; - nextin = 0; + next_infd = 0; - for (i = 0; i < pi->num_cmds; i++) { + cmd_no = 0; + while (cmd_no < pi->num_cmds) { struct fd_pair pipefds; #if !BB_MMU volatile nommu_save_t nommu_save; @@ -4369,7 +4378,8 @@ static NOINLINE int run_pipe(struct pipe *pi) nommu_save.argv = NULL; nommu_save.argv_from_re_execing = NULL; #endif - command = &(pi->cmds[i]); + command = &pi->cmds[cmd_no]; + cmd_no++; if (command->argv) { debug_printf_exec(": pipe member '%s' '%s'...\n", command->argv[0], command->argv[1]); @@ -4380,7 +4390,7 @@ static NOINLINE int run_pipe(struct pipe *pi) /* pipes are inserted between pairs of commands */ pipefds.rd = 0; pipefds.wr = 1; - if ((i + 1) < pi->num_cmds) + if (cmd_no < pi->num_cmds) xpiped_pair(pipefds); command->pid = BB_MMU ? fork() : vfork(); @@ -4413,7 +4423,7 @@ static NOINLINE int run_pipe(struct pipe *pi) if (open(bb_dev_null, O_RDONLY)) xopen("/", O_RDONLY); } else { - xmove_fd(nextin, 0); + xmove_fd(next_infd, 0); } xmove_fd(pipefds.wr, 1); if (pipefds.rd > 1) @@ -4460,12 +4470,12 @@ static NOINLINE int run_pipe(struct pipe *pi) #endif } - if (i) - close(nextin); - if ((i + 1) < pi->num_cmds) + if (cmd_no > 1) + close(next_infd); + if (cmd_no < pi->num_cmds) close(pipefds.wr); /* Pass read (output) pipe end to next iteration */ - nextin = pipefds.rd; + next_infd = pipefds.rd; } if (!pi->alive_cmds) { @@ -7153,7 +7163,7 @@ int hush_main(int argc, char **argv) #endif case 'n': case 'x': - if (!set_mode('-', opt)) + if (set_mode('-', opt) == 0) /* no error */ break; default: #ifndef BB_VER -- cgit v1.2.3-55-g6feb From 8fa1f5d543266816967949812b65790fbe7cdcd4 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 15 Jul 2010 08:18:46 +0200 Subject: hush: fix faloout from previous commit Signed-off-by: Denys Vlasenko --- include/busybox.h | 13 ++++++++----- shell/hush.c | 26 ++++++++++++-------------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/include/busybox.h b/include/busybox.h index 48ce856ea..48fc0b4c8 100644 --- a/include/busybox.h +++ b/include/busybox.h @@ -35,18 +35,21 @@ extern const uint16_t applet_nameofs[]; extern const uint8_t applet_install_loc[]; #if ENABLE_FEATURE_SUID || ENABLE_FEATURE_PREFER_APPLETS -#define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x0fff)) +# define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x0fff)) #else -#define APPLET_NAME(i) (applet_names + applet_nameofs[i]) +# define APPLET_NAME(i) (applet_names + applet_nameofs[i]) #endif #if ENABLE_FEATURE_PREFER_APPLETS -#define APPLET_IS_NOFORK(i) (applet_nameofs[i] & (1 << 12)) -#define APPLET_IS_NOEXEC(i) (applet_nameofs[i] & (1 << 13)) +# define APPLET_IS_NOFORK(i) (applet_nameofs[i] & (1 << 12)) +# define APPLET_IS_NOEXEC(i) (applet_nameofs[i] & (1 << 13)) +#else +# define APPLET_IS_NOFORK(i) 0 +# define APPLET_IS_NOEXEC(i) 0 #endif #if ENABLE_FEATURE_SUID -#define APPLET_SUID(i) ((applet_nameofs[i] >> 14) & 0x3) +# define APPLET_SUID(i) ((applet_nameofs[i] >> 14) & 0x3) #endif #if ENABLE_FEATURE_INSTALLER diff --git a/shell/hush.c b/shell/hush.c index 8a467be80..7dacfa0b1 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -4328,9 +4328,7 @@ static NOINLINE int run_pipe(struct pipe *pi) } #endif } -#if ENABLE_FEATURE_SH_STANDALONE clean_up_and_ret: -#endif restore_redirects(squirrel); unset_vars(new_env); add_vars(old_vars); @@ -4342,20 +4340,20 @@ static NOINLINE int run_pipe(struct pipe *pi) return rcode; } -#if ENABLE_FEATURE_SH_STANDALONE - i = find_applet_by_name(argv_expanded[0]); - if (i >= 0 && APPLET_IS_NOFORK(i)) { - rcode = setup_redirects(command, squirrel); - if (rcode == 0) { - new_env = expand_assignments(argv, command->assignment_cnt); - old_vars = set_vars_and_save_old(new_env); - debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", - argv_expanded[0], argv_expanded[1]); - rcode = run_nofork_applet(i, argv_expanded); + if (ENABLE_FEATURE_SH_STANDALONE) { + int n = find_applet_by_name(argv_expanded[0]); + if (n >= 0 && APPLET_IS_NOFORK(n)) { + rcode = setup_redirects(command, squirrel); + if (rcode == 0) { + new_env = expand_assignments(argv, command->assignment_cnt); + old_vars = set_vars_and_save_old(new_env); + debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", + argv_expanded[0], argv_expanded[1]); + rcode = run_nofork_applet(n, argv_expanded); + } + goto clean_up_and_ret; } - goto clean_up_and_ret; } -#endif /* It is neither builtin nor applet. We must fork. */ } -- cgit v1.2.3-55-g6feb From b3389de04b1fe398e5f88446dd23a7826139da7d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 15 Jul 2010 12:33:37 +0200 Subject: hush: fix typo in comment Signed-off-by: Denys Vlasenko --- shell/hush.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/hush.c b/shell/hush.c index 7dacfa0b1..14f8f2422 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -4246,7 +4246,7 @@ static NOINLINE int run_pipe(struct pipe *pi) set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); argv++; } - /* Redirect error sets $? to 1. Othervise, + /* Redirect error sets $? to 1. Otherwise, * if evaluating assignment value set $?, retain it. * Try "false; q=`exit 2`; echo $?" - should print 2: */ if (rcode == 0) -- cgit v1.2.3-55-g6feb From 3f5fae07725b0cc24587c7965f17ac57e5610bfb Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 16 Jul 2010 12:35:35 +0200 Subject: hush: add support for set -x function old new delta run_pipe 1442 1568 +126 dump_cmd_in_x_mode - 126 +126 builtin_trap 441 462 +21 pseudo_exec_argv 171 187 +16 reset_traps_to_defaults 214 229 +15 check_and_run_traps 227 232 +5 hush_exit 98 101 +3 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 6/0 up/down: 312/0) Total: 312 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/shell/hush.c b/shell/hush.c index 14f8f2422..7640bd6ba 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -532,6 +532,7 @@ struct globals { smallint flag_return_in_progress; #endif smallint fake_mode; + smallint x_mode; smallint exiting; /* used to prevent EXIT trap recursion */ /* These four support $?, $#, and $1 */ smalluint last_exitcode; @@ -3692,6 +3693,31 @@ static void execvp_or_die(char **argv) _exit(127); /* bash compat */ } +static void dump_cmd_in_x_mode(char **argv) +{ + if (G.x_mode && argv) { + /* We want to output the line in one write op */ + char *buf, *p; + int len; + int n; + + len = 3; + n = 0; + while (argv[n]) + len += strlen(argv[n++]) + 1; + buf = xmalloc(len); + buf[0] = '+'; + p = buf + 1; + n = 0; + while (argv[n]) + p += sprintf(p, " %s", argv[n++]); + *p++ = '\n'; + *p = '\0'; + fputs(buf, stderr); + free(buf); + } +} + #if BB_MMU #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ pseudo_exec_argv(argv, assignment_cnt, argv_expanded) @@ -3714,6 +3740,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, char **new_env; new_env = expand_assignments(argv, assignment_cnt); + dump_cmd_in_x_mode(new_env); if (!argv[assignment_cnt]) { /* Case when we are here: ... | var=val | ... @@ -3742,6 +3769,7 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, nommu_save->argv = argv; #endif } + dump_cmd_in_x_mode(argv); #if ENABLE_FEATURE_SH_STANDALONE || BB_MMU if (strchr(argv[0], '/') != NULL) @@ -4239,13 +4267,19 @@ static NOINLINE int run_pipe(struct pipe *pi) rcode = setup_redirects(command, squirrel); restore_redirects(squirrel); /* Set shell variables */ + if (G.x_mode) + bb_putchar_stderr('+'); while (*argv) { p = expand_string_to_string(*argv); + if (G.x_mode) + fprintf(stderr, " %s", p); debug_printf_exec("set shell var:'%s'->'%s'\n", *argv, p); set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); argv++; } + if (G.x_mode) + bb_putchar_stderr('\n'); /* Redirect error sets $? to 1. Otherwise, * if evaluating assignment value set $?, retain it. * Try "false; q=`exit 2`; echo $?" - should print 2: */ @@ -4305,6 +4339,8 @@ static NOINLINE int run_pipe(struct pipe *pi) rcode = setup_redirects(command, squirrel); if (rcode == 0) { new_env = expand_assignments(argv, command->assignment_cnt); + dump_cmd_in_x_mode(new_env); + dump_cmd_in_x_mode(argv_expanded); old_vars = set_vars_and_save_old(new_env); if (!funcp) { debug_printf_exec(": builtin '%s' '%s'...\n", @@ -4346,6 +4382,8 @@ static NOINLINE int run_pipe(struct pipe *pi) rcode = setup_redirects(command, squirrel); if (rcode == 0) { new_env = expand_assignments(argv, command->assignment_cnt); + dump_cmd_in_x_mode(new_env); + dump_cmd_in_x_mode(argv_expanded); old_vars = set_vars_and_save_old(new_env); debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); @@ -6932,7 +6970,7 @@ static int set_mode(const char cstate, const char mode) int state = (cstate == '-' ? 1 : 0); switch (mode) { case 'n': G.fake_mode = state; break; - case 'x': /*G.debug_mode = state;*/ break; + case 'x': G.x_mode = state; break; default: return EXIT_FAILURE; } return EXIT_SUCCESS; -- cgit v1.2.3-55-g6feb From 202a2d121905a6245cdf7441c9f83ff213b5502e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 16 Jul 2010 12:36:14 +0200 Subject: hush: make set -x support optional Signed-off-by: Denys Vlasenko --- include/applets.src.h | 5 -- include/usage.src.h | 6 -- shell/Config.src | 106 ---------------------------------- shell/Kbuild.src | 2 - shell/hush.c | 155 +++++++++++++++++++++++++++++++++++++++++++++++--- 5 files changed, 147 insertions(+), 127 deletions(-) diff --git a/include/applets.src.h b/include/applets.src.h index 9162b66c7..5d84597b0 100644 --- a/include/applets.src.h +++ b/include/applets.src.h @@ -76,7 +76,6 @@ IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_DROP)) IF_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_DROP, awk)) IF_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_DROP, basename)) IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) -IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash)) IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_DROP)) //IF_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_DROP)) IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) @@ -183,7 +182,6 @@ IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, _BB_DIR_USR_BIN, _BB_SUID_DROP, hexdu IF_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_DROP, hostid)) IF_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_DROP)) IF_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP)) IF_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_ID(APPLET(id, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) @@ -218,7 +216,6 @@ IF_KILL(APPLET(kill, _BB_DIR_BIN, _BB_SUID_DROP)) IF_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall)) IF_KILLALL5(APPLET_ODDNAME(killall5, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall5)) IF_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_LASH(APPLET(lash, _BB_DIR_BIN, _BB_SUID_DROP)) IF_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_DROP, length)) IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_DROP)) @@ -273,7 +270,6 @@ IF_MODPROBE_SMALL(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP)) IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP)) IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP))) IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP)) IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_DROP)) IF_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_DROP)) IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP)) @@ -349,7 +345,6 @@ IF_SETSEBOOL(APPLET(setsebool, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) IF_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_DROP)) IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, setuidgid)) IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) -IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh)) IF_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha1sum)) IF_SHA256SUM(APPLET_ODDNAME(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha256sum)) IF_SHA512SUM(APPLET_ODDNAME(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum)) diff --git a/include/usage.src.h b/include/usage.src.h index 94a3256b1..b3396006f 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -119,12 +119,6 @@ INSERT #define sh_full_usage "" #define ash_trivial_usage NOUSAGE_STR #define ash_full_usage "" -#define hush_trivial_usage NOUSAGE_STR -#define hush_full_usage "" -#define lash_trivial_usage NOUSAGE_STR -#define lash_full_usage "" -#define msh_trivial_usage NOUSAGE_STR -#define msh_full_usage "" #define bash_trivial_usage NOUSAGE_STR #define bash_full_usage "" diff --git a/shell/Config.src b/shell/Config.src index 800911966..f415a5fa6 100644 --- a/shell/Config.src +++ b/shell/Config.src @@ -110,112 +110,6 @@ config ASH_EXPAND_PRMT This option recreates the prompt string from the environment variable each time it is displayed. -config HUSH - bool "hush" - default y - help - hush is a small shell (22k). It handles the normal flow control - constructs such as if/then/elif/else/fi, for/in/do/done, while loops, - case/esac. Redirections, here documents, $((arithmetic)) - and functions are supported. - - It will compile and work on no-mmu systems. - - It does not handle select, aliases, brace expansion, - tilde expansion, &>file and >&file redirection of stdout+stderr. - -config HUSH_BASH_COMPAT - bool "bash-compatible extensions" - default y - depends on HUSH - help - Enable bash-compatible extensions. - -config HUSH_HELP - bool "help builtin" - default y - depends on HUSH - help - Enable help builtin in hush. Code size + ~1 kbyte. - -config HUSH_INTERACTIVE - bool "Interactive mode" - default y - depends on HUSH - help - Enable interactive mode (prompt and command editing). - Without this, hush simply reads and executes commands - from stdin just like a shell script from a file. - No prompt, no PS1/PS2 magic shell variables. - -config HUSH_JOB - bool "Job control" - default y - depends on HUSH_INTERACTIVE - help - Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current - command (not entire shell), fg/bg builtins work. Without this option, - "cmd &" still works by simply spawning a process and immediately - prompting for next command (or executing next command in a script), - but no separate process group is formed. - -config HUSH_TICK - bool "Process substitution" - default y - depends on HUSH - help - Enable process substitution `command` and $(command) in hush. - -config HUSH_IF - bool "Support if/then/elif/else/fi" - default y - depends on HUSH - help - Enable if/then/elif/else/fi in hush. - -config HUSH_LOOPS - bool "Support for, while and until loops" - default y - depends on HUSH - help - Enable for, while and until loops in hush. - -config HUSH_CASE - bool "Support case ... esac statement" - default y - depends on HUSH - help - Enable case ... esac statement in hush. +400 bytes. - -config HUSH_FUNCTIONS - bool "Support funcname() { commands; } syntax" - default y - depends on HUSH - help - Enable support for shell functions in hush. +800 bytes. - -config HUSH_LOCAL - bool "Support local builtin" - default y - depends on HUSH_FUNCTIONS - help - Enable support for local variables in functions. - -config HUSH_EXPORT_N - bool "Support export '-n' option" - default y - depends on HUSH - help - Enable support for export '-n' option in hush. It is a bash extension. - -config HUSH_RANDOM_SUPPORT - bool "Pseudorandom generator and $RANDOM variable" - default y - depends on HUSH - help - Enable pseudorandom generator and dynamic variable "$RANDOM". - Each read of "$RANDOM" will generate a new pseudorandom value. - choice prompt "Choose which shell is aliased to 'sh' name" diff --git a/shell/Kbuild.src b/shell/Kbuild.src index d76b35386..c7eb5b61a 100644 --- a/shell/Kbuild.src +++ b/shell/Kbuild.src @@ -9,9 +9,7 @@ lib-y:= INSERT lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o -lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o lib-$(CONFIG_CTTYHACK) += cttyhack.o lib-$(CONFIG_SH_MATH_SUPPORT) += math.o lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o -lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o diff --git a/shell/hush.c b/shell/hush.c index 7640bd6ba..c67aebdd7 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -101,6 +101,136 @@ # define PIPE_BUF 4096 /* amount of buffering in a pipe */ #endif +//applet:IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_LASH(APPLET(lash, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh)) +//applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash)) + +//kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o +//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o + +//config:config HUSH +//config: bool "hush" +//config: default y +//config: help +//config: hush is a small shell (22k). It handles the normal flow control +//config: constructs such as if/then/elif/else/fi, for/in/do/done, while loops, +//config: case/esac. Redirections, here documents, $((arithmetic)) +//config: and functions are supported. +//config: +//config: It will compile and work on no-mmu systems. +//config: +//config: It does not handle select, aliases, brace expansion, +//config: tilde expansion, &>file and >&file redirection of stdout+stderr. +//config: +//config:config HUSH_BASH_COMPAT +//config: bool "bash-compatible extensions" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable bash-compatible extensions. +//config: +//config:config HUSH_HELP +//config: bool "help builtin" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable help builtin in hush. Code size + ~1 kbyte. +//config: +//config:config HUSH_INTERACTIVE +//config: bool "Interactive mode" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable interactive mode (prompt and command editing). +//config: Without this, hush simply reads and executes commands +//config: from stdin just like a shell script from a file. +//config: No prompt, no PS1/PS2 magic shell variables. +//config: +//config:config HUSH_JOB +//config: bool "Job control" +//config: default y +//config: depends on HUSH_INTERACTIVE +//config: help +//config: Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current +//config: command (not entire shell), fg/bg builtins work. Without this option, +//config: "cmd &" still works by simply spawning a process and immediately +//config: prompting for next command (or executing next command in a script), +//config: but no separate process group is formed. +//config: +//config:config HUSH_TICK +//config: bool "Process substitution" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable process substitution `command` and $(command) in hush. +//config: +//config:config HUSH_IF +//config: bool "Support if/then/elif/else/fi" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable if/then/elif/else/fi in hush. +//config: +//config:config HUSH_LOOPS +//config: bool "Support for, while and until loops" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable for, while and until loops in hush. +//config: +//config:config HUSH_CASE +//config: bool "Support case ... esac statement" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable case ... esac statement in hush. +400 bytes. +//config: +//config:config HUSH_FUNCTIONS +//config: bool "Support funcname() { commands; } syntax" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable support for shell functions in hush. +800 bytes. +//config: +//config:config HUSH_LOCAL +//config: bool "Support local builtin" +//config: default y +//config: depends on HUSH_FUNCTIONS +//config: help +//config: Enable support for local variables in functions. +//config: +//config:config HUSH_RANDOM_SUPPORT +//config: bool "Pseudorandom generator and $RANDOM variable" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable pseudorandom generator and dynamic variable "$RANDOM". +//config: Each read of "$RANDOM" will generate a new pseudorandom value. +//config: +//config:config HUSH_EXPORT_N +//config: bool "Support 'export -n' option" +//config: default y +//config: depends on HUSH +//config: help +//config: export -n unexports variables. It is a bash extension. +//config: +//config:config HUSH_MODE_X +//config: bool "Support 'hush -x' option and 'set -x' command" +//config: default y +//config: depends on HUSH +//config: help +//config: This instructs hush to print commands before execution. Adds ~300 bytes. +//config: + +//usage:#define hush_trivial_usage NOUSAGE_STR +//usage:#define hush_full_usage "" +//usage:#define lash_trivial_usage NOUSAGE_STR +//usage:#define lash_full_usage "" +//usage:#define msh_trivial_usage NOUSAGE_STR +//usage:#define msh_full_usage "" + /* Build knobs */ #define LEAK_HUNTING 0 @@ -531,8 +661,13 @@ struct globals { */ smallint flag_return_in_progress; #endif - smallint fake_mode; + smallint n_mode; +#if ENABLE_HUSH_MODE_X smallint x_mode; +# define G_x_mode G.x_mode +#else +# define G_x_mode 0 +#endif smallint exiting; /* used to prevent EXIT trap recursion */ /* These four support $?, $#, and $1 */ smalluint last_exitcode; @@ -3693,9 +3828,10 @@ static void execvp_or_die(char **argv) _exit(127); /* bash compat */ } +#if ENABLE_HUSH_MODE_X static void dump_cmd_in_x_mode(char **argv) { - if (G.x_mode && argv) { + if (G_x_mode && argv) { /* We want to output the line in one write op */ char *buf, *p; int len; @@ -3717,6 +3853,9 @@ static void dump_cmd_in_x_mode(char **argv) free(buf); } } +#else +# define dump_cmd_in_x_mode(argv) ((void)0) +#endif #if BB_MMU #define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ @@ -4267,18 +4406,18 @@ static NOINLINE int run_pipe(struct pipe *pi) rcode = setup_redirects(command, squirrel); restore_redirects(squirrel); /* Set shell variables */ - if (G.x_mode) + if (G_x_mode) bb_putchar_stderr('+'); while (*argv) { p = expand_string_to_string(*argv); - if (G.x_mode) + if (G_x_mode) fprintf(stderr, " %s", p); debug_printf_exec("set shell var:'%s'->'%s'\n", *argv, p); set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); argv++; } - if (G.x_mode) + if (G_x_mode) bb_putchar_stderr('\n'); /* Redirect error sets $? to 1. Otherwise, * if evaluating assignment value set $?, retain it. @@ -4943,7 +5082,7 @@ static int run_and_free_list(struct pipe *pi) { int rcode = 0; debug_printf_exec("run_and_free_list entered\n"); - if (!G.fake_mode) { + if (!G.n_mode) { debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); rcode = run_list(pi); } @@ -6969,8 +7108,8 @@ static int set_mode(const char cstate, const char mode) { int state = (cstate == '-' ? 1 : 0); switch (mode) { - case 'n': G.fake_mode = state; break; - case 'x': G.x_mode = state; break; + case 'n': G.n_mode = state; break; + case 'x': IF_HUSH_MODE_X(G_x_mode = state;) break; default: return EXIT_FAILURE; } return EXIT_SUCCESS; -- cgit v1.2.3-55-g6feb From 29082231d0cb1a5b327de5d515b16f332d4dbdaf Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 16 Jul 2010 13:52:32 +0200 Subject: hush: fix multimple dependent variable expansion cases function old new delta get_local_var_value 100 171 +71 expand_assignments 46 76 +30 reset_traps_to_defaults 229 238 +9 maybe_set_to_sigexit 47 50 +3 init_sigmasks 211 214 +3 builtin_trap 462 465 +3 expand_vars_to_list 2412 2408 -4 run_pipe 1568 1533 -35 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 6/2 up/down: 119/-39) Total: 80 bytes Signed-off-by: Denys Vlasenko --- shell/hush.c | 108 +++++++++++++++++++++-------- shell/hush_test/hush-vars/var_serial.right | 5 ++ shell/hush_test/hush-vars/var_serial.tests | 22 ++++++ 3 files changed, 107 insertions(+), 28 deletions(-) create mode 100644 shell/hush_test/hush-vars/var_serial.right create mode 100755 shell/hush_test/hush-vars/var_serial.tests diff --git a/shell/hush.c b/shell/hush.c index c67aebdd7..c5a8ea617 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -221,7 +221,8 @@ //config: default y //config: depends on HUSH //config: help -//config: This instructs hush to print commands before execution. Adds ~300 bytes. +//config: This instructs hush to print commands before execution. +//config: Adds ~300 bytes. //config: //usage:#define hush_trivial_usage NOUSAGE_STR @@ -664,7 +665,7 @@ struct globals { smallint n_mode; #if ENABLE_HUSH_MODE_X smallint x_mode; -# define G_x_mode G.x_mode +# define G_x_mode (G.x_mode) #else # define G_x_mode 0 #endif @@ -688,6 +689,7 @@ struct globals { const char *cwd; struct variable *top_var; /* = &G.shell_ver (set in main()) */ struct variable shell_ver; + char **expanded_assignments; #if ENABLE_HUSH_FUNCTIONS struct function *top_func; # if ENABLE_HUSH_LOCAL @@ -1459,9 +1461,23 @@ static struct variable *get_local_var(const char *name) static const char* FAST_FUNC get_local_var_value(const char *name) { - struct variable **pp = get_ptr_to_local_var(name); - if (pp) - return strchr((*pp)->varstr, '=') + 1; + struct variable **vpp; + + if (G.expanded_assignments) { + char **cpp = G.expanded_assignments; + int len = strlen(name); + while (*cpp) { + char *cp = *cpp; + if (strncmp(cp, name, len) == 0 && cp[len] == '=') + return cp + len + 1; + cpp++; + } + } + + vpp = get_ptr_to_local_var(name); + if (vpp) + return strchr((*vpp)->varstr, '=') + 1; + if (strcmp(name, "PPID") == 0) return utoa(G.root_ppid); // bash compat: UID? EUID? @@ -3090,11 +3106,14 @@ static char* expand_strvec_to_string(char **argv) static char **expand_assignments(char **argv, int count) { int i; - char **p = NULL; + char **p; + + G.expanded_assignments = p = NULL; /* Expand assignments into one string each */ for (i = 0; i < count; i++) { - p = add_string_to_strings(p, expand_string_to_string(argv[i])); + G.expanded_assignments = p = add_string_to_strings(p, expand_string_to_string(argv[i])); } + G.expanded_assignments = NULL; return p; } @@ -4316,6 +4335,27 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe) * backgrounded: cmd & { list } & * subshell: ( list ) [&] */ +#if !ENABLE_HUSH_MODE_X +#define redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel, char argv_expanded) \ + redirect_and_varexp_helper(new_env_p, old_vars_p, command, squirrel) +#endif +static int redirect_and_varexp_helper(char ***new_env_p, struct variable **old_vars_p, struct command *command, int squirrel[3], char **argv_expanded) +{ + /* setup_redirects acts on file descriptors, not FILEs. + * This is perfect for work that comes after exec(). + * Is it really safe for inline use? Experimentally, + * things seem to work. */ + int rcode = setup_redirects(command, squirrel); + if (rcode == 0) { + char **new_env = expand_assignments(command->argv, command->assignment_cnt); + *new_env_p = new_env; + dump_cmd_in_x_mode(new_env); + dump_cmd_in_x_mode(argv_expanded); + if (old_vars_p) + *old_vars_p = set_vars_and_save_old(new_env); + } + return rcode; +} static NOINLINE int run_pipe(struct pipe *pi) { static const char *const null_ptr = NULL; @@ -4325,7 +4365,6 @@ static NOINLINE int run_pipe(struct pipe *pi) struct command *command; char **argv_expanded; char **argv; - char *p; /* it is not always needed, but we aim to smaller code */ int squirrel[] = { -1, -1, -1 }; int rcode; @@ -4402,19 +4441,45 @@ static NOINLINE int run_pipe(struct pipe *pi) if (argv[command->assignment_cnt] == NULL) { /* Assignments, but no command */ /* Ensure redirects take effect (that is, create files). - * Try "a=t >file": */ + * Try "a=t >file" */ +#if 0 /* A few cases in testsuite fail with this code. FIXME */ + rcode = redirect_and_varexp_helper(&new_env, /*old_vars:*/ NULL, command, squirrel, /*argv_expanded:*/ NULL); + /* Set shell variables */ + if (new_env) { + argv = new_env; + while (*argv) { + set_local_var(*argv, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); + /* Do we need to flag set_local_var() errors? + * "assignment to readonly var" and "putenv error" + */ + argv++; + } + } + /* Redirect error sets $? to 1. Otherwise, + * if evaluating assignment value set $?, retain it. + * Try "false; q=`exit 2`; echo $?" - should print 2: */ + if (rcode == 0) + rcode = G.last_exitcode; + /* Exit, _skipping_ variable restoring code: */ + goto clean_up_and_ret0; + +#else /* Older, bigger, but more correct code */ + rcode = setup_redirects(command, squirrel); restore_redirects(squirrel); /* Set shell variables */ if (G_x_mode) bb_putchar_stderr('+'); while (*argv) { - p = expand_string_to_string(*argv); + char *p = expand_string_to_string(*argv); if (G_x_mode) fprintf(stderr, " %s", p); debug_printf_exec("set shell var:'%s'->'%s'\n", *argv, p); set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); + /* Do we need to flag set_local_var() errors? + * "assignment to readonly var" and "putenv error" + */ argv++; } if (G_x_mode) @@ -4424,13 +4489,11 @@ static NOINLINE int run_pipe(struct pipe *pi) * Try "false; q=`exit 2`; echo $?" - should print 2: */ if (rcode == 0) rcode = G.last_exitcode; - /* Do we need to flag set_local_var() errors? - * "assignment to readonly var" and "putenv error" - */ IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) debug_leave(); debug_printf_exec("run_pipe: return %d\n", rcode); return rcode; +#endif } /* Expand the rest into (possibly) many strings each */ @@ -4471,16 +4534,8 @@ static NOINLINE int run_pipe(struct pipe *pi) goto clean_up_and_ret1; } } - /* setup_redirects acts on file descriptors, not FILEs. - * This is perfect for work that comes after exec(). - * Is it really safe for inline use? Experimentally, - * things seem to work. */ - rcode = setup_redirects(command, squirrel); + rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); if (rcode == 0) { - new_env = expand_assignments(argv, command->assignment_cnt); - dump_cmd_in_x_mode(new_env); - dump_cmd_in_x_mode(argv_expanded); - old_vars = set_vars_and_save_old(new_env); if (!funcp) { debug_printf_exec(": builtin '%s' '%s'...\n", x->b_cmd, argv_expanded[1]); @@ -4504,9 +4559,10 @@ static NOINLINE int run_pipe(struct pipe *pi) #endif } clean_up_and_ret: - restore_redirects(squirrel); unset_vars(new_env); add_vars(old_vars); +/* clean_up_and_ret0: */ + restore_redirects(squirrel); clean_up_and_ret1: free(argv_expanded); IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) @@ -4518,12 +4574,8 @@ static NOINLINE int run_pipe(struct pipe *pi) if (ENABLE_FEATURE_SH_STANDALONE) { int n = find_applet_by_name(argv_expanded[0]); if (n >= 0 && APPLET_IS_NOFORK(n)) { - rcode = setup_redirects(command, squirrel); + rcode = redirect_and_varexp_helper(&new_env, &old_vars, command, squirrel, argv_expanded); if (rcode == 0) { - new_env = expand_assignments(argv, command->assignment_cnt); - dump_cmd_in_x_mode(new_env); - dump_cmd_in_x_mode(argv_expanded); - old_vars = set_vars_and_save_old(new_env); debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", argv_expanded[0], argv_expanded[1]); rcode = run_nofork_applet(n, argv_expanded); diff --git a/shell/hush_test/hush-vars/var_serial.right b/shell/hush_test/hush-vars/var_serial.right new file mode 100644 index 000000000..42aa33057 --- /dev/null +++ b/shell/hush_test/hush-vars/var_serial.right @@ -0,0 +1,5 @@ +Assignments only: c=a +Assignments and a command: c=a +Assignments and a builtin: c=a +Assignments and a function: c=a +Done diff --git a/shell/hush_test/hush-vars/var_serial.tests b/shell/hush_test/hush-vars/var_serial.tests new file mode 100755 index 000000000..6b4a4cdf7 --- /dev/null +++ b/shell/hush_test/hush-vars/var_serial.tests @@ -0,0 +1,22 @@ +a=a + +b=b +c=c +# Second assignment depends on the first: +b=$a c=$b +echo Assignments only: c=$c + +b=b +c=c +b=$a c=$b "$THIS_SH" -c 'echo Assignments and a command: c=$c' + +b=b +c=c +b=$a c=$b eval 'echo Assignments and a builtin: c=$c' + +b=b +c=c +f() { echo Assignments and a function: c=$c; } +b=$a c=$b f + +echo Done -- cgit v1.2.3-55-g6feb