From 379e8e81afed0613271e39e33190c6dfec78b695 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 26 Mar 2015 10:49:02 +0100 Subject: typo fix Signed-off-by: Denys Vlasenko --- e2fsprogs/old_e2fsprogs/e2fsck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2fsprogs/old_e2fsprogs/e2fsck.c b/e2fsprogs/old_e2fsprogs/e2fsck.c index 8400a92ce..0799b64ad 100644 --- a/e2fsprogs/old_e2fsprogs/e2fsck.c +++ b/e2fsprogs/old_e2fsprogs/e2fsck.c @@ -11462,7 +11462,7 @@ static int release_inode_blocks(e2fsck_t ctx, ext2_ino_t ino, count = 1; } if (retval) { - bb_error_msg(_("while calling ext2fs_adjust_ea_refocunt for inode %d"), + bb_error_msg(_("while calling ext2fs_adjust_ea_refcount for inode %d"), ino); return 1; } -- cgit v1.2.3-55-g6feb From 9472e8a86fa1837bccec9e25dd18fd3c88c5e209 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 31 Mar 2015 21:46:26 +0200 Subject: ftpd: change_identity() must be after chroot() Otherwise chroot() doesn't work for non-root Signed-off-by: Denys Vlasenko --- networking/ftpd.c | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/networking/ftpd.c b/networking/ftpd.c index 0c10e1f25..2351d6dd3 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c @@ -1116,6 +1116,9 @@ int ftpd_main(int argc, char **argv) int ftpd_main(int argc UNUSED_PARAM, char **argv) #endif { +#if ENABLE_FEATURE_FTP_AUTHENTICATION + struct passwd *pw = NULL; +#endif unsigned abs_timeout; unsigned verbose_S; smallint opts; @@ -1193,29 +1196,23 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) signal(SIGALRM, timeout_handler); #if ENABLE_FEATURE_FTP_AUTHENTICATION - { - struct passwd *pw = NULL; - - while (1) { - uint32_t cmdval = cmdio_get_cmd_and_arg(); - + while (1) { + uint32_t cmdval = cmdio_get_cmd_and_arg(); if (cmdval == const_USER) { - pw = getpwnam(G.ftp_arg); - cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify password\r\n"); - } else if (cmdval == const_PASS) { - if (check_password(pw, G.ftp_arg) > 0) { - break; /* login success */ - } - cmdio_write_raw(STR(FTP_LOGINERR)" Login failed\r\n"); - pw = NULL; - } else if (cmdval == const_QUIT) { - WRITE_OK(FTP_GOODBYE); - return 0; - } else { - cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n"); + pw = getpwnam(G.ftp_arg); + cmdio_write_raw(STR(FTP_GIVEPWORD)" Please specify password\r\n"); + } else if (cmdval == const_PASS) { + if (check_password(pw, G.ftp_arg) > 0) { + break; /* login success */ } + cmdio_write_raw(STR(FTP_LOGINERR)" Login failed\r\n"); + pw = NULL; + } else if (cmdval == const_QUIT) { + WRITE_OK(FTP_GOODBYE); + return 0; + } else { + cmdio_write_raw(STR(FTP_LOGINERR)" Login with USER and PASS\r\n"); } - change_identity(pw); } WRITE_OK(FTP_LOGINOK); #endif @@ -1233,6 +1230,10 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) xchroot(argv[0]); } +#if ENABLE_FEATURE_FTP_AUTHENTICATION + change_identity(pw); +#endif + /* RFC-959 Section 5.1 * The following commands and options MUST be supported by every * server-FTP and user-FTP, except in cases where the underlying -- cgit v1.2.3-55-g6feb From 1186894f773e13ab9ca2b3e05a194e9b88796fbe Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 31 Mar 2015 22:00:55 +0200 Subject: update example ntp.script Handle an interesting corner case when NTP server is reachable... but on a different IP now. Signed-off-by: Denys Vlasenko --- examples/var_service/ntpd/ntp.script | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/examples/var_service/ntpd/ntp.script b/examples/var_service/ntpd/ntp.script index 76c34bf74..8542181eb 100755 --- a/examples/var_service/ntpd/ntp.script +++ b/examples/var_service/ntpd/ntp.script @@ -10,12 +10,30 @@ dt=`date '+%Y-%m-%d %H:%M:%S'` +echo "`tail -n 199 -- "$0.log" 2>/dev/null`" >"$0.log.$$" + +if test x"$1" = x"unsync" \ +; then + # No replies for our NTP requests were seen for some time. + # + # Among more mundate cases like network outages, this happens + # if we ran for a LONG time (days) and ntp server's IP has changed. + # ntpd has no code to re-resolve peers' addresses to IPs, + # we need to help it: + # + echo "$dt: $1"\ + "syncronization lost, restarting ntpd"\ + >>"$0.log.$$" + mv -- "$0.log.$$" "$0.log" + kill $PPID + exit +fi + if test x"$stratum" != x"" \ && test x"$poll_interval" != x"" \ && test 4 -ge "$stratum" \ && test 128 -le "$poll_interval" \ ; then - echo "`tail -n 199 -- "$0.log" 2>/dev/null`" >"$0.log.$$" echo "$dt: $1"\ "freq_drift_ppm=$freq_drift_ppm"\ "offset=$offset"\ @@ -27,7 +45,6 @@ if test x"$stratum" != x"" \ exec hwclock --systohc fi -echo "`tail -n 199 -- "$0.log" 2>/dev/null`" >"$0.log.$$" echo "$dt: $1"\ "freq_drift_ppm=$freq_drift_ppm"\ "offset=$offset"\ -- cgit v1.2.3-55-g6feb From 86a7f18f211af1abda5c855d2674b0fcb53de524 Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Thu, 2 Apr 2015 23:03:46 +0200 Subject: *: Switch to POSIX utmpx API UTMP is SVID legacy, UTMPX is mandated by POSIX. Glibc and uClibc have identical layout of UTMP and UTMPX, both of these libc treat _PATH_UTMPX as _PATH_UTMP so from a user-perspective nothing changes except the names of the API entrypoints. Signed-off-by: Bernhard Reutner-Fischer --- coreutils/who.c | 8 ++++---- include/libbb.h | 2 +- init/halt.c | 4 ++-- libbb/utmp.c | 44 ++++++++++++++++++++++---------------------- miscutils/last.c | 8 ++++---- miscutils/last_fancy.c | 16 ++++++++++------ miscutils/runlevel.c | 12 ++++++------ miscutils/wall.c | 8 ++++---- procps/uptime.c | 6 +++--- 9 files changed, 56 insertions(+), 52 deletions(-) diff --git a/coreutils/who.c b/coreutils/who.c index f955ce6d3..8337212c9 100644 --- a/coreutils/who.c +++ b/coreutils/who.c @@ -73,7 +73,7 @@ static void idle_string(char *str6, time_t t) int who_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int who_main(int argc UNUSED_PARAM, char **argv) { - struct utmp *ut; + struct utmpx *ut; unsigned opt; int do_users = (ENABLE_USERS && (!ENABLE_WHO || applet_name[0] == 'u')); const char *fmt = "%s"; @@ -83,8 +83,8 @@ int who_main(int argc UNUSED_PARAM, char **argv) if (opt & 2) // -H printf("USER\t\tTTY\t\tIDLE\tTIME\t\t HOST\n"); - setutent(); - while ((ut = getutent()) != NULL) { + setutxent(); + while ((ut = getutxent()) != NULL) { if (ut->ut_user[0] && ((opt & 1) || ut->ut_type == USER_PROCESS) ) { @@ -126,6 +126,6 @@ int who_main(int argc UNUSED_PARAM, char **argv) if (do_users) bb_putchar('\n'); if (ENABLE_FEATURE_CLEAN_UP) - endutent(); + endutxent(); return EXIT_SUCCESS; } diff --git a/include/libbb.h b/include/libbb.h index 26b686805..0f8363b78 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -84,7 +84,7 @@ # include #endif #if ENABLE_FEATURE_UTMP -# include +# include #endif #if ENABLE_LOCALE_SUPPORT # include diff --git a/init/halt.c b/init/halt.c index 7974adb17..ad12d9148 100644 --- a/init/halt.c +++ b/init/halt.c @@ -74,7 +74,7 @@ static void write_wtmp(void) { - struct utmp utmp; + struct utmpx utmp; struct utsname uts; /* "man utmp" says wtmp file should *not* be created automagically */ /*if (access(bb_path_wtmp_file, R_OK|W_OK) == -1) { @@ -88,7 +88,7 @@ static void write_wtmp(void) utmp.ut_line[0] = '~'; utmp.ut_line[1] = '~'; /* = strcpy(utmp.ut_line, "~~"); */ uname(&uts); safe_strncpy(utmp.ut_host, uts.release, sizeof(utmp.ut_host)); - updwtmp(bb_path_wtmp_file, &utmp); + updwtmpx(bb_path_wtmp_file, &utmp); } #else #define write_wtmp() ((void)0) diff --git a/libbb/utmp.c b/libbb/utmp.c index 8ad9ba27e..bd07670db 100644 --- a/libbb/utmp.c +++ b/libbb/utmp.c @@ -16,7 +16,7 @@ static void touch(const char *filename) void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname) { - struct utmp utent; + struct utmpx utent; char *id; unsigned width; @@ -45,17 +45,17 @@ void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, con tty_name += 3; strncpy(id, tty_name, width); - touch(_PATH_UTMP); - //utmpname(_PATH_UTMP); - setutent(); + touch(_PATH_UTMPX); + //utmpxname(_PATH_UTMPX); + setutxent(); /* Append new one (hopefully, unless we collide on ut_id) */ - pututline(&utent); - endutent(); + pututxline(&utent); + endutxent(); #if ENABLE_FEATURE_WTMP /* "man utmp" says wtmp file should *not* be created automagically */ /*touch(bb_path_wtmp_file);*/ - updwtmp(bb_path_wtmp_file, &utent); + updwtmpx(bb_path_wtmp_file, &utent); #endif } @@ -64,17 +64,17 @@ void FAST_FUNC write_new_utmp(pid_t pid, int new_type, const char *tty_name, con */ void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const char *username, const char *hostname) { - struct utmp utent; - struct utmp *utp; + struct utmpx utent; + struct utmpx *utp; - touch(_PATH_UTMP); - //utmpname(_PATH_UTMP); - setutent(); + touch(_PATH_UTMPX); + //utmpxname(_PATH_UTMPX); + setutxent(); /* Did init/getty/telnetd/sshd/... create an entry for us? * It should be (new_type-1), but we'd also reuse * any other potentially stale xxx_PROCESS entry */ - while ((utp = getutent()) != NULL) { + while ((utp = getutxent()) != NULL) { if (utp->ut_pid == pid // && ut->ut_line[0] && utp->ut_id[0] /* must have nonzero id */ @@ -88,25 +88,25 @@ void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const /* Stale record. Nuke hostname */ memset(utp->ut_host, 0, sizeof(utp->ut_host)); } - /* NB: pututline (see later) searches for matching utent - * using getutid(utent) - we must not change ut_id + /* NB: pututxline (see later) searches for matching utxent + * using getutxid(utent) - we must not change ut_id * if we want *exactly this* record to be overwritten! */ break; } } - //endutent(); - no need, pututline can deal with (and actually likes) + //endutxent(); - no need, pututxline can deal with (and actually likes) //the situation when utmp file is positioned on found record if (!utp) { if (new_type != DEAD_PROCESS) write_new_utmp(pid, new_type, tty_name, username, hostname); else - endutent(); + endutxent(); return; } - /* Make a copy. We can't use *utp, pututline's internal getutid + /* Make a copy. We can't use *utp, pututxline's internal getutxid * will overwrite it before it is used! */ utent = *utp; @@ -120,14 +120,14 @@ void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const utent.ut_tv.tv_sec = time(NULL); /* Update, or append new one */ - //setutent(); - pututline(&utent); - endutent(); + //setutxent(); + pututxline(&utent); + endutxent(); #if ENABLE_FEATURE_WTMP /* "man utmp" says wtmp file should *not* be created automagically */ /*touch(bb_path_wtmp_file);*/ - updwtmp(bb_path_wtmp_file, &utent); + updwtmpx(bb_path_wtmp_file, &utent); #endif } diff --git a/miscutils/last.c b/miscutils/last.c index a144c7e47..6d8b58463 100644 --- a/miscutils/last.c +++ b/miscutils/last.c @@ -32,21 +32,21 @@ #if defined UT_LINESIZE \ && ((UT_LINESIZE != 32) || (UT_NAMESIZE != 32) || (UT_HOSTSIZE != 256)) -#error struct utmp member char[] size(s) have changed! +#error struct utmpx member char[] size(s) have changed! #elif defined __UT_LINESIZE \ && ((__UT_LINESIZE != 32) || (__UT_NAMESIZE != 64) || (__UT_HOSTSIZE != 256)) -#error struct utmp member char[] size(s) have changed! +#error struct utmpx member char[] size(s) have changed! #endif #if EMPTY != 0 || RUN_LVL != 1 || BOOT_TIME != 2 || NEW_TIME != 3 || \ OLD_TIME != 4 -#error Values for the ut_type field of struct utmp changed +#error Values for the ut_type field of struct utmpx changed #endif int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int last_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { - struct utmp ut; + struct utmpx ut; int n, file = STDIN_FILENO; time_t t_tmp; off_t pos; diff --git a/miscutils/last_fancy.c b/miscutils/last_fancy.c index 16ed9e920..8194e31b5 100644 --- a/miscutils/last_fancy.c +++ b/miscutils/last_fancy.c @@ -22,6 +22,10 @@ #define HEADER_LINE_WIDE "USER", "TTY", \ INET6_ADDRSTRLEN, INET6_ADDRSTRLEN, "HOST", "LOGIN", " TIME", "" +#if !defined __UT_LINESIZE && defined UT_LINESIZE +# define __UT_LINESIZE UT_LINESIZE +#endif + enum { NORMAL, LOGGED, @@ -39,7 +43,7 @@ enum { #define show_wide (option_mask32 & LAST_OPT_W) -static void show_entry(struct utmp *ut, int state, time_t dur_secs) +static void show_entry(struct utmpx *ut, int state, time_t dur_secs) { unsigned days, hours, mins; char duration[sizeof("(%u+02:02)") + sizeof(int)*3]; @@ -104,7 +108,7 @@ static void show_entry(struct utmp *ut, int state, time_t dur_secs) duration_str); } -static int get_ut_type(struct utmp *ut) +static int get_ut_type(struct utmpx *ut) { if (ut->ut_line[0] == '~') { if (strcmp(ut->ut_user, "shutdown") == 0) { @@ -142,7 +146,7 @@ static int get_ut_type(struct utmp *ut) return ut->ut_type; } -static int is_runlevel_shutdown(struct utmp *ut) +static int is_runlevel_shutdown(struct utmpx *ut) { if (((ut->ut_pid & 255) == '0') || ((ut->ut_pid & 255) == '6')) { return 1; @@ -154,7 +158,7 @@ static int is_runlevel_shutdown(struct utmp *ut) int last_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int last_main(int argc UNUSED_PARAM, char **argv) { - struct utmp ut; + struct utmpx ut; const char *filename = _PATH_WTMP; llist_t *zlist; off_t pos; @@ -242,9 +246,9 @@ int last_main(int argc UNUSED_PARAM, char **argv) { llist_t *el, *next; for (el = zlist; el; el = next) { - struct utmp *up = (struct utmp *)el->data; + struct utmpx *up = (struct utmpx *)el->data; next = el->link; - if (strncmp(up->ut_line, ut.ut_line, UT_LINESIZE) == 0) { + if (strncmp(up->ut_line, ut.ut_line, __UT_LINESIZE) == 0) { if (show) { show_entry(&ut, NORMAL, up->ut_tv.tv_sec); show = 0; diff --git a/miscutils/runlevel.c b/miscutils/runlevel.c index 76231df22..8558db862 100644 --- a/miscutils/runlevel.c +++ b/miscutils/runlevel.c @@ -29,19 +29,19 @@ int runlevel_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int runlevel_main(int argc UNUSED_PARAM, char **argv) { - struct utmp *ut; + struct utmpx *ut; char prev; - if (argv[1]) utmpname(argv[1]); + if (argv[1]) utmpxname(argv[1]); - setutent(); - while ((ut = getutent()) != NULL) { + setutxent(); + while ((ut = getutxent()) != NULL) { if (ut->ut_type == RUN_LVL) { prev = ut->ut_pid / 256; if (prev == 0) prev = 'N'; printf("%c %c\n", prev, ut->ut_pid % 256); if (ENABLE_FEATURE_CLEAN_UP) - endutent(); + endutxent(); return 0; } } @@ -49,6 +49,6 @@ int runlevel_main(int argc UNUSED_PARAM, char **argv) puts("unknown"); if (ENABLE_FEATURE_CLEAN_UP) - endutent(); + endutxent(); return 1; } diff --git a/miscutils/wall.c b/miscutils/wall.c index bb709ee39..50658f457 100644 --- a/miscutils/wall.c +++ b/miscutils/wall.c @@ -32,7 +32,7 @@ int wall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int wall_main(int argc UNUSED_PARAM, char **argv) { - struct utmp *ut; + struct utmpx *ut; char *msg; int fd; @@ -46,8 +46,8 @@ int wall_main(int argc UNUSED_PARAM, char **argv) msg = xmalloc_read(fd, NULL); if (ENABLE_FEATURE_CLEAN_UP && argv[1]) close(fd); - setutent(); - while ((ut = getutent()) != NULL) { + setutxent(); + while ((ut = getutxent()) != NULL) { char *line; if (ut->ut_type != USER_PROCESS) continue; @@ -56,7 +56,7 @@ int wall_main(int argc UNUSED_PARAM, char **argv) free(line); } if (ENABLE_FEATURE_CLEAN_UP) { - endutent(); + endutxent(); free(msg); } return EXIT_SUCCESS; diff --git a/procps/uptime.c b/procps/uptime.c index 778812a6f..149bae6e5 100644 --- a/procps/uptime.c +++ b/procps/uptime.c @@ -81,10 +81,10 @@ int uptime_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) #if ENABLE_FEATURE_UPTIME_UTMP_SUPPORT { - struct utmp *ut; + struct utmpx *ut; unsigned users = 0; - while ((ut = getutent()) != NULL) { - if ((ut->ut_type == USER_PROCESS) && (ut->ut_name[0] != '\0')) + while ((ut = getutxent()) != NULL) { + if ((ut->ut_type == USER_PROCESS) && (ut->ut_user[0] != '\0')) users++; } printf(", %u users", users); -- cgit v1.2.3-55-g6feb From 7b729edd33aea5361e0740df800a1a0a1ff70f7f Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Thu, 2 Apr 2015 00:55:17 +0300 Subject: update copyright years Copyright years seem to be out of date, e.g. coreutils/truncate.c has Copyright (C) 2015. Signed-off-by: Aaro Koskinen Signed-off-by: Bernhard Reutner-Fischer --- libbb/appletlib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 8fd8fd525..e0b843d30 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -631,7 +631,7 @@ static int busybox_main(char **argv) full_write2_str(bb_banner); /* reuse const string */ full_write2_str(" multi-call binary.\n"); /* reuse */ full_write2_str( - "BusyBox is copyrighted by many authors between 1998-2012.\n" + "BusyBox is copyrighted by many authors between 1998-2015.\n" "Licensed under GPLv2. See source distribution for detailed\n" "copyright notices.\n" "\n" -- cgit v1.2.3-55-g6feb From e0ddb65cb234db6482d80febee1a63778f818db6 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 14 Apr 2015 14:15:15 +0200 Subject: build system: make CONFIG_EXTRA_LDFLAGS go to LDFLAGS, not EXTRA_LDFLAGS Signed-off-by: Denys Vlasenko --- Makefile.flags | 2 +- examples/android-build | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Makefile.flags b/Makefile.flags index 307afa7f5..a1ed1480a 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -163,7 +163,7 @@ SKIP_STRIP = y endif ifneq ($(CONFIG_EXTRA_LDFLAGS),) -EXTRA_LDFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_LDFLAGS))) +LDFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_LDFLAGS))) #")) endif diff --git a/examples/android-build b/examples/android-build index 89f3b637a..123ba966e 100755 --- a/examples/android-build +++ b/examples/android-build @@ -29,4 +29,6 @@ else LDLIBS="dl m c gcc" fi +# It's possible with newer version +# you need to use CFLAGS_busybox instead of EXTRA_LDFLAGS below: make EXTRA_LDFLAGS="$LDFLAGS" LDLIBS="$LDLIBS" "$@" -- cgit v1.2.3-55-g6feb From a90490fb69f78148beacf371b603c16276137879 Mon Sep 17 00:00:00 2001 From: Alfonso Ranieri Date: Tue, 14 Apr 2015 14:32:39 +0200 Subject: volume_id: fix a buglet introduced by is_prefixed_with() conversion Signed-off-by: Alfonso Ranieri Signed-off-by: Denys Vlasenko --- util-linux/volume_id/get_devname.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util-linux/volume_id/get_devname.c b/util-linux/volume_id/get_devname.c index 53bdbdf09..6b97df113 100644 --- a/util-linux/volume_id/get_devname.c +++ b/util-linux/volume_id/get_devname.c @@ -304,7 +304,7 @@ int resolve_mount_spec(char **fsname) if (is_prefixed_with(*fsname, "UUID=")) tmp = get_devname_from_uuid(*fsname + 5); - else if (is_prefixed_with(*fsname, "LABEL=") == 0) + else if (is_prefixed_with(*fsname, "LABEL=")) tmp = get_devname_from_label(*fsname + 6); if (tmp == *fsname) -- cgit v1.2.3-55-g6feb From f7466e477691fd29f47ebe8ae27489e065c69e5e Mon Sep 17 00:00:00 2001 From: Felix Fietkau Date: Thu, 9 Apr 2015 10:20:16 +0200 Subject: find: fix regression in status processing for path arguments Regression added in commit 14158b4127dba30466c50147b868a6a89702960b "find: add optional support for '-exec ... {} +'" This commit causes find to exit on the first path argument that was not found, which breaks existing scripts and is incompatible to other implementations. Instead of exiting on the first failure, return EXIT_FAILURE at the end if any error occurred. Signed-off-by: Felix Fietkau Signed-off-by: Denys Vlasenko --- findutils/find.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/findutils/find.c b/findutils/find.c index 83aa63f92..ced8922e7 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -1460,12 +1460,10 @@ int find_main(int argc UNUSED_PARAM, char **argv) NULL, /* user data */ 0) /* depth */ ) { - status = EXIT_FAILURE; - goto out; + status |= EXIT_FAILURE; } } - IF_FEATURE_FIND_EXEC_PLUS(status = flush_exec_plus();) -out: + IF_FEATURE_FIND_EXEC_PLUS(status |= flush_exec_plus();) return status; } -- cgit v1.2.3-55-g6feb From 71a5b67ba0339265153217df646827a1213e03f5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Thu, 16 Apr 2015 12:44:02 +0200 Subject: uevent: new applet This applet listens on netlink socket with kernel's uevent messages. Run-tested. function old new delta uevent_main - 416 +416 packed_usage 30671 30713 +42 applet_names 2531 2538 +7 applet_main 1468 1472 +4 RCVBUF - 4 +4 applet_nameofs 734 736 +2 ------------------------------------------------------------------------------ (add/remove: 3/0 grow/shrink: 4/0 up/down: 475/0) Total: 475 bytes Signed-off-by: Denys Vlasenko --- util-linux/uevent.c | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 util-linux/uevent.c diff --git a/util-linux/uevent.c b/util-linux/uevent.c new file mode 100644 index 000000000..fb98b4845 --- /dev/null +++ b/util-linux/uevent.c @@ -0,0 +1,127 @@ +/* + * Copyright 2015 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config UEVENT +//config: bool "uevent" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: uevent is a netlink listener for kernel uevent notifications +//config: sent via netlink. It is usually used for dynamic device creation. + +//applet:IF_UEVENT(APPLET(uevent, BB_DIR_SBIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_UEVENT) += uevent.o + +//usage:#define uevent_trivial_usage +//usage: "[PROG [ARGS]]" +//usage:#define uevent_full_usage "\n\n" +//usage: "uevent runs PROG for every netlink notification." +//usage: "\n""PROG's environment contains data passed from the kernel." +//usage: "\n""Typical usage (daemon for dynamic device node creation):" +//usage: "\n"" # uevent mdev & mdev -s" + +#include "libbb.h" +#include + +#define BUFFER_SIZE 16*1024 + +#define env ((char **)&bb_common_bufsiz1) +enum { + MAX_ENV = COMMON_BUFSIZE / sizeof(env[0]) - 1, +}; + +#ifndef SO_RCVBUFFORCE +#define SO_RCVBUFFORCE 33 +#endif +static const int RCVBUF = 2 * 1024 * 1024; + +int uevent_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int uevent_main(int argc UNUSED_PARAM, char **argv) +{ + struct sockaddr_nl sa; + int fd; + + argv++; + + // Subscribe for UEVENT kernel messages + sa.nl_family = AF_NETLINK; + sa.nl_pad = 0; + sa.nl_pid = getpid(); + sa.nl_groups = 1 << 0; + fd = xsocket(AF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT); + xbind(fd, (struct sockaddr *) &sa, sizeof(sa)); + close_on_exec_on(fd); + + // Without a sufficiently big RCVBUF, a ton of simultaneous events + // can trigger ENOBUFS on read, which is unrecoverable. + // Reproducer: + // uevent mdev & + // find /sys -name uevent -exec sh -c 'echo add >"{}"' ';' + // + // SO_RCVBUFFORCE (root only) can go above net.core.rmem_max sysctl + setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &RCVBUF, sizeof(RCVBUF)); + setsockopt(fd, SOL_SOCKET, SO_RCVBUFFORCE, &RCVBUF, sizeof(RCVBUF)); + if (0) { + int z; + socklen_t zl = sizeof(z); + getsockopt(fd, SOL_SOCKET, SO_RCVBUF, &z, &zl); + bb_error_msg("SO_RCVBUF:%d", z); + } + + for (;;) { + char *netbuf; + char *s, *end; + ssize_t len; + int idx; + + // In many cases, a system sits for *days* waiting + // for a new uevent notification to come in. + // We use a fresh mmap so that buffer is not allocated + // until kernel actually starts filling it. + netbuf = mmap(NULL, BUFFER_SIZE, + PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, + /* ignored: */ -1, 0); + if (netbuf == MAP_FAILED) + bb_perror_msg_and_die("mmap"); + + // Here we block, possibly for a very long time + len = safe_read(fd, netbuf, BUFFER_SIZE - 1); + if (len < 0) + bb_perror_msg_and_die("read"); + end = netbuf + len; + *end = '\0'; + + // Each netlink message starts with "ACTION@/path" + // (which we currently ignore), + // followed by environment variables. + if (!argv[0]) + putchar('\n'); + idx = 0; + s = netbuf; + while (s < end) { + if (!argv[0]) + puts(s); + if (strchr(s, '=') && idx < MAX_ENV) + env[idx++] = s; + s += strlen(s) + 1; + } + env[idx] = NULL; + + idx = 0; + while (env[idx]) + putenv(env[idx++]); + if (argv[0]) + spawn_and_wait(argv); + idx = 0; + while (env[idx]) + bb_unsetenv(env[idx++]); + munmap(netbuf, BUFFER_SIZE); + } + + return 0; // not reached +} -- cgit v1.2.3-55-g6feb From 63f4d32c9859c1ed341debefddad4b9c0ae944cc Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 17 Apr 2015 14:24:55 +0200 Subject: sed: implement ",+N" range end function old new delta add_cmd 1115 1173 +58 process_files 2226 2253 +27 sed_main 696 702 +6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 91/0) Total: 91 bytes Signed-off-by: Denys Vlasenko --- editors/sed.c | 41 ++++++++++++++++++++++++++++++++++++----- testsuite/sed.tests | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/editors/sed.c b/editors/sed.c index 2c64ad500..7bbf820d8 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -53,6 +53,7 @@ * Reference * http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html + * http://sed.sourceforge.net/sedfaq3.html */ //config:config SED @@ -109,7 +110,8 @@ typedef struct sed_cmd_s { regex_t *sub_match; /* For 's/sub_match/string/' */ int beg_line; /* 'sed 1p' 0 == apply commands to all lines */ int beg_line_orig; /* copy of the above, needed for -i */ - int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */ + int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($). -2-N = +N */ + int end_line_orig; FILE *sw_file; /* File (sw) command writes to, -1 for none. */ char *string; /* Data string for (saicytb) commands. */ @@ -640,10 +642,29 @@ static void add_cmd(const char *cmdstr) int idx; cmdstr++; - idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match); - if (!idx) + if (*cmdstr == '+' && isdigit(cmdstr[1])) { + /* http://sed.sourceforge.net/sedfaq3.html#s3.3 + * Under GNU sed 3.02+, ssed, and sed15+, + * may also be a notation of the form +num, + * indicating the next num lines after is + * matched. + * GNU sed 4.2.1 accepts even "+" (meaning "+0"). + * We don't (we check for isdigit, see above), think + * about the "+-3" case. + */ + char *end; + /* code is smaller compared to using &cmdstr here: */ + idx = strtol(cmdstr+1, &end, 10); + sed_cmd->end_line = -2 - idx; + cmdstr = end; + } else { + idx = get_address(cmdstr, &sed_cmd->end_line, &sed_cmd->end_match); + cmdstr += idx; + idx--; /* if 0, trigger error check below */ + } + if (idx < 0) bb_error_msg_and_die("no address after comma"); - cmdstr += idx; + sed_cmd->end_line_orig = sed_cmd->end_line; } /* skip whitespace before the command */ @@ -1089,10 +1110,19 @@ static void process_files(void) /* Is this line the end of the current match? */ if (matched) { + if (sed_cmd->end_line <= -2) { + /* address2 is +N, i.e. N lines from beg_line */ + sed_cmd->end_line = linenum + (-sed_cmd->end_line - 2); + } /* once matched, "n,xxx" range is dead, disabling it */ if (sed_cmd->beg_line > 0) { sed_cmd->beg_line = -2; } + dbg("end1:%d", sed_cmd->end_line ? sed_cmd->end_line == -1 + ? !next_line : (sed_cmd->end_line <= linenum) + : !sed_cmd->end_match); + dbg("end2:%d", sed_cmd->end_match && old_matched + && !regexec(sed_cmd->end_match,pattern_space, 0, NULL, 0)); sed_cmd->in_match = !( /* has the ending line come, or is this a single address command? */ (sed_cmd->end_line @@ -1551,9 +1581,10 @@ int sed_main(int argc UNUSED_PARAM, char **argv) free(G.outname); G.outname = NULL; - /* Re-enable disabled range matches */ + /* Fix disabled range matches and mangled ",+N" ranges */ for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { sed_cmd->beg_line = sed_cmd->beg_line_orig; + sed_cmd->end_line = sed_cmd->end_line_orig; } } /* Here, to handle "sed 'cmds' nonexistent_file" case we did: diff --git a/testsuite/sed.tests b/testsuite/sed.tests index 19f2915ce..34479e55f 100755 --- a/testsuite/sed.tests +++ b/testsuite/sed.tests @@ -333,6 +333,38 @@ testing "sed s///NUM test" \ "sed -e 's/a/b/2; s/a/c/g'" \ "cb\n" "" "aa\n" +testing "sed /regex/,N{...} addresses work" \ + "sed /^2/,2{d}" \ + "1\n3\n4\n5\n" \ + "" \ + "1\n2\n3\n4\n5\n" + +testing "sed /regex/,+N{...} addresses work" \ + "sed /^2/,+2{d}" \ + "1\n5\n" \ + "" \ + "1\n2\n3\n4\n5\n" + +testing "sed /regex/,+N{...} -i works" \ + "cat - >input2; sed /^4/,+2{d} -i input input2; echo \$?; cat input input2; rm input2" \ + "0\n""1\n2\n3\n7\n8\n""1\n2\n7\n8\n" \ + "1\n2\n3\n4\n5\n6\n7\n8\n" \ + "1\n2\n4\n5\n6\n7\n8\n" \ + +# GNU sed 4.2.1 would also accept "/^4/,+{d}" with the same meaning, we don't +testing "sed /regex/,+0{...} -i works" \ + "cat - >input2; sed /^4/,+0{d} -i input input2; echo \$?; cat input input2; rm input2" \ + "0\n""1\n2\n3\n5\n6\n7\n8\n""1\n2\n5\n6\n7\n8\n" \ + "1\n2\n3\n4\n5\n6\n7\n8\n" \ + "1\n2\n4\n5\n6\n7\n8\n" \ + +# GNU sed 4.2.1 would also accept "/^4/,+d" with the same meaning, we don't +testing "sed /regex/,+0 -i works" \ + "cat - >input2; sed /^4/,+0d -i input input2; echo \$?; cat input input2; rm input2" \ + "0\n""1\n2\n3\n5\n6\n7\n8\n""1\n2\n5\n6\n7\n8\n" \ + "1\n2\n3\n4\n5\n6\n7\n8\n" \ + "1\n2\n4\n5\n6\n7\n8\n" \ + # testing "description" "commands" "result" "infile" "stdin" exit $FAILCOUNT -- cgit v1.2.3-55-g6feb From 0a0acb55db8d7c4dec445573f1b0528d126b9e1f Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 18 Apr 2015 19:36:38 +0200 Subject: ash: fix handling of duplicate "local" Signed-off-by: Denys Vlasenko --- shell/ash.c | 51 +++++++++++++++++++++---------- shell/ash_test/ash-heredoc/heredoc1.right | 2 +- shell/ash_test/ash-vars/var3.right | 5 +++ shell/ash_test/ash-vars/var3.tests | 1 + 4 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 shell/ash_test/ash-vars/var3.right create mode 100755 shell/ash_test/ash-vars/var3.tests diff --git a/shell/ash.c b/shell/ash.c index b568013b4..697a64fea 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -2030,7 +2030,7 @@ varcmp(const char *p, const char *q) int c, d; while ((c = *p) == (d = *q)) { - if (!c || c == '=') + if (c == '\0' || c == '=') goto out; p++; q++; @@ -2247,7 +2247,7 @@ setvar(const char *name, const char *val, int flags) } static void FAST_FUNC -setvar2(const char *name, const char *val) +setvar0(const char *name, const char *val) { setvar(name, val, 0); } @@ -2310,7 +2310,7 @@ unsetvar(const char *s) free(vp); INT_ON; } else { - setvar2(s, 0); + setvar0(s, NULL); vp->flags &= ~VEXPORT; } ok: @@ -5505,7 +5505,7 @@ ash_arith(const char *s) arith_t result; math_state.lookupvar = lookupvar; - math_state.setvar = setvar2; + math_state.setvar = setvar0; //math_state.endofname = endofname; INT_OFF; @@ -6360,7 +6360,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, switch (subtype) { case VSASSIGN: - setvar2(varname, startp); + setvar0(varname, startp); amount = startp - expdest; STADJUST(amount, expdest); return startp; @@ -8591,7 +8591,7 @@ evalfor(union node *n, int flags) loopnest++; flags &= EV_TESTED; for (sp = arglist.list; sp; sp = sp->next) { - setvar2(n->nfor.var, sp->text); + setvar0(n->nfor.var, sp->text); evaltree(n->nfor.body, flags); if (evalskip) { if (evalskip == SKIPCONT && --skipcount <= 0) { @@ -8970,21 +8970,37 @@ mklocal(char *name) struct localvar *lvp; struct var **vpp; struct var *vp; + char *eq = strchr(name, '='); INT_OFF; - lvp = ckzalloc(sizeof(struct localvar)); + /* Cater for duplicate "local". Examples: + * x=0; f() { local x=1; echo $x; local x; echo $x; }; f; echo $x + * x=0; f() { local x=1; echo $x; local x=2; echo $x; }; f; echo $x + */ + lvp = localvars; + while (lvp) { + if (varcmp(lvp->vp->var_text, name) == 0) { + if (eq) + setvareq(name, 0); + /* else: + * it's a duplicate "local VAR" declaration, do nothing + */ + return; + } + lvp = lvp->next; + } + + lvp = ckzalloc(sizeof(*lvp)); if (LONE_DASH(name)) { char *p; p = ckmalloc(sizeof(optlist)); lvp->text = memcpy(p, optlist, sizeof(optlist)); vp = NULL; } else { - char *eq; - vpp = hashvar(name); vp = *findvar(vpp, name); - eq = strchr(name, '='); if (vp == NULL) { + /* variable did not exist yet */ if (eq) setvareq(name, VSTRFIXED); else @@ -8994,12 +9010,15 @@ mklocal(char *name) } else { lvp->text = vp->var_text; lvp->flags = vp->flags; + /* make sure neither "struct var" nor string gets freed + * during (un)setting: + */ vp->flags |= VSTRFIXED|VTEXTFIXED; if (eq) setvareq(name, 0); else /* "local VAR" unsets VAR: */ - setvar(name, NULL, 0); + setvar0(name, NULL); } } lvp->vp = vp; @@ -9491,7 +9510,7 @@ evalcommand(union node *cmd, int flags) * '_' in 'vi' command mode during line editing... * However I implemented that within libedit itself. */ - setvar2("_", lastarg); + setvar0("_", lastarg); } popstackmark(&smark); } @@ -12885,7 +12904,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) * to jump out of it. */ INT_OFF; - r = shell_builtin_read(setvar2, + r = shell_builtin_read(setvar0, argptr, bltinlookup("IFS"), /* can be NULL */ read_flags, @@ -13046,14 +13065,14 @@ init(void) } } - setvar2("PPID", utoa(getppid())); + setvar0("PPID", utoa(getppid())); #if ENABLE_ASH_BASH_COMPAT p = lookupvar("SHLVL"); setvar("SHLVL", utoa((p ? atoi(p) : 0) + 1), VEXPORT); if (!lookupvar("HOSTNAME")) { struct utsname uts; uname(&uts); - setvar2("HOSTNAME", uts.nodename); + setvar0("HOSTNAME", uts.nodename); } #endif p = lookupvar("PWD"); @@ -13309,7 +13328,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) hp = lookupvar("HOME"); if (hp) { hp = concat_path_file(hp, ".ash_history"); - setvar2("HISTFILE", hp); + setvar0("HISTFILE", hp); free((char*)hp); hp = lookupvar("HISTFILE"); } diff --git a/shell/ash_test/ash-heredoc/heredoc1.right b/shell/ash_test/ash-heredoc/heredoc1.right index 895f5ee80..40aa5a5fe 100644 --- a/shell/ash_test/ash-heredoc/heredoc1.right +++ b/shell/ash_test/ash-heredoc/heredoc1.right @@ -1 +1 @@ -heredoc1.tests: line 3: syntax error: unexpected "then" +./heredoc1.tests: line 3: syntax error: unexpected "then" diff --git a/shell/ash_test/ash-vars/var3.right b/shell/ash_test/ash-vars/var3.right new file mode 100644 index 000000000..8eb0e3337 --- /dev/null +++ b/shell/ash_test/ash-vars/var3.right @@ -0,0 +1,5 @@ +1 +1 + + +0 diff --git a/shell/ash_test/ash-vars/var3.tests b/shell/ash_test/ash-vars/var3.tests new file mode 100755 index 000000000..97b102cbe --- /dev/null +++ b/shell/ash_test/ash-vars/var3.tests @@ -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 -- cgit v1.2.3-55-g6feb From 73327a048b112ba2b742b758bb5a3caf95c7bf1a Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 18 Apr 2015 19:38:13 +0200 Subject: hush: document buggy handling of duplicate "local" Signed-off-by: Denys Vlasenko --- shell/hush_test/hush-bugs/var3.right | 5 +++++ shell/hush_test/hush-bugs/var3.tests | 1 + 2 files changed, 6 insertions(+) create mode 100644 shell/hush_test/hush-bugs/var3.right create mode 100755 shell/hush_test/hush-bugs/var3.tests diff --git a/shell/hush_test/hush-bugs/var3.right b/shell/hush_test/hush-bugs/var3.right new file mode 100644 index 000000000..8eb0e3337 --- /dev/null +++ b/shell/hush_test/hush-bugs/var3.right @@ -0,0 +1,5 @@ +1 +1 + + +0 diff --git a/shell/hush_test/hush-bugs/var3.tests b/shell/hush_test/hush-bugs/var3.tests new file mode 100755 index 000000000..97b102cbe --- /dev/null +++ b/shell/hush_test/hush-bugs/var3.tests @@ -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 -- cgit v1.2.3-55-g6feb From bd77e9d6093dc8632788a3c3efffd53ac8ba3233 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Apr 2015 18:54:49 +0200 Subject: mdev: improve logging Signed-off-by: Denys Vlasenko --- util-linux/mdev.c | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/util-linux/mdev.c b/util-linux/mdev.c index ccc00d365..884e5de33 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -283,7 +283,7 @@ struct globals { unsigned rule_idx; #endif struct rule cur_rule; - char timestr[sizeof("60.123456")]; + char timestr[sizeof("HH:MM:SS.123456")]; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { \ @@ -923,7 +923,11 @@ static char *curtime(void) { struct timeval tv; gettimeofday(&tv, NULL); - sprintf(G.timestr, "%u.%06u", (unsigned)tv.tv_sec % 60, (unsigned)tv.tv_usec); + sprintf( + strftime_HHMMSS(G.timestr, sizeof(G.timestr), &tv.tv_sec), + ".%06u", + (unsigned)tv.tv_usec + ); return G.timestr; } @@ -984,7 +988,7 @@ wait_for_seqfile(const char *seq) break; } if (do_once) { - dbg2("%s waiting for '%s'", curtime(), seqbuf); + dbg2("%s mdev.seq='%s', need '%s'", curtime(), seqbuf, seq); do_once = 0; } if (sigtimedwait(&set_CHLD, NULL, &ts) >= 0) { @@ -992,7 +996,7 @@ wait_for_seqfile(const char *seq) continue; /* don't decrement timeout! */ } if (--timeout == 0) { - dbg1("%s waiting for '%s'", "timed out", seqbuf); + dbg1("%s mdev.seq='%s'", "timed out", seqbuf); break; } } -- cgit v1.2.3-55-g6feb From ad795510d9fd6f4290be170c84c0d30eb1af7245 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 19 Apr 2015 18:55:12 +0200 Subject: mdev: if a "future" mdev.seq is seen, do not overwrite it with ours This was seen to happen if two mdevs are run in parallel, mdev.seq is empty, and the "newer" one manages to write it first. function old new delta mdev_main 1366 1388 +22 atoll - 20 +20 Signed-off-by: Denys Vlasenko --- util-linux/mdev.c | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/util-linux/mdev.c b/util-linux/mdev.c index 884e5de33..ca4b91510 100644 --- a/util-linux/mdev.c +++ b/util-linux/mdev.c @@ -947,7 +947,7 @@ static void open_mdev_log(const char *seq, unsigned my_pid) * Active mdev pokes us with SIGCHLD to check the new file. */ static int -wait_for_seqfile(const char *seq) +wait_for_seqfile(unsigned expected_seq) { /* We time out after 2 sec */ static const struct timespec ts = { 0, 32*1000*1000 }; @@ -962,12 +962,14 @@ wait_for_seqfile(const char *seq) for (;;) { int seqlen; - char seqbuf[sizeof(int)*3 + 2]; + char seqbuf[sizeof(long)*3 + 2]; + unsigned seqbufnum; if (seq_fd < 0) { seq_fd = open("mdev.seq", O_RDWR); if (seq_fd < 0) break; + close_on_exec_on(seq_fd); } seqlen = pread(seq_fd, seqbuf, sizeof(seqbuf) - 1, 0); if (seqlen < 0) { @@ -978,17 +980,25 @@ wait_for_seqfile(const char *seq) seqbuf[seqlen] = '\0'; if (seqbuf[0] == '\n' || seqbuf[0] == '\0') { /* seed file: write out seq ASAP */ - xwrite_str(seq_fd, seq); + xwrite_str(seq_fd, utoa(expected_seq)); xlseek(seq_fd, 0, SEEK_SET); dbg2("first seq written"); break; } - if (strcmp(seq, seqbuf) == 0) { + seqbufnum = atoll(seqbuf); + if (seqbufnum == expected_seq) { /* correct idx */ break; } + if (seqbufnum > expected_seq) { + /* a later mdev runs already (this was seen by users to happen) */ + /* do not overwrite seqfile on exit */ + close(seq_fd); + seq_fd = -1; + break; + } if (do_once) { - dbg2("%s mdev.seq='%s', need '%s'", curtime(), seqbuf, seq); + dbg2("%s mdev.seq='%s', need '%u'", curtime(), seqbuf, expected_seq); do_once = 0; } if (sigtimedwait(&set_CHLD, NULL, &ts) >= 0) { @@ -1079,6 +1089,7 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) char *env_devname; char *env_devpath; unsigned my_pid; + unsigned seqnum = seqnum; /* for compiler */ int seq_fd; smalluint op; @@ -1100,7 +1111,11 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) my_pid = getpid(); open_mdev_log(seq, my_pid); - seq_fd = seq ? wait_for_seqfile(seq) : -1; + seq_fd = -1; + if (seq) { + seqnum = atoll(seq); + seq_fd = wait_for_seqfile(seqnum); + } dbg1("%s " "ACTION:%s SUBSYSTEM:%s DEVNAME:%s DEVPATH:%s" @@ -1128,7 +1143,7 @@ int mdev_main(int argc UNUSED_PARAM, char **argv) dbg1("%s exiting", curtime()); if (seq_fd >= 0) { - xwrite_str(seq_fd, utoa(xatou(seq) + 1)); + xwrite_str(seq_fd, utoa(seqnum + 1)); signal_mdevs(my_pid); } } -- cgit v1.2.3-55-g6feb From 61d6ae244af424b2a05468307723f21c8810ab9e Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Sun, 19 Apr 2015 10:50:25 +0100 Subject: libbb: remove unnecessary argument to nonblock_immune_read The loop_on_EINTR argument to nonblock_immune_read is always set to 1. function old new delta xmalloc_reads 200 195 -5 pgetc 488 483 -5 argstr 1313 1308 -5 nonblock_immune_read 123 86 -37 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/4 up/down: 0/-52) Total: -52 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- include/libbb.h | 2 +- libbb/read_printf.c | 8 ++++---- shell/ash.c | 6 +++--- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/include/libbb.h b/include/libbb.h index 0f8363b78..21da5f100 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -713,7 +713,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; diff --git a/libbb/read_printf.c b/libbb/read_printf.c index 5ed6e3632..b6a17cc36 100644 --- a/libbb/read_printf.c +++ b/libbb/read_printf.c @@ -45,20 +45,20 @@ * which detects EAGAIN and uses poll() to wait on the fd. * Thankfully, poll() doesn't care about O_NONBLOCK flag. */ -ssize_t FAST_FUNC nonblock_immune_read(int fd, void *buf, size_t count, int loop_on_EINTR) +ssize_t FAST_FUNC nonblock_immune_read(int fd, void *buf, size_t count) { struct pollfd pfd[1]; ssize_t n; while (1) { - n = loop_on_EINTR ? safe_read(fd, buf, count) : read(fd, buf, count); + n = safe_read(fd, buf, count); if (n >= 0 || errno != EAGAIN) return n; /* fd is in O_NONBLOCK mode. Wait using poll and repeat */ pfd[0].fd = fd; pfd[0].events = POLLIN; /* note: safe_poll pulls in printf */ - loop_on_EINTR ? safe_poll(pfd, 1, -1) : poll(pfd, 1, -1); + safe_poll(pfd, 1, -1); } } @@ -81,7 +81,7 @@ char* FAST_FUNC xmalloc_reads(int fd, size_t *maxsz_p) p = buf + sz; sz += 128; } - if (nonblock_immune_read(fd, p, 1, /*loop_on_EINTR:*/ 1) != 1) { + if (nonblock_immune_read(fd, p, 1) != 1) { /* EOF/error */ if (p == buf) { /* we read nothing */ free(buf); diff --git a/shell/ash.c b/shell/ash.c index 697a64fea..c51fb804d 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5923,7 +5923,7 @@ expbackq(union node *cmd, int quoted, int quotes) read: if (in.fd < 0) break; - i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1); + i = nonblock_immune_read(in.fd, buf, sizeof(buf)); TRACE(("expbackq: read returns %d\n", i)); if (i <= 0) break; @@ -9696,7 +9696,7 @@ preadfd(void) #if ENABLE_FEATURE_EDITING retry: if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) - nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); + nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); else { int timeout = -1; # if ENABLE_ASH_IDLE_TIMEOUT @@ -9738,7 +9738,7 @@ preadfd(void) } } #else - nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); + nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); #endif #if 0 /* disabled: nonblock_immune_read() handles this problem */ -- cgit v1.2.3-55-g6feb From 7d86384b246434e72533332f7f409a7aa9efeacb Mon Sep 17 00:00:00 2001 From: Bernhard Reutner-Fischer Date: Sun, 19 Apr 2015 23:45:17 +0200 Subject: include: Fallback to UTMP unless there is UTMPX support Fixes compilation against uClibc-0.9.30 for instance Signed-off-by: Bernhard Reutner-Fischer --- include/libbb.h | 25 ++++++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/include/libbb.h b/include/libbb.h index 21da5f100..f0ac1f50d 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -84,7 +84,30 @@ # include #endif #if ENABLE_FEATURE_UTMP -# include +# if defined __UCLIBC__ && ( \ + (UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 32) \ + && UCLIBC_VERSION < KERNEL_VERSION(0, 9, 34) \ + && defined __UCLIBC_HAS_UTMPX__ \ + ) || ( \ + UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 34) \ + ) \ + ) +# include +# elif defined __UCLIBC__ +# include +# define utmpx utmp +# define setutxent setutent +# define endutxent endutent +# define getutxent getutent +# define getutxid getutid +# define getutxline getutline +# define pututxline pututline +# define utmpxname utmpname +# define updwtmpx updwtmp +# define _PATH_UTMPX _PATH_UTMP +# else +# include +# endif #endif #if ENABLE_LOCALE_SUPPORT # include -- cgit v1.2.3-55-g6feb From de5edadee2dca2896492f97ab3a56e389305e74d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Tue, 21 Apr 2015 16:00:41 +0200 Subject: special-case {true,false,test} --help This also removes their help texts. function old new delta run_applet_no_and_exit 442 452 +10 packed_usage 30713 30625 -88 Signed-off-by: Denys Vlasenko --- coreutils/false.c | 8 +++----- coreutils/test.c | 11 +++-------- coreutils/true.c | 8 +++----- libbb/appletlib.c | 22 ++++++++++++---------- 4 files changed, 21 insertions(+), 28 deletions(-) diff --git a/coreutils/false.c b/coreutils/false.c index 59c2f321a..0591a6cdc 100644 --- a/coreutils/false.c +++ b/coreutils/false.c @@ -10,11 +10,9 @@ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/000095399/utilities/false.html */ -//usage:#define false_trivial_usage -//usage: "" -//usage:#define false_full_usage "\n\n" -//usage: "Return an exit code of FALSE (1)" -//usage: +/* "false --help" is special-cased to ignore --help */ +//usage:#define false_trivial_usage NOUSAGE_STR +//usage:#define false_full_usage "" //usage:#define false_example_usage //usage: "$ false\n" //usage: "$ echo $?\n" diff --git a/coreutils/test.c b/coreutils/test.c index 88cc55050..7b8b10cd9 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -39,14 +39,9 @@ //config: help //config: Enable 64-bit support in test. -/* "test --help" does not print help (POSIX compat), only "[ --help" does. - * We display " EXPRESSION ]" here (not " EXPRESSION") - * Unfortunately, it screws up generated BusyBox.html. TODO. */ -//usage:#define test_trivial_usage -//usage: "EXPRESSION ]" -//usage:#define test_full_usage "\n\n" -//usage: "Check file types, compare values etc. Return a 0/1 exit code\n" -//usage: "depending on logical value of EXPRESSION" +/* "test --help" is special-cased to ignore --help */ +//usage:#define test_trivial_usage NOUSAGE_STR +//usage:#define test_full_usage "" //usage: //usage:#define test_example_usage //usage: "$ test 1 -eq 2\n" diff --git a/coreutils/true.c b/coreutils/true.c index 382e476a8..89f892961 100644 --- a/coreutils/true.c +++ b/coreutils/true.c @@ -10,11 +10,9 @@ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/true.html */ -//usage:#define true_trivial_usage -//usage: "" -//usage:#define true_full_usage "\n\n" -//usage: "Return an exit code of TRUE (0)" -//usage: +/* "true --help" is special-cased to ignore --help */ +//usage:#define true_trivial_usage NOUSAGE_STR +//usage:#define true_full_usage "" //usage:#define true_example_usage //usage: "$ true\n" //usage: "$ echo $?\n" diff --git a/libbb/appletlib.c b/libbb/appletlib.c index e0b843d30..ba3d6e7a0 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -748,23 +748,25 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) xfunc_error_retval = EXIT_FAILURE; applet_name = APPLET_NAME(applet_no); -#if defined APPLET_NO_test /* Special case. POSIX says "test --help" * should be no different from e.g. "test --foo". * Thus for "test", we skip --help check. + * "true" and "false" are also special. */ - if (applet_no != APPLET_NO_test) + if (1 +#if defined APPLET_NO_test + && applet_no != APPLET_NO_test +#endif +#if defined APPLET_NO_true + && applet_no != APPLET_NO_true #endif - { - if (argc == 2 && strcmp(argv[1], "--help") == 0) { #if defined APPLET_NO_false - /* Someone insisted that "false --help" must exit 1. Sigh */ - if (applet_no != APPLET_NO_false) + && applet_no != APPLET_NO_false #endif - { - /* Make "foo --help" exit with 0: */ - xfunc_error_retval = 0; - } + ) { + if (argc == 2 && strcmp(argv[1], "--help") == 0) { + /* Make "foo --help" exit with 0: */ + xfunc_error_retval = 0; bb_show_usage(); } } -- cgit v1.2.3-55-g6feb From cee59053dcf47b4a3ab87f7654c1ed20620def16 Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Sat, 25 Apr 2015 21:32:48 +0200 Subject: Bionic lacks ttyname_r; provide a workaround Signed-off-by: Matt Whitlock Signed-off-by: Denys Vlasenko --- include/platform.h | 7 +++++++ libbb/platform.c | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+) diff --git a/include/platform.h b/include/platform.h index df9594507..d5ab7bc29 100644 --- a/include/platform.h +++ b/include/platform.h @@ -368,6 +368,7 @@ 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 @@ -480,6 +481,7 @@ typedef unsigned smalluint; #if defined(ANDROID) || defined(__ANDROID__) # undef HAVE_DPRINTF +# undef HAVE_TTYNAME_R # undef HAVE_GETLINE # undef HAVE_STPCPY # undef HAVE_STRCHRNUL @@ -505,6 +507,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))) diff --git a/libbb/platform.c b/libbb/platform.c index 8d90ca4e9..03bbb798b 100644 --- a/libbb/platform.c +++ b/libbb/platform.c @@ -194,3 +194,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 -- cgit v1.2.3-55-g6feb From 93b98ff5726fd620e1f123d04072b956412c1b55 Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Sun, 26 Apr 2015 13:14:50 +0200 Subject: Bionic lacks tcdrain; provide a workaround Signed-off-by: Matt Whitlock Signed-off-by: Denys Vlasenko --- libbb/missing_syscalls.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libbb/missing_syscalls.c b/libbb/missing_syscalls.c index dd430e3e2..e3c1e924b 100644 --- a/libbb/missing_syscalls.c +++ b/libbb/missing_syscalls.c @@ -39,4 +39,9 @@ int pivot_root(const char *new_root, const char *put_old) { return syscall(__NR_pivot_root, new_root, put_old); } + +int tcdrain(int fd) +{ + return ioctl(fd, TCSBRK, 1); +} #endif -- cgit v1.2.3-55-g6feb From bbd53216f80912944da0d4ca72bf3ed3188ca156 Mon Sep 17 00:00:00 2001 From: Aaro Koskinen Date: Sun, 26 Apr 2015 14:22:05 +0200 Subject: gzip: add support for compression levels 4-9 function old new delta gzip_main 192 282 +90 static.gzip_level_config - 24 +24 packed_usage 30439 30459 +20 fill_window 216 220 +4 pack_gzip 1789 1729 -60 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 3/1 up/down: 138/-60) Total: 78 bytes Signed-off-by: Aaro Koskinen Signed-off-by: Denys Vlasenko --- archival/gzip.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 10 deletions(-) diff --git a/archival/gzip.c b/archival/gzip.c index bc1f9c60b..42b2f0b2e 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -62,14 +62,27 @@ aa: 85.1% -- replaced with aa.gz //config: 1: larger buffers, larger hash-tables //config: 2: larger buffers, largest hash-tables //config: Larger models may give slightly better compression +//config: +//config:config FEATURE_GZIP_LEVELS +//config: bool "Enable compression levels" +//config: default n +//config: depends on GZIP +//config: help +//config: Enable support for compression levels 4-9. The default level +//config: is 6. If levels 1-3 are specified, 4 is used. +//config: If this option is not selected, -N options are ignored and -9 +//config: is used. //applet:IF_GZIP(APPLET(gzip, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_GZIP) += gzip.o //usage:#define gzip_trivial_usage -//usage: "[-cfd] [FILE]..." +//usage: "[-cfd" IF_FEATURE_GZIP_LEVELS("123456789") "] [FILE]..." //usage:#define gzip_full_usage "\n\n" //usage: "Compress FILEs (or stdin)\n" +//usage: IF_FEATURE_GZIP_LEVELS( +//usage: "\n -1..9 Compression level" +//usage: ) //usage: "\n -d Decompress" //usage: "\n -c Write to stdout" //usage: "\n -f Force" @@ -252,6 +265,8 @@ enum { * input file length plus MIN_LOOKAHEAD. */ +#ifndef ENABLE_FEATURE_GZIP_LEVELS + max_chain_length = 4096, /* To speed up deflation, hash chains are never searched beyond this length. * A higher limit improves compression ratio but degrades the speed. @@ -283,11 +298,23 @@ enum { * For deflate_fast() (levels <= 3) good is ignored and lazy has a different * meaning. */ +#endif /* ENABLE_FEATURE_GZIP_LEVELS */ }; struct globals { +#ifdef ENABLE_FEATURE_GZIP_LEVELS + unsigned max_chain_length; + unsigned max_lazy_match; + unsigned good_match; + unsigned nice_match; +#define max_chain_length (G1.max_chain_length) +#define max_lazy_match (G1.max_lazy_match) +#define good_match (G1.good_match) +#define nice_match (G1.nice_match) +#endif + lng block_start; /* window position at the beginning of the current output block. Gets @@ -2161,24 +2188,48 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) #endif { unsigned opt; +#ifdef ENABLE_FEATURE_GZIP_LEVELS + static const struct { + uint8_t good; + uint8_t chain_shift; + uint8_t lazy2; + uint8_t nice2; + } gzip_level_config[6] = { + {4, 4, 4/2, 16/2}, /* Level 4 */ + {8, 5, 16/2, 32/2}, /* Level 5 */ + {8, 7, 16/2, 128/2}, /* Level 6 */ + {8, 8, 32/2, 128/2}, /* Level 7 */ + {32, 10, 128/2, 258/2}, /* Level 8 */ + {32, 12, 258/2, 258/2}, /* Level 9 */ + }; +#endif + + SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2)) + + sizeof(struct globals)); #if ENABLE_FEATURE_GZIP_LONG_OPTIONS applet_long_options = gzip_longopts; #endif /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ - opt = getopt32(argv, "cfv" IF_GUNZIP("dt") "q123456789n"); + opt = getopt32(argv, "cfv" IF_GUNZIP("dt") "qn123456789"); #if ENABLE_GUNZIP /* gunzip_main may not be visible... */ if (opt & 0x18) // -d and/or -t return gunzip_main(argc, argv); #endif - option_mask32 &= 0x7; /* ignore -q, -0..9 */ - //if (opt & 0x1) // -c - //if (opt & 0x2) // -f - //if (opt & 0x4) // -v - argv += optind; - - SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2)) - + sizeof(struct globals)); +#ifdef ENABLE_FEATURE_GZIP_LEVELS + opt >>= ENABLE_GUNZIP ? 7 : 5; /* drop cfv[dt]qn bits */ + if (opt == 0) + opt = 1 << 6; /* default: 6 */ + /* Map 1..3 to 4 */ + if (opt & 0x7) + opt |= 1 << 4; + opt = ffs(opt >> 3); + max_chain_length = 1 << gzip_level_config[opt].chain_shift; + good_match = gzip_level_config[opt].good; + max_lazy_match = gzip_level_config[opt].lazy2 * 2; + nice_match = gzip_level_config[opt].nice2 * 2; +#endif + option_mask32 &= 0x7; /* retain only -cfv */ /* Allocate all global buffers (for DYN_ALLOC option) */ ALLOC(uch, G1.l_buf, INBUFSIZ); @@ -2190,5 +2241,6 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) /* Initialize the CRC32 table */ global_crc32_table = crc32_filltable(NULL, 0); + argv += optind; return bbunpack(argv, pack_gzip, append_ext, "gz"); } -- cgit v1.2.3-55-g6feb From 4d8ddb810d52f5ad1bcef8bda07687200117e56b Mon Sep 17 00:00:00 2001 From: Andrew Fuller Date: Sun, 3 May 2015 18:18:25 +0200 Subject: vi: basic undo feature shouldn't depend on yankmark Currently basic undo functionality with the 'u' key depends on FEATURE_VI_YANKMARK. These two features are separate, so we can remove this dependency. Signed-off-by: Andrew Fuller Signed-off-by: Denys Vlasenko --- editors/vi.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/editors/vi.c b/editors/vi.c index 495332a46..2e4f7fcb5 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3676,11 +3676,6 @@ static void do_cmd(int c) string_insert(dot, p, ALLOW_UNDO); // insert the string end_cmd_q(); // stop adding to q break; -#if ENABLE_FEATURE_VI_UNDO - case 'u': // u- undo last operation - undo_pop(); - break; -#endif case 'U': // U- Undo; replace current line with original version if (reg[Ureg] != NULL) { p = begin_line(dot); @@ -3692,6 +3687,11 @@ static void do_cmd(int c) } break; #endif /* FEATURE_VI_YANKMARK */ +#if ENABLE_FEATURE_VI_UNDO + case 'u': // u- undo last operation + undo_pop(); + break; +#endif case '$': // $- goto end of line case KEYCODE_END: // Cursor Key End for (;;) { -- cgit v1.2.3-55-g6feb From c77a58fb2d84d4ee3883d385bc44bbfcfc7093c9 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 3 May 2015 18:24:33 +0200 Subject: typo fix Signed-off-by: Denys Vlasenko --- README | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README b/README index b940e357a..ada5935b9 100644 --- a/README +++ b/README @@ -185,7 +185,7 @@ Supported hardware: Under 2.4 Linux kernels, kernel module loading was implemented in a platform-specific manner. Busybox's insmod utility has been reported to work under ARM, CRIS, H8/300, x86, ia64, x86_64, m68k, MIPS, PowerPC, S390, - SH3/4/5, Sparc, v850e, and x86_64. Anything else probably won't work. + SH3/4/5, Sparc, and v850e. Anything else probably won't work. The module loading mechanism for the 2.6 kernel is much more generic, and we believe 2.6.x kernel module loading support should work on all -- cgit v1.2.3-55-g6feb From b4059f6309c5129a619bd1a95d27919231e07860 Mon Sep 17 00:00:00 2001 From: Thiago Jung Bauermann Date: Sun, 3 May 2015 18:40:12 +0200 Subject: libarchive: auto-detect .Z files as well Signed-off-by: Thiago Jung Bauermann Signed-off-by: Denys Vlasenko --- archival/libarchive/open_transformer.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index ab6aa3afc..be536a3d7 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c @@ -185,6 +185,13 @@ static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_comp USE_FOR_NOMMU(xstate->xformer_prog = "gunzip";) goto found_magic; } + if (ENABLE_FEATURE_SEAMLESS_Z + && magic.b16[0] == COMPRESS_MAGIC + ) { + xstate->xformer = unpack_Z_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "uncompress";) + goto found_magic; + } if (ENABLE_FEATURE_SEAMLESS_BZ2 && magic.b16[0] == BZIP2_MAGIC ) { -- cgit v1.2.3-55-g6feb From f23e3ec529c300712d529fa805d2e1f254bf1884 Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Sun, 3 May 2015 18:57:44 +0200 Subject: Bionic lacks mempcpy; enable existing workaround Signed-off-by: Matt Whitlock Signed-off-by: Denys Vlasenko --- include/platform.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/platform.h b/include/platform.h index d5ab7bc29..8896a6b99 100644 --- a/include/platform.h +++ b/include/platform.h @@ -484,6 +484,7 @@ typedef unsigned smalluint; # undef HAVE_TTYNAME_R # undef HAVE_GETLINE # undef HAVE_STPCPY +# undef HAVE_MEMPCPY # undef HAVE_STRCHRNUL # undef HAVE_STRVERSCMP # undef HAVE_UNLOCKED_LINE_OPS -- cgit v1.2.3-55-g6feb From 778efe37eed03de6e194a746925f1160181ff587 Mon Sep 17 00:00:00 2001 From: Matt Whitlock Date: Sun, 3 May 2015 18:59:50 +0200 Subject: Conditionalize Bionic workarounds on __ANDROID_API__ Signed-off-by: Matt Whitlock Signed-off-by: Denys Vlasenko --- include/platform.h | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/include/platform.h b/include/platform.h index 8896a6b99..1706b1847 100644 --- a/include/platform.h +++ b/include/platform.h @@ -480,10 +480,16 @@ typedef unsigned smalluint; #endif #if defined(ANDROID) || defined(__ANDROID__) -# undef HAVE_DPRINTF -# undef HAVE_TTYNAME_R -# 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 -- cgit v1.2.3-55-g6feb From bdb540e04f3eb52c4cd790c45c5d8efd6d749c70 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 11 May 2015 16:55:16 +0200 Subject: tar: do not try to decode GNU extended headers as pax headers function old new delta get_header_tar 1736 1692 -44 Signed-off-by: Denys Vlasenko --- archival/libarchive/get_header_tar.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c index 2dbcdb50c..fb68673b9 100644 --- a/archival/libarchive/get_header_tar.c +++ b/archival/libarchive/get_header_tar.c @@ -350,7 +350,14 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) case '6': file_header->mode |= S_IFIFO; goto size0; + case 'g': /* pax global header */ + case 'x': { /* pax extended header */ + if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ + goto skip_ext_hdr; + process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g')); + goto again_after_align; #if ENABLE_FEATURE_TAR_GNU_EXTENSIONS +/* See http://www.gnu.org/software/tar/manual/html_node/Extensions.html */ case 'L': /* free: paranoia: tar with several consecutive longnames */ free(p_longname); @@ -370,18 +377,17 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) archive_handle->offset += file_header->size; /* return get_header_tar(archive_handle); */ goto again; - case 'D': /* GNU dump dir */ - case 'M': /* Continuation of multi volume archive */ - case 'N': /* Old GNU for names > 100 characters */ - case 'S': /* Sparse file */ - case 'V': /* Volume header */ +/* + * case 'S': // Sparse file + * Was seen in the wild. Not supported (yet?). + * See https://www.gnu.org/software/tar/manual/html_section/tar_92.html + * for the format. (An "Old GNU Format" was seen, not PAX formats). + */ +// case 'D': /* GNU dump dir */ +// case 'M': /* Continuation of multi volume archive */ +// case 'N': /* Old GNU for names > 100 characters */ +// case 'V': /* Volume header */ #endif - case 'g': /* pax global header */ - case 'x': { /* pax extended header */ - if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ - goto skip_ext_hdr; - process_pax_hdr(archive_handle, file_header->size, (tar.typeflag == 'g')); - goto again_after_align; } skip_ext_hdr: { -- cgit v1.2.3-55-g6feb From 17b16223f39c983a5d0eba8d3ab656a8d123b621 Mon Sep 17 00:00:00 2001 From: Thiago Jung Bauermann Date: Mon, 11 May 2015 17:18:59 +0200 Subject: bzcat.tests: Run both .gz and .bz2 tests, and add .Z tests Signed-off-by: Thiago Jung Bauermann Signed-off-by: Denys Vlasenko --- testsuite/bzcat.tests | 74 ++++++++++++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 24 deletions(-) diff --git a/testsuite/bzcat.tests b/testsuite/bzcat.tests index 1c1fd6563..9a1c28425 100755 --- a/testsuite/bzcat.tests +++ b/testsuite/bzcat.tests @@ -2,8 +2,6 @@ FAILCOUNT=0 -ext=bz2 - bb="busybox " unset LC_ALL @@ -11,6 +9,11 @@ unset LC_MESSAGES unset LANG unset LANGUAGE +hello_Z() { + # Compressed "HELLO\n" + $ECHO -ne "\x1f\x9d\x90\x48\x8a\x30\x61\xf2\x44\x01" +} + hello_gz() { # Gzipped "HELLO\n" #_________________________ vvv vvv vvv vvv - mtime @@ -25,32 +28,34 @@ hello_bz2() { $ECHO -ne "\x17\x72\x45\x38\x50\x90\x5b\xb8\xe8\xa3" } -prep() { - rm -f t* - hello_$ext >t1.$ext - hello_$ext >t2.$ext -} +for ext in gz bz2 Z +do + prep() { + rm -f t1.$ext t2.$ext t_actual + hello_$ext >t1.$ext + hello_$ext >t2.$ext + } -check() { - eval $2 >t_actual 2>&1 - if $ECHO -ne "$expected" | cmp - t_actual; then - echo "PASS: $1" - else - echo "FAIL: $1" - FAILCOUNT=$((FAILCOUNT + 1)) - fi -} + check() { + eval $2 >t_actual 2>&1 + if $ECHO -ne "$expected" | cmp - t_actual; then + echo "PASS: $1" + else + echo "FAIL: $1" + FAILCOUNT=$((FAILCOUNT + 1)) + fi + } -mkdir testdir 2>/dev/null -( -cd testdir || { echo "cannot cd testdir!"; exit 1; } + mkdir testdir 2>/dev/null + ( + cd testdir || { echo "cannot cd testdir!"; exit 1; } -expected="HELLO\nok\n" -prep; check "bzcat: dont delete src" "${bb}bzcat t2.bz2; test -f t2.bz2 && echo ok" - -) -rm -rf testdir + expected="HELLO\nok\n" + prep; check "zcat: dont delete $ext src" "${bb}zcat t2.$ext; test -f t2.$ext && echo ok" + ) + rm -rf testdir +done # Copyright 2011 by Denys Vlasenko @@ -60,6 +65,8 @@ rm -rf testdir # testing "test name" "command" "expected result" "file input" "stdin" +## bzip algorithm + # "input" file is bzipped file with "a\n" data testing "bzcat can print many files" \ "$ECHO -ne '$hexdump' | bzcat input input; echo \$?" \ @@ -79,6 +86,25 @@ testing "bzcat can handle compressed zero-length bzip2 files" \ "0\n" \ "\x42\x5a\x68\x39\x17\x72\x45\x38\x50\x90\x00\x00\x00\x00" "" +## compress algorithm + +# "input" file is compressed (.Z) file with "a\n" data +testing "zcat can print many files" \ +"$ECHO -ne '$hexdump' | zcat input input; echo \$?" \ +"\ +a +a +0 +" "\ +\x1f\x9d\x90\x61\x14\x00\ +" "" + +# "input" file is compressed (.Z) zero byte file +testing "zcat can handle compressed zero-length compressed (.Z) files" \ +"$ECHO -ne '$hexdump' | zcat input input; echo \$?" \ +"0\n" \ +"\x1f\x9d\x90\x00" "" + exit $((FAILCOUNT <= 255 ? FAILCOUNT : 255)) -- cgit v1.2.3-55-g6feb From b2cca32a37b969cce3b3bce693708759d44d3d15 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 May 2015 17:22:10 +0200 Subject: i2c-tools: fix 'i2cdetect -l' Calling 'i2cdetect -l' only displays usage and exits. Fix it by correctly parsing command-line arguments. Signed-off-by: Bartosz Golaszewski Signed-off-by: Denys Vlasenko --- miscutils/i2c_tools.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index 03bb03974..2805cf3b0 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c @@ -1284,13 +1284,16 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv) unsigned opts; opt_complementary = "q--r:r--q:" /* mutually exclusive */ - "-1:?3"; /* from 1 to 3 args */ + "?3"; /* up to 3 args */ opts = getopt32(argv, optstr); argv += optind; if (opts & opt_l) list_i2c_busses_and_exit(); + if (!argv[0]) + bb_show_usage(); + bus_num = i2c_bus_lookup(argv[0]); fd = i2c_dev_open(bus_num); get_funcs_matrix(fd, &funcs); -- cgit v1.2.3-55-g6feb From 7ca5c51cc8c54f35b6265d815d8a8be19e0821b0 Mon Sep 17 00:00:00 2001 From: Bartosz Golaszewski Date: Mon, 11 May 2015 17:26:27 +0200 Subject: i2c-tools: only try /dev/i2c/* if opening /dev/i2c-* fails with ENOENT Trying to access /dev/i2c/* on every error after opening /dev/i2c-* can mislead users who e.g. don't have root access. Instead of bailing-out with "permission denied" we currently print "no such file or directory". Fix it by trying open("/dev/i2c/%d") only if we got ENOENT. Upstream i2cdetect tries to get any info it can from /sys and /proc even when invoked by an unprivileged user, but we don't want to add unnecessary bloat. Signed-off-by: Bartosz Golaszewski Signed-off-by: Denys Vlasenko --- miscutils/i2c_tools.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index 2805cf3b0..7034dc9a8 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c @@ -379,8 +379,12 @@ static int i2c_dev_open(int i2cbus) sprintf(filename, "/dev/i2c-%d", i2cbus); fd = open(filename, O_RDWR); if (fd < 0) { - filename[8] = '/'; /* change to "/dev/i2c/%d" */ - fd = xopen(filename, O_RDWR); + if (errno == ENOENT) { + filename[8] = '/'; /* change to "/dev/i2c/%d" */ + fd = xopen(filename, O_RDWR); + } else { + bb_perror_msg_and_die("can't open '%s'", filename); + } } return fd; -- cgit v1.2.3-55-g6feb From a818777d4249e934ef7c9e6e7df8475d6692f315 Mon Sep 17 00:00:00 2001 From: Daniel Thompson Date: Tue, 12 May 2015 07:56:04 +0100 Subject: libbb: Enable support for !CONFIG_MULTIUSER Linux recently gained a new config option, CONFIG_MULTIUSER, that makes support for non-root users optional. This results in a number of syscalls being disabled: setuid, setregid, setgid, setreuid, setresuid, getresuid, setresgid, getresgid, setgroups, getgroups, setfsuid, setfsgid, capget, capset. Currently a number of busybox applets, including login, struggle to run when CONFIG_MULTIUSER is disabled. Even the root user is unable to login: login: can't set groups: Functi This patch adds code to make change_identity() a nop on single user systems. It works by recognising the signature errno value (ENOSYS, due to the system calls being disabled) and, to avoid security risks, only deploys when the current uid and target uid is the same. After the patch is applied any attempt to switch to a non-root user will fail. Thus a badly configured userspace (for example, one that tries to start a daemon as a non-root user when the kernel cannot support this) will report errors as one would expect. Signed-off-by: Daniel Thompson Signed-off-by: Denys Vlasenko --- libbb/change_identity.c | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/libbb/change_identity.c b/libbb/change_identity.c index 619db09a8..d48d86326 100644 --- a/libbb/change_identity.c +++ b/libbb/change_identity.c @@ -33,9 +33,28 @@ /* Become the user and group(s) specified by PW. */ void FAST_FUNC change_identity(const struct passwd *pw) { - if (initgroups(pw->pw_name, pw->pw_gid) == -1) - bb_perror_msg_and_die("can't set groups"); + int res; + + res = initgroups(pw->pw_name, pw->pw_gid); endgrent(); /* helps to close a fd used internally by libc */ + + if (res != 0) { + /* + * If initgroups() fails because a system call is unimplemented + * then we are running on a Linux kernel compiled without multiuser + * support (CONFIG_MULTIUSER is not defined). + * + * If we are running without multiuser support *and* the target uid + * already matches the current uid then we can skip the change of + * identity. + */ + if (errno == ENOSYS && pw->pw_uid == getuid()) { + return; + } + + bb_perror_msg_and_die("can't set groups"); + } + xsetgid(pw->pw_gid); xsetuid(pw->pw_uid); } -- cgit v1.2.3-55-g6feb From 1285aa62f914ba894b82880e57bd81cfbc41f180 Mon Sep 17 00:00:00 2001 From: Eugene Rudoy Date: Sun, 26 Apr 2015 23:32:00 +0200 Subject: ash: consider "local -" case while iterating over local variables in mklocal. fixes segfault introduced in 0a0acb55db8d7c4dec445573f1b0528d126b9e1f with functions using "local -". test-case: f() { local -; local x; }; f note: with this change applied multiple 'local -'s still cause multiple entries to be added to the localvars list. this problem will be addressed in a separate commit. Signed-off-by: Eugene Rudoy Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index c51fb804d..3e9997b53 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -8979,7 +8979,7 @@ mklocal(char *name) */ lvp = localvars; while (lvp) { - if (varcmp(lvp->vp->var_text, name) == 0) { + if (lvp->vp && varcmp(lvp->vp->var_text, name) == 0) { if (eq) setvareq(name, 0); /* else: -- cgit v1.2.3-55-g6feb From e0a4e107aa9d1e03546c090b07874dff1865705e Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 13 May 2015 02:20:14 +0200 Subject: ash: explain what "local -" does Signed-off-by: Denys Vlasenko --- shell/ash.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell/ash.c b/shell/ash.c index 3e9997b53..7af8842bb 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -8962,7 +8962,8 @@ parse_command_args(char **argv, const char **path) * Make a variable a local variable. When a variable is made local, it's * value and flags are saved in a localvar structure. The saved values * will be restored when the shell function returns. We handle the name - * "-" as a special case. + * "-" as a special case: it makes changes to "set +-options" local + * (options will be restored on return from the function). */ static void mklocal(char *name) -- cgit v1.2.3-55-g6feb From d68d1fbd6cb31a61975112acb1c792735a063847 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:49:28 +0200 Subject: ash: code shrink around varvalue Based on commit c989d72 from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta strtodest - 40 +40 memtodest 123 147 +24 parse_command 1443 1440 -3 readtoken1 3205 3199 -6 argstr 1203 1180 -23 varvalue 788 660 -128 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 1/4 up/down: 64/-160) Total: -96 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 84 ++++++++++++++++++++++++++++--------------------------------- 1 file changed, 38 insertions(+), 46 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index 7af8842bb..a81922add 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5539,6 +5539,11 @@ ash_arith(const char *s) #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ +/* Add CTLESC when necessary. */ +#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_REDIR) +/* Do not skip NUL characters. */ +#define QUOTES_KEEPNUL EXP_TILDE + /* * Structure specifying which parts of the string should be searched * for IFS characters. @@ -5695,29 +5700,34 @@ preglob(const char *pattern, int quoted, int flag) static void memtodest(const char *p, size_t len, int syntax, int quotes) { - char *q = expdest; + char *q; + + if (!len) + return; - q = makestrspace(quotes ? len * 2 : len, q); + q = makestrspace((quotes & QUOTES_ESC) ? len * 2 : len, expdest); - while (len--) { + do { unsigned char c = *p++; - if (c == '\0') - continue; - if (quotes) { + if (c) { int n = SIT(c, syntax); - if (n == CCTL || n == CBACK) + if ((quotes & QUOTES_ESC) && + (n == CCTL || n == CBACK)) USTPUTC(CTLESC, q); - } + } else if (!(quotes & QUOTES_KEEPNUL)) + continue; USTPUTC(c, q); - } + } while (--len); expdest = q; } -static void +static size_t strtodest(const char *p, int syntax, int quotes) { - memtodest(p, strlen(p), syntax, quotes); + size_t len = strlen(p); + memtodest(p, len, syntax, quotes); + return len; } /* @@ -5790,7 +5800,7 @@ exptilde(char *startp, char *p, int flags) char *name; struct passwd *pw; const char *home; - int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); + int quotes = flags & QUOTES_ESC; name = p + 1; @@ -6043,7 +6053,7 @@ argstr(char *p, int flags, struct strlist *var_str_list) '\0' }; const char *reject = spclchars; - int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); /* do CTLESC */ + int quotes = flags & QUOTES_ESC; int breakall = flags & EXP_WORD; int inquotes; size_t length; @@ -6608,13 +6618,16 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) const char *p; int num; int i; - int sepq = 0; ssize_t len = 0; - int subtype = varflags & VSTYPE; - int quotes = flags & (EXP_FULL | EXP_CASE | EXP_REDIR); + int sep; int quoted = varflags & VSQUOTE; + int subtype = varflags & VSTYPE; + int discard = subtype == VSPLUS || subtype == VSLENGTH; + int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; int syntax = quoted ? DQSYNTAX : BASESYNTAX; + sep = quoted ? ((flags & EXP_FULL) << CHAR_BIT) : 0; + switch (*name) { case '$': num = rootpid; @@ -6649,7 +6662,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) break; case '@': { char **ap; - int sep; + char sepc; if (quoted && (flags & EXP_FULL)) { /* note: this is not meant as PEOF value */ @@ -6659,39 +6672,20 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) /* fall through */ case '*': sep = ifsset() ? (unsigned char)(ifsval()[0]) : ' '; - i = SIT(sep, syntax); - if (quotes && (i == CCTL || i == CBACK)) - sepq = 1; param: ap = shellparam.p; + sepc = sep; if (!ap) return -1; while ((p = *ap++) != NULL) { - size_t partlen; - - partlen = strlen(p); - len += partlen; - - if (!(subtype == VSPLUS || subtype == VSLENGTH)) - memtodest(p, partlen, syntax, quotes); + len += strtodest(p, syntax, quotes); if (*ap && sep) { - char *q; - len++; - if (subtype == VSPLUS || subtype == VSLENGTH) { - continue; - } - q = expdest; - if (sepq) - STPUTC(CTLESC, q); - /* note: may put NUL despite sep != 0 - * (see sep = 1 << CHAR_BIT above) */ - STPUTC(sep, q); - expdest = q; + memtodest(&sepc, 1, syntax, quotes); } } - return len; + break; } /* case '@' and '*' */ case '0': case '1': @@ -6740,9 +6734,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) if (!p) return -1; - len = strlen(p); - if (!(subtype == VSPLUS || subtype == VSLENGTH)) - memtodest(p, len, syntax, quotes); + len = strtodest(p, syntax, quotes); #if ENABLE_UNICODE_SUPPORT if (subtype == VSLENGTH && len > 0) { reinit_unicode_for_ash(); @@ -6751,10 +6743,10 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) } } #endif - return len; + break; } - if (subtype == VSPLUS || subtype == VSLENGTH) + if (discard) STADJUST(-len, expdest); return len; } @@ -6870,7 +6862,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) patloc = expdest - (char *)stackblock(); if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, startloc, varflags, - /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR), + /* quotes: */ flags & QUOTES_ESC, var_str_list) ) { int amount = expdest - ( -- cgit v1.2.3-55-g6feb From eb6b48ba743d510ad9e6f9c3a8b3899d1eb9b5f3 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:51:35 +0200 Subject: ash: perform tilde expansion in all parameter expansion words Previously tilde expansion was not carried out for =?#% expansion words. Test case: a=~root:~root echo ${a#~root} Old result: /root:/root New result: :/root Based on commit dd721f71 from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta subevalvar 1152 1153 +1 Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 4 ++-- shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right | 1 + shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests | 2 ++ 3 files changed, 5 insertions(+), 2 deletions(-) create mode 100644 shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right create mode 100755 shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests diff --git a/shell/ash.c b/shell/ash.c index a81922add..4c43f1f30 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -6361,8 +6361,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype, // p, varname, strloc, subtype, startloc, varflags, quotes); herefd = -1; - argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, - var_str_list); + argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? + EXP_CASE : 0), var_str_list); STPUTC('\0', expdest); herefd = saveherefd; argbackq = saveargbackq; diff --git a/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right new file mode 100644 index 000000000..2357750c5 --- /dev/null +++ b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.right @@ -0,0 +1 @@ +:/root diff --git a/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests new file mode 100755 index 000000000..6605315d0 --- /dev/null +++ b/shell/ash_test/ash-vars/var-expand-tilde-in-parameter-expansion.tests @@ -0,0 +1,2 @@ +a=~root:~root +echo ${a#~root} -- cgit v1.2.3-55-g6feb From 3df47f9cbbb7f16608cbc642026625cdf7f06aa9 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:53:26 +0200 Subject: ash: do not expand tilde in parameter expansion within quotes Test case: unset a echo "${a:-~root}" Old result: /root New result: ~root Based on commit 170f44d from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta evalvar 598 604 +6 parse_command 1440 1443 +3 localcmd 325 327 +2 readtoken1 3199 3200 +1 argstr 1180 1164 -16 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 4/1 up/down: 12/-16) Total: -4 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 8 +++----- ...var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right | 1 + ...var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests | 2 ++ 3 files changed, 6 insertions(+), 5 deletions(-) create mode 100644 shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right create mode 100755 shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests diff --git a/shell/ash.c b/shell/ash.c index 4c43f1f30..d87166c4f 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5529,7 +5529,7 @@ ash_arith(const char *s) #define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ #define EXP_WORD 0x80 /* expand word in parameter expansion */ -#define EXP_QWORD 0x100 /* expand word in quoted parameter expansion */ +#define EXP_QUOTED 0x100 /* expand word in double quotes */ /* * rmescape() flags */ @@ -6054,7 +6054,7 @@ argstr(char *p, int flags, struct strlist *var_str_list) }; const char *reject = spclchars; int quotes = flags & QUOTES_ESC; - int breakall = flags & EXP_WORD; + int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; int inquotes; size_t length; int startloc; @@ -6072,8 +6072,6 @@ argstr(char *p, int flags, struct strlist *var_str_list) flags &= ~EXP_TILDE; tilde: q = p; - if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD)) - q++; if (*q == '~') p = exptilde(p, q, flags); } @@ -6790,7 +6788,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) if (varlen < 0) { argstr( p, - flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD), + flags | EXP_TILDE | EXP_WORD | (quoted ? EXP_QUOTED : 0), var_str_list ); goto end; diff --git a/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right new file mode 100644 index 000000000..4b9b4f038 --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right @@ -0,0 +1 @@ +~root diff --git a/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests new file mode 100755 index 000000000..d8eb8fc1b --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests @@ -0,0 +1,2 @@ +unset a +echo "${a:-~root}" -- cgit v1.2.3-55-g6feb From 7e4ed267b645090fb576e1c876a88a9c73faabe9 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:54:43 +0200 Subject: ash: remove superfluous code in arithmetic mode Based on commits 1a74845, cfc3d6a and ff13779 from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta evalcommand 1197 1204 +7 localcmd 327 325 -2 readtoken1 3200 3180 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 1/2 up/down: 7/-22) Total: -15 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index d87166c4f..ee7642a64 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -11282,9 +11282,7 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) goto quotemark; case CENDQUOTE: IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) - if (eofmark != NULL && arinest == 0 - && varnest == 0 - ) { + if (eofmark != NULL && varnest == 0) { USTPUTC(c, out); } else { if (dqvarnest == 0) { @@ -11320,7 +11318,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) if (pgetc() == ')') { if (--arinest == 0) { syntax = prevsyntax; - dblquote = (syntax == DQSYNTAX); c = CTLENDARI; } } else { @@ -11645,7 +11642,7 @@ parsesub: { ((unsigned char *)stackblock())[typeloc] = subtype | flags; if (subtype != VSNORMAL) { varnest++; - if (dblquote || arinest) { + if (dblquote) { dqvarnest++; } } -- cgit v1.2.3-55-g6feb From ad88bdee0c382b9f1cbbb2d76cc739afb2790a60 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:56:16 +0200 Subject: ash: remove arithmetic expansion collapsing at parse time Collapsing arithmetic expansion is incorrect when the inner arithmetic expansion is a part of a parameter expansion. Test case: unset a echo $((3 + ${a:=$((4 + 5))})) echo $a Old result: 12 (4 + 5) New result: 12 9 Based on commit bb777a6 from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta readtoken1 3180 3163 -17 Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 18 ++++++------------ ...t-collapse-arithmetic-expansion-at-parse-time.right | 2 ++ ...t-collapse-arithmetic-expansion-at-parse-time.tests | 3 +++ 3 files changed, 11 insertions(+), 12 deletions(-) create mode 100644 shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right create mode 100755 shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests diff --git a/shell/ash.c b/shell/ash.c index ee7642a64..33a477d80 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -11316,9 +11316,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) parenlevel--; } else { if (pgetc() == ')') { + c = CTLENDARI; if (--arinest == 0) { syntax = prevsyntax; - c = CTLENDARI; } } else { /* @@ -11809,18 +11809,12 @@ parsearith: { if (++arinest == 1) { prevsyntax = syntax; syntax = ARISYNTAX; - USTPUTC(CTLARI, out); - if (dblquote) - USTPUTC('"', out); - else - USTPUTC(' ', out); - } else { - /* - * we collapse embedded arithmetic expansion to - * parenthesis, which should be equivalent - */ - USTPUTC('(', out); } + USTPUTC(CTLARI, out); + if (dblquote) + USTPUTC('"', out); + else + USTPUTC(' ', out); goto parsearith_return; } #endif diff --git a/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right new file mode 100644 index 000000000..81a15855c --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right @@ -0,0 +1,2 @@ +12 +9 diff --git a/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests new file mode 100755 index 000000000..e97a08a57 --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests @@ -0,0 +1,3 @@ +unset a +echo $((3 + ${a:=$((4 + 5))})) +echo $a -- cgit v1.2.3-55-g6feb From 549deab5abd59c1ab752754170f69aa2248e72c9 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:57:51 +0200 Subject: ash: move parse-time quote flag detection to run-time Because the parser does not recursively parse parameter expansion with respect to quotes, we can't accurately determine quote status at parse time. This patch works around this by moving the quote detection to run-time where we do interpret it recursively. Test case: foo=\\ echo "<${foo#[\\]}>" Old result: <\> New result: <> Do not quote back slashes in parameter expansions outside quotes. Test case: a=/b/c/* b=\\ echo ${a%$b*} Old result: /b/c/* New result: /b/c/ Based on commits 880d952, 7cfd8be, 0d7d660 and a7c21a6 from git://git.kernel.org/pub/scm/utils/dash/dash.git by Herbert Xu function old new delta argstr 1164 1193 +29 memtodest 147 174 +27 subevalvar 1153 1177 +24 redirect 1279 1282 +3 dolatstr 5 7 +2 static.spclchars 10 9 -1 expandarg 962 960 -2 evalcase 273 271 -2 evalcommand 1204 1197 -7 rmescapes 236 227 -9 preglob 27 8 -19 evalvar 604 582 -22 cmdputs 389 334 -55 readtoken1 3163 3061 -102 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 5/9 up/down: 85/-219) Total: -134 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 164 +++++++++------------ ...es-in-parameter-expansions-outside-quotes.right | 1 + ...es-in-parameter-expansions-outside-quotes.tests | 3 + .../ash-vars/var-runtime-quote-detection.right | 1 + .../ash-vars/var-runtime-quote-detection.tests | 1 + 5 files changed, 72 insertions(+), 98 deletions(-) create mode 100644 shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right create mode 100755 shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests create mode 100644 shell/ash_test/ash-vars/var-runtime-quote-detection.right create mode 100755 shell/ash_test/ash-vars/var-runtime-quote-detection.tests diff --git a/shell/ash.c b/shell/ash.c index 33a477d80..e7e70817f 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -598,8 +598,6 @@ out2str(const char *p) #define CTLVAR ((unsigned char)'\202') /* variable defn */ #define CTLENDVAR ((unsigned char)'\203') #define CTLBACKQ ((unsigned char)'\204') -#define CTLQUOTE 01 /* ored with CTLBACKQ code if in quotes */ -/* CTLBACKQ | CTLQUOTE == '\205' */ #define CTLARI ((unsigned char)'\206') /* arithmetic expression */ #define CTLENDARI ((unsigned char)'\207') #define CTLQUOTEMARK ((unsigned char)'\210') @@ -608,7 +606,6 @@ out2str(const char *p) /* variable substitution byte (follows CTLVAR) */ #define VSTYPE 0x0f /* type of variable substitution */ #define VSNUL 0x10 /* colon--treat the empty string as unset */ -#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ /* values of VSTYPE field */ #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ @@ -628,8 +625,9 @@ out2str(const char *p) #endif static const char dolatstr[] ALIGN1 = { - CTLVAR, VSNORMAL|VSQUOTE, '@', '=', '\0' + CTLQUOTEMARK, CTLVAR, VSNORMAL, '@', '=', CTLQUOTEMARK, '\0' }; +#define DOLATSTRLEN 6 #define NCMD 0 #define NPIPE 1 @@ -865,9 +863,7 @@ trace_puts_quoted(char *s) case '\\': c = '\\'; goto backslash; case CTLESC: c = 'e'; goto backslash; case CTLVAR: c = 'v'; goto backslash; - case CTLVAR+CTLQUOTE: c = 'V'; goto backslash; case CTLBACKQ: c = 'q'; goto backslash; - case CTLBACKQ+CTLQUOTE: c = 'Q'; goto backslash; backslash: putc('\\', tracefile); putc(c, tracefile); @@ -1030,7 +1026,6 @@ sharg(union node *arg, FILE *fp) putc('}', fp); break; case CTLBACKQ: - case CTLBACKQ|CTLQUOTE: putc('$', fp); putc('(', fp); shtree(bqlist->n, -1, NULL, fp); @@ -4413,11 +4408,7 @@ cmdputs(const char *s) str = "${#"; else str = "${"; - if (!(subtype & VSQUOTE) == !(quoted & 1)) - goto dostr; - quoted ^= 1; - c = '"'; - break; + goto dostr; case CTLENDVAR: str = "\"}" + !(quoted & 1); quoted >>= 1; @@ -4426,9 +4417,6 @@ cmdputs(const char *s) case CTLBACKQ: str = "$(...)"; goto dostr; - case CTLBACKQ+CTLQUOTE: - str = "\"$(...)\""; - goto dostr; #if ENABLE_SH_MATH_SUPPORT case CTLARI: str = "$(("; @@ -5526,7 +5514,7 @@ ash_arith(const char *s) #define EXP_VARTILDE 0x4 /* expand tildes in an assignment */ #define EXP_REDIR 0x8 /* file glob for a redirection (1 match only) */ #define EXP_CASE 0x10 /* keeps quotes around for CASE pattern */ -#define EXP_RECORD 0x20 /* need to record arguments for ifs breakup */ +#define EXP_QPAT 0x20 /* pattern in quoted parameter expansion */ #define EXP_VARTILDE2 0x40 /* expand tildes after colons only */ #define EXP_WORD 0x80 /* expand word in parameter expansion */ #define EXP_QUOTED 0x100 /* expand word in double quotes */ @@ -5535,12 +5523,11 @@ ash_arith(const char *s) */ #define RMESCAPE_ALLOC 0x1 /* Allocate a new string */ #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ -#define RMESCAPE_QUOTED 0x4 /* Remove CTLESC unless in quotes */ #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ /* Add CTLESC when necessary. */ -#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_REDIR) +#define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR) /* Do not skip NUL characters. */ #define QUOTES_KEEPNUL EXP_TILDE @@ -5641,13 +5628,11 @@ rmescapes(char *str, int flag) } } - inquotes = (flag & RMESCAPE_QUOTED) ^ RMESCAPE_QUOTED; + inquotes = 0; globbing = flag & RMESCAPE_GLOB; protect_against_glob = globbing; while (*p) { if ((unsigned char)*p == CTLQUOTEMARK) { -// TODO: if no RMESCAPE_QUOTED in flags, inquotes never becomes 0 -// (alternates between RMESCAPE_QUOTED and ~RMESCAPE_QUOTED). Is it ok? // Note: both inquotes and protect_against_glob only affect whether // CTLESC, gets converted to or to \ inquotes = ~inquotes; @@ -5655,16 +5640,15 @@ rmescapes(char *str, int flag) protect_against_glob = globbing; continue; } - if (*p == '\\') { - /* naked back slash */ - protect_against_glob = 0; - goto copy; - } if ((unsigned char)*p == CTLESC) { p++; - if (protect_against_glob && inquotes && *p != '/') { + if (protect_against_glob) { *q++ = '\\'; } + } else if (*p == '\\' && !inquotes) { + /* naked back slash */ + protect_against_glob = 0; + goto copy; } protect_against_glob = globbing; copy: @@ -5685,13 +5669,9 @@ rmescapes(char *str, int flag) * Returns an stalloced string. */ static char * -preglob(const char *pattern, int quoted, int flag) +preglob(const char *pattern, int flag) { - flag |= RMESCAPE_GLOB; - if (quoted) { - flag |= RMESCAPE_QUOTED; - } - return rmescapes((char *)pattern, flag); + return rmescapes((char *)pattern, flag | RMESCAPE_GLOB); } /* @@ -5712,7 +5692,9 @@ memtodest(const char *p, size_t len, int syntax, int quotes) if (c) { int n = SIT(c, syntax); if ((quotes & QUOTES_ESC) && - (n == CCTL || n == CBACK)) + ((n == CCTL) || + (((quotes & EXP_FULL) || syntax != BASESYNTAX) && + n == CBACK))) USTPUTC(CTLESC, q); } else if (!(quotes & QUOTES_KEEPNUL)) continue; @@ -5905,7 +5887,7 @@ evalbackcmd(union node *n, struct backcmd *result) * Expand stuff in backwards quotes. */ static void -expbackq(union node *cmd, int quoted, int quotes) +expbackq(union node *cmd, int flag) { struct backcmd in; int i; @@ -5913,7 +5895,7 @@ expbackq(union node *cmd, int quoted, int quotes) char *p; char *dest; int startloc; - int syntax = quoted ? DQSYNTAX : BASESYNTAX; + int syntax = flag & EXP_QUOTED ? DQSYNTAX : BASESYNTAX; struct stackmark smark; INT_OFF; @@ -5929,7 +5911,7 @@ expbackq(union node *cmd, int quoted, int quotes) if (i == 0) goto read; for (;;) { - memtodest(p, i, syntax, quotes); + memtodest(p, i, syntax, flag & QUOTES_ESC); read: if (in.fd < 0) break; @@ -5953,7 +5935,7 @@ expbackq(union node *cmd, int quoted, int quotes) STUNPUTC(dest); expdest = dest; - if (quoted == 0) + if (!(flag & EXP_QUOTED)) recordregion(startloc, dest - (char *)stackblock(), 0); TRACE(("evalbackq: size:%d:'%.*s'\n", (int)((dest - (char *)stackblock()) - startloc), @@ -5967,11 +5949,10 @@ expbackq(union node *cmd, int quoted, int quotes) * evaluate, place result in (backed up) result, adjust string position. */ static void -expari(int quotes) +expari(int flag) { char *p, *start; int begoff; - int flag; int len; /* ifsfree(); */ @@ -6009,16 +5990,14 @@ expari(int quotes) removerecordregions(begoff); - flag = p[1]; - expdest = p; - if (quotes) - rmescapes(p + 2, 0); + if (flag & QUOTES_ESC) + rmescapes(p + 1, 0); - len = cvtnum(ash_arith(p + 2)); + len = cvtnum(ash_arith(p + 1)); - if (flag != '"') + if (!(flag & EXP_QUOTED)) recordregion(begoff, begoff + len, 0); } #endif @@ -6046,14 +6025,12 @@ argstr(char *p, int flags, struct strlist *var_str_list) CTLESC, CTLVAR, CTLBACKQ, - CTLBACKQ | CTLQUOTE, #if ENABLE_SH_MATH_SUPPORT CTLENDARI, #endif '\0' }; const char *reject = spclchars; - int quotes = flags & QUOTES_ESC; int breakall = (flags & (EXP_WORD | EXP_QUOTED)) == EXP_WORD; int inquotes; size_t length; @@ -6128,19 +6105,14 @@ argstr(char *p, int flags, struct strlist *var_str_list) case CTLENDVAR: /* ??? */ goto breakloop; case CTLQUOTEMARK: + inquotes ^= EXP_QUOTED; /* "$@" syntax adherence hack */ - if (!inquotes - && memcmp(p, dolatstr, 4) == 0 - && ( p[4] == (char)CTLQUOTEMARK - || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK) - ) - ) { - p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1; + if (inquotes && !memcmp(p, dolatstr + 1, DOLATSTRLEN - 1)) { + p = evalvar(p + 1, flags | inquotes, /* var_str_list: */ NULL) + 1; goto start; } - inquotes = !inquotes; addquote: - if (quotes) { + if (flags & QUOTES_ESC) { p--; length++; startloc++; @@ -6149,22 +6121,30 @@ argstr(char *p, int flags, struct strlist *var_str_list) case CTLESC: startloc++; length++; + + /* + * Quoted parameter expansion pattern: remove quote + * unless inside inner quotes or we have a literal + * backslash. + */ + if (((flags | inquotes) & (EXP_QPAT | EXP_QUOTED)) == + EXP_QPAT && *p != '\\') + break; + goto addquote; case CTLVAR: TRACE(("argstr: evalvar('%s')\n", p)); - p = evalvar(p, flags, var_str_list); + p = evalvar(p, flags | inquotes, var_str_list); TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); goto start; case CTLBACKQ: - c = '\0'; - case CTLBACKQ|CTLQUOTE: - expbackq(argbackq->n, c, quotes); + expbackq(argbackq->n, flags | inquotes); argbackq = argbackq->next; goto start; #if ENABLE_SH_MATH_SUPPORT case CTLENDARI: p--; - expari(quotes); + expari(flags | inquotes); goto start; #endif } @@ -6296,13 +6276,13 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) #if ENABLE_ASH_BASH_COMPAT static char * -parse_sub_pattern(char *arg, int varflags) +parse_sub_pattern(char *arg, int quoted) { char *idx, *repl = NULL; unsigned char c; //char *org_arg = arg; - //bb_error_msg("arg:'%s' varflags:%x", arg, varflags); + //bb_error_msg("arg:'%s' quoted:%x", arg, quoted); idx = arg; while (1) { c = *arg; @@ -6318,7 +6298,7 @@ parse_sub_pattern(char *arg, int varflags) *idx++ = c; arg++; /* - * Example: v='ab\c'; echo ${v/\\b/_\\_\z_} + * Example: v='a\bc'; echo ${v/\\b/_\\_\z_} * The result is a_\_z_c (not a\_\_z_c)! * * Enable debug prints in this function and you'll see: @@ -6328,7 +6308,7 @@ parse_sub_pattern(char *arg, int varflags) * IOW: search pattern and replace string treat backslashes * differently! That is the reason why we check repl below: */ - if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE)) + if (c == '\\' && *arg == '\\' && repl && !quoted) arg++; /* skip both '\', not just first one */ } *idx = c; /* NUL */ @@ -6340,9 +6320,10 @@ parse_sub_pattern(char *arg, int varflags) static const char * subevalvar(char *p, char *varname, int strloc, int subtype, - int startloc, int varflags, int quotes, struct strlist *var_str_list) + int startloc, int varflags, int flag, struct strlist *var_str_list) { struct nodelist *saveargbackq = argbackq; + int quotes = flag & QUOTES_ESC; char *startp; char *loc; char *rmesc, *rmescend; @@ -6360,7 +6341,8 @@ subevalvar(char *p, char *varname, int strloc, int subtype, herefd = -1; argstr(p, EXP_TILDE | (subtype != VSASSIGN && subtype != VSQUESTION ? - EXP_CASE : 0), var_str_list); + (flag & (EXP_QUOTED | EXP_QPAT) ? EXP_QPAT : EXP_CASE) : 0), + var_str_list); STPUTC('\0', expdest); herefd = saveherefd; argbackq = saveargbackq; @@ -6471,7 +6453,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, } rmescend--; str = (char *)stackblock() + strloc; - preglob(str, varflags & VSQUOTE, 0); + preglob(str, 0); #if ENABLE_ASH_BASH_COMPAT workloc = expdest - (char *)stackblock(); @@ -6479,7 +6461,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, char *idx, *end; if (!repl) { - repl = parse_sub_pattern(str, varflags); + repl = parse_sub_pattern(str, flag & EXP_QUOTED); //bb_error_msg("repl:'%s'", repl); if (!repl) repl = nullstr; @@ -6618,7 +6600,7 @@ varvalue(char *name, int varflags, int flags, struct strlist *var_str_list) int i; ssize_t len = 0; int sep; - int quoted = varflags & VSQUOTE; + int quoted = flags & EXP_QUOTED; int subtype = varflags & VSTYPE; int discard = subtype == VSPLUS || subtype == VSLENGTH; int quotes = (discard ? 0 : (flags & QUOTES_ESC)) | QUOTES_KEEPNUL; @@ -6758,7 +6740,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) { char varflags; char subtype; - char quoted; + int quoted; char easy; char *var; int patloc; @@ -6767,7 +6749,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) varflags = (unsigned char) *p++; subtype = varflags & VSTYPE; - quoted = varflags & VSQUOTE; + quoted = flags & EXP_QUOTED; var = p; easy = (!quoted || (*var == '@' && shellparam.nparam)); startloc = expdest - (char *)stackblock(); @@ -6788,7 +6770,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) if (varlen < 0) { argstr( p, - flags | EXP_TILDE | EXP_WORD | (quoted ? EXP_QUOTED : 0), + flags | EXP_TILDE | EXP_WORD, var_str_list ); goto end; @@ -6802,7 +6784,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) if (varlen < 0) { if (subevalvar(p, var, /* strloc: */ 0, subtype, startloc, varflags, - /* quotes: */ 0, + /* quotes: */ flags & ~QUOTES_ESC, var_str_list) ) { varflags &= ~VSNUL; @@ -6859,10 +6841,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) STPUTC('\0', expdest); patloc = expdest - (char *)stackblock(); if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, - startloc, varflags, - /* quotes: */ flags & QUOTES_ESC, - var_str_list) - ) { + startloc, varflags, flags, var_str_list)) { int amount = expdest - ( (char *)stackblock() + patloc - 1 ); @@ -6881,7 +6860,7 @@ evalvar(char *p, int flags, struct strlist *var_str_list) unsigned char c = *p++; if (c == CTLESC) p++; - else if (c == CTLBACKQ || c == (CTLBACKQ|CTLQUOTE)) { + else if (c == CTLBACKQ) { if (varlen >= 0) argbackq = argbackq->next; } else if (c == CTLVAR) { @@ -7217,7 +7196,7 @@ expandmeta(struct strlist *str /*, int flag*/) savelastp = exparg.lastp; INT_OFF; - p = preglob(str->text, 0, RMESCAPE_ALLOC | RMESCAPE_HEAP); + p = preglob(str->text, RMESCAPE_ALLOC | RMESCAPE_HEAP); { int i = strlen(str->text); expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */ @@ -7307,7 +7286,7 @@ static void expandhere(union node *arg, int fd) { herefd = fd; - expandarg(arg, (struct arglist *)NULL, 0); + expandarg(arg, (struct arglist *)NULL, EXP_QUOTED); full_write(fd, stackblock(), expdest - (char *)stackblock()); } @@ -7317,7 +7296,7 @@ expandhere(union node *arg, int fd) static int patmatch(char *pattern, const char *string) { - return pmatch(preglob(pattern, 0, 0), string); + return pmatch(preglob(pattern, 0), string); } /* @@ -8570,7 +8549,7 @@ evalfor(union node *n, int flags) arglist.list = NULL; arglist.lastp = &arglist.list; for (argp = n->nfor.args; argp; argp = argp->narg.next) { - expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); + expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); /* XXX */ if (evalskip) goto out; @@ -11260,11 +11239,9 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) && c != '$' && (c != '"' || eofmark != NULL) ) { - USTPUTC(CTLESC, out); USTPUTC('\\', out); } - if (SIT(c, SQSYNTAX) == CCTL) - USTPUTC(CTLESC, out); + USTPUTC(CTLESC, out); USTPUTC(c, out); quotef = 1; } @@ -11637,8 +11614,6 @@ parsesub: { do_pungetc: pungetc(); } - if (dblquote || arinest) - flags |= VSQUOTE; ((unsigned char *)stackblock())[typeloc] = subtype | flags; if (subtype != VSNORMAL) { varnest++; @@ -11792,10 +11767,7 @@ parsebackq: { } parsebackquote = savepbq; exception_handler = savehandler; - if (arinest || dblquote) - USTPUTC(CTLBACKQ | CTLQUOTE, out); - else - USTPUTC(CTLBACKQ, out); + USTPUTC(CTLBACKQ, out); if (oldstyle) goto parsebackq_oldreturn; goto parsebackq_newreturn; @@ -11811,10 +11783,6 @@ parsearith: { syntax = ARISYNTAX; } USTPUTC(CTLARI, out); - if (dblquote) - USTPUTC('"', out); - else - USTPUTC(' ', out); goto parsearith_return; } #endif @@ -12129,7 +12097,7 @@ expandstr(const char *ps) n.narg.text = wordtext; n.narg.backquote = backquotelist; - expandarg(&n, NULL, 0); + expandarg(&n, NULL, EXP_QUOTED); return stackblock(); } #endif diff --git a/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right new file mode 100644 index 000000000..030ebdeb6 --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right @@ -0,0 +1 @@ +/b/c/ diff --git a/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests new file mode 100755 index 000000000..fb9371467 --- /dev/null +++ b/shell/ash_test/ash-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests @@ -0,0 +1,3 @@ +a=/b/c/* +b=\\ +echo ${a%$b*} diff --git a/shell/ash_test/ash-vars/var-runtime-quote-detection.right b/shell/ash_test/ash-vars/var-runtime-quote-detection.right new file mode 100644 index 000000000..b554d9e46 --- /dev/null +++ b/shell/ash_test/ash-vars/var-runtime-quote-detection.right @@ -0,0 +1 @@ +<> diff --git a/shell/ash_test/ash-vars/var-runtime-quote-detection.tests b/shell/ash_test/ash-vars/var-runtime-quote-detection.tests new file mode 100755 index 000000000..e570631fd --- /dev/null +++ b/shell/ash_test/ash-vars/var-runtime-quote-detection.tests @@ -0,0 +1 @@ +foo=\\ echo "<${foo#[\\]}>" -- cgit v1.2.3-55-g6feb From 417622cc2e1ce0f3bc797b3997f5728433c8ccee Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 09:59:14 +0200 Subject: ash: fix breakage of ${v/pat/str} The commit ash: move parse-time quote flag detection to run-time breaks pattern substitution in parameter expansion. Fix this and revise the code so that the different handling of the pattern and the replacement string takes place in rmescapes rather than the separate function parse_sub_pattern. function old new delta rmescapes 227 273 +46 static.qchars 3 4 +1 subevalvar 1177 1157 -20 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/1 up/down: 47/-20) Total: 27 bytes Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- shell/ash.c | 79 ++++++++++++++++++++++--------------------------------------- 1 file changed, 28 insertions(+), 51 deletions(-) diff --git a/shell/ash.c b/shell/ash.c index e7e70817f..282f761fc 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -5525,6 +5525,7 @@ ash_arith(const char *s) #define RMESCAPE_GLOB 0x2 /* Add backslashes for glob */ #define RMESCAPE_GROW 0x8 /* Grow strings instead of stalloc */ #define RMESCAPE_HEAP 0x10 /* Malloc strings instead of stalloc */ +#define RMESCAPE_SLASH 0x20 /* Stop globbing after slash */ /* Add CTLESC when necessary. */ #define QUOTES_ESC (EXP_FULL | EXP_CASE | EXP_QPAT | EXP_REDIR) @@ -5594,14 +5595,16 @@ esclen(const char *start, const char *p) static char * rmescapes(char *str, int flag) { - static const char qchars[] ALIGN1 = { CTLESC, CTLQUOTEMARK, '\0' }; + static const char qchars[] ALIGN1 = { + IF_ASH_BASH_COMPAT('/',) CTLESC, CTLQUOTEMARK, '\0' }; char *p, *q, *r; unsigned inquotes; unsigned protect_against_glob; unsigned globbing; + IF_ASH_BASH_COMPAT(unsigned slash = flag & RMESCAPE_SLASH;) - p = strpbrk(str, qchars); + p = strpbrk(str, qchars IF_ASH_BASH_COMPAT(+ !slash)); if (!p) return str; @@ -5650,6 +5653,13 @@ rmescapes(char *str, int flag) protect_against_glob = 0; goto copy; } +#if ENABLE_ASH_BASH_COMPAT + else if (*p == '/' && slash) { + /* stop handling globbing and mark location of slash */ + globbing = slash = 0; + *p = CTLESC; + } +#endif protect_against_glob = globbing; copy: *q++ = *p++; @@ -6274,50 +6284,6 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); } -#if ENABLE_ASH_BASH_COMPAT -static char * -parse_sub_pattern(char *arg, int quoted) -{ - char *idx, *repl = NULL; - unsigned char c; - - //char *org_arg = arg; - //bb_error_msg("arg:'%s' quoted:%x", arg, quoted); - idx = arg; - while (1) { - c = *arg; - if (!c) - break; - if (c == '/') { - /* Only the first '/' seen is our separator */ - if (!repl) { - repl = idx + 1; - c = '\0'; - } - } - *idx++ = c; - arg++; - /* - * Example: v='a\bc'; echo ${v/\\b/_\\_\z_} - * The result is a_\_z_c (not a\_\_z_c)! - * - * Enable debug prints in this function and you'll see: - * ash: arg:'\\b/_\\_z_' varflags:d - * ash: pattern:'\\b' repl:'_\_z_' - * That is, \\b is interpreted as \\b, but \\_ as \_! - * IOW: search pattern and replace string treat backslashes - * differently! That is the reason why we check repl below: - */ - if (c == '\\' && *arg == '\\' && repl && !quoted) - arg++; /* skip both '\', not just first one */ - } - *idx = c; /* NUL */ - //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl); - - return repl; -} -#endif /* ENABLE_ASH_BASH_COMPAT */ - static const char * subevalvar(char *p, char *varname, int strloc, int subtype, int startloc, int varflags, int flag, struct strlist *var_str_list) @@ -6328,7 +6294,7 @@ subevalvar(char *p, char *varname, int strloc, int subtype, char *loc; char *rmesc, *rmescend; char *str; - IF_ASH_BASH_COMPAT(const char *repl = NULL;) + IF_ASH_BASH_COMPAT(char *repl = NULL;) IF_ASH_BASH_COMPAT(int pos, len, orig_len;) int saveherefd = herefd; int amount, resetloc; @@ -6453,7 +6419,17 @@ subevalvar(char *p, char *varname, int strloc, int subtype, } rmescend--; str = (char *)stackblock() + strloc; - preglob(str, 0); + /* + * Example: v='a\bc'; echo ${v/\\b/_\\_\z_} + * The result is a_\_z_c (not a\_\_z_c)! + * + * The search pattern and replace string treat backslashes differently! + * RMESCAPE_SLASH causes preglob to work differently on the pattern + * and string. It's only used on the first call. + */ + preglob(str, IF_ASH_BASH_COMPAT( + (subtype == VSREPLACE || subtype == VSREPLACEALL) && !repl ? + RMESCAPE_SLASH :) 0); #if ENABLE_ASH_BASH_COMPAT workloc = expdest - (char *)stackblock(); @@ -6461,11 +6437,12 @@ subevalvar(char *p, char *varname, int strloc, int subtype, char *idx, *end; if (!repl) { - repl = parse_sub_pattern(str, flag & EXP_QUOTED); - //bb_error_msg("repl:'%s'", repl); - if (!repl) + if ((repl=strchr(str, CTLESC))) + *repl++ = '\0'; + else repl = nullstr; } + //bb_error_msg("str:'%s' repl:'%s'", str, repl); /* If there's no pattern to match, return the expansion unmolested */ if (str[0] == '\0') -- cgit v1.2.3-55-g6feb From 523006798c45307830eaae9d29ca9fdc1a1b50af Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Mon, 18 May 2015 10:13:21 +0200 Subject: testsuite: add some tests for ash Signed-off-by: Ron Yorston Signed-off-by: Denys Vlasenko --- .../ash-vars/var-pattern-replacement-in-parameter-expansion-1.right | 1 + .../ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests | 2 ++ .../ash-vars/var-pattern-replacement-in-parameter-expansion-2.right | 1 + .../ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests | 2 ++ .../ash-vars/var-pattern-replacement-in-parameter-expansion-3.right | 1 + .../ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests | 2 ++ .../ash-vars/var-pattern-replacement-in-parameter-expansion-4.right | 1 + .../ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests | 2 ++ .../ash-vars/var-pattern-replacement-in-parameter-expansion-5.right | 1 + .../ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests | 2 ++ 10 files changed, 15 insertions(+) create mode 100644 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.right create mode 100755 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests create mode 100644 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.right create mode 100755 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests create mode 100644 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.right create mode 100755 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests create mode 100644 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.right create mode 100755 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests create mode 100644 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.right create mode 100755 shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.right new file mode 100644 index 000000000..2da327222 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.right @@ -0,0 +1 @@ +a_\_z_c diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests new file mode 100755 index 000000000..e4529c631 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-1.tests @@ -0,0 +1,2 @@ +v="a\bc" +echo ${v/\\b/_\\_\z_} diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.right new file mode 100644 index 000000000..7447c0a04 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.right @@ -0,0 +1 @@ +ax/yc diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests new file mode 100755 index 000000000..2db1db897 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-2.tests @@ -0,0 +1,2 @@ +v="abc" +echo ${v/b/x/y} diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.right new file mode 100644 index 000000000..5ea5ff892 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.right @@ -0,0 +1 @@ +axcabc diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests new file mode 100755 index 000000000..0935e4509 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-3.tests @@ -0,0 +1,2 @@ +v="abcabc" +echo ${v/b/x} diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.right new file mode 100644 index 000000000..46dd750c1 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.right @@ -0,0 +1 @@ +axcaxc diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests new file mode 100755 index 000000000..d8de84347 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-4.tests @@ -0,0 +1,2 @@ +v="abcabc" +echo ${v//b/x} diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.right b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.right new file mode 100644 index 000000000..699b27b0c --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.right @@ -0,0 +1 @@ +axc diff --git a/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests new file mode 100755 index 000000000..552388877 --- /dev/null +++ b/shell/ash_test/ash-vars/var-pattern-replacement-in-parameter-expansion-5.tests @@ -0,0 +1,2 @@ +v="ab/c" +echo ${v/b\//x} -- cgit v1.2.3-55-g6feb From 9a595bb36ded308e6d4336aef2c1cd3ac738a398 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Mon, 18 May 2015 10:23:16 +0200 Subject: hush: add recent ash tests to hush testsuite too (they all pass for hush) Signed-off-by: Denys Vlasenko --- .../var-do-not-collapse-arithmetic-expansion-at-parse-time.right | 2 ++ .../var-do-not-collapse-arithmetic-expansion-at-parse-time.tests | 3 +++ .../var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right | 1 + .../var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests | 2 ++ ...-not-quote-backslashes-in-parameter-expansions-outside-quotes.right | 1 + ...-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests | 3 +++ .../hush-vars/var-pattern-replacement-in-parameter-expansion-1.right | 1 + .../hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests | 2 ++ .../hush-vars/var-pattern-replacement-in-parameter-expansion-2.right | 1 + .../hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests | 2 ++ .../hush-vars/var-pattern-replacement-in-parameter-expansion-3.right | 1 + .../hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests | 2 ++ .../hush-vars/var-pattern-replacement-in-parameter-expansion-4.right | 1 + .../hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests | 2 ++ .../hush-vars/var-pattern-replacement-in-parameter-expansion-5.right | 1 + .../hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests | 2 ++ shell/hush_test/hush-vars/var-runtime-quote-detection.right | 1 + shell/hush_test/hush-vars/var-runtime-quote-detection.tests | 1 + 18 files changed, 29 insertions(+) create mode 100644 shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right create mode 100755 shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests create mode 100644 shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right create mode 100755 shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests create mode 100644 shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right create mode 100755 shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests create mode 100644 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.right create mode 100755 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests create mode 100644 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.right create mode 100755 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests create mode 100644 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.right create mode 100755 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests create mode 100644 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.right create mode 100755 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests create mode 100644 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.right create mode 100755 shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests create mode 100644 shell/hush_test/hush-vars/var-runtime-quote-detection.right create mode 100755 shell/hush_test/hush-vars/var-runtime-quote-detection.tests diff --git a/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right new file mode 100644 index 000000000..81a15855c --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.right @@ -0,0 +1,2 @@ +12 +9 diff --git a/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests new file mode 100755 index 000000000..e97a08a57 --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-collapse-arithmetic-expansion-at-parse-time.tests @@ -0,0 +1,3 @@ +unset a +echo $((3 + ${a:=$((4 + 5))})) +echo $a diff --git a/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right new file mode 100644 index 000000000..4b9b4f038 --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.right @@ -0,0 +1 @@ +~root diff --git a/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests new file mode 100755 index 000000000..d8eb8fc1b --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-expand-tilde-in-parameter-expansion-in-quotes.tests @@ -0,0 +1,2 @@ +unset a +echo "${a:-~root}" diff --git a/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right b/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right new file mode 100644 index 000000000..030ebdeb6 --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.right @@ -0,0 +1 @@ +/b/c/ diff --git a/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests b/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests new file mode 100755 index 000000000..fb9371467 --- /dev/null +++ b/shell/hush_test/hush-vars/var-do-not-quote-backslashes-in-parameter-expansions-outside-quotes.tests @@ -0,0 +1,3 @@ +a=/b/c/* +b=\\ +echo ${a%$b*} diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.right new file mode 100644 index 000000000..2da327222 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.right @@ -0,0 +1 @@ +a_\_z_c diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests new file mode 100755 index 000000000..e4529c631 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-1.tests @@ -0,0 +1,2 @@ +v="a\bc" +echo ${v/\\b/_\\_\z_} diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.right new file mode 100644 index 000000000..7447c0a04 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.right @@ -0,0 +1 @@ +ax/yc diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests new file mode 100755 index 000000000..2db1db897 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-2.tests @@ -0,0 +1,2 @@ +v="abc" +echo ${v/b/x/y} diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.right new file mode 100644 index 000000000..5ea5ff892 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.right @@ -0,0 +1 @@ +axcabc diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests new file mode 100755 index 000000000..0935e4509 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-3.tests @@ -0,0 +1,2 @@ +v="abcabc" +echo ${v/b/x} diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.right new file mode 100644 index 000000000..46dd750c1 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.right @@ -0,0 +1 @@ +axcaxc diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests new file mode 100755 index 000000000..d8de84347 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-4.tests @@ -0,0 +1,2 @@ +v="abcabc" +echo ${v//b/x} diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.right b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.right new file mode 100644 index 000000000..699b27b0c --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.right @@ -0,0 +1 @@ +axc diff --git a/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests new file mode 100755 index 000000000..552388877 --- /dev/null +++ b/shell/hush_test/hush-vars/var-pattern-replacement-in-parameter-expansion-5.tests @@ -0,0 +1,2 @@ +v="ab/c" +echo ${v/b\//x} diff --git a/shell/hush_test/hush-vars/var-runtime-quote-detection.right b/shell/hush_test/hush-vars/var-runtime-quote-detection.right new file mode 100644 index 000000000..b554d9e46 --- /dev/null +++ b/shell/hush_test/hush-vars/var-runtime-quote-detection.right @@ -0,0 +1 @@ +<> diff --git a/shell/hush_test/hush-vars/var-runtime-quote-detection.tests b/shell/hush_test/hush-vars/var-runtime-quote-detection.tests new file mode 100755 index 000000000..e570631fd --- /dev/null +++ b/shell/hush_test/hush-vars/var-runtime-quote-detection.tests @@ -0,0 +1 @@ +foo=\\ echo "<${foo#[\\]}>" -- cgit v1.2.3-55-g6feb