aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archival/libarchive/get_header_tar.c2
-rw-r--r--archival/tar.c12
-rw-r--r--coreutils/chmod.c13
-rw-r--r--coreutils/chown.c9
-rw-r--r--coreutils/uudecode.c6
-rw-r--r--debianutils/run_parts.c12
-rw-r--r--editors/diff.c22
-rw-r--r--findutils/find.c17
-rw-r--r--findutils/grep.c24
-rw-r--r--findutils/xargs.c21
-rw-r--r--include/dump.h39
-rw-r--r--include/libbb.h34
-rw-r--r--libbb/appletlib.c9
-rw-r--r--libbb/dump.c94
-rw-r--r--libbb/hash_md5_sha.c75
-rw-r--r--libbb/inet_cksum.c4
-rw-r--r--libbb/kernel_version.c20
-rw-r--r--libbb/loop.c4
-rw-r--r--libbb/ptr_to_globals.c4
-rw-r--r--libbb/recursive_action.c72
-rw-r--r--libbb/update_passwd.c15
-rw-r--r--mailutils/reformime.c5
-rw-r--r--modutils/depmod.c12
-rw-r--r--modutils/modprobe-small.c3
-rw-r--r--modutils/modprobe.c14
-rw-r--r--networking/httpd.c69
-rw-r--r--networking/ip.c2
-rw-r--r--networking/libiproute/iprule.c32
-rw-r--r--networking/netstat.c28
-rw-r--r--networking/nslookup.c5
-rw-r--r--networking/ntpd.c9
-rw-r--r--networking/ping.c4
-rw-r--r--networking/traceroute.c2
-rw-r--r--networking/udhcp/common.c10
-rw-r--r--networking/udhcp/common.h6
-rw-r--r--networking/udhcp/d6_dhcpc.c2
-rw-r--r--networking/udhcp/d6_packet.c2
-rw-r--r--networking/udhcp/dhcpc.c4
-rw-r--r--networking/udhcp/packet.c4
-rw-r--r--procps/mpstat.c2
-rw-r--r--selinux/chcon.c8
-rw-r--r--selinux/setfiles.c8
-rw-r--r--shell/ash.c120
-rw-r--r--shell/ash_test/ash-misc/wait7.right2
-rwxr-xr-xshell/ash_test/ash-misc/wait7.tests7
-rw-r--r--shell/hush_test/hush-misc/wait7.right2
-rwxr-xr-xshell/hush_test/hush-misc/wait7.tests7
-rw-r--r--shell/math.c4
-rwxr-xr-xtestsuite/hexdump.tests19
-rwxr-xr-xtestsuite/xargs.tests8
-rwxr-xr-xtestsuite/xxd.tests34
-rw-r--r--util-linux/getopt.c5
-rw-r--r--util-linux/hexdump_xxd.c1
-rw-r--r--util-linux/losetup.c2
-rw-r--r--util-linux/lspci.c11
-rw-r--r--util-linux/lsusb.c10
-rw-r--r--util-linux/mdev.c20
-rw-r--r--util-linux/mount.c65
-rw-r--r--util-linux/setpriv.c9
-rw-r--r--util-linux/switch_root.c4
-rw-r--r--util-linux/volume_id/get_devname.c14
61 files changed, 655 insertions, 428 deletions
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index b3131ff2d..2ab3c04b8 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -352,7 +352,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
/* case 0: */
case '0':
#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
- if (last_char_is(file_header->name, '/')) {
+ if (file_header->name && last_char_is(file_header->name, '/')) {
goto set_dir;
}
#endif
diff --git a/archival/tar.c b/archival/tar.c
index 4ab38db29..93184cc2a 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -297,7 +297,8 @@ static void writeLongname(int fd, int type, const char *name, int dir)
header.typeflag = type;
strcpy(header.name, "././@LongLink");
/* This sets mode/uid/gid/mtime to "00...00<NUL>" strings */
- memset(header.mode, '0', sizeof(struct prefilled));
+ memset((char*)&header + offsetof(struct tar_header_t, mode), /* make gcc-9.x happy */
+ '0', sizeof(struct prefilled));
header.mode [sizeof(header.mode ) - 1] = '\0';
header.uid [sizeof(header.uid ) - 1] = '\0';
header.gid [sizeof(header.gid ) - 1] = '\0';
@@ -490,10 +491,11 @@ static int exclude_file(const llist_t *excluded_files, const char *file)
# define exclude_file(excluded_files, file) 0
# endif
-static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statbuf,
- void *userData, int depth UNUSED_PARAM)
+static int FAST_FUNC writeFileToTarball(struct recursive_state *state,
+ const char *fileName,
+ struct stat *statbuf)
{
- struct TarBallInfo *tbInfo = (struct TarBallInfo *) userData;
+ struct TarBallInfo *tbInfo = (struct TarBallInfo *) state->userData;
const char *header_name;
int inputFileFd = -1;
@@ -699,7 +701,7 @@ static NOINLINE int writeTarFile(
/* Read the directory/files and iterate over them one at a time */
while (filelist) {
if (!recursive_action(filelist->data, recurseFlags,
- writeFileToTarball, writeFileToTarball, tbInfo, 0)
+ writeFileToTarball, writeFileToTarball, tbInfo)
) {
errorFlag = TRUE;
}
diff --git a/coreutils/chmod.c b/coreutils/chmod.c
index 27e9b6b86..d2988c490 100644
--- a/coreutils/chmod.c
+++ b/coreutils/chmod.c
@@ -65,12 +65,14 @@
* symbolic links encountered during recursive directory traversals.
*/
-static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, void* param, int depth)
+static int FAST_FUNC fileAction(struct recursive_state *state,
+ const char *fileName,
+ struct stat *statbuf)
{
mode_t newmode;
/* match coreutils behavior */
- if (depth == 0) {
+ if (state->depth == 0) {
/* statbuf holds lstat result, but we need stat (follow link) */
if (stat(fileName, statbuf))
goto err;
@@ -79,9 +81,9 @@ static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, void
return TRUE;
}
- newmode = bb_parse_mode((char *)param, statbuf->st_mode);
+ newmode = bb_parse_mode((char *)state->userData, statbuf->st_mode);
if (newmode == (mode_t)-1)
- bb_error_msg_and_die("invalid mode '%s'", (char *)param);
+ bb_error_msg_and_die("invalid mode '%s'", (char *)state->userData);
if (chmod(fileName, newmode) == 0) {
if (OPT_VERBOSE
@@ -136,8 +138,7 @@ int chmod_main(int argc UNUSED_PARAM, char **argv)
OPT_RECURSE, // recurse
fileAction, // file action
fileAction, // dir action
- smode, // user data
- 0) // depth
+ smode) // user data
) {
retval = EXIT_FAILURE;
}
diff --git a/coreutils/chown.c b/coreutils/chown.c
index a1c5c0224..ffccc6cce 100644
--- a/coreutils/chown.c
+++ b/coreutils/chown.c
@@ -97,10 +97,10 @@ struct param_t {
chown_fptr chown_func;
};
-static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf,
- void *vparam, int depth UNUSED_PARAM)
+static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM,
+ const char *fileName, struct stat *statbuf)
{
-#define param (*(struct param_t*)vparam)
+#define param (*(struct param_t*)state->userData)
#define opt option_mask32
uid_t u = (param.ugid.uid == (uid_t)-1L) ? statbuf->st_uid : param.ugid.uid;
gid_t g = (param.ugid.gid == (gid_t)-1L) ? statbuf->st_gid : param.ugid.gid;
@@ -159,8 +159,7 @@ int chown_main(int argc UNUSED_PARAM, char **argv)
flags, /* flags */
fileAction, /* file action */
fileAction, /* dir action */
- &param, /* user data */
- 0) /* depth */
+ &param) /* user data */
) {
retval = EXIT_FAILURE;
}
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c
index dc8ef5cca..5b2edd649 100644
--- a/coreutils/uudecode.c
+++ b/coreutils/uudecode.c
@@ -110,9 +110,7 @@ static void FAST_FUNC read_stduu(FILE *src_stream, FILE *dst_stream, int flags U
}
bb_simple_error_msg_and_die("short file");
}
-#endif
-#if ENABLE_UUDECODE
int uudecode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int uudecode_main(int argc UNUSED_PARAM, char **argv)
{
@@ -202,10 +200,10 @@ int base64_main(int argc UNUSED_PARAM, char **argv)
*--argv = (char*)"-";
src_stream = xfopen_stdin(argv[0]);
if (opts) {
- read_base64(src_stream, stdout, /*flags:*/ (char)EOF);
+ read_base64(src_stream, stdout, /*flags:*/ (unsigned char)EOF);
} else {
enum {
- SRC_BUF_SIZE = 76/4*3, /* This *MUST* be a multiple of 3 */
+ SRC_BUF_SIZE = 76 / 4 * 3, /* this *MUST* be a multiple of 3 */
DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3),
};
char src_buf[SRC_BUF_SIZE];
diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c
index c80cc863f..585a4b58f 100644
--- a/debianutils/run_parts.c
+++ b/debianutils/run_parts.c
@@ -131,12 +131,13 @@ static int bb_alphasort(const void *p1, const void *p2)
return (option_mask32 & OPT_r) ? -r : r;
}
-static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUSED_PARAM, int depth)
+static int FAST_FUNC act(struct recursive_state *state,
+ const char *file, struct stat *statbuf)
{
- if (depth == 1)
+ if (state->depth == 0)
return TRUE;
- if (depth == 2
+ if (state->depth == 1
&& ( !(statbuf->st_mode & (S_IFREG | S_IFLNK))
|| invalid_name(file)
|| (!(option_mask32 & OPT_l) && access(file, X_OK) != 0))
@@ -199,9 +200,8 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv)
ACTION_RECURSE|ACTION_FOLLOWLINKS,
act, /* file action */
act, /* dir action */
- NULL, /* user data */
- 1 /* depth */
- );
+ NULL /* user data */
+ );
if (!names)
return 0;
diff --git a/editors/diff.c b/editors/diff.c
index dc40ab4f1..280091756 100644
--- a/editors/diff.c
+++ b/editors/diff.c
@@ -803,11 +803,11 @@ struct dlist {
};
/* This function adds a filename to dl, the directory listing. */
-static int FAST_FUNC add_to_dirlist(const char *filename,
- struct stat *sb UNUSED_PARAM,
- void *userdata, int depth UNUSED_PARAM)
+static int FAST_FUNC add_to_dirlist(struct recursive_state *state,
+ const char *filename,
+ struct stat *sb UNUSED_PARAM)
{
- struct dlist *const l = userdata;
+ struct dlist *const l = state->userData;
const char *file = filename + l->len;
while (*file == '/')
file++;
@@ -820,12 +820,12 @@ static int FAST_FUNC add_to_dirlist(const char *filename,
/* If recursion is not set, this function adds the directory
* to the list and prevents recursive_action from recursing into it.
*/
-static int FAST_FUNC skip_dir(const char *filename,
- struct stat *sb, void *userdata,
- int depth)
+static int FAST_FUNC skip_dir(struct recursive_state *state,
+ const char *filename,
+ struct stat *sb)
{
- if (!(option_mask32 & FLAG(r)) && depth) {
- add_to_dirlist(filename, sb, userdata, depth);
+ if (!(option_mask32 & FLAG(r)) && state->depth) {
+ add_to_dirlist(state, filename, sb);
return SKIP;
}
if (!(option_mask32 & FLAG(N))) {
@@ -833,7 +833,7 @@ static int FAST_FUNC skip_dir(const char *filename,
* which do not exist on the "other side".
* Testcase: diff -r /tmp /
* (it would recurse deep into /proc without this code) */
- struct dlist *const l = userdata;
+ struct dlist *const l = state->userData;
filename += l->len;
if (filename[0]) {
struct stat osb;
@@ -868,7 +868,7 @@ static void diffdir(char *p[2], const char *s_start)
* add_to_dirlist will remove it. */
list[i].len = strlen(p[i]);
recursive_action(p[i], ACTION_RECURSE | ACTION_FOLLOWLINKS,
- add_to_dirlist, skip_dir, &list[i], 0);
+ add_to_dirlist, skip_dir, &list[i]);
/* Sort dl alphabetically.
* GNU diff does this ignoring any number of trailing dots.
* We don't, so for us dotted files almost always are
diff --git a/findutils/find.c b/findutils/find.c
index 9a2c61b75..e2947afb4 100644
--- a/findutils/find.c
+++ b/findutils/find.c
@@ -889,10 +889,10 @@ ACTF(links)
}
#endif
-static int FAST_FUNC fileAction(const char *fileName,
- struct stat *statbuf,
- void *userData UNUSED_PARAM,
- int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM))
+static int FAST_FUNC fileAction(
+ struct recursive_state *state IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM),
+ const char *fileName,
+ struct stat *statbuf)
{
int r;
int same_fs = 1;
@@ -911,12 +911,12 @@ static int FAST_FUNC fileAction(const char *fileName,
#endif
#if ENABLE_FEATURE_FIND_MAXDEPTH
- if (depth < G.minmaxdepth[0]) {
+ if (state->depth < G.minmaxdepth[0]) {
if (same_fs)
return TRUE; /* skip this, continue recursing */
return SKIP; /* stop recursing */
}
- if (depth > G.minmaxdepth[1])
+ if (state->depth > G.minmaxdepth[1])
return SKIP; /* stop recursing */
#endif
@@ -927,7 +927,7 @@ static int FAST_FUNC fileAction(const char *fileName,
#if ENABLE_FEATURE_FIND_MAXDEPTH
if (S_ISDIR(statbuf->st_mode)) {
- if (depth == G.minmaxdepth[1])
+ if (state->depth == G.minmaxdepth[1])
return SKIP;
}
#endif
@@ -1570,8 +1570,7 @@ int find_main(int argc UNUSED_PARAM, char **argv)
G.recurse_flags,/* flags */
fileAction, /* file action */
fileAction, /* dir action */
- NULL, /* user data */
- 0) /* depth */
+ NULL) /* user data */
) {
G.exitstatus |= EXIT_FAILURE;
}
diff --git a/findutils/grep.c b/findutils/grep.c
index b456ed467..10cca83e7 100644
--- a/findutils/grep.c
+++ b/findutils/grep.c
@@ -656,10 +656,9 @@ static void load_pattern_list(llist_t **lst, char *pattern)
llist_add_to(lst, new_grep_list_data(p, 0));
}
-static int FAST_FUNC file_action_grep(const char *filename,
- struct stat *statbuf,
- void* matched,
- int depth UNUSED_PARAM)
+static int FAST_FUNC file_action_grep(struct recursive_state *state UNUSED_PARAM,
+ const char *filename,
+ struct stat *statbuf)
{
FILE *file;
@@ -686,7 +685,7 @@ static int FAST_FUNC file_action_grep(const char *filename,
return 0;
}
cur_file = filename;
- *(int*)matched |= grep_file(file);
+ *(int*)state->userData |= grep_file(file);
fclose(file);
return 1;
}
@@ -694,15 +693,16 @@ static int FAST_FUNC file_action_grep(const char *filename,
static int grep_dir(const char *dir)
{
int matched = 0;
- recursive_action(dir,
- /* recurse=yes */ ACTION_RECURSE |
- /* followLinks=always */ ((option_mask32 & OPT_R) ? ACTION_FOLLOWLINKS : 0) |
- /* followLinks=command line only */ ACTION_FOLLOWLINKS_L0 |
- /* depthFirst=yes */ ACTION_DEPTHFIRST,
+ recursive_action(dir, 0
+ | ACTION_RECURSE
+ | ((option_mask32 & OPT_R) ? ACTION_FOLLOWLINKS : 0)
+ | ACTION_FOLLOWLINKS_L0 /* grep -r ... SYMLINK follows it */
+ | ACTION_DEPTHFIRST
+ | 0,
/* fileAction= */ file_action_grep,
/* dirAction= */ NULL,
- /* userData= */ &matched,
- /* depth= */ 0);
+ /* userData= */ &matched
+ );
return matched;
}
diff --git a/findutils/xargs.c b/findutils/xargs.c
index ff04bfe7c..e2b3527f3 100644
--- a/findutils/xargs.c
+++ b/findutils/xargs.c
@@ -80,9 +80,11 @@
/* This is a NOEXEC applet. Be very careful! */
-//#define dbg_msg(...) bb_error_msg(__VA_ARGS__)
-#define dbg_msg(...) ((void)0)
-
+#if 0
+# define dbg_msg(...) bb_error_msg(__VA_ARGS__)
+#else
+# define dbg_msg(...) ((void)0)
+#endif
#ifdef TEST
# ifndef ENABLE_FEATURE_XARGS_SUPPORT_CONFIRMATION
@@ -466,9 +468,18 @@ static char* FAST_FUNC process_stdin_with_replace(int n_max_chars, int n_max_arg
while (1) {
int c = getchar();
+ if (p == buf) {
+ if (c == EOF)
+ goto ret; /* last line is empty, return "" */
+ if (c == G.eol_ch)
+ continue; /* empty line, ignore */
+ /* Skip leading whitespace of each line: try
+ * echo -e ' \t\v1 2 3 ' | xargs -I% echo '[%]'
+ */
+ if (ISSPACE(c))
+ continue;
+ }
if (c == EOF || c == G.eol_ch) {
- if (p == buf)
- goto ret; /* empty line */
c = '\0';
}
*p++ = c;
diff --git a/include/dump.h b/include/dump.h
index 4c237ef05..f4759c193 100644
--- a/include/dump.h
+++ b/include/dump.h
@@ -2,50 +2,15 @@
PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
-#define F_IGNORE 0x01 /* %_A */
-#define F_SETREP 0x02 /* rep count set, not default */
-#define F_ADDRESS 0x001 /* print offset */
-#define F_BPAD 0x002 /* blank pad */
-#define F_C 0x004 /* %_c */
-#define F_CHAR 0x008 /* %c */
-#define F_DBL 0x010 /* %[EefGf] */
-#define F_INT 0x020 /* %[di] */
-#define F_P 0x040 /* %_p */
-#define F_STR 0x080 /* %s */
-#define F_U 0x100 /* %_u */
-#define F_UINT 0x200 /* %[ouXx] */
-#define F_TEXT 0x400 /* no conversions */
-
enum dump_vflag_t { ALL, DUP, FIRST, WAIT }; /* -v values */
-typedef struct PR {
- struct PR *nextpr; /* next print unit */
- unsigned flags; /* flag values */
- int bcnt; /* byte count */
- char *cchar; /* conversion character */
- char *fmt; /* printf format */
- char *nospace; /* no whitespace version */
-} PR;
-
-typedef struct FU {
- struct FU *nextfu; /* next format unit */
- struct PR *nextpr; /* next print unit */
- unsigned flags; /* flag values */
- int reps; /* repetition count */
- int bcnt; /* byte count */
- char *fmt; /* format string */
-} FU;
-
-typedef struct FS { /* format strings */
- struct FS *nextfs; /* linked list of format strings */
- struct FU *nextfu; /* linked list of format units */
- int bcnt;
-} FS;
+typedef struct FS FS;
typedef struct dumper_t {
off_t dump_skip; /* bytes to skip */
int dump_length; /* max bytes to read */
smallint dump_vflag; /*enum dump_vflag_t*/
+ const char *eofstring;
FS *fshead;
} dumper_t;
diff --git a/include/libbb.h b/include/libbb.h
index 8c7978456..1b7c0b83a 100644
--- a/include/libbb.h
+++ b/include/libbb.h
@@ -339,12 +339,13 @@ struct BUG_off_t_size_is_misdetected {
#endif
#endif
-#if defined(__GLIBC__)
-/* glibc uses __errno_location() to get a ptr to errno */
-/* We can just memorize it once - no multithreading in busybox :) */
+#if defined(errno)
+/* If errno is a define, assume it's "define errno (*__errno_location())"
+ * and we will cache it's result in this variable */
extern int *const bb_errno;
#undef errno
#define errno (*bb_errno)
+#define bb_cached_errno_ptr 1
#endif
#if !(ULONG_MAX > 0xffffffff)
@@ -436,15 +437,23 @@ enum {
ACTION_FOLLOWLINKS = (1 << 1),
ACTION_FOLLOWLINKS_L0 = (1 << 2),
ACTION_DEPTHFIRST = (1 << 3),
- /*ACTION_REVERSE = (1 << 4), - unused */
- ACTION_QUIET = (1 << 5),
- ACTION_DANGLING_OK = (1 << 6),
+ ACTION_QUIET = (1 << 4),
+ ACTION_DANGLING_OK = (1 << 5),
};
typedef uint8_t recurse_flags_t;
-extern int recursive_action(const char *fileName, unsigned flags,
- int FAST_FUNC (*fileAction)(const char *fileName, struct stat* statbuf, void* userData, int depth),
- int FAST_FUNC (*dirAction)(const char *fileName, struct stat* statbuf, void* userData, int depth),
- void* userData, unsigned depth) FAST_FUNC;
+typedef struct recursive_state {
+ unsigned flags;
+ unsigned depth;
+ void *userData;
+ int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf);
+ int FAST_FUNC (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf);
+} recursive_state_t;
+int recursive_action(const char *fileName, unsigned flags,
+ int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf),
+ int FAST_FUNC (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf),
+ void *userData
+) FAST_FUNC;
+
extern int device_open(const char *device, int mode) FAST_FUNC;
enum { GETPTY_BUFSIZE = 16 }; /* more than enough for "/dev/ttyXXX" */
extern int xgetpty(char *line) FAST_FUNC;
@@ -817,7 +826,7 @@ ssize_t recv_from_to(int fd, void *buf, size_t len, int flags,
struct sockaddr *to,
socklen_t sa_size) FAST_FUNC;
-uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC;
+uint16_t inet_cksum(const void *addr, int len) FAST_FUNC;
int parse_pasv_epsv(char *buf) FAST_FUNC;
/* 0 if argv[0] is NULL: */
@@ -1515,7 +1524,8 @@ int del_loop(const char *device) FAST_FUNC;
* malloc and return it in *devname.
* return value is the opened fd to the loop device, or < on error
*/
-int set_loop(char **devname, const char *file, unsigned long long offset, unsigned flags) FAST_FUNC;
+int set_loop(char **devname, const char *file, unsigned long long offset,
+ unsigned long long sizelimit, unsigned flags) FAST_FUNC;
/* These constants match linux/loop.h (without BB_ prefix): */
#define BB_LO_FLAGS_READ_ONLY 1
#define BB_LO_FLAGS_AUTOCLEAR 4
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index a515c3fe3..5f59f1273 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -25,6 +25,11 @@
*
* FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :(
*/
+
+/* Define this accessor before we #define "errno" our way */
+#include <errno.h>
+static inline int *get_perrno(void) { return &errno; }
+
#include "busybox.h"
#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \
@@ -303,8 +308,8 @@ void lbb_prepare(const char *applet
void lbb_prepare(const char *applet
IF_FEATURE_INDIVIDUAL(, char **argv))
{
-#ifdef __GLIBC__
- (*(int **)not_const_pp(&bb_errno)) = __errno_location();
+#ifdef bb_cached_errno_ptr
+ (*(int **)not_const_pp(&bb_errno)) = get_perrno();
barrier();
#endif
applet_name = applet;
diff --git a/libbb/dump.c b/libbb/dump.c
index 8029cca0e..7a07d6605 100644
--- a/libbb/dump.c
+++ b/libbb/dump.c
@@ -13,13 +13,43 @@
#include "libbb.h"
#include "dump.h"
-static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789";
-
-static const char size_conv_str[] ALIGN1 =
-"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
-
-static const char int_convs[] ALIGN1 = "diouxX";
-
+#define F_IGNORE 0x01 /* %_A */
+#define F_SETREP 0x02 /* rep count set, not default */
+#define F_ADDRESS 0x001 /* print offset */
+#define F_BPAD 0x002 /* blank pad */
+#define F_C 0x004 /* %_c */
+#define F_CHAR 0x008 /* %c */
+#define F_DBL 0x010 /* %[EefGf] */
+#define F_INT 0x020 /* %[di] */
+#define F_P 0x040 /* %_p */
+#define F_STR 0x080 /* %s */
+#define F_U 0x100 /* %_u */
+#define F_UINT 0x200 /* %[ouXx] */
+#define F_TEXT 0x400 /* no conversions */
+
+typedef struct PR {
+ struct PR *nextpr; /* next print unit */
+ unsigned flags; /* flag values */
+ int bcnt; /* byte count */
+ char *cchar; /* conversion character */
+ char *fmt; /* printf format */
+ char *nospace; /* no whitespace version */
+} PR;
+
+typedef struct FU {
+ struct FU *nextfu; /* next format unit */
+ struct PR *nextpr; /* next print unit */
+ unsigned flags; /* flag values */
+ int reps; /* repetition count */
+ int bcnt; /* byte count */
+ char *fmt; /* format string */
+} FU;
+
+typedef struct FS { /* format strings */
+ struct FS *nextfs; /* linked list of format strings */
+ struct FU *nextfu; /* linked list of format units */
+ int bcnt;
+} FS;
typedef struct priv_dumper_t {
dumper_t pub;
@@ -39,6 +69,13 @@ typedef struct priv_dumper_t {
unsigned char *get__savp;
} priv_dumper_t;
+static const char dot_flags_width_chars[] ALIGN1 = ".#-+ 0123456789";
+
+static const char size_conv_str[] ALIGN1 =
+"\x1\x4\x4\x4\x4\x4\x4\x8\x8\x8\x8\010cdiouxXeEfgG";
+
+static const char int_convs[] ALIGN1 = "diouxX";
+
dumper_t* FAST_FUNC alloc_dumper(void)
{
priv_dumper_t *dumper = xzalloc(sizeof(*dumper));
@@ -48,7 +85,6 @@ dumper_t* FAST_FUNC alloc_dumper(void)
return &dumper->pub;
}
-
static NOINLINE int bb_dump_size(FS *fs)
{
FU *fu;
@@ -284,7 +320,9 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs)
* repeat it as necessary.
*
* if rep count is greater than 1, no trailing whitespace
- * gets output from the last iteration of the format unit.
+ * gets output from the last iteration of the format unit:
+ * 2/1 "%02x " prints "XX XX", not "XX XX "
+ * 2/1 "%02x\n" prints "XX\nXX", not "XX\nXX\n"
*/
for (fu = fs->nextfu; fu; fu = fu->nextfu) {
if (!fu->nextfu
@@ -394,7 +432,6 @@ static unsigned char *get(priv_dumper_t *dumper)
if (dumper->pub.dump_vflag != DUP) {
puts("*");
}
- return NULL;
}
memset(dumper->get__curp + nread, 0, need);
dumper->eaddress = dumper->address + nread;
@@ -453,7 +490,7 @@ static void bpad(PR *pr)
for (p2 = ++p1; *p1 && strchr(" -0+#", *p1); ++p1)
if (pr->nospace)
pr->nospace--;
- while ((*p2++ = *p1++) != 0)
+ while ((*p2++ = *p1++) != '\0')
continue;
}
@@ -520,36 +557,43 @@ static void conv_u(PR *pr, unsigned char *p)
static void display(priv_dumper_t* dumper)
{
- FS *fs;
- FU *fu;
- PR *pr;
- int cnt;
- unsigned char *bp, *savebp;
- off_t saveaddress;
+ unsigned char *bp;
unsigned char savech = '\0';
while ((bp = get(dumper)) != NULL) {
+ FS *fs;
+ unsigned char *savebp;
+ off_t saveaddress;
+
fs = dumper->pub.fshead;
savebp = bp;
saveaddress = dumper->address;
for (; fs; fs = fs->nextfs, bp = savebp, dumper->address = saveaddress) {
+ FU *fu;
for (fu = fs->nextfu; fu; fu = fu->nextfu) {
+ int cnt;
if (fu->flags & F_IGNORE) {
break;
}
for (cnt = fu->reps; cnt; --cnt) {
+ PR *pr;
for (pr = fu->nextpr; pr; dumper->address += pr->bcnt,
bp += pr->bcnt, pr = pr->nextpr) {
- if (dumper->eaddress && dumper->address >= dumper->eaddress
- && !(pr->flags & (F_TEXT | F_BPAD))
+ if (dumper->eaddress
+ && dumper->address >= dumper->eaddress
) {
- bpad(pr);
+ if (dumper->pub.eofstring) {
+ /* xxd support: requested to not pad incomplete blocks */
+ fputs(dumper->pub.eofstring, stdout);
+ return;
+ }
+ if (!(pr->flags & (F_TEXT | F_BPAD)))
+ bpad(pr);
}
if (cnt == 1 && pr->nospace) {
savech = *pr->nospace;
*pr->nospace = '\0';
}
-/* PRINT; */
switch (pr->flags) {
case F_ADDRESS:
printf(pr->fmt, (unsigned) dumper->address);
@@ -638,7 +682,9 @@ static void display(priv_dumper_t* dumper)
}
}
}
+
if (dumper->endfu) {
+ PR *pr;
/*
* if eaddress not set, error or file size was multiple
* of blocksize, and no partial block ever found.
@@ -695,8 +741,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
{
const char *p;
FS *tfs;
- FU *tfu, **nextfupp;
- const char *savep;
+ FU **nextfupp;
/* start new linked list of format units */
tfs = xzalloc(sizeof(FS)); /*DBU:[dave@cray.com] start out NULL */
@@ -713,6 +758,9 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt)
/* take the format string and break it up into format units */
p = fmt;
for (;;) {
+ FU *tfu;
+ const char *savep;
+
p = skip_whitespace(p);
if (*p == '\0') {
break;
diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c
index 9db79ea8b..d8f210173 100644
--- a/libbb/hash_md5_sha.c
+++ b/libbb/hash_md5_sha.c
@@ -38,35 +38,6 @@ static ALWAYS_INLINE uint64_t rotl64(uint64_t x, unsigned n)
return (x << n) | (x >> (64 - n));
}
-/* Feed data through a temporary buffer.
- * The internal buffer remembers previous data until it has 64
- * bytes worth to pass on.
- */
-static void FAST_FUNC common64_hash(md5_ctx_t *ctx, const void *buffer, size_t len)
-{
- unsigned bufpos = ctx->total64 & 63;
-
- ctx->total64 += len;
-
- while (1) {
- unsigned remaining = 64 - bufpos;
- if (remaining > len)
- remaining = len;
- /* Copy data into aligned buffer */
- memcpy(ctx->wbuffer + bufpos, buffer, remaining);
- len -= remaining;
- buffer = (const char *)buffer + remaining;
- bufpos += remaining;
- /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */
- bufpos -= 64;
- if (bufpos != 0)
- break;
- /* Buffer is filled up, process it */
- ctx->process_block(ctx);
- /*bufpos = 0; - already is */
- }
-}
-
/* Process the remaining bytes in the buffer */
static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed)
{
@@ -449,7 +420,29 @@ void FAST_FUNC md5_begin(md5_ctx_t *ctx)
/* Used also for sha1 and sha256 */
void FAST_FUNC md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len)
{
- common64_hash(ctx, buffer, len);
+ unsigned bufpos = ctx->total64 & 63;
+
+ ctx->total64 += len;
+
+ while (1) {
+ unsigned remaining = 64 - bufpos;
+ if (remaining > len)
+ remaining = len;
+ /* Copy data into aligned buffer */
+ memcpy(ctx->wbuffer + bufpos, buffer, remaining);
+ len -= remaining;
+ buffer = (const char *)buffer + remaining;
+ bufpos += remaining;
+
+ /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */
+ bufpos -= 64;
+ if (bufpos != 0)
+ break;
+
+ /* Buffer is filled up, process it */
+ ctx->process_block(ctx);
+ /*bufpos = 0; - already is */
+ }
}
/* Process the remaining bytes in the buffer and put result from CTX
@@ -816,7 +809,7 @@ void FAST_FUNC sha512_begin(sha512_ctx_t *ctx)
int i;
/* Two extra iterations zero out ctx->total64[2] */
uint64_t *tp = ctx->total64;
- for (i = 0; i < 2+8; i++)
+ for (i = 0; i < 8 + 2; i++)
tp[i] = ((uint64_t)(init256[i]) << 32) + init512_lo[i];
/*ctx->total64[0] = ctx->total64[1] = 0; - already done */
}
@@ -832,22 +825,7 @@ void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len)
ctx->total64[0] += len;
if (ctx->total64[0] < len)
ctx->total64[1]++;
-# if 0
- remaining = 128 - bufpos;
- /* Hash whole blocks */
- while (len >= remaining) {
- memcpy(ctx->wbuffer + bufpos, buffer, remaining);
- buffer = (const char *)buffer + remaining;
- len -= remaining;
- remaining = 128;
- bufpos = 0;
- sha512_process_block128(ctx);
- }
-
- /* Save last, partial blosk */
- memcpy(ctx->wbuffer + bufpos, buffer, len);
-# else
while (1) {
remaining = 128 - bufpos;
if (remaining > len)
@@ -857,15 +835,16 @@ void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len)
len -= remaining;
buffer = (const char *)buffer + remaining;
bufpos += remaining;
+
/* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */
bufpos -= 128;
if (bufpos != 0)
break;
+
/* Buffer is filled up, process it */
sha512_process_block128(ctx);
/*bufpos = 0; - already is */
}
-# endif
}
#endif /* NEED_SHA512 */
@@ -1398,10 +1377,12 @@ void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len)
bufpos++;
remaining--;
}
+
/* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */
bufpos -= ctx->input_block_bytes;
if (bufpos != 0)
break;
+
/* Buffer is filled up, process it */
sha3_process_block72(ctx->state);
/*bufpos = 0; - already is */
diff --git a/libbb/inet_cksum.c b/libbb/inet_cksum.c
index 3d5dc3adf..fee8648f3 100644
--- a/libbb/inet_cksum.c
+++ b/libbb/inet_cksum.c
@@ -6,8 +6,10 @@
#include "libbb.h"
-uint16_t FAST_FUNC inet_cksum(uint16_t *addr, int nleft)
+uint16_t FAST_FUNC inet_cksum(const void *ptr, int nleft)
{
+ const uint16_t *addr = ptr;
+
/*
* Our algorithm is simple, using a 32 bit accumulator,
* we add sequential 16 bit words to it, and at the end, fold
diff --git a/libbb/kernel_version.c b/libbb/kernel_version.c
index 7769a091b..6bb32ce5f 100644
--- a/libbb/kernel_version.c
+++ b/libbb/kernel_version.c
@@ -19,15 +19,17 @@ int FAST_FUNC get_linux_version_code(void)
{
struct utsname name;
char *t;
- int i, r;
+ int r;
uname(&name); /* never fails */
- t = name.release;
- r = 0;
- for (i = 0; i < 3; i++) {
- t = strtok(t, ".");
- r = r * 256 + (t ? atoi(t) : 0);
- t = NULL;
- }
- return r;
+ t = name.release - 1;
+ r = 1;
+ do {
+ r <<= 8;
+ if (t) {
+ r += atoi(++t);
+ t = strchr(t, '.');
+ }
+ } while (r < 0x1000000);
+ return r - 0x1000000;
}
diff --git a/libbb/loop.c b/libbb/loop.c
index ada0c7638..85b2724e5 100644
--- a/libbb/loop.c
+++ b/libbb/loop.c
@@ -102,7 +102,8 @@ int FAST_FUNC get_free_loop(void)
* search will re-use an existing loop device already bound to that
* file/offset if it finds one.
*/
-int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, unsigned flags)
+int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset,
+ unsigned long long sizelimit, unsigned flags)
{
char dev[LOOP_NAMESIZE];
char *try;
@@ -185,6 +186,7 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse
memset(&loopinfo, 0, sizeof(loopinfo));
safe_strncpy((char *)loopinfo.lo_file_name, file, LO_NAME_SIZE);
loopinfo.lo_offset = offset;
+ loopinfo.lo_sizelimit = sizelimit;
/*
* Used by mount to set LO_FLAGS_AUTOCLEAR.
* LO_FLAGS_READ_ONLY is not set because RO is controlled by open type of the file.
diff --git a/libbb/ptr_to_globals.c b/libbb/ptr_to_globals.c
index 8ba9cd154..2232c6864 100644
--- a/libbb/ptr_to_globals.c
+++ b/libbb/ptr_to_globals.c
@@ -14,7 +14,7 @@ struct globals;
* but here we make it live in R/W memory */
struct globals *ptr_to_globals;
-#ifdef __GLIBC__
+#ifdef errno
int *bb_errno;
#endif
@@ -27,7 +27,7 @@ int *bb_errno;
* on weird architectures, compilers, linkers and so on */
struct globals *const ptr_to_globals __attribute__ ((section (".data")));
-#ifdef __GLIBC__
+#ifdef errno
int *const bb_errno __attribute__ ((section (".data")));
#endif
diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c
index 0831ecc3a..b1c4bfad7 100644
--- a/libbb/recursive_action.c
+++ b/libbb/recursive_action.c
@@ -21,10 +21,9 @@
* is so stinking huge.
*/
-static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM,
- struct stat *statbuf UNUSED_PARAM,
- void* userData UNUSED_PARAM,
- int depth UNUSED_PARAM)
+static int FAST_FUNC true_action(struct recursive_state *state UNUSED_PARAM,
+ const char *fileName UNUSED_PARAM,
+ struct stat *statbuf UNUSED_PARAM)
{
return TRUE;
}
@@ -65,12 +64,7 @@ static int FAST_FUNC true_action(const char *fileName UNUSED_PARAM,
* 1: stat(statbuf). Calls dirAction and optionally recurse on link to dir.
*/
-int FAST_FUNC recursive_action(const char *fileName,
- unsigned flags,
- int FAST_FUNC (*fileAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
- int FAST_FUNC (*dirAction)(const char *fileName, struct stat *statbuf, void* userData, int depth),
- void* userData,
- unsigned depth)
+static int recursive_action1(recursive_state_t *state, const char *fileName)
{
struct stat statbuf;
unsigned follow;
@@ -78,24 +72,21 @@ int FAST_FUNC recursive_action(const char *fileName,
DIR *dir;
struct dirent *next;
- if (!fileAction) fileAction = true_action;
- if (!dirAction) dirAction = true_action;
-
follow = ACTION_FOLLOWLINKS;
- if (depth == 0)
+ if (state->depth == 0)
follow = ACTION_FOLLOWLINKS | ACTION_FOLLOWLINKS_L0;
- follow &= flags;
+ follow &= state->flags;
status = (follow ? stat : lstat)(fileName, &statbuf);
if (status < 0) {
#ifdef DEBUG_RECURS_ACTION
- bb_error_msg("status=%d flags=%x", status, flags);
+ bb_error_msg("status=%d flags=%x", status, state->flags);
#endif
- if ((flags & ACTION_DANGLING_OK)
+ if ((state->flags & ACTION_DANGLING_OK)
&& errno == ENOENT
&& lstat(fileName, &statbuf) == 0
) {
/* Dangling link */
- return fileAction(fileName, &statbuf, userData, depth);
+ return state->fileAction(state, fileName, &statbuf);
}
goto done_nak_warn;
}
@@ -103,20 +94,20 @@ int FAST_FUNC recursive_action(const char *fileName,
/* If S_ISLNK(m), then we know that !S_ISDIR(m).
* Then we can skip checking first part: if it is true, then
* (!dir) is also true! */
- if ( /* (!(flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */
+ if ( /* (!(state->flags & ACTION_FOLLOWLINKS) && S_ISLNK(statbuf.st_mode)) || */
!S_ISDIR(statbuf.st_mode)
) {
- return fileAction(fileName, &statbuf, userData, depth);
+ return state->fileAction(state, fileName, &statbuf);
}
/* It's a directory (or a link to one, and followLinks is set) */
- if (!(flags & ACTION_RECURSE)) {
- return dirAction(fileName, &statbuf, userData, depth);
+ if (!(state->flags & ACTION_RECURSE)) {
+ return state->dirAction(state, fileName, &statbuf);
}
- if (!(flags & ACTION_DEPTHFIRST)) {
- status = dirAction(fileName, &statbuf, userData, depth);
+ if (!(state->flags & ACTION_DEPTHFIRST)) {
+ status = state->dirAction(state, fileName, &statbuf);
if (status == FALSE)
goto done_nak_warn;
if (status == SKIP)
@@ -140,11 +131,13 @@ int FAST_FUNC recursive_action(const char *fileName,
continue;
/* process every file (NB: ACTION_RECURSE is set in flags) */
- s = recursive_action(nextFile, flags, fileAction, dirAction,
- userData, depth + 1);
+ state->depth++;
+ s = recursive_action1(state, nextFile);
if (s == FALSE)
status = FALSE;
free(nextFile);
+ state->depth--;
+
//#define RECURSE_RESULT_ABORT -1
// if (s == RECURSE_RESULT_ABORT) {
// closedir(dir);
@@ -153,15 +146,36 @@ int FAST_FUNC recursive_action(const char *fileName,
}
closedir(dir);
- if (flags & ACTION_DEPTHFIRST) {
- if (!dirAction(fileName, &statbuf, userData, depth))
+ if (state->flags & ACTION_DEPTHFIRST) {
+ if (!state->dirAction(state, fileName, &statbuf))
goto done_nak_warn;
}
return status;
done_nak_warn:
- if (!(flags & ACTION_QUIET))
+ if (!(state->flags & ACTION_QUIET))
bb_simple_perror_msg(fileName);
return FALSE;
}
+
+int FAST_FUNC recursive_action(const char *fileName,
+ unsigned flags,
+ int FAST_FUNC (*fileAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf),
+ int FAST_FUNC (*dirAction)(struct recursive_state *state, const char *fileName, struct stat* statbuf),
+ void *userData)
+{
+ /* Keeping a part of variables of recusive descent in a "state structure"
+ * instead of passing ALL of them down as parameters of recursive_action1()
+ * relieves register pressure, both in recursive_action1()
+ * and in every file/dirAction().
+ */
+ recursive_state_t state;
+ state.flags = flags;
+ state.depth = 0;
+ state.userData = userData;
+ state.fileAction = fileAction ? fileAction : true_action;
+ state.dirAction = dirAction ? dirAction : true_action;
+
+ return recursive_action1(&state, fileName);
+}
diff --git a/libbb/update_passwd.c b/libbb/update_passwd.c
index c605c4c64..7b67f30cd 100644
--- a/libbb/update_passwd.c
+++ b/libbb/update_passwd.c
@@ -18,17 +18,20 @@
#if ENABLE_SELINUX
static void check_selinux_update_passwd(const char *username)
{
- security_context_t context;
- char *seuser;
+ security_context_t seuser;
+ char *p;
if (getuid() != (uid_t)0 || is_selinux_enabled() == 0)
return; /* No need to check */
- if (getprevcon_raw(&context) < 0)
+ if (getprevcon_raw(&seuser) < 0)
bb_simple_perror_msg_and_die("getprevcon failed");
- seuser = strtok(context, ":");
- if (!seuser)
- bb_error_msg_and_die("invalid context '%s'", context);
+
+ p = strchr(seuser, ':');
+ if (!p)
+ bb_error_msg_and_die("invalid context '%s'", seuser);
+ *p = '\0';
+
if (strcmp(seuser, username) != 0) {
security_class_t tclass;
access_vector_t av;
diff --git a/mailutils/reformime.c b/mailutils/reformime.c
index 321729e0a..307656a15 100644
--- a/mailutils/reformime.c
+++ b/mailutils/reformime.c
@@ -115,6 +115,7 @@ static int parse(const char *boundary, char **argv)
/* Split to tokens */
{
char *s, *p;
+ char *tokstate;
unsigned ntokens;
const char *delims = ";=\" \t\n";
@@ -127,13 +128,13 @@ static int parse(const char *boundary, char **argv)
}
dbg_error_msg("L:'%s'", p);
ntokens = 0;
- s = strtok(s, delims);
+ s = strtok_r(s, delims, &tokstate);
while (s) {
tokens[ntokens] = s;
if (ntokens < ARRAY_SIZE(tokens) - 1)
ntokens++;
dbg_error_msg("L[%d]='%s'", ntokens, s);
- s = strtok(NULL, delims);
+ s = strtok_r(NULL, delims, &tokstate);
}
tokens[ntokens] = NULL;
dbg_error_msg("EMPTYLINE, ntokens:%d", ntokens);
diff --git a/modutils/depmod.c b/modutils/depmod.c
index 318e7cdc7..bb42bbefe 100644
--- a/modutils/depmod.c
+++ b/modutils/depmod.c
@@ -32,10 +32,11 @@
* for each depends, look through our list of full paths and emit if found
*/
-static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM,
- void *data, int depth UNUSED_PARAM)
+static int FAST_FUNC parse_module(struct recursive_state *state,
+ const char *fname,
+ struct stat *sb UNUSED_PARAM)
{
- module_db *modules = data;
+ module_db *modules = state->userData;
char *image, *ptr;
module_entry *e;
@@ -201,11 +202,12 @@ int depmod_main(int argc UNUSED_PARAM, char **argv)
memset(&modules, 0, sizeof(modules));
if (*argv) {
do {
- parse_module(*argv, /*sb (unused):*/ NULL, &modules, 0);
+ recursive_action(*argv, 0 /* no ACTION_RECURSE! */,
+ parse_module, NULL, &modules);
} while (*++argv);
} else {
recursive_action(".", ACTION_RECURSE,
- parse_module, NULL, &modules, 0);
+ parse_module, NULL, &modules);
}
/* Generate dependency and alias files */
diff --git a/modutils/modprobe-small.c b/modutils/modprobe-small.c
index a94b0b9a6..18cfac481 100644
--- a/modutils/modprobe-small.c
+++ b/modutils/modprobe-small.c
@@ -751,8 +751,7 @@ static int process_module(char *name, const char *cmdline_options)
ACTION_RECURSE, /* flags */
fileAction, /* file action */
NULL, /* dir action */
- name, /* user data */
- 0 /* depth */
+ name /* user data */
);
dbg1_error_msg("dirscan complete");
/* Module was not found, or load failed, or is_remove */
diff --git a/modutils/modprobe.c b/modutils/modprobe.c
index 70c45903a..eeeff7609 100644
--- a/modutils/modprobe.c
+++ b/modutils/modprobe.c
@@ -235,10 +235,9 @@ static void add_probe(const char *name)
}
}
-static int FAST_FUNC config_file_action(const char *filename,
- struct stat *statbuf UNUSED_PARAM,
- void *userdata UNUSED_PARAM,
- int depth)
+static int FAST_FUNC config_file_action(struct recursive_state *state,
+ const char *filename,
+ struct stat *statbuf UNUSED_PARAM)
{
char *tokens[3];
parser_t *p;
@@ -255,7 +254,7 @@ static int FAST_FUNC config_file_action(const char *filename,
* that we shouldn't recurse into /etc/modprobe.d/dir/
* _subdirectories_:
*/
- if (depth > 1)
+ if (state->depth > 1)
return SKIP; /* stop recursing */
//TODO: instead, can use dirAction in recursive_action() to SKIP dirs
//on depth == 1 level. But that's more code...
@@ -264,7 +263,7 @@ static int FAST_FUNC config_file_action(const char *filename,
* depth==0: read_config("modules.{symbols,alias}") must work,
* "include FILE_NOT_ENDING_IN_CONF" must work too.
*/
- if (depth != 0) {
+ if (state->depth != 0) {
if (!is_suffixed_with(base, ".conf"))
goto error;
}
@@ -329,8 +328,7 @@ static int FAST_FUNC config_file_action(const char *filename,
static int read_config(const char *path)
{
return recursive_action(path, ACTION_RECURSE | ACTION_QUIET,
- config_file_action, NULL, NULL,
- /*depth:*/ 0);
+ config_file_action, NULL, NULL);
}
static const char *humanly_readable_name(struct module_entry *m)
diff --git a/networking/httpd.c b/networking/httpd.c
index 0297cf9ec..961f8cab4 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -245,6 +245,13 @@
//config: help
//config: RFC2616 says that server MUST add Date header to response.
//config: But it is almost useless and can be omitted.
+//config:
+//config:config FEATURE_HTTPD_ACL_IP
+//config: bool "ACL IP"
+//config: default y
+//config: depends on HTTPD
+//config: help
+//config: Support IP deny/allow rules
//applet:IF_HTTPD(APPLET(httpd, BB_DIR_USR_SBIN, BB_SUID_DROP))
@@ -314,6 +321,7 @@ typedef struct Htaccess {
char before_colon[1]; /* really bigger, must be last */
} Htaccess;
+#if ENABLE_FEATURE_HTTPD_ACL_IP
/* Must have "next" as a first member */
typedef struct Htaccess_IP {
struct Htaccess_IP *next;
@@ -321,6 +329,7 @@ typedef struct Htaccess_IP {
unsigned mask;
int allow_deny;
} Htaccess_IP;
+#endif
/* Must have "next" as a first member */
typedef struct Htaccess_Proxy {
@@ -449,7 +458,9 @@ struct globals {
const char *found_mime_type;
const char *found_moved_temporarily;
+#if ENABLE_FEATURE_HTTPD_ACL_IP
Htaccess_IP *ip_a_d; /* config allow/deny lines */
+#endif
IF_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
IF_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
@@ -499,7 +510,6 @@ struct globals {
#define found_mime_type (G.found_mime_type )
#define found_moved_temporarily (G.found_moved_temporarily)
#define last_mod (G.last_mod )
-#define ip_a_d (G.ip_a_d )
#define g_realm (G.g_realm )
#define remoteuser (G.remoteuser )
#define file_size (G.file_size )
@@ -560,11 +570,14 @@ static ALWAYS_INLINE void free_Htaccess_list(Htaccess **pptr)
free_llist((has_next_ptr**)pptr);
}
+#if ENABLE_FEATURE_HTTPD_ACL_IP
static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr)
{
free_llist((has_next_ptr**)pptr);
}
+#endif
+#if ENABLE_FEATURE_HTTPD_ACL_IP
/* Returns presumed mask width in bits or < 0 on error.
* Updates strp, stores IP at provided pointer */
static int scan_ip(const char **strp, unsigned *ipp, unsigned char endc)
@@ -649,6 +662,7 @@ static int scan_ip_mask(const char *str, unsigned *ipp, unsigned *maskp)
*maskp = (uint32_t)(~mask);
return 0;
}
+#endif
/*
* Parse configuration file into in-memory linked list.
@@ -678,7 +692,9 @@ static void parse_conf(const char *path, int flag)
char buf[160];
/* discard old rules */
- free_Htaccess_IP_list(&ip_a_d);
+#if ENABLE_FEATURE_HTTPD_ACL_IP
+ free_Htaccess_IP_list(&G.ip_a_d);
+#endif
flg_deny_all = 0;
/* retain previous auth and mime config only for subdir parse */
if (flag != SUBDIR_PARSE) {
@@ -783,6 +799,7 @@ static void parse_conf(const char *path, int flag)
continue;
}
+#if ENABLE_FEATURE_HTTPD_ACL_IP
if (ch == 'A' || ch == 'D') {
Htaccess_IP *pip;
@@ -804,13 +821,13 @@ static void parse_conf(const char *path, int flag)
pip->allow_deny = ch;
if (ch == 'D') {
/* Deny:from_IP - prepend */
- pip->next = ip_a_d;
- ip_a_d = pip;
+ pip->next = G.ip_a_d;
+ G.ip_a_d = pip;
} else {
/* A:from_IP - append (thus all D's precedes A's) */
- Htaccess_IP *prev_IP = ip_a_d;
+ Htaccess_IP *prev_IP = G.ip_a_d;
if (prev_IP == NULL) {
- ip_a_d = pip;
+ G.ip_a_d = pip;
} else {
while (prev_IP->next)
prev_IP = prev_IP->next;
@@ -819,6 +836,7 @@ static void parse_conf(const char *path, int flag)
}
continue;
}
+#endif
#if ENABLE_FEATURE_HTTPD_ERROR_PAGES
if (flag == FIRST_PARSE && ch == 'E') {
@@ -999,6 +1017,12 @@ static char *encodeString(const char *string)
*/
static void decodeBase64(char *Data)
{
+# if ENABLE_BASE64 || ENABLE_UUDECODE
+ /* Call decode_base64() from uuencode.c */
+ char *eptr = Data;
+ decode_base64(&eptr, Data);
+ *eptr = '\0';
+# else
const unsigned char *in = (const unsigned char *)Data;
/* The decoded size will be at most 3/4 the size of the encoded */
unsigned ch = 0;
@@ -1032,6 +1056,7 @@ static void decodeBase64(char *Data)
}
}
*Data = '\0';
+# endif
}
#endif
@@ -1920,11 +1945,12 @@ static NOINLINE void send_file_and_exit(const char *url, int what)
log_and_exit();
}
+#if ENABLE_FEATURE_HTTPD_ACL_IP
static void if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip)
{
Htaccess_IP *cur;
- for (cur = ip_a_d; cur; cur = cur->next) {
+ for (cur = G.ip_a_d; cur; cur = cur->next) {
#if DEBUG
fprintf(stderr,
"checkPermIP: '%s' ? '%u.%u.%u.%u/%u.%u.%u.%u'\n",
@@ -1949,6 +1975,9 @@ static void if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip)
if (flg_deny_all) /* depends on whether we saw "D:*" */
send_headers_and_exit(HTTP_FORBIDDEN);
}
+#else
+# define if_ip_denied_send_HTTP_FORBIDDEN_and_exit(arg) ((void)0)
+#endif
#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
@@ -2184,7 +2213,9 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
char *urlcopy;
char *urlp;
char *tptr;
+#if ENABLE_FEATURE_HTTPD_ACL_IP
unsigned remote_ip;
+#endif
#if ENABLE_FEATURE_HTTPD_CGI
unsigned total_headers_len;
#endif
@@ -2206,17 +2237,6 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
* (IOW, server process doesn't need to waste 8k) */
iobuf = xmalloc(IOBUF_SIZE);
- remote_ip = 0;
- if (fromAddr->u.sa.sa_family == AF_INET) {
- remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr);
- }
-#if ENABLE_FEATURE_IPV6
- if (fromAddr->u.sa.sa_family == AF_INET6
- && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0
- && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0
- && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff)
- remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]);
-#endif
if (ENABLE_FEATURE_HTTPD_CGI || DEBUG || verbose) {
/* NB: can be NULL (user runs httpd -i by hand?) */
rmt_ip_str = xmalloc_sockaddr2dotted(&fromAddr->u.sa);
@@ -2228,7 +2248,20 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr)
if (verbose > 2)
bb_simple_error_msg("connected");
}
+#if ENABLE_FEATURE_HTTPD_ACL_IP
+ remote_ip = 0;
+ if (fromAddr->u.sa.sa_family == AF_INET) {
+ remote_ip = ntohl(fromAddr->u.sin.sin_addr.s_addr);
+ }
+# if ENABLE_FEATURE_IPV6
+ if (fromAddr->u.sa.sa_family == AF_INET6
+ && fromAddr->u.sin6.sin6_addr.s6_addr32[0] == 0
+ && fromAddr->u.sin6.sin6_addr.s6_addr32[1] == 0
+ && ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[2]) == 0xffff)
+ remote_ip = ntohl(fromAddr->u.sin6.sin6_addr.s6_addr32[3]);
+# endif
if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip);
+#endif
/* Install timeout handler. get_line() needs it. */
signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit);
diff --git a/networking/ip.c b/networking/ip.c
index 7d3faf7f8..33bea5f49 100644
--- a/networking/ip.c
+++ b/networking/ip.c
@@ -252,7 +252,7 @@
//usage:#define iprule_trivial_usage
//usage: "[list] | add|del SELECTOR ACTION"
//usage:#define iprule_full_usage "\n\n"
-//usage: " SELECTOR := [from PREFIX] [to PREFIX] [tos TOS] [fwmark FWMARK]\n"
+//usage: " SELECTOR := [from PREFIX] [to PREFIX] [tos TOS] [fwmark FWMARK[/MASK]]\n"
//usage: " [dev IFACE] [pref NUMBER]\n"
//usage: " ACTION := [table TABLE_ID] [nat ADDR]\n"
//usage: " [prohibit|reject|unreachable]\n"
diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c
index 0ce0dfeef..50acfe4e7 100644
--- a/networking/libiproute/iprule.c
+++ b/networking/libiproute/iprule.c
@@ -17,8 +17,10 @@
#include <arpa/inet.h>
/* from <linux/fib_rules.h>: */
-#define FRA_SUPPRESS_IFGROUP 13
-#define FRA_SUPPRESS_PREFIXLEN 14
+#define FRA_FWMARK 10
+#define FRA_SUPPRESS_IFGROUP 13
+#define FRA_SUPPRESS_PREFIXLEN 14
+#define FRA_FWMASK 16
#include "ip_common.h" /* #include "libbb.h" is inside */
#include "rt_names.h"
@@ -117,8 +119,18 @@ static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM,
if (r->rtm_tos) {
printf("tos %s ", rtnl_dsfield_n2a(r->rtm_tos));
}
- if (tb[RTA_PROTOINFO]) {
- printf("fwmark %#x ", *(uint32_t*)RTA_DATA(tb[RTA_PROTOINFO]));
+
+ if (tb[FRA_FWMARK] || tb[FRA_FWMASK]) {
+ uint32_t mark = 0, mask = 0;
+
+ if (tb[FRA_FWMARK])
+ mark = *(uint32_t*)RTA_DATA(tb[FRA_FWMARK]);
+ if (tb[FRA_FWMASK]
+ && (mask = *(uint32_t*)RTA_DATA(tb[FRA_FWMASK])) != 0xFFFFFFFF
+ )
+ printf("fwmark %#x/%#x ", mark, mask);
+ else
+ printf("fwmark %#x ", mark);
}
if (tb[RTA_IIF]) {
@@ -257,10 +269,18 @@ static int iprule_modify(int cmd, char **argv)
invarg_1_to_2(*argv, "TOS");
req.r.rtm_tos = tos;
} else if (key == ARG_fwmark) {
- uint32_t fwmark;
+ char *slash;
+ uint32_t fwmark, fwmask;
NEXT_ARG();
+ slash = strchr(*argv, '/');
+ if (slash)
+ *slash = '\0';
fwmark = get_u32(*argv, keyword_fwmark);
- addattr32(&req.n, sizeof(req), RTA_PROTOINFO, fwmark);
+ addattr32(&req.n, sizeof(req), FRA_FWMARK, fwmark);
+ if (slash) {
+ fwmask = get_u32(slash + 1, "fwmask");
+ addattr32(&req.n, sizeof(req), FRA_FWMASK, fwmask);
+ }
} else if (key == ARG_realms) {
uint32_t realm;
NEXT_ARG();
diff --git a/networking/netstat.c b/networking/netstat.c
index 936610f89..3ab7b0d21 100644
--- a/networking/netstat.c
+++ b/networking/netstat.c
@@ -272,10 +272,9 @@ static long extract_socket_inode(const char *lname)
return inode;
}
-static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName,
- struct stat *statbuf UNUSED_PARAM,
- void *pid_slash_progname,
- int depth UNUSED_PARAM)
+static int FAST_FUNC add_to_prg_cache_if_socket(struct recursive_state *state,
+ const char *fileName,
+ struct stat *statbuf UNUSED_PARAM)
{
char *linkname;
long inode;
@@ -284,16 +283,17 @@ static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName,
if (linkname != NULL) {
inode = extract_socket_inode(linkname);
free(linkname);
- if (inode >= 0)
- prg_cache_add(inode, (char *)pid_slash_progname);
+ if (inode >= 0) {
+ char *pid_slash_progname = state->userData;
+ prg_cache_add(inode, pid_slash_progname);
+ }
}
return TRUE;
}
-static int FAST_FUNC dir_act(const char *fileName,
- struct stat *statbuf UNUSED_PARAM,
- void *userData UNUSED_PARAM,
- int depth)
+static int FAST_FUNC dir_act(struct recursive_state *state,
+ const char *fileName,
+ struct stat *statbuf UNUSED_PARAM)
{
const char *pid;
char *pid_slash_progname;
@@ -301,7 +301,7 @@ static int FAST_FUNC dir_act(const char *fileName,
char cmdline_buf[512];
int n, len;
- if (depth == 0) /* "/proc" itself */
+ if (state->depth == 0) /* "/proc" itself */
return TRUE; /* continue looking one level below /proc */
pid = fileName + sizeof("/proc/")-1; /* point after "/proc/" */
@@ -321,8 +321,8 @@ static int FAST_FUNC dir_act(const char *fileName,
ACTION_RECURSE | ACTION_QUIET,
add_to_prg_cache_if_socket,
NULL,
- (void *)pid_slash_progname,
- 0);
+ (void *)pid_slash_progname
+ );
free(pid_slash_progname);
if (!n)
@@ -337,7 +337,7 @@ static void prg_cache_load(void)
prg_cache_loaded = 1;
load_ok = recursive_action("/proc", ACTION_RECURSE | ACTION_QUIET,
- NULL, dir_act, NULL, 0);
+ NULL, dir_act, NULL);
if (load_ok)
return;
diff --git a/networking/nslookup.c b/networking/nslookup.c
index c43e60558..759de5c83 100644
--- a/networking/nslookup.c
+++ b/networking/nslookup.c
@@ -703,12 +703,13 @@ static void parse_resolvconf(void)
while (fgets(line, sizeof(line), resolv)) {
char *p, *arg;
+ char *tokstate;
- p = strtok(line, " \t\n");
+ p = strtok_r(line, " \t\n", &tokstate);
if (!p)
continue;
dbg("resolv_key:'%s'\n", p);
- arg = strtok(NULL, "\n");
+ arg = strtok_r(NULL, "\n", &tokstate);
dbg("resolv_arg:'%s'\n", arg);
if (!arg)
continue;
diff --git a/networking/ntpd.c b/networking/ntpd.c
index d721fe80c..44e711232 100644
--- a/networking/ntpd.c
+++ b/networking/ntpd.c
@@ -2025,6 +2025,15 @@ recv_and_process_peer_pkt(peer_t *p)
offset = 0;
+ /* The below can happen as follows:
+ * = we receive two peer rsponses at once.
+ * = recv_and_process_peer_pkt(PEER1) -> update_local_clock()
+ * -> step_time() and it closes all other fds, sets all ->fd to -1.
+ * = recv_and_process_peer_pkt(PEER2) sees PEER2->fd == -1
+ */
+ if (p->p_fd < 0)
+ return;
+
/* We can recvfrom here and check from.IP, but some multihomed
* ntp servers reply from their *other IP*.
* TODO: maybe we should check at least what we can: from.port == 123?
diff --git a/networking/ping.c b/networking/ping.c
index 47b6ab1b2..5f7e5b9b5 100644
--- a/networking/ping.c
+++ b/networking/ping.c
@@ -217,7 +217,7 @@ static void ping4(len_and_sockaddr *lsa)
/*memset(pkt, 0, sizeof(G.packet)); already is */
pkt->icmp_type = ICMP_ECHO;
pkt->icmp_id = G.myid;
- pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet));
+ pkt->icmp_cksum = inet_cksum(pkt, sizeof(G.packet));
xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len);
@@ -529,7 +529,7 @@ static void sendping4(int junk UNUSED_PARAM)
/* No hton: we'll read it back on the same machine */
*(uint32_t*)&pkt->icmp_dun = G.cur_us = monotonic_us();
- pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, datalen + ICMP_MINLEN);
+ pkt->icmp_cksum = inet_cksum(pkt, datalen + ICMP_MINLEN);
sendping_tail(sendping4, ICMP_MINLEN);
}
diff --git a/networking/traceroute.c b/networking/traceroute.c
index 5068f654b..1c4dc3e4a 100644
--- a/networking/traceroute.c
+++ b/networking/traceroute.c
@@ -468,7 +468,7 @@ send_probe(int seq, int ttl)
/* Always calculate checksum for icmp packets */
outicmp->icmp_cksum = 0;
outicmp->icmp_cksum = inet_cksum(
- (uint16_t *)outicmp,
+ outicmp,
((char*)outip + packlen) - (char*)outicmp
);
if (outicmp->icmp_cksum == 0)
diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c
index 20d843bab..4bc719001 100644
--- a/networking/udhcp/common.c
+++ b/networking/udhcp/common.c
@@ -526,7 +526,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg,
/* Cheat, the only *const* str possible is "" */
str = (char *) const_str;
- opt = strtok(str, " \t=:");
+ opt = strtok_r(str, " \t=:", &str);
if (!opt)
return 0;
@@ -550,10 +550,10 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg,
char *val;
if (optflag->flags == OPTION_BIN) {
- val = strtok(NULL, ""); /* do not split "'q w e'" */
+ val = strtok_r(NULL, "", &str); /* do not split "'q w e'" */
if (val) trim(val);
} else
- val = strtok(NULL, ", \t");
+ val = strtok_r(NULL, ", \t", &str);
if (!val)
break;
@@ -567,7 +567,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg,
break;
case OPTION_IP_PAIR:
retval = udhcp_str2nip(val, buffer);
- val = strtok(NULL, ", \t/-");
+ val = strtok_r(NULL, ", \t/-", &str);
if (!val)
retval = 0;
if (retval)
@@ -631,7 +631,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg,
*slash = '\0';
retval = udhcp_str2nip(val, buffer + 1);
buffer[0] = mask = bb_strtou(slash + 1, NULL, 10);
- val = strtok(NULL, ", \t/-");
+ val = strtok_r(NULL, ", \t/-", &str);
if (!val || mask > 32 || errno)
retval = 0;
if (retval) {
diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h
index 81c1dcbdc..3cbd2d3c8 100644
--- a/networking/udhcp/common.h
+++ b/networking/udhcp/common.h
@@ -46,7 +46,7 @@ struct dhcp_packet {
uint8_t file[128]; /* boot file name (ASCIZ) */
uint32_t cookie; /* fixed first four option bytes (99,130,83,99 dec) */
uint8_t options[DHCP_OPTIONS_BUFSIZE + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS];
-} PACKED;
+};
#define DHCP_PKT_SNAME_LEN 64
#define DHCP_PKT_FILE_LEN 128
#define DHCP_PKT_SNAME_LEN_STR "64"
@@ -56,12 +56,12 @@ struct ip_udp_dhcp_packet {
struct iphdr ip;
struct udphdr udp;
struct dhcp_packet data;
-} PACKED;
+};
struct udp_dhcp_packet {
struct udphdr udp;
struct dhcp_packet data;
-} PACKED;
+};
enum {
IP_UDP_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS,
diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c
index fc2d672b7..ac8af91d3 100644
--- a/networking/udhcp/d6_dhcpc.c
+++ b/networking/udhcp/d6_dhcpc.c
@@ -947,7 +947,7 @@ static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6, struct d6_pac
// packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
// check = packet.udp.check;
// packet.udp.check = 0;
-// if (check && check != inet_cksum((uint16_t *)&packet, bytes)) {
+// if (check && check != inet_cksum(&packet, bytes)) {
// log1("packet with bad UDP checksum received, ignoring");
// return -2;
// }
diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c
index 446497e15..167a813e3 100644
--- a/networking/udhcp/d6_packet.c
+++ b/networking/udhcp/d6_packet.c
@@ -103,7 +103,7 @@ int FAST_FUNC d6_send_raw_packet(
*/
packet.ip6.ip6_hlim = IPPROTO_UDP;
packet.udp.check = inet_cksum(
- (uint16_t *)&packet + 2,
+ (uint8_t *)&packet + 4,
offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size
);
/* fix 'hop limit' and 'next header' after UDP checksumming */
diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c
index e13eb3f9f..66aa38c20 100644
--- a/networking/udhcp/dhcpc.c
+++ b/networking/udhcp/dhcpc.c
@@ -935,7 +935,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
/* verify IP checksum */
check = packet.ip.check;
packet.ip.check = 0;
- if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) {
+ if (check != inet_cksum(&packet.ip, sizeof(packet.ip))) {
log1s("bad IP header checksum, ignoring");
return -2;
}
@@ -960,7 +960,7 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd)
packet.ip.tot_len = packet.udp.len; /* yes, this is needed */
check = packet.udp.check;
packet.udp.check = 0;
- if (check && check != inet_cksum((uint16_t *)&packet, bytes)) {
+ if (check && check != inet_cksum(&packet, bytes)) {
log1s("packet with bad UDP checksum received, ignoring");
return -2;
}
diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c
index 6d4375237..51374646d 100644
--- a/networking/udhcp/packet.c
+++ b/networking/udhcp/packet.c
@@ -164,14 +164,14 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt,
packet.udp.len = htons(UDP_DHCP_SIZE - padding);
/* for UDP checksumming, ip.len is set to UDP packet len */
packet.ip.tot_len = packet.udp.len;
- packet.udp.check = inet_cksum((uint16_t *)&packet,
+ packet.udp.check = inet_cksum(&packet,
IP_UDP_DHCP_SIZE - padding);
/* but for sending, it is set to IP packet len */
packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding);
packet.ip.ihl = sizeof(packet.ip) >> 2;
packet.ip.version = IPVERSION;
packet.ip.ttl = IPDEFTTL;
- packet.ip.check = inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip));
+ packet.ip.check = inet_cksum(&packet.ip, sizeof(packet.ip));
udhcp_dump_packet(dhcp_pkt);
result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0,
diff --git a/procps/mpstat.c b/procps/mpstat.c
index 52a436a55..c78c1f0a0 100644
--- a/procps/mpstat.c
+++ b/procps/mpstat.c
@@ -923,7 +923,7 @@ int mpstat_main(int argc UNUSED_PARAM, char **argv)
char *t;
G.p_option = 1;
- for (t = strtok(opt_set_cpu, ","); t; t = strtok(NULL, ",")) {
+ for (t = strtok_r(opt_set_cpu, ",", &opt_set_cpu); t; t = strtok_r(NULL, ",", &opt_set_cpu)) {
if (strcmp(t, "ALL") == 0) {
/* Select every CPU */
memset(G.cpu_bitmap, 0xff, G.cpu_bitmap_len);
diff --git a/selinux/chcon.c b/selinux/chcon.c
index afe7f713d..9b13679b8 100644
--- a/selinux/chcon.c
+++ b/selinux/chcon.c
@@ -62,11 +62,9 @@ static char *type = NULL;
static char *range = NULL;
static char *specified_context = NULL;
-static int FAST_FUNC change_filedir_context(
+static int FAST_FUNC change_filedir_context(struct recursive_state *state UNUSED_PARAM,
const char *fname,
- struct stat *stbuf UNUSED_PARAM,
- void *userData UNUSED_PARAM,
- int depth UNUSED_PARAM)
+ struct stat *stbuf UNUSED_PARAM)
{
context_t context = NULL;
security_context_t file_context = NULL;
@@ -207,7 +205,7 @@ int chcon_main(int argc UNUSED_PARAM, char **argv)
((option_mask32 & OPT_RECURSIVE) ? ACTION_RECURSE : 0),
change_filedir_context,
change_filedir_context,
- NULL, 0) != TRUE)
+ NULL) != TRUE)
errors = 1;
}
return errors;
diff --git a/selinux/setfiles.c b/selinux/setfiles.c
index 55bfb4d02..a617b95d8 100644
--- a/selinux/setfiles.c
+++ b/selinux/setfiles.c
@@ -463,11 +463,9 @@ static int restore(const char *file)
* This function is called by recursive_action on each file during
* the directory traversal.
*/
-static int FAST_FUNC apply_spec(
+static int FAST_FUNC apply_spec(struct recursive_state *state UNUSED_PARAM,
const char *file,
- struct stat *sb,
- void *userData UNUSED_PARAM,
- int depth UNUSED_PARAM)
+ struct stat *sb)
{
if (!follow_mounts) {
/* setfiles does not process across different mount points */
@@ -535,7 +533,7 @@ static int process_one(char *name)
ACTION_RECURSE,
apply_spec,
apply_spec,
- NULL, 0) != TRUE
+ NULL) != TRUE
) {
bb_error_msg("error while labeling %s", name);
goto err;
diff --git a/shell/ash.c b/shell/ash.c
index ecb9b132b..58da0a2a0 100644
--- a/shell/ash.c
+++ b/shell/ash.c
@@ -2770,7 +2770,7 @@ updatepwd(const char *dir)
lim++;
}
}
- p = strtok(cdcomppath, "/");
+ p = strtok_r(cdcomppath, "/", &cdcomppath);
while (p) {
switch (*p) {
case '.':
@@ -2789,7 +2789,7 @@ updatepwd(const char *dir)
new = stack_putstr(p, new);
USTPUTC('/', new);
}
- p = strtok(NULL, "/");
+ p = strtok_r(NULL, "/", &cdcomppath);
}
if (new > lim)
STUNPUTC(new);
@@ -4273,64 +4273,55 @@ sprint_status48(char *os, int status, int sigonly)
return s - os;
}
+#define DOWAIT_NONBLOCK 0
+#define DOWAIT_BLOCK 1
+#define DOWAIT_BLOCK_OR_SIG 2
+#if BASH_WAIT_N
+# define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */
+#endif
+
static int
-wait_block_or_sig(int *status)
+waitproc(int block, int *status)
{
- int pid;
+ sigset_t oldmask;
+ int flags = block == DOWAIT_BLOCK ? 0 : WNOHANG;
+ int err;
- do {
- sigset_t mask;
+#if JOBS
+ if (doing_jobctl)
+ flags |= WUNTRACED;
+#endif
- /* Poll all children for changes in their state */
+ do {
got_sigchld = 0;
- /* if job control is active, accept stopped processes too */
- pid = waitpid(-1, status, doing_jobctl ? (WNOHANG|WUNTRACED) : WNOHANG);
- if (pid != 0)
- break; /* Error (e.g. EINTR, ECHILD) or pid */
+ do
+ err = waitpid(-1, status, flags);
+ while (err < 0 && errno == EINTR);
- /* Children exist, but none are ready. Sleep until interesting signal */
-#if 1
- sigfillset(&mask);
- sigprocmask2(SIG_SETMASK, &mask); /* mask is updated */
- while (!got_sigchld && !pending_sig) {
- sigsuspend(&mask);
- /* ^^^ add "sigdelset(&mask, SIGCHLD);" before sigsuspend
- * to make sure SIGCHLD is not masked off?
- * It was reported that this:
- * fn() { : | return; }
- * shopt -s lastpipe
- * fn
- * exec ash SCRIPT
- * under bash 4.4.23 runs SCRIPT with SIGCHLD masked,
- * making "wait" commands in SCRIPT block forever.
- */
- }
- sigprocmask(SIG_SETMASK, &mask, NULL);
-#else /* unsafe: a signal can set pending_sig after check, but before pause() */
+ if (err || (err = -!block))
+ break;
+
+ sigfillset(&oldmask);
+ sigprocmask2(SIG_SETMASK, &oldmask); /* mask is updated */
while (!got_sigchld && !pending_sig)
- pause();
-#endif
+ sigsuspend(&oldmask);
+ sigprocmask(SIG_SETMASK, &oldmask, NULL);
+ //simpler, but unsafe: a signal can set pending_sig after check, but before pause():
+ //while (!got_sigchld && !pending_sig)
+ // pause();
- /* If it was SIGCHLD, poll children again */
} while (got_sigchld);
- return pid;
+ return err;
}
-#define DOWAIT_NONBLOCK 0
-#define DOWAIT_BLOCK 1
-#define DOWAIT_BLOCK_OR_SIG 2
-#if BASH_WAIT_N
-# define DOWAIT_JOBSTATUS 0x10 /* OR this to get job's exitstatus instead of pid */
-#endif
-
static int
waitone(int block, struct job *job)
{
int pid;
int status;
struct job *jp;
- struct job *thisjob;
+ struct job *thisjob = NULL;
#if BASH_WAIT_N
bool want_jobexitstatus = (block & DOWAIT_JOBSTATUS);
block = (block & ~DOWAIT_JOBSTATUS);
@@ -4357,21 +4348,8 @@ waitone(int block, struct job *job)
* SIG_DFL handler does not wake sigsuspend().
*/
INT_OFF;
- if (block == DOWAIT_BLOCK_OR_SIG) {
- pid = wait_block_or_sig(&status);
- } else {
- int wait_flags = 0;
- if (block == DOWAIT_NONBLOCK)
- wait_flags = WNOHANG;
- /* if job control is active, accept stopped processes too */
- if (doing_jobctl)
- wait_flags |= WUNTRACED;
- /* NB: _not_ safe_waitpid, we need to detect EINTR */
- pid = waitpid(-1, &status, wait_flags);
- }
- TRACE(("wait returns pid=%d, status=0x%x, errno=%d(%s)\n",
- pid, status, errno, strerror(errno)));
- thisjob = NULL;
+ pid = waitproc(block, &status);
+ TRACE(("wait returns pid %d, status=%d\n", pid, status));
if (pid <= 0)
goto out;
@@ -4453,15 +4431,27 @@ waitone(int block, struct job *job)
static int
dowait(int block, struct job *jp)
{
- int pid = block == DOWAIT_NONBLOCK ? got_sigchld : 1;
+ smallint gotchld = *(volatile smallint *)&got_sigchld;
+ int rpid;
+ int pid;
+
+ if (jp && jp->state != JOBRUNNING)
+ block = DOWAIT_NONBLOCK;
+
+ if (block == DOWAIT_NONBLOCK && !gotchld)
+ return 1;
- while (jp ? jp->state == JOBRUNNING : pid > 0) {
- if (!jp)
- got_sigchld = 0;
+ rpid = 1;
+
+ do {
pid = waitone(block, jp);
- }
+ rpid &= !!pid;
- return pid;
+ if (!pid || (jp && jp->state != JOBRUNNING))
+ block = DOWAIT_NONBLOCK;
+ } while (pid >= 0);
+
+ return rpid;
}
#if JOBS
@@ -4708,7 +4698,7 @@ waitcmd(int argc UNUSED_PARAM, char **argv)
job = getjob(*argv, 0);
}
/* loop until process terminated or stopped */
- dowait(DOWAIT_BLOCK_OR_SIG, NULL);
+ dowait(DOWAIT_BLOCK_OR_SIG, job);
if (pending_sig)
goto sigout;
job->waited = 1;
@@ -12811,7 +12801,7 @@ parsebackq: {
goto done;
case '\\':
- pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */
+ pc = pgetc(); /* not pgetc_eatbnl! */
if (pc != '\\' && pc != '`' && pc != '$'
&& (!synstack->dblquote || pc != '"')
) {
diff --git a/shell/ash_test/ash-misc/wait7.right b/shell/ash_test/ash-misc/wait7.right
new file mode 100644
index 000000000..4b6445841
--- /dev/null
+++ b/shell/ash_test/ash-misc/wait7.right
@@ -0,0 +1,2 @@
+Background1
+Ok:0
diff --git a/shell/ash_test/ash-misc/wait7.tests b/shell/ash_test/ash-misc/wait7.tests
new file mode 100755
index 000000000..a54a778e5
--- /dev/null
+++ b/shell/ash_test/ash-misc/wait7.tests
@@ -0,0 +1,7 @@
+sleep 1 && echo "Background1" &
+pid=$!
+sleep 3 && echo "Background2: BUG!" &
+# Shouldn't wait for 2nd bkgd:
+wait $pid
+kill $!
+echo Ok:$?
diff --git a/shell/hush_test/hush-misc/wait7.right b/shell/hush_test/hush-misc/wait7.right
new file mode 100644
index 000000000..4b6445841
--- /dev/null
+++ b/shell/hush_test/hush-misc/wait7.right
@@ -0,0 +1,2 @@
+Background1
+Ok:0
diff --git a/shell/hush_test/hush-misc/wait7.tests b/shell/hush_test/hush-misc/wait7.tests
new file mode 100755
index 000000000..a54a778e5
--- /dev/null
+++ b/shell/hush_test/hush-misc/wait7.tests
@@ -0,0 +1,7 @@
+sleep 1 && echo "Background1" &
+pid=$!
+sleep 3 && echo "Background2: BUG!" &
+# Shouldn't wait for 2nd bkgd:
+wait $pid
+kill $!
+echo Ok:$?
diff --git a/shell/math.c b/shell/math.c
index aac5017d0..2942cdd26 100644
--- a/shell/math.c
+++ b/shell/math.c
@@ -251,7 +251,7 @@ typedef struct remembered_name {
} remembered_name;
-static arith_t FAST_FUNC
+static arith_t
evaluate_string(arith_state_t *math_state, const char *expr);
static const char*
@@ -582,7 +582,7 @@ static arith_t strto_arith_t(const char *nptr, char **endptr)
# endif
#endif
-static arith_t FAST_FUNC
+static arith_t
evaluate_string(arith_state_t *math_state, const char *expr)
{
operator lasttok;
diff --git a/testsuite/hexdump.tests b/testsuite/hexdump.tests
index 45a0c1300..cfb20187e 100755
--- a/testsuite/hexdump.tests
+++ b/testsuite/hexdump.tests
@@ -15,4 +15,23 @@ testing 'hexdump -C with four NULs' \
'' \
'\0\0\0\0'
+testing "hexdump does not think last padded block matches any full block" \
+ "hexdump -e '1/1 \"%02x|\"1/1 \"%02x!\\n\"'" \
+ "\
+00|00!
+*
+00| !
+" \
+ '' \
+ '\0\0\0\0\0\0\0\0\0\0\0'
+
+testing "hexdump thinks last full block can match" \
+ "hexdump -e '1/1 \"%02x|\"1/1 \"%02x!\\n\"'" \
+ "\
+00|00!
+*
+" \
+ '' \
+ '\0\0\0\0\0\0\0\0\0\0\0\0'
+
exit $FAILCOUNT
diff --git a/testsuite/xargs.tests b/testsuite/xargs.tests
index 159f1ff69..e7c7c4b3d 100755
--- a/testsuite/xargs.tests
+++ b/testsuite/xargs.tests
@@ -61,4 +61,12 @@ testing "xargs -n2" \
SKIP=
+optional FEATURE_XARGS_SUPPORT_QUOTES
+testing "xargs -I skips empty lines and leading whitespace" \
+ "xargs -I% echo '[%]'" \
+ "[2]\n[4]\n[6 6 ]\n[7]\n" \
+ "" " \n2\n\n4\n\n 6 6 \n \v \t 7\n\t\n\v\n"
+
+SKIP=
+
exit $FAILCOUNT
diff --git a/testsuite/xxd.tests b/testsuite/xxd.tests
new file mode 100755
index 000000000..2e80be5fe
--- /dev/null
+++ b/testsuite/xxd.tests
@@ -0,0 +1,34 @@
+#!/bin/sh
+
+# Copyright 2020 by Denys Vlasenko <vda.linux@googlemail.com>
+# Licensed under GPLv2, see file LICENSE in this source tree.
+
+. ./testing.sh
+
+# testing "description" "command" "result" "infile" "stdin"
+testing 'xxd -p with one NUL' \
+ 'xxd -p' \
+ "\
+00
+" \
+ '' \
+ '\0'
+
+testing 'xxd -p with 30 NULs' \
+ 'xxd -p' \
+ "\
+000000000000000000000000000000000000000000000000000000000000
+" \
+ '' \
+ '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
+
+testing 'xxd -p with 31 NULs' \
+ 'xxd -p' \
+ "\
+000000000000000000000000000000000000000000000000000000000000
+00
+" \
+ '' \
+ '\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0'
+
+exit $FAILCOUNT
diff --git a/util-linux/getopt.c b/util-linux/getopt.c
index db7db6ff8..1fa402429 100644
--- a/util-linux/getopt.c
+++ b/util-linux/getopt.c
@@ -289,12 +289,13 @@ static struct option *add_long_options(struct option *long_options, char *option
{
int long_nr = 0;
int arg_opt, tlen;
- char *tokptr = strtok(options, ", \t\n");
+ char *tokptr;
if (long_options)
while (long_options[long_nr].name)
long_nr++;
+ tokptr = strtok_r(options, ", \t\n", &options);
while (tokptr) {
arg_opt = no_argument;
tlen = strlen(tokptr);
@@ -318,7 +319,7 @@ static struct option *add_long_options(struct option *long_options, char *option
long_nr++;
/*memset(&long_options[long_nr], 0, sizeof(long_options[0])); - xrealloc_vector did it */
}
- tokptr = strtok(NULL, ", \t\n");
+ tokptr = strtok_r(NULL, ", \t\n", &options);
}
return long_options;
}
diff --git a/util-linux/hexdump_xxd.c b/util-linux/hexdump_xxd.c
index 6cf6d0297..f2d1ecb2c 100644
--- a/util-linux/hexdump_xxd.c
+++ b/util-linux/hexdump_xxd.c
@@ -141,6 +141,7 @@ int xxd_main(int argc UNUSED_PARAM, char **argv)
bb_dump_add(dumper, buf);
} else {
bb_dump_add(dumper, "\"\n\"");
+ dumper->eofstring = "\n";
}
return bb_dump_dump(dumper, argv);
diff --git a/util-linux/losetup.c b/util-linux/losetup.c
index ac8b79502..24f7a2349 100644
--- a/util-linux/losetup.c
+++ b/util-linux/losetup.c
@@ -150,7 +150,7 @@ int losetup_main(int argc UNUSED_PARAM, char **argv)
if (opt & OPT_P) {
flags |= BB_LO_FLAGS_PARTSCAN;
}
- if (set_loop(&d, argv[0], offset, flags) < 0)
+ if (set_loop(&d, argv[0], offset, 0, flags) < 0)
bb_simple_perror_msg_and_die(argv[0]);
return EXIT_SUCCESS;
}
diff --git a/util-linux/lspci.c b/util-linux/lspci.c
index 2f0b5fab9..c22cbcc1e 100644
--- a/util-linux/lspci.c
+++ b/util-linux/lspci.c
@@ -37,11 +37,9 @@ enum {
/*
* PCI_SLOT_NAME PCI_CLASS: PCI_VID:PCI_DID [PCI_SUBSYS_VID:PCI_SUBSYS_DID] [DRIVER]
*/
-static int FAST_FUNC fileAction(
+static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM,
const char *fileName,
- struct stat *statbuf UNUSED_PARAM,
- void *userData UNUSED_PARAM,
- int depth UNUSED_PARAM)
+ struct stat *statbuf UNUSED_PARAM)
{
parser_t *parser;
char *tokens[3];
@@ -117,8 +115,7 @@ int lspci_main(int argc UNUSED_PARAM, char **argv)
ACTION_RECURSE,
fileAction,
NULL, /* dirAction */
- NULL, /* userData */
- 0 /* depth */);
-
+ NULL /* userData */
+ );
return EXIT_SUCCESS;
}
diff --git a/util-linux/lsusb.c b/util-linux/lsusb.c
index 64a00eee2..9abb748ce 100644
--- a/util-linux/lsusb.c
+++ b/util-linux/lsusb.c
@@ -24,11 +24,9 @@
#include "libbb.h"
-static int FAST_FUNC fileAction(
+static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM,
const char *fileName,
- struct stat *statbuf UNUSED_PARAM,
- void *userData UNUSED_PARAM,
- int depth UNUSED_PARAM)
+ struct stat *statbuf UNUSED_PARAM)
{
parser_t *parser;
char *tokens[4];
@@ -80,8 +78,8 @@ int lsusb_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM)
ACTION_RECURSE,
fileAction,
NULL, /* dirAction */
- NULL, /* userData */
- 0 /* depth */);
+ NULL /* userData */
+ );
return EXIT_SUCCESS;
}
diff --git a/util-linux/mdev.c b/util-linux/mdev.c
index f42bebc20..59dbcf0cd 100644
--- a/util-linux/mdev.c
+++ b/util-linux/mdev.c
@@ -845,13 +845,12 @@ static ssize_t readlink2(char *buf, size_t bufsize)
/* File callback for /sys/ traversal.
* We act only on "/sys/.../dev" (pseudo)file
*/
-static int FAST_FUNC fileAction(const char *fileName,
- struct stat *statbuf UNUSED_PARAM,
- void *userData,
- int depth UNUSED_PARAM)
+static int FAST_FUNC fileAction(struct recursive_state *state,
+ const char *fileName,
+ struct stat *statbuf UNUSED_PARAM)
{
size_t len = strlen(fileName) - 4; /* can't underflow */
- char *path = userData; /* char array[PATH_MAX + SCRATCH_SIZE] */
+ char *path = state->userData; /* char array[PATH_MAX + SCRATCH_SIZE] */
char subsys[PATH_MAX];
int res;
@@ -888,12 +887,11 @@ static int FAST_FUNC fileAction(const char *fileName,
}
/* Directory callback for /sys/ traversal */
-static int FAST_FUNC dirAction(const char *fileName UNUSED_PARAM,
- struct stat *statbuf UNUSED_PARAM,
- void *userData UNUSED_PARAM,
- int depth)
+static int FAST_FUNC dirAction(struct recursive_state *state,
+ const char *fileName UNUSED_PARAM,
+ struct stat *statbuf UNUSED_PARAM)
{
- return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE);
+ return (state->depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE);
}
/* For the full gory details, see linux/Documentation/firmware_class/README
@@ -1149,7 +1147,7 @@ static void initial_scan(char *temp)
/* Create all devices from /sys/dev hierarchy */
recursive_action("/sys/dev",
ACTION_RECURSE | ACTION_FOLLOWLINKS,
- fileAction, dirAction, temp, 0);
+ fileAction, dirAction, temp);
}
#if ENABLE_FEATURE_MDEV_DAEMON
diff --git a/util-linux/mount.c b/util-linux/mount.c
index b92e2c297..fc5161d7f 100644
--- a/util-linux/mount.c
+++ b/util-linux/mount.c
@@ -1230,6 +1230,7 @@ static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *fi
* then data pointer is interpreted as a string. */
struct nfs_mount_data data;
char *opt;
+ char *tokstate;
struct hostent *hp;
struct sockaddr_in server_addr;
struct sockaddr_in mount_server_addr;
@@ -1348,7 +1349,7 @@ static NOINLINE int nfsmount(struct mntent *mp, unsigned long vfsflags, char *fi
nfsvers = 0;
/* parse options */
- if (filteropts) for (opt = strtok(filteropts, ","); opt; opt = strtok(NULL, ",")) {
+ if (filteropts) for (opt = strtok_r(filteropts, ",", &tokstate); opt; opt = strtok_r(NULL, ",", &tokstate)) {
char *opteq = strchr(opt, '=');
if (opteq) {
int val, idx;
@@ -1886,6 +1887,58 @@ static int nfsmount(struct mntent *mp, unsigned long vfsflags, char *filteropts)
#endif // !ENABLE_FEATURE_MOUNT_NFS
+// Find "...,NAME=NUM,..." in the option string, remove "NAME=NUM" option
+// and return NUM.
+// Return 0 if not found.
+// All instances must be parsed and removed (for example, since kernel 5.4
+// squashfs: Unknown parameter 'sizelimit'
+// will result if loopback mount option "sizelimit=NNN" is not removed
+// and squashfs sees it in option string).
+static unsigned long long cut_out_ull_opt(char *opts, const char *name_eq)
+{
+ unsigned long long ret = 0;
+
+ if (!opts) // allow NULL opts (simplifies callers' work)
+ return ret;
+
+ for (;;) {
+ char *end;
+ char *opt;
+
+ // Find comma-delimited "NAME="
+ for (;;) {
+ opt = strstr(opts, name_eq);
+ if (!opt)
+ return ret;
+ if (opt == opts)
+ break; // found it (it's first opt)
+ if (opt[-1] == ',') {
+ opts = opt - 1;
+ break; // found it (it's not a first opt)
+ }
+ // False positive like "VNAME=", we are at "N".
+ // - skip it, loop back to searching
+ opts = opt + 1;
+ }
+
+ ret = bb_strtoull(opt + strlen(name_eq), &end, 0);
+ if (errno && errno != EINVAL) {
+ err:
+ bb_error_msg_and_die("bad option '%s'", opt);
+ }
+ if (*end == '\0') {
+ // It is "[,]NAME=NUM\0" - truncate it and return
+ *opts = '\0';
+ return ret;
+ }
+ if (*end != ',')
+ goto err;
+ // We are at trailing comma
+ // Remove "NAME=NUM," and loop back to check for duplicate opts
+ overlapping_strcpy(opt, end + 1);
+ }
+}
+
// Mount one directory. Handles CIFS, NFS, loopback, autobind, and filesystem
// type detection. Returns 0 for success, nonzero for failure.
// NB: mp->xxx fields may be trashed on exit
@@ -2029,9 +2082,16 @@ static int singlemount(struct mntent *mp, int ignore_busy)
) {
// Do we need to allocate a loopback device for it?
if (ENABLE_FEATURE_MOUNT_LOOP && S_ISREG(st.st_mode)) {
+ unsigned long long offset;
+ unsigned long long sizelimit;
+
loopFile = bb_simplify_path(mp->mnt_fsname);
mp->mnt_fsname = NULL; // will receive malloced loop dev name
+ // Parse and remove loopback options
+ offset = cut_out_ull_opt(filteropts, "offset=");
+ sizelimit = cut_out_ull_opt(filteropts, "sizelimit=");
+
// mount always creates AUTOCLEARed loopdevs, so that umounting
// drops them without any code in the userspace.
// This happens since circa linux-2.6.25:
@@ -2040,7 +2100,8 @@ static int singlemount(struct mntent *mp, int ignore_busy)
// Subject: Allow auto-destruction of loop devices
loopfd = set_loop(&mp->mnt_fsname,
loopFile,
- 0,
+ offset,
+ sizelimit,
((vfsflags & MS_RDONLY) ? BB_LO_FLAGS_READ_ONLY : 0)
| BB_LO_FLAGS_AUTOCLEAR
);
diff --git a/util-linux/setpriv.c b/util-linux/setpriv.c
index 37e8821a1..1e4b201ed 100644
--- a/util-linux/setpriv.c
+++ b/util-linux/setpriv.c
@@ -144,10 +144,11 @@ static unsigned parse_cap(const char *cap)
static void set_inh_caps(char *capstring)
{
struct caps caps;
+ char *string;
getcaps(&caps);
- capstring = strtok(capstring, ",");
+ capstring = strtok_r(capstring, ",", &string);
while (capstring) {
unsigned cap;
@@ -159,7 +160,7 @@ static void set_inh_caps(char *capstring)
caps.data[CAP_TO_INDEX(cap)].inheritable |= CAP_TO_MASK(cap);
else
caps.data[CAP_TO_INDEX(cap)].inheritable &= ~CAP_TO_MASK(cap);
- capstring = strtok(NULL, ",");
+ capstring = strtok_r(NULL, ",", &string);
}
if (capset(&caps.header, caps.data) != 0)
@@ -170,7 +171,7 @@ static void set_ambient_caps(char *string)
{
char *cap;
- cap = strtok(string, ",");
+ cap = strtok_r(string, ",", &string);
while (cap) {
unsigned idx;
@@ -182,7 +183,7 @@ static void set_ambient_caps(char *string)
if (prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_LOWER, idx, 0, 0) < 0)
bb_simple_perror_msg("cap_ambient_lower");
}
- cap = strtok(NULL, ",");
+ cap = strtok_r(NULL, ",", &string);
}
}
#endif /* FEATURE_SETPRIV_CAPABILITIES */
diff --git a/util-linux/switch_root.c b/util-linux/switch_root.c
index c65096c27..f2674b5ac 100644
--- a/util-linux/switch_root.c
+++ b/util-linux/switch_root.c
@@ -164,7 +164,7 @@ static void drop_capabilities(char *string)
{
char *cap;
- cap = strtok(string, ",");
+ cap = strtok_r(string, ",", &string);
while (cap) {
unsigned cap_idx;
@@ -174,7 +174,7 @@ static void drop_capabilities(char *string)
drop_bounding_set(cap_idx);
drop_capset(cap_idx);
bb_error_msg("dropped capability: %s", cap);
- cap = strtok(NULL, ",");
+ cap = strtok_r(NULL, ",", &string);
}
}
#endif
diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c
index 34f5d119f..00cfb2826 100644
--- a/util-linux/volume_id/get_devname.c
+++ b/util-linux/volume_id/get_devname.c
@@ -102,10 +102,9 @@ uuidcache_addentry(char *device, /*int major, int minor,*/ char *label, char *uu
* add a cache entry for this device.
* If device node does not exist, it will be temporarily created. */
static int FAST_FUNC
-uuidcache_check_device(const char *device,
- struct stat *statbuf,
- void *userData UNUSED_PARAM,
- int depth UNUSED_PARAM)
+uuidcache_check_device(struct recursive_state *state UNUSED_PARAM,
+ const char *device,
+ struct stat *statbuf)
{
/* note: this check rejects links to devices, among other nodes */
if (!S_ISBLK(statbuf->st_mode)
@@ -145,12 +144,13 @@ uuidcache_init(int scan_devices)
* This is unacceptably complex. Let's just scan /dev.
* (Maybe add scanning of /sys/block/XXX/dev for devices
* somehow not having their /dev/XXX entries created?) */
- if (scan_devices)
+ if (scan_devices) {
recursive_action("/dev", ACTION_RECURSE,
uuidcache_check_device, /* file_action */
NULL, /* dir_action */
- NULL, /* userData */
- 0 /* depth */);
+ NULL /* userData */
+ );
+ }
return uuidCache;
}