diff --git a/.gitignore b/.gitignore index 7840855c0..3eb5d22ab 100644 --- a/.gitignore +++ b/.gitignore @@ -40,3 +40,11 @@ core /busybox.links /runtest-tempdir-links /testsuite/echo-ne + +# +# cscope output +# +cscope.files +cscope.in.out +cscope.out +cscope.po.out diff --git a/Makefile b/Makefile index b1aaa87be..9a620e66b 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ SRCS = \ libbb/messages.c \ libbb/appletlib.c \ libbb/bb.basename.c \ - libbb/mempcpy.c \ + libbb/auto.string.c \ libbb/vfork.and.run.c \ libbb/poll.c \ libbb/get.exec.path.c \ diff --git a/Makefile.mk b/Makefile.mk index 9a9c11458..b48e828b6 100644 --- a/Makefile.mk +++ b/Makefile.mk @@ -35,7 +35,6 @@ LIBBB_B_SRC = \ libbb/escape.seq.c \ libbb/messages.c \ libbb/bb.basename.c \ - libbb/mempcpy.c \ libbb/get.exec.path.c \ libbb/exec.gno.c @@ -54,7 +53,8 @@ LIBBB_C_SRC = \ libbb/parse.mode.c \ libbb/poll.c \ libbb/pgrp.c \ - libbb/qsort.c + libbb/qsort.c \ + libbb/auto.string.c LIBBB_D_SRC = \ libbb/xfuncs.printf.c \ diff --git a/coreutils/test.c b/coreutils/test.c index f6dc0f81b..92ffd6bbf 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -39,14 +39,9 @@ //config: help //config: Enable 64-bit support in test. -/* "test --help" does not print help (POSIX compat), only "[ --help" does. - * We display " EXPRESSION ]" here (not " EXPRESSION") - * Unfortunately, it screws up generated BusyBox.html. TODO. */ -//usage:#define test_trivial_usage -//usage: "EXPRESSION ]" -//usage:#define test_full_usage "\n\n" -//usage: "Check file types, compare values etc. Return a 0/1 exit code\n" -//usage: "depending on logical value of EXPRESSION" +/* "test --help" is special-cased to ignore --help */ +//usage:#define test_trivial_usage NOUSAGE_STR +//usage:#define test_full_usage "" //usage: //usage:#define test_example_usage //usage: "$ test 1 -eq 2\n" diff --git a/include/autoconf.h b/include/autoconf.h index ff4e3ebb8..5c8018042 100644 --- a/include/autoconf.h +++ b/include/autoconf.h @@ -164,21 +164,13 @@ #define ENABLE_FEATURE_CLEAN_UP 0 #define IF_FEATURE_CLEAN_UP(x) #define IF_NOT_FEATURE_CLEAN_UP(x) x -#define CONFIG_FEATURE_UTMP 1 -#define ENABLE_FEATURE_UTMP 1 -#ifdef MAKE_SUID -# define IF_FEATURE_UTMP(x) x "CONFIG_FEATURE_UTMP" -#else -# define IF_FEATURE_UTMP(x) x -#endif +#undef CONFIG_FEATURE_UTMP +#define ENABLE_FEATURE_UTMP 0 +#define IF_FEATURE_UTMP(x) #define IF_NOT_FEATURE_UTMP(x) -#define CONFIG_FEATURE_WTMP 1 -#define ENABLE_FEATURE_WTMP 1 -#ifdef MAKE_SUID -# define IF_FEATURE_WTMP(x) x "CONFIG_FEATURE_WTMP" -#else -# define IF_FEATURE_WTMP(x) x -#endif +#undef CONFIG_FEATURE_WTMP +#define ENABLE_FEATURE_WTMP 0 +#define IF_FEATURE_WTMP(x) #define IF_NOT_FEATURE_WTMP(x) #define CONFIG_FEATURE_PIDFILE 1 #define ENABLE_FEATURE_PIDFILE 1 diff --git a/include/busybox.h b/include/busybox.h index 9bb0042dc..c8a9fc86d 100644 --- a/include/busybox.h +++ b/include/busybox.h @@ -5,7 +5,7 @@ #ifndef BUSYBOX_H #define BUSYBOX_H 1 -#define BB_VER "1.23.1 (GNO hush 1.1)" +#define BB_VER "1.24.0 (GNO hush 1.2-dev)" #include "libbb.h" /* BB_DIR_foo and BB_SUID_bar constants: */ diff --git a/include/libbb.h b/include/libbb.h index 31a1e46a4..c76b0b026 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -104,7 +104,30 @@ # include #endif #if ENABLE_FEATURE_UTMP -# include +# if defined __UCLIBC__ && ( \ + (UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 32) \ + && UCLIBC_VERSION < KERNEL_VERSION(0, 9, 34) \ + && defined __UCLIBC_HAS_UTMPX__ \ + ) || ( \ + UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 34) \ + ) \ + ) +# include +# elif defined __UCLIBC__ +# include +# define utmpx utmp +# define setutxent setutent +# define endutxent endutent +# define getutxent getutent +# define getutxid getutid +# define getutxline getutline +# define pututxline pututline +# define utmpxname utmpname +# define updwtmpx updwtmp +# define _PATH_UTMPX _PATH_UTMP +# else +# include +# endif #endif #if ENABLE_LOCALE_SUPPORT # include @@ -396,6 +419,8 @@ const char *bb_basename(const char *name) FAST_FUNC; /* NB: can violate const-ness (similarly to strchr) */ char *last_char_is(const char *s, int c) FAST_FUNC; const char* endofname(const char *name) FAST_FUNC; +char *is_prefixed_with(const char *string, const char *key) FAST_FUNC; +char *is_suffixed_with(const char *string, const char *key) FAST_FUNC; int ndelay_on(int fd) FAST_FUNC; int ndelay_off(int fd) FAST_FUNC; @@ -433,8 +458,6 @@ char *xrealloc_getcwd_or_warn(char *cwd) FAST_FUNC; char *xmalloc_follow_symlinks(const char *path) FAST_FUNC RETURNS_MALLOC; -void *mempcpy(void *dst, const void *src, size_t len); - void bb_signals(long int sigs, sig_t f) FAST_FUNC; /* syscalls like read() will be interrupted with EINTR: */ @@ -512,6 +535,11 @@ void xlisten(int s, int backlog) FAST_FUNC; void xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen) FAST_FUNC; ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, socklen_t tolen) FAST_FUNC; + +int setsockopt_int(int fd, int level, int optname, int optval) FAST_FUNC; +int setsockopt_1(int fd, int level, int optname) FAST_FUNC; +int setsockopt_SOL_SOCKET_int(int fd, int optname, int optval) FAST_FUNC; +int setsockopt_SOL_SOCKET_1(int fd, int optname) FAST_FUNC; /* SO_REUSEADDR allows a server to rebind to an address that is already * "in use" by old connections to e.g. previous server instance which is * killed or crashed. Without it bind will fail until all such connections @@ -519,6 +547,7 @@ ssize_t xsendto(int s, const void *buf, size_t len, const struct sockaddr *to, * regardless of SO_REUSEADDR (unlike some other flavors of Unix). * Turn it on before you call bind(). */ void setsockopt_reuseaddr(int fd) FAST_FUNC; /* On Linux this never fails. */ +int setsockopt_keepalive(int fd) FAST_FUNC; int setsockopt_broadcast(int fd) FAST_FUNC; int setsockopt_bindtodevice(int fd, const char *iface) FAST_FUNC; /* NB: returns port in host byte order */ @@ -613,6 +642,7 @@ uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC; char *xstrdup(const char *s) FAST_FUNC RETURNS_MALLOC; char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC; +void *xmemdup(const void *s, int n) FAST_FUNC RETURNS_MALLOC; void overlapping_strcpy(char *dst, const char *src) FAST_FUNC; char *safe_strncpy(char *dst, const char *src, size_t size) FAST_FUNC; char *strncpy_IFNAMSIZ(char *dst, const char *src) FAST_FUNC; @@ -625,6 +655,7 @@ void bb_putchar_binary(int ch) FAST_FUNC; /* Note: does not use stdio, writes to fd 2 directly */ int bb_putchar_stderr(char ch) FAST_FUNC; char *xasprintf(const char *format, ...) __attribute__ ((format(printf, 1, 2))) FAST_FUNC RETURNS_MALLOC; +char *auto_string(char *str) FAST_FUNC; // gcc-4.1.1 still isn't good enough at optimizing it // (+200 bytes compared to macro) //static ALWAYS_INLINE @@ -677,7 +708,7 @@ void* xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx) F extern ssize_t safe_read(int fd, void *buf, size_t count) FAST_FUNC; -extern ssize_t nonblock_immune_read(int fd, void *buf, size_t count, int loop_on_EINTR) FAST_FUNC; +extern ssize_t nonblock_immune_read(int fd, void *buf, size_t count) FAST_FUNC; // NB: will return short read on error, not -1, // if some data was read before error occurred extern ssize_t full_read(int fd, void *buf, size_t count) FAST_FUNC; @@ -808,6 +839,8 @@ struct suffix_mult { }; extern const struct suffix_mult bkm_suffixes[]; #define km_suffixes (bkm_suffixes + 1) +extern const struct suffix_mult cwbkMG_suffixes[]; +#define kMG_suffixes (cwbkMG_suffixes + 3) #include "xatonum.h" /* Specialized: */ @@ -870,9 +903,11 @@ int ingroup(uid_t u, gid_t g); #if ENABLE_FEATURE_UTMP void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname); +void FAST_FUNC update_utmp_DEAD_PROCESS(pid_t pid); #else # define write_new_utmp(pid, new_type, tty_name, username, hostname) ((void)0) # define update_utmp(pid, new_type, tty_name, username, hostname) ((void)0) +# define update_utmp_DEAD_PROCESS(pid) ((void)0) #endif @@ -1007,9 +1042,8 @@ enum { }; extern const char *msg_eol; extern smallint logmode; -extern int die_sleep; extern uint8_t xfunc_error_retval; -extern jmp_buf die_jmp; +extern void (*die_func)(void); extern void xfunc_die(void) NORETURN FAST_FUNC; extern void bb_show_usage(void) NORETURN FAST_FUNC; extern void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; @@ -1123,7 +1157,8 @@ char *bb_ask_stdin(const char * prompt) FAST_FUNC; char *bb_ask(const int fd, int timeout, const char * prompt) FAST_FUNC; int bb_ask_confirmation(void) FAST_FUNC; -int bb_parse_mode(const char* s, mode_t* theMode) FAST_FUNC; +/* Returns -1 if input is invalid. current_mode is a base for e.g. "u+rw" */ +int bb_parse_mode(const char* s, unsigned cur_mode) FAST_FUNC; /* * Config file parser @@ -1543,7 +1578,7 @@ extern const char bb_path_wtmp_file[] ALIGN1; #endif extern const int const_int_0; -extern const int const_int_1; +//extern const int const_int_1; /* Providing hard guarantee on minimum size (think of BUFSIZ == 128) */ @@ -1675,7 +1710,6 @@ void _exit_wrapper(int status) NORETURN; typedef void (*bbunit_testfunc)(void); struct bbunit_listelem { - struct bbunit_listelem* next; const char* name; bbunit_testfunc testfunc; }; diff --git a/include/platform.h b/include/platform.h index 4b8ecae59..3c4fe5677 100644 --- a/include/platform.h +++ b/include/platform.h @@ -161,6 +161,43 @@ typedef unsigned long uintptr_t; #endif +/* ---- Unaligned access ------------------------------------ */ + +typedef int bb__aliased_int FIX_ALIASING; +typedef long bb__aliased_long FIX_ALIASING; +typedef uint16_t bb__aliased_uint16_t FIX_ALIASING; +typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; + +/* NB: unaligned parameter should be a pointer, aligned one - + * a lvalue. This makes it more likely to not swap them by mistake + */ +#if defined(i386) || defined(__x86_64__) || defined(__powerpc__) +# define BB_UNALIGNED_MEMACCESS_OK 1 +# define move_from_unaligned_int(v, intp) ((v) = *(bb__aliased_int*)(intp)) +# define move_from_unaligned_long(v, longp) ((v) = *(bb__aliased_long*)(longp)) +# define move_from_unaligned16(v, u16p) ((v) = *(bb__aliased_uint16_t*)(u16p)) +# define move_from_unaligned32(v, u32p) ((v) = *(bb__aliased_uint32_t*)(u32p)) +# define move_to_unaligned16(u16p, v) (*(bb__aliased_uint16_t*)(u16p) = (v)) +# define move_to_unaligned32(u32p, v) (*(bb__aliased_uint32_t*)(u32p) = (v)) +/* #elif ... - add your favorite arch today! */ +#else +# define BB_UNALIGNED_MEMACCESS_OK 0 +/* performs reasonably well (gcc usually inlines memcpy here) */ +# define move_from_unaligned_int(v, intp) (memcpy(&(v), (intp), sizeof(int))) +# define move_from_unaligned_long(v, longp) (memcpy(&(v), (longp), sizeof(long))) +# define move_from_unaligned16(v, u16p) (memcpy(&(v), (u16p), 2)) +# define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4)) +# define move_to_unaligned16(u16p, v) do { \ + uint16_t __t = (v); \ + memcpy((u16p), &__t, 2); \ +} while (0) +# define move_to_unaligned32(u32p, v) do { \ + uint32_t __t = (v); \ + memcpy((u32p), &__t, 4); \ +} while (0) +#endif + + /* ---- Size-saving "small" ints (arch-dependent) ----------- */ #if defined(i386) || defined(__x86_64__) || defined(__mips__) || defined(__cris__) @@ -290,10 +327,12 @@ typedef unsigned smalluint; #define HAVE_DPRINTF 1 #define HAVE_MEMRCHR 1 #define HAVE_MKDTEMP 1 +#define HAVE_TTYNAME_R 1 #define HAVE_PTSNAME_R 1 #define HAVE_SETBIT 1 #define HAVE_SIGHANDLER_T 1 #define HAVE_STPCPY 1 +#define HAVE_MEMPCPY 1 #define HAVE_STRCASESTR 1 #define HAVE_STRCHRNUL 1 #define HAVE_STRSEP 1 @@ -371,9 +410,12 @@ typedef unsigned smalluint; #if defined(__APPLE__) # undef HAVE_STRCHRNUL +# undef HAVE_MEMPCPY #endif #if defined(__FreeBSD__) +/* users say mempcpy is not present in FreeBSD 9.x */ +# undef HAVE_MEMPCPY # undef HAVE_CLEARENV # undef HAVE_FDATASYNC # undef HAVE_MNTENT_H @@ -398,9 +440,17 @@ typedef unsigned smalluint; #endif #if defined(ANDROID) || defined(__ANDROID__) -# undef HAVE_DPRINTF -# undef HAVE_GETLINE -# undef HAVE_STPCPY +# if __ANDROID_API__ < 8 +# undef HAVE_DPRINTF +# else +# define dprintf fdprintf +# endif +# if __ANDROID_API__ < 21 +# undef HAVE_TTYNAME_R +# undef HAVE_GETLINE +# undef HAVE_STPCPY +# endif +# undef HAVE_MEMPCPY # undef HAVE_STRCHRNUL # undef HAVE_STRVERSCMP # undef HAVE_UNLOCKED_LINE_OPS @@ -408,6 +458,7 @@ typedef unsigned smalluint; #endif #if defined(__GNO__) +# undef HAVE_MEMPCPY # undef HAVE_CLEARENV # undef HAVE_FDATASYNC # undef HAVE_DPRINTF @@ -446,6 +497,11 @@ extern void *memrchr(const void *s, int c, size_t n) FAST_FUNC; extern char *mkdtemp(char *template) FAST_FUNC; #endif +#ifndef HAVE_TTYNAME_R +#define ttyname_r bb_ttyname_r +extern int ttyname_r(int fd, char *buf, size_t buflen); +#endif + #ifndef HAVE_SETBIT # define setbit(a, b) ((a)[(b) >> 3] |= 1 << ((b) & 7)) # define clrbit(a, b) ((a)[(b) >> 3] &= ~(1 << ((b) & 7))) @@ -463,6 +519,18 @@ typedef void (*sighandler_t)(int, int); extern char *stpcpy(char *p, const char *to_add) FAST_FUNC; #endif +#ifndef HAVE_MEMPCPY +#include +/* In case we are wrong about !HAVE_MEMPCPY, and toolchain _does_ have + * mempcpy(), avoid colliding with it: + */ +#define mempcpy bb__mempcpy +static ALWAYS_INLINE void *mempcpy(void *dest, const void *src, size_t len) +{ + return memcpy(dest, src, len) + len; +} +#endif + #ifndef HAVE_STRCASESTR extern char *strcasestr(const char *s, const char *pattern) FAST_FUNC; #endif diff --git a/libbb/auto.string.c b/libbb/auto.string.c new file mode 100644 index 000000000..ae940069a --- /dev/null +++ b/libbb/auto.string.c @@ -0,0 +1,23 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 2015 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//kbuild:lib-y += auto_string.o + +#include "libbb.h" + +char* FAST_FUNC auto_string(char *str) +{ + static char *saved[4]; + static uint8_t cur_saved; /* = 0 */ + + free(saved[cur_saved]); + saved[cur_saved] = str; + cur_saved = (cur_saved + 1) & (ARRAY_SIZE(saved)-1); + + return str; +} diff --git a/libbb/cmp.str.array.c b/libbb/cmp.str.array.c index 4b10cc138..2f51237a3 100644 --- a/libbb/cmp.str.array.c +++ b/libbb/cmp.str.array.c @@ -5,6 +5,49 @@ #include "libbb.h" +/* + * Return NULL if string is not prefixed with key. Return pointer to the + * first character in string after the prefix key. If key is an empty string, + * return pointer to the beginning of string. + */ +char* FAST_FUNC is_prefixed_with(const char *string, const char *key) +{ +#if 0 /* Two passes over key - probably slower */ + int len = strlen(key); + if (strncmp(string, key, len) == 0) + return string + len; + return NULL; +#else /* Open-coded */ + while (*key != '\0') { + if (*key != *string) + return NULL; + key++; + string++; + } + return (char*)string; +#endif +} + +/* + * Return NULL if string is not suffixed with key. Return pointer to the + * beginning of prefix key in string. If key is an empty string return pointer + * to the end of string. + */ +char* FAST_FUNC is_suffixed_with(const char *string, const char *key) +{ + size_t key_len = strlen(key); + ssize_t len_diff = strlen(string) - key_len; + + if (len_diff >= 0) { + string += len_diff; + if (strcmp(string, key) == 0) { + return (char*)string; + } + } + + return NULL; +} + /* returns the array index of the string */ /* (index of first match is returned, or -1) */ int FAST_FUNC index_in_str_array(const char *const string_array[], const char *key) @@ -39,10 +82,9 @@ int FAST_FUNC index_in_strings(const char *strings, const char *key) int FAST_FUNC index_in_substr_array(const char *const string_array[], const char *key) { int i; - int len = strlen(key); - if (len) { + if (key[0]) { for (i = 0; string_array[i] != 0; i++) { - if (strncmp(string_array[i], key, len) == 0) { + if (is_prefixed_with(string_array[i], key)) { return i; } } @@ -93,3 +135,37 @@ smallint FAST_FUNC yesno(const char *str) return ret / 3; } #endif + +#if ENABLE_UNIT_TEST + +BBUNIT_DEFINE_TEST(is_prefixed_with) +{ + BBUNIT_ASSERT_STREQ(" bar", is_prefixed_with("foo bar", "foo")); + BBUNIT_ASSERT_STREQ("bar", is_prefixed_with("foo bar", "foo ")); + BBUNIT_ASSERT_STREQ("", is_prefixed_with("foo", "foo")); + BBUNIT_ASSERT_STREQ("foo", is_prefixed_with("foo", "")); + BBUNIT_ASSERT_STREQ("", is_prefixed_with("", "")); + + BBUNIT_ASSERT_NULL(is_prefixed_with("foo", "bar foo")); + BBUNIT_ASSERT_NULL(is_prefixed_with("foo foo", "bar")); + BBUNIT_ASSERT_NULL(is_prefixed_with("", "foo")); + + BBUNIT_ENDTEST; +} + +BBUNIT_DEFINE_TEST(is_suffixed_with) +{ + BBUNIT_ASSERT_STREQ("bar", is_suffixed_with("foo bar", "bar")); + BBUNIT_ASSERT_STREQ("foo", is_suffixed_with("foo", "foo")); + BBUNIT_ASSERT_STREQ("", is_suffixed_with("foo", "")); + BBUNIT_ASSERT_STREQ("", is_suffixed_with("", "")); + BBUNIT_ASSERT_STREQ("foo", is_suffixed_with("barfoofoo", "foo")); + + BBUNIT_ASSERT_NULL(is_suffixed_with("foo", "bar foo")); + BBUNIT_ASSERT_NULL(is_suffixed_with("foo foo", "bar")); + BBUNIT_ASSERT_NULL(is_suffixed_with("", "foo")); + + BBUNIT_ENDTEST; +} + +#endif /* ENABLE_UNIT_TEST */ diff --git a/libbb/lineedit.c b/libbb/lineedit.c index 1602a3cab..8ac3b09ef 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -819,36 +819,25 @@ static char *username_path_completion(char *ud) return tilde_name; } -#define LINE_BUFF_SIZE 256 /* ~use - find all users with this prefix. * Return the length of the prefix used for matching. */ static NOINLINE unsigned complete_username(const char *ud) { - /* Using _r function to avoid pulling in static buffers */ - char *line_buff; - struct passwd pwd; - struct passwd *result; + struct passwd *pw; unsigned userlen; ud++; /* skip ~ */ userlen = strlen(ud); - - line_buff = malloc(LINE_BUFF_SIZE); - if (!line_buff) - goto ret; setpwent(); - while (!getpwent_r(&pwd, line_buff, LINE_BUFF_SIZE, &result)) { - /* Null usernames should result in all users as possible completions. */ - if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) { - add_match(xasprintf("~%s/", pwd.pw_name)); + while ((pw = getpwent()) != NULL) { /* Null usernames should result in all users as possible completions. */ + if (/* !ud[0] || */ is_prefixed_with(pw->pw_name, ud)) { + add_match(xasprintf("~%s/", pw->pw_name)); } } - endpwent(); + endpwent(); /* don't keep password file open */ - free(line_buff); - ret: return 1 + userlen; } # endif /* FEATURE_USERNAME_COMPLETION */ @@ -960,7 +949,7 @@ static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) if (!pfind[0] && DOT_OR_DOTDOT(name_found)) continue; /* match? */ - if (strncmp(name_found, pfind, pf_len) != 0) + if (!is_prefixed_with(name_found, pfind)) continue; /* no */ found = concat_path_file(paths[i], name_found); @@ -2069,15 +2058,16 @@ static void parse_and_put_prompt(const char *prmt_ptr) cwd_buf = xrealloc_getcwd_or_warn(NULL); if (!cwd_buf) cwd_buf = (char *)bb_msg_unknown; - else { + else if (home_pwd_buf[0]) { + char *after_home_user; + /* /home/user[/something] -> ~[/something] */ - l = strlen(home_pwd_buf); - if (l != 0 - && strncmp(home_pwd_buf, cwd_buf, l) == 0 - && (cwd_buf[l] == '/' || cwd_buf[l] == '\0') + after_home_user = is_prefixed_with(cwd_buf, home_pwd_buf); + if (after_home_user + && (*after_home_user == '/' || *after_home_user == '\0') ) { cwd_buf[0] = '~'; - overlapping_strcpy(cwd_buf + 1, cwd_buf + l); + overlapping_strcpy(cwd_buf + 1, after_home_user); } } } diff --git a/libbb/mempcpy.c b/libbb/mempcpy.c deleted file mode 100644 index e428878bc..000000000 --- a/libbb/mempcpy.c +++ /dev/null @@ -1,26 +0,0 @@ -/* Copy memory area and return pointer after last written byte. - Adapted from Gnulib (as of Dec 15, 2014). - Copyright (C) 2003, 2007, 2009-2014 Free Software Foundation, Inc. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, see . */ - -#include - -/* Copy N bytes of SRC to DEST, return pointer to bytes after the - last written byte. */ -void * -mempcpy (void *dest, const void *src, size_t n) -{ - return (char *) memcpy (dest, src, n) + n; -} diff --git a/libbb/messages.c b/libbb/messages.c index 0bdf53180..b32316340 100644 --- a/libbb/messages.c +++ b/libbb/messages.c @@ -42,7 +42,7 @@ const char bb_PATH_root_path[] ALIGN1 = "PATH=/sbin:/usr/sbin:/bin:/usr/bin" BB_ADDITIONAL_PATH; -const int const_int_1 = 1; +//const int const_int_1 = 1; /* explicitly = 0, otherwise gcc may make it a common variable * and it will end up in bss */ const int const_int_0 = 0; diff --git a/libbb/parse.mode.c b/libbb/parse.mode.c index 5a4e1c579..bddd39bca 100644 --- a/libbb/parse.mode.c +++ b/libbb/parse.mode.c @@ -15,7 +15,7 @@ #define FILEMODEBITS (S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO) -int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) +int FAST_FUNC bb_parse_mode(const char *s, unsigned current_mode) { static const mode_t who_mask[] = { S_ISUID | S_ISGID | S_ISVTX | S_IRWXU | S_IRWXG | S_IRWXO, /* a */ @@ -46,13 +46,12 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) tmp = strtoul(s, &e, 8); if (*e || (tmp > 07777U)) { /* Check range and trailing chars. */ - return 0; + return -1; } - *current_mode = tmp; - return 1; + return tmp; } - new_mode = *current_mode; + new_mode = current_mode; /* Note: we allow empty clauses, and hence empty modes. * We treat an empty mode as no change to perms. */ @@ -71,7 +70,7 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) if (*p == *s) { wholist |= who_mask[(int)(p-who_chars)]; if (!*++s) { - return 0; + return -1; } goto WHO_LIST; } @@ -80,7 +79,7 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) do { /* Process action list. */ if ((*s != '+') && (*s != '-')) { if (*s != '=') { - return 0; + return -1; } /* Since op is '=', clear all bits corresponding to the * wholist, or all file bits if wholist is empty. */ @@ -145,6 +144,5 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) } while (*s && (*s != ',')); } - *current_mode = new_mode; - return 1; + return new_mode; } diff --git a/libbb/platform.c b/libbb/platform.c index e3f91f7bf..7863375dc 100644 --- a/libbb/platform.c +++ b/libbb/platform.c @@ -209,3 +209,22 @@ ssize_t FAST_FUNC getline(char **lineptr, size_t *n, FILE *stream) return len; } #endif + +#ifndef HAVE_TTYNAME_R +int ttyname_r(int fd, char *buf, size_t buflen) +{ + int r; + char path[sizeof("/proc/self/fd/%d") + sizeof(int)*3]; + + if (!isatty(fd)) + return errno == EINVAL ? ENOTTY : errno; + sprintf(path, "/proc/self/fd/%d", fd); + r = readlink(path, buf, buflen); + if (r < 0) + return errno; + if (r >= buflen) + return ERANGE; + buf[r] = '\0'; + return 0; +} +#endif diff --git a/libbb/printable.str.c b/libbb/printable.str.c index a316f60de..077d58d32 100644 --- a/libbb/printable.str.c +++ b/libbb/printable.str.c @@ -11,9 +11,6 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str) { - static char *saved[4]; - static unsigned cur_saved; /* = 0 */ - char *dst; const char *s; @@ -56,10 +53,5 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str) } } #endif - - free(saved[cur_saved]); - saved[cur_saved] = dst; - cur_saved = (cur_saved + 1) & (ARRAY_SIZE(saved)-1); - - return dst; + return auto_string(dst); } diff --git a/libbb/skip.whitespc.c b/libbb/skip.whitespc.c index 8c7b674c3..b6cfbba4d 100644 --- a/libbb/skip.whitespc.c +++ b/libbb/skip.whitespc.c @@ -33,7 +33,7 @@ char* FAST_FUNC skip_non_whitespace(const char *s) char* FAST_FUNC skip_dev_pfx(const char *tty_name) { - if (strncmp(tty_name, "/dev/", 5) == 0) + if (is_prefixed_with(tty_name, "/dev/")) tty_name += 5; return (char*)tty_name; } diff --git a/libbb/xatonum.c b/libbb/xatonum.c index e77c53a77..5f32db432 100644 --- a/libbb/xatonum.c +++ b/libbb/xatonum.c @@ -70,3 +70,24 @@ const struct suffix_mult bkm_suffixes[] = { { "m", 1024*1024 }, { "", 0 } }; + +const struct suffix_mult cwbkMG_suffixes[] = { + { "c", 1 }, + { "w", 2 }, + { "b", 512 }, + { "kB", 1000 }, + { "kD", 1000 }, + { "k", 1024 }, + { "KB", 1000 }, /* compat with coreutils dd */ + { "KD", 1000 }, /* compat with coreutils dd */ + { "K", 1024 }, /* compat with coreutils dd */ + { "MB", 1000000 }, + { "MD", 1000000 }, + { "M", 1024*1024 }, + { "GB", 1000000000 }, + { "GD", 1000000000 }, + { "G", 1024*1024*1024 }, + /* "D" suffix for decimal is not in coreutils manpage, looks like it's deprecated */ + /* coreutils also understands TPEZY suffixes for tera- and so on, with B suffix for decimal */ + { "", 0 } +}; diff --git a/libbb/xfunc.die.c b/libbb/xfunc.die.c index ab41c03f3..9a058559f 100644 --- a/libbb/xfunc.die.c +++ b/libbb/xfunc.die.c @@ -7,35 +7,17 @@ * Licensed under GPLv2, see file LICENSE in this source tree. */ -/* Keeping it separate allows to NOT suck in stdio for VERY small applets. +/* Keeping it separate allows to NOT pull in stdio for VERY small applets. * Try building busybox with only "true" enabled... */ #include "libbb.h" -int die_sleep; -#if ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH -jmp_buf die_jmp; -#endif +void (*die_func)(void); void FAST_FUNC xfunc_die(void) { - if (die_sleep) { - if ((ENABLE_FEATURE_PREFER_APPLETS || ENABLE_HUSH) - && die_sleep < 0 - ) { - /* Special case. We arrive here if NOFORK applet - * calls xfunc, which then decides to die. - * We don't die, but jump instead back to caller. - * NOFORK applets still cannot carelessly call xfuncs: - * p = xmalloc(10); - * q = xmalloc(10); // BUG! if this dies, we leak p! - */ - /* -2222 means "zero" (longjmp can't pass 0) - * run_nofork_applet() catches -2222. */ - longjmp(die_jmp, xfunc_error_retval ? xfunc_error_retval : -2222); - } - sleep(die_sleep); - } + if (die_func) + die_func(); if (!is_forked_child()) exit(xfunc_error_retval); else diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index c54736be9..e244aa0fb 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -318,7 +318,6 @@ off_t FAST_FUNC fdlength(int fd) else bottom = pos; // If we can't, it's smaller. - } else { if (bottom == top) { if (!top) return 0; diff --git a/libbb/xfuncs.printf.c b/libbb/xfuncs.printf.c index 97814fd56..611a9397d 100644 --- a/libbb/xfuncs.printf.c +++ b/libbb/xfuncs.printf.c @@ -112,6 +112,11 @@ char* FAST_FUNC xstrndup(const char *s, int n) return memcpy(t, s, n); } +void* FAST_FUNC xmemdup(const void *s, int n) +{ + return memcpy(xmalloc(n), s, n); +} + // Die if we can't open a file and return a FILE* to it. // Notice we haven't got xfread(), This is for use with fscanf() and friends. FILE* FAST_FUNC xfopen(const char *path, const char *mode) diff --git a/shell/hush.c b/shell/hush.c index 396b99b82..4f2bdc81b 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -472,7 +472,7 @@ enum { MAYBE_ASSIGNMENT = 0, DEFINITELY_ASSIGNMENT = 1, NOT_ASSIGNMENT = 2, - /* Not an assigment, but next word may be: "if v=xyz cmd;" */ + /* Not an assignment, but next word may be: "if v=xyz cmd;" */ WORD_IS_KEYWORD = 3 }; /* Used for initialization: o_string foo = NULL_O_STRING; */ @@ -1683,10 +1683,11 @@ static sighandler_t install_sighandler(int sig, sighandler_t handler) #if ENABLE_HUSH_JOB +static void xfunc_has_died(void); /* After [v]fork, in child: do not restore tty pgrp on xfunc death */ -# define disable_restore_tty_pgrp_on_exit() (die_sleep = 0) +# define disable_restore_tty_pgrp_on_exit() (die_func = NULL) /* After [v]fork, in parent: restore tty pgrp on xfunc death */ -# define enable_restore_tty_pgrp_on_exit() (die_sleep = -1) +# define enable_restore_tty_pgrp_on_exit() (die_func = xfunc_has_died) /* Restores tty foreground process group, and exits. * May be called as signal handler for fatal signal @@ -1820,6 +1821,15 @@ static void hush_exit(int exitcode) #endif } +static void xfunc_has_died(void) NORETURN; +static void xfunc_has_died(void) +{ + /* xfunc has failed! die die die */ + /* no EXIT traps, this is an escape hatch! */ + G.exiting = 1; + hush_exit(xfunc_error_retval); +} + //TODO: return a mask of ALL handled sigs? static int check_and_run_traps(void) @@ -3415,11 +3425,29 @@ static int reserved_word(o_string *word, struct parse_context *ctx) old->command->group = ctx->list_head; old->command->cmd_type = CMD_NORMAL; # if !BB_MMU - o_addstr(&old->as_string, ctx->as_string.data); - o_free_unsafe(&ctx->as_string); - old->command->group_as_string = xstrdup(old->as_string.data); - debug_printf_parse(("pop, remembering as:'%s'\n", - old->command->group_as_string)); + /* At this point, the compound command's string is in + * ctx->as_string... except for the leading keyword! + * Consider this example: "echo a | if true; then echo a; fi" + * ctx->as_string will contain "true; then echo a; fi", + * with "if " remaining in old->as_string! + */ + { + char *str; + int len = old->as_string.length; + /* Concatenate halves */ + o_addstr(&old->as_string, ctx->as_string.data); + o_free_unsafe(&ctx->as_string); + /* Find where leading keyword starts in first half */ + str = old->as_string.data + len; + if (str > old->as_string.data) + str--; /* skip whitespace after keyword */ + while (str > old->as_string.data && isalpha(str[-1])) + str--; + /* Ugh, we're done with this horrid hack */ + old->command->group_as_string = xstrdup(str); + debug_printf_parse(("pop, remembering as:'%s'\n", + old->command->group_as_string)); + } # endif *ctx = *old; /* physical copy */ free(old); @@ -4518,7 +4546,7 @@ static struct pipe *parse_stream(char **pstring, pi = NULL; } #if !BB_MMU - debug_printf_parse(("as_string '%s'\n", ctx.as_string.data)); + debug_printf_parse(("as_string1 '%s'\n", ctx.as_string.data)); if (pstring) *pstring = ctx.as_string.data; else @@ -4669,7 +4697,7 @@ static struct pipe *parse_stream(char **pstring, ) { o_free(&dest); #if !BB_MMU - debug_printf_parse(("as_string '%s'\n", ctx.as_string.data)); + debug_printf_parse(("as_string2 '%s'\n", ctx.as_string.data)); if (pstring) *pstring = ctx.as_string.data; else @@ -4909,9 +4937,6 @@ static struct pipe *parse_stream(char **pstring, * with redirect_opt_num(), but bash doesn't do it. * "echo foo 2| cat" yields "foo 2". */ done_command(&ctx); -#if !BB_MMU - o_reset_to_empty_unquoted(&ctx.as_string); -#endif } goto new_cmd; case '(': @@ -5660,7 +5685,6 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS))); } break; - } /* switch (char after ) */ if (val && val[0]) { @@ -6211,7 +6235,83 @@ static FILE *generate_stream_from_string(const char *s, pid_t *pid_p) #if BB_MMU pid = xfork(); if (pid == 0) { /* child */ +<<<<<<< HEAD xforked_child(&args_struct); +======= + disable_restore_tty_pgrp_on_exit(); + /* Process substitution is not considered to be usual + * 'command execution'. + * SUSv3 says ctrl-Z should be ignored, ctrl-C should not. + */ + bb_signals(0 + + (1 << SIGTSTP) + + (1 << SIGTTIN) + + (1 << SIGTTOU) + , SIG_IGN); + CLEAR_RANDOM_T(&G.random_gen); /* or else $RANDOM repeats in child */ + close(channel[0]); /* NB: close _first_, then move fd! */ + xmove_fd(channel[1], 1); + /* Prevent it from trying to handle ctrl-z etc */ + IF_HUSH_JOB(G.run_list_level = 1;) + /* Awful hack for `trap` or $(trap). + * + * http://www.opengroup.org/onlinepubs/009695399/utilities/trap.html + * contains an example where "trap" is executed in a subshell: + * + * save_traps=$(trap) + * ... + * eval "$save_traps" + * + * Standard does not say that "trap" in subshell shall print + * parent shell's traps. It only says that its output + * must have suitable form, but then, in the above example + * (which is not supposed to be normative), it implies that. + * + * bash (and probably other shell) does implement it + * (traps are reset to defaults, but "trap" still shows them), + * but as a result, "trap" logic is hopelessly messed up: + * + * # trap + * trap -- 'echo Ho' SIGWINCH <--- we have a handler + * # (trap) <--- trap is in subshell - no output (correct, traps are reset) + * # true | trap <--- trap is in subshell - no output (ditto) + * # echo `true | trap` <--- in subshell - output (but traps are reset!) + * trap -- 'echo Ho' SIGWINCH + * # echo `(trap)` <--- in subshell in subshell - output + * trap -- 'echo Ho' SIGWINCH + * # echo `true | (trap)` <--- in subshell in subshell in subshell - output! + * trap -- 'echo Ho' SIGWINCH + * + * The rules when to forget and when to not forget traps + * get really complex and nonsensical. + * + * Our solution: ONLY bare $(trap) or `trap` is special. + */ + s = skip_whitespace(s); + if (is_prefixed_with(s, "trap") + && skip_whitespace(s + 4)[0] == '\0' + ) { + static const char *const argv[] = { NULL, NULL }; + builtin_trap((char**)argv); + exit(0); /* not _exit() - we need to fflush */ + } +# if BB_MMU + reset_traps_to_defaults(); + parse_and_run_string(s); + _exit(G.last_exitcode); +# else + /* We re-execute after vfork on NOMMU. This makes this script safe: + * yes "0123456789012345678901234567890" | dd bs=32 count=64k >BIG + * huge=`cat BIG` # was blocking here forever + * echo OK + */ + re_execute_shell(&to_free, + s, + G.global_argv[0], + G.global_argv + 1, + NULL); +# endif +>>>>>>> 7ab00a0de9cfeeacff70a74402808d225ba07397 } #else pid = xvfork_and_run(xforked_child, &args_struct); @@ -7226,7 +7326,7 @@ static int checkjobs(struct pipe *fg_pipe) int sig = WTERMSIG(status); if (i == fg_pipe->num_cmds-1) /* TODO: use strsignal() instead for bash compat? but that's bloat... */ - printf("%s\n", sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); + puts(sig == SIGINT || sig == SIGPIPE ? "" : get_signame(sig)); /* TODO: if (WCOREDUMP(status)) + " (core dumped)"; */ /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? * Maybe we need to use sig | 128? */ @@ -8601,12 +8701,7 @@ int hush_main(int argc, char **argv) /* Initialize some more globals to non-zero values */ cmdedit_update_prompt(); - if (setjmp(die_jmp)) { - /* xfunc has failed! die die die */ - /* no EXIT traps, this is an escape hatch! */ - G.exiting = 1; - hush_exit(xfunc_error_retval); - } + die_func = xfunc_has_died; /* Shell is non-interactive at first. We need to call * install_special_sighandlers() if we are going to execute "sh