Merge with BusyBox 1.24.0.

There's really only one bug fix in here that should be significant for GNO hush. The other changes should be inconsequential, AFAIK.
This commit is contained in:
Stephen Heumann 2015-10-17 01:08:06 -05:00
commit 16cd3c0619
51 changed files with 494 additions and 168 deletions

8
.gitignore vendored
View File

@ -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

View File

@ -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 \

View File

@ -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 \

View File

@ -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 "<applet> EXPRESSION ]" here (not "<applet> 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"

View File

@ -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

View File

@ -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: */

View File

@ -104,7 +104,30 @@
# include <selinux/av_permissions.h>
#endif
#if ENABLE_FEATURE_UTMP
# include <utmp.h>
# 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 <utmpx.h>
# elif defined __UCLIBC__
# include <utmp.h>
# 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 <utmpx.h>
# endif
#endif
#if ENABLE_LOCALE_SUPPORT
# include <locale.h>
@ -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;
};

View File

@ -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 <string.h>
/* 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

23
libbb/auto.string.c Normal file
View File

@ -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;
}

View File

@ -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 */

View File

@ -819,36 +819,25 @@ static char *username_path_completion(char *ud)
return tilde_name;
}
#define LINE_BUFF_SIZE 256
/* ~use<tab> - 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);
}
}
}

View File

@ -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 <http://www.gnu.org/licenses/>. */
#include <string.h>
/* 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;
}

View File

@ -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;

View File

@ -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;
}

View File

@ -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

View File

@ -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);
}

View File

@ -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;
}

View File

@ -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 }
};

View File

@ -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

View File

@ -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;

View File

@ -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)

View File

@ -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 <SPECIAL_VAR_SYMBOL>) */
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 <script>",
@ -8902,9 +8997,7 @@ int hush_main(int argc, char **argv)
install_special_sighandlers();
}
# endif
/* -1 is special - makes xfuncs longjmp, not exit
* (we reset die_sleep = 0 whereever we [v]fork) */
enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
enable_restore_tty_pgrp_on_exit();
# if ENABLE_HUSH_SAVEHISTORY && MAX_HISTORY > 0
{
@ -9765,24 +9858,29 @@ static int FAST_FUNC builtin_umask(char **argv)
int rc;
mode_t mask;
rc = 1;
mask = umask(0);
argv = skip_dash_dash(argv);
if (argv[0]) {
mode_t old_mask = mask;
mask ^= 0777;
rc = bb_parse_mode(argv[0], &mask);
mask ^= 0777;
if (rc == 0) {
/* numeric umasks are taken as-is */
/* symbolic umasks are inverted: "umask a=rx" calls umask(222) */
if (!isdigit(argv[0][0]))
mask ^= 0777;
mask = bb_parse_mode(argv[0], mask);
if (!isdigit(argv[0][0]))
mask ^= 0777;
if ((unsigned)mask > 0777) {
mask = old_mask;
/* bash messages:
* bash: umask: 'q': invalid symbolic mode operator
* bash: umask: 999: octal number out of range
*/
bb_error_msg("%s: invalid mode '%s'", "umask", argv[0]);
rc = 0;
}
} else {
rc = 1;
/* Mimic bash */
printf("%04o\n", (unsigned) mask);
/* fall through and restore mask which we set to 0 */
@ -9927,12 +10025,9 @@ static int FAST_FUNC builtin_wait(char **argv)
return EXIT_FAILURE;
}
if (waitpid(pid, &status, 0) == pid) {
ret = WEXITSTATUS(status);
if (WIFSIGNALED(status))
ret = 128 + WTERMSIG(status);
else if (WIFEXITED(status))
ret = WEXITSTATUS(status);
else /* wtf? */
ret = EXIT_FAILURE;
} else {
bb_perror_msg("wait %s", *argv);
ret = 127;

View File

@ -0,0 +1,5 @@
1
1
0

View File

@ -0,0 +1 @@
x=0; f() { local x=1; echo $x; local x; echo $x; unset x; echo $x; local x; echo $x; }; f; echo $x

View File

@ -0,0 +1,2 @@
glob3.tests
./glob3.tests

View File

@ -0,0 +1,2 @@
echo "glob3.test"*
echo "./glob3.test"*

View File

@ -0,0 +1,2 @@
Ok
0

View File

@ -0,0 +1,15 @@
#!/bin/sh
func()
{
while read p; do echo "$p"; done
}
pipe_to_func()
{
# We had a NOMMU bug which caused "echo Ok |" part ot be lost
echo Ok | func
}
pipe_to_func | cat
echo $?

View File

@ -0,0 +1 @@
/b/c/

View File

@ -0,0 +1,3 @@
a=/b/c/*
b=\\
echo ${a%$b*}

View File

@ -0,0 +1,2 @@
12
9

View File

@ -0,0 +1,3 @@
unset a
echo $((3 + ${a:=$((4 + 5))}))
echo $a

View File

@ -0,0 +1 @@
a_\_z_c

View File

@ -0,0 +1,2 @@
v="a\bc"
echo ${v/\\b/_\\_\z_}

View File

@ -0,0 +1 @@
ax/yc

View File

@ -0,0 +1,2 @@
v="abc"
echo ${v/b/x/y}

View File

@ -0,0 +1 @@
axcabc

View File

@ -0,0 +1,2 @@
v="abcabc"
echo ${v/b/x}

View File

@ -0,0 +1 @@
axcaxc

View File

@ -0,0 +1,2 @@
v="abcabc"
echo ${v//b/x}

View File

@ -0,0 +1 @@
axc