mirror of https://github.com/sheumann/hush
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
commit
16cd3c0619
|
@ -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
|
||||
|
|
2
Makefile
2
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 \
|
||||
|
|
|
@ -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 \
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: */
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
161
shell/hush.c
161
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 <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;
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
1
|
||||
1
|
||||
|
||||
|
||||
0
|
|
@ -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
|
|
@ -0,0 +1,2 @@
|
|||
glob3.tests
|
||||
./glob3.tests
|
|
@ -0,0 +1,2 @@
|
|||
echo "glob3.test"*
|
||||
echo "./glob3.test"*
|
|
@ -0,0 +1,2 @@
|
|||
Ok
|
||||
0
|
|
@ -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 $?
|
|
@ -0,0 +1 @@
|
|||
/b/c/
|
|
@ -0,0 +1,3 @@
|
|||
a=/b/c/*
|
||||
b=\\
|
||||
echo ${a%$b*}
|
|
@ -0,0 +1,2 @@
|
|||
12
|
||||
9
|
|
@ -0,0 +1,3 @@
|
|||
unset a
|
||||
echo $((3 + ${a:=$((4 + 5))}))
|
||||
echo $a
|
|
@ -0,0 +1 @@
|
|||
a_\_z_c
|
|
@ -0,0 +1,2 @@
|
|||
v="a\bc"
|
||||
echo ${v/\\b/_\\_\z_}
|
|
@ -0,0 +1 @@
|
|||
ax/yc
|
|
@ -0,0 +1,2 @@
|
|||
v="abc"
|
||||
echo ${v/b/x/y}
|
|
@ -0,0 +1 @@
|
|||
axcabc
|
|
@ -0,0 +1,2 @@
|
|||
v="abcabc"
|
||||
echo ${v/b/x}
|
|
@ -0,0 +1 @@
|
|||
axcaxc
|
|
@ -0,0 +1,2 @@
|
|||
v="abcabc"
|
||||
echo ${v//b/x}
|
|
@ -0,0 +1 @@
|
|||
axc
|