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.
master
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