aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-03-05 04:59:25 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2020-03-05 04:59:25 +0000
commit2d39270127fafc8b2b7f98834f47f536d768bdfe (patch)
tree4dc72a4a153486d86e427ac07b3eeb38b47e3eb3
parentc4623c7396c6cb8437c815c4803eb5f3488a2bee (diff)
parent5cd86c891268b8d4480c60208f14aa0240094075 (diff)
downloadtoybox-android11-qpr1-release.tar.gz
Change-Id: I8312d38c67ca2e57ade01e1ca38bc3dbb86da9bf
-rw-r--r--Config.in42
-rw-r--r--android/device/generated/flags.h8
-rw-r--r--android/device/generated/globals.h7
-rw-r--r--android/device/generated/help.h2
-rw-r--r--android/linux/generated/flags.h8
-rw-r--r--android/linux/generated/globals.h7
-rw-r--r--android/linux/generated/help.h2
-rw-r--r--android/mac/generated/flags.h8
-rw-r--r--android/mac/generated/globals.h7
-rw-r--r--android/mac/generated/help.h2
-rw-r--r--kconfig/macos_miniconfig1
-rw-r--r--lib/env.c7
-rwxr-xr-xrun-tests-on-android.sh7
-rwxr-xr-xscripts/cross.sh1
-rwxr-xr-xscripts/genconfig.sh2
-rwxr-xr-xscripts/make.sh13
-rwxr-xr-xscripts/mcm-buildall.sh88
-rw-r--r--scripts/mkflags.c6
-rwxr-xr-xscripts/mkroot.sh52
-rwxr-xr-xtests/sh.test136
-rw-r--r--toys/net/ping.c52
-rw-r--r--toys/other/lsattr.c11
-rw-r--r--toys/pending/wget.c3
-rw-r--r--toys/posix/patch.c96
-rw-r--r--toys/posix/ps.c5
25 files changed, 393 insertions, 180 deletions
diff --git a/Config.in b/Config.in
index 67583372..362b22f3 100644
--- a/Config.in
+++ b/Config.in
@@ -165,22 +165,34 @@ config TOYBOX_UID_USR
help
When commands like useradd/groupadd allocate user IDs, start here.
-config TOYBOX_MUSL_NOMMU_IS_BROKEN
- bool "Workaround for musl-libc breakage on nommu systems."
+config TOYBOX_FORCE_NOMMU
+ bool "Enable nommu support when the build can't detect it."
default n
help
- When using musl-libc on a nommu system, you'll need to say "y" here.
-
- Although uclibc lets you detect support for things like fork() and
- daemon() at compile time, musl intentionally includes broken versions
- that always return -ENOSYS on nommu systems, and goes out of its way
- to prevent any cross-compile compatible compile-time probes for a
- nommu system. (It doesn't even #define __MUSL__ in features.h.)
-
- Musl does this despite the fact that a nommu system can't even run
- standard ELF binaries, and requires specially packaged executables.
- So our only choice is to manually provide a musl nommu bug workaround
- you can manually select to enable (larger, slower) nommu support with
- musl.
+ When using musl-libc on a nommu system, you'll need to say "y" here
+ unless you used the patch in the mcm-buildall.sh script. You can also
+ say "y" here to test the nommu codepaths on an mmu system.
+
+ A nommu system can't use fork(), it can only vfork() which suspends
+ the parent until the child calls exec() or exits. When a program
+ needs a second instance of itself to run specific code at the same
+ time as the parent, it must use a more complicated approach (such as
+ exec("/proc/self/exe") then pass data to the new child through a pipe)
+ which is larger and slower, especially for things like toysh subshells
+ that need to duplicate a lot of internal state in the child process
+ fork() gives you for free.
+
+ Libraries like uclibc omit fork() on nommu systems, allowing
+ compile-time probes to select which codepath to use. But musl
+ intentionally includes a broken version of fork() that always returns
+ -ENOSYS on nommu systems, and goes out of its way to prevent any
+ cross-compile compatible compile-time probes for a nommu system.
+ (It doesn't even #define __MUSL__ in features.h.) Musl does this
+ despite the fact that a nommu system can't even run standard ELF
+ binaries (requiring specially packaged executables) because it wants
+ to force every program to either include all nommu code in every
+ instance ever built, or drop nommu support altogether.
+
+ Building a toolchain scripts/mcm-buildall.sh patches musl to fix this.
endmenu
diff --git a/android/device/generated/flags.h b/android/device/generated/flags.h
index 155cfc9f..fcf9e60d 100644
--- a/android/device/generated/flags.h
+++ b/android/device/generated/flags.h
@@ -2,7 +2,7 @@
#undef FORCED_FLAGLL
#ifdef FORCE_FLAGS
#define FORCED_FLAG 1
-#define FORCED_FLAGLL 1LL
+#define FORCED_FLAGLL 1ULL
#else
#define FORCED_FLAG 0
#define FORCED_FLAGLL 0
@@ -3849,7 +3849,7 @@
#define FLAG_C (FORCED_FLAG<<28)
#define FLAG_D (FORCED_FLAG<<29)
#define FLAG_E (FORCED_FLAG<<30)
-#define FLAG_F (FORCED_FLAG<<31)
+#define FLAG_F (FORCED_FLAGLL<<31)
#define FLAG_G (FORCED_FLAGLL<<32)
#define FLAG_H (FORCED_FLAGLL<<33)
#define FLAG_I (FORCED_FLAGLL<<34)
@@ -4343,7 +4343,7 @@
#define FLAG_S (1<<28)
#define FLAG_exclude_dir (1<<29)
#define FLAG_color (1<<30)
-#define FLAG_line_buffered (1<<31)
+#define FLAG_line_buffered (1LL<<31)
#endif
#ifdef FOR_groupadd
@@ -4804,7 +4804,7 @@
#define FLAG_g (1<<28)
#define FLAG_Z (1<<29)
#define FLAG_show_control_chars (1<<30)
-#define FLAG_full_time (1<<31)
+#define FLAG_full_time (1LL<<31)
#define FLAG_color (1LL<<32)
#endif
diff --git a/android/device/generated/globals.h b/android/device/generated/globals.h
index 6b93ddd9..4a201bf0 100644
--- a/android/device/generated/globals.h
+++ b/android/device/generated/globals.h
@@ -314,6 +314,8 @@ struct lsattr_data {
long p;
long add, rm, set;
+ // !add and !rm tell us whether they were used, but `chattr =` is meaningful.
+ int have_set;
};
// toys/other/lspci.c
@@ -1324,9 +1326,8 @@ struct patch_data {
char *i, *d;
long p, g, F;
- struct double_list *current_hunk;
- long oldline, oldlen, newline, newlen;
- long linenum;
+ void *current_hunk;
+ long oldline, oldlen, newline, newlen, linenum, outnum;
int context, state, filein, fileout, filepatch, hunknum;
char *tempname;
};
diff --git a/android/device/generated/help.h b/android/device/generated/help.h
index 863a9df0..55613a5f 100644
--- a/android/device/generated/help.h
+++ b/android/device/generated/help.h
@@ -1,4 +1,4 @@
-#define HELP_toybox_musl_nommu_is_broken "When using musl-libc on a nommu system, you'll need to say \"y\" here.\n\nAlthough uclibc lets you detect support for things like fork() and\ndaemon() at compile time, musl intentionally includes broken versions\nthat always return -ENOSYS on nommu systems, and goes out of its way\nto prevent any cross-compile compatible compile-time probes for a\nnommu system. (It doesn't even #define __MUSL__ in features.h.)\n\nMusl does this despite the fact that a nommu system can't even run\nstandard ELF binaries, and requires specially packaged executables.\nSo our only choice is to manually provide a musl nommu bug workaround\nyou can manually select to enable (larger, slower) nommu support with\nmusl."
+#define HELP_toybox_force_nommu "When using musl-libc on a nommu system, you'll need to say \"y\" here\nunless you used the patch in the mcm-buildall.sh script. You can also\nsay \"y\" here to test the nommu codepaths on an mmu system.\n\nA nommu system can't use fork(), it can only vfork() which suspends\nthe parent until the child calls exec() or exits. When a program\nneeds a second instance of itself to run specific code at the same\ntime as the parent, it must use a more complicated approach (such as\nexec(\"/proc/self/exe\") then pass data to the new child through a pipe)\nwhich is larger and slower, especially for things like toysh subshells\nthat need to duplicate a lot of internal state in the child process\nfork() gives you for free.\n\nLibraries like uclibc omit fork() on nommu systems, allowing\ncompile-time probes to select which codepath to use. But musl\nintentionally includes a broken version of fork() that always returns\n-ENOSYS on nommu systems, and goes out of its way to prevent any\ncross-compile compatible compile-time probes for a nommu system.\n(It doesn't even #define __MUSL__ in features.h.) Musl does this\ndespite the fact that a nommu system can't even run standard ELF\nbinaries (requiring specially packaged executables) because it wants\nto force every program to either include all nommu code in every\ninstance ever built, or drop nommu support altogether.\n\nBuilding a toolchain scripts/mcm-buildall.sh patches musl to fix this."
#define HELP_toybox_uid_usr "When commands like useradd/groupadd allocate user IDs, start here."
diff --git a/android/linux/generated/flags.h b/android/linux/generated/flags.h
index 63c91821..a87b9352 100644
--- a/android/linux/generated/flags.h
+++ b/android/linux/generated/flags.h
@@ -2,7 +2,7 @@
#undef FORCED_FLAGLL
#ifdef FORCE_FLAGS
#define FORCED_FLAG 1
-#define FORCED_FLAGLL 1LL
+#define FORCED_FLAGLL 1ULL
#else
#define FORCED_FLAG 0
#define FORCED_FLAGLL 0
@@ -3849,7 +3849,7 @@
#define FLAG_C (FORCED_FLAG<<28)
#define FLAG_D (FORCED_FLAG<<29)
#define FLAG_E (FORCED_FLAG<<30)
-#define FLAG_F (FORCED_FLAG<<31)
+#define FLAG_F (FORCED_FLAGLL<<31)
#define FLAG_G (FORCED_FLAGLL<<32)
#define FLAG_H (FORCED_FLAGLL<<33)
#define FLAG_I (FORCED_FLAGLL<<34)
@@ -4343,7 +4343,7 @@
#define FLAG_S (1<<28)
#define FLAG_exclude_dir (1<<29)
#define FLAG_color (1<<30)
-#define FLAG_line_buffered (1<<31)
+#define FLAG_line_buffered (1LL<<31)
#endif
#ifdef FOR_groupadd
@@ -4804,7 +4804,7 @@
#define FLAG_g (1<<28)
#define FLAG_Z (1<<29)
#define FLAG_show_control_chars (1<<30)
-#define FLAG_full_time (1<<31)
+#define FLAG_full_time (1LL<<31)
#define FLAG_color (1LL<<32)
#endif
diff --git a/android/linux/generated/globals.h b/android/linux/generated/globals.h
index 6b93ddd9..4a201bf0 100644
--- a/android/linux/generated/globals.h
+++ b/android/linux/generated/globals.h
@@ -314,6 +314,8 @@ struct lsattr_data {
long p;
long add, rm, set;
+ // !add and !rm tell us whether they were used, but `chattr =` is meaningful.
+ int have_set;
};
// toys/other/lspci.c
@@ -1324,9 +1326,8 @@ struct patch_data {
char *i, *d;
long p, g, F;
- struct double_list *current_hunk;
- long oldline, oldlen, newline, newlen;
- long linenum;
+ void *current_hunk;
+ long oldline, oldlen, newline, newlen, linenum, outnum;
int context, state, filein, fileout, filepatch, hunknum;
char *tempname;
};
diff --git a/android/linux/generated/help.h b/android/linux/generated/help.h
index 6f1f4eb5..6621ed1c 100644
--- a/android/linux/generated/help.h
+++ b/android/linux/generated/help.h
@@ -1,4 +1,4 @@
-#define HELP_toybox_musl_nommu_is_broken "When using musl-libc on a nommu system, you'll need to say \"y\" here.\n\nAlthough uclibc lets you detect support for things like fork() and\ndaemon() at compile time, musl intentionally includes broken versions\nthat always return -ENOSYS on nommu systems, and goes out of its way\nto prevent any cross-compile compatible compile-time probes for a\nnommu system. (It doesn't even #define __MUSL__ in features.h.)\n\nMusl does this despite the fact that a nommu system can't even run\nstandard ELF binaries, and requires specially packaged executables.\nSo our only choice is to manually provide a musl nommu bug workaround\nyou can manually select to enable (larger, slower) nommu support with\nmusl."
+#define HELP_toybox_force_nommu "When using musl-libc on a nommu system, you'll need to say \"y\" here\nunless you used the patch in the mcm-buildall.sh script. You can also\nsay \"y\" here to test the nommu codepaths on an mmu system.\n\nA nommu system can't use fork(), it can only vfork() which suspends\nthe parent until the child calls exec() or exits. When a program\nneeds a second instance of itself to run specific code at the same\ntime as the parent, it must use a more complicated approach (such as\nexec(\"/proc/self/exe\") then pass data to the new child through a pipe)\nwhich is larger and slower, especially for things like toysh subshells\nthat need to duplicate a lot of internal state in the child process\nfork() gives you for free.\n\nLibraries like uclibc omit fork() on nommu systems, allowing\ncompile-time probes to select which codepath to use. But musl\nintentionally includes a broken version of fork() that always returns\n-ENOSYS on nommu systems, and goes out of its way to prevent any\ncross-compile compatible compile-time probes for a nommu system.\n(It doesn't even #define __MUSL__ in features.h.) Musl does this\ndespite the fact that a nommu system can't even run standard ELF\nbinaries (requiring specially packaged executables) because it wants\nto force every program to either include all nommu code in every\ninstance ever built, or drop nommu support altogether.\n\nBuilding a toolchain scripts/mcm-buildall.sh patches musl to fix this."
#define HELP_toybox_uid_usr "When commands like useradd/groupadd allocate user IDs, start here."
diff --git a/android/mac/generated/flags.h b/android/mac/generated/flags.h
index 81598978..7b026e67 100644
--- a/android/mac/generated/flags.h
+++ b/android/mac/generated/flags.h
@@ -2,7 +2,7 @@
#undef FORCED_FLAGLL
#ifdef FORCE_FLAGS
#define FORCED_FLAG 1
-#define FORCED_FLAGLL 1LL
+#define FORCED_FLAGLL 1ULL
#else
#define FORCED_FLAG 0
#define FORCED_FLAGLL 0
@@ -3849,7 +3849,7 @@
#define FLAG_C (FORCED_FLAG<<28)
#define FLAG_D (FORCED_FLAG<<29)
#define FLAG_E (FORCED_FLAG<<30)
-#define FLAG_F (FORCED_FLAG<<31)
+#define FLAG_F (FORCED_FLAGLL<<31)
#define FLAG_G (FORCED_FLAGLL<<32)
#define FLAG_H (FORCED_FLAGLL<<33)
#define FLAG_I (FORCED_FLAGLL<<34)
@@ -4343,7 +4343,7 @@
#define FLAG_S (1<<28)
#define FLAG_exclude_dir (1<<29)
#define FLAG_color (1<<30)
-#define FLAG_line_buffered (1<<31)
+#define FLAG_line_buffered (1LL<<31)
#endif
#ifdef FOR_groupadd
@@ -4804,7 +4804,7 @@
#define FLAG_g (1<<28)
#define FLAG_Z (1<<29)
#define FLAG_show_control_chars (1<<30)
-#define FLAG_full_time (1<<31)
+#define FLAG_full_time (1LL<<31)
#define FLAG_color (1LL<<32)
#endif
diff --git a/android/mac/generated/globals.h b/android/mac/generated/globals.h
index 6b93ddd9..4a201bf0 100644
--- a/android/mac/generated/globals.h
+++ b/android/mac/generated/globals.h
@@ -314,6 +314,8 @@ struct lsattr_data {
long p;
long add, rm, set;
+ // !add and !rm tell us whether they were used, but `chattr =` is meaningful.
+ int have_set;
};
// toys/other/lspci.c
@@ -1324,9 +1326,8 @@ struct patch_data {
char *i, *d;
long p, g, F;
- struct double_list *current_hunk;
- long oldline, oldlen, newline, newlen;
- long linenum;
+ void *current_hunk;
+ long oldline, oldlen, newline, newlen, linenum, outnum;
int context, state, filein, fileout, filepatch, hunknum;
char *tempname;
};
diff --git a/android/mac/generated/help.h b/android/mac/generated/help.h
index 6f1f4eb5..6621ed1c 100644
--- a/android/mac/generated/help.h
+++ b/android/mac/generated/help.h
@@ -1,4 +1,4 @@
-#define HELP_toybox_musl_nommu_is_broken "When using musl-libc on a nommu system, you'll need to say \"y\" here.\n\nAlthough uclibc lets you detect support for things like fork() and\ndaemon() at compile time, musl intentionally includes broken versions\nthat always return -ENOSYS on nommu systems, and goes out of its way\nto prevent any cross-compile compatible compile-time probes for a\nnommu system. (It doesn't even #define __MUSL__ in features.h.)\n\nMusl does this despite the fact that a nommu system can't even run\nstandard ELF binaries, and requires specially packaged executables.\nSo our only choice is to manually provide a musl nommu bug workaround\nyou can manually select to enable (larger, slower) nommu support with\nmusl."
+#define HELP_toybox_force_nommu "When using musl-libc on a nommu system, you'll need to say \"y\" here\nunless you used the patch in the mcm-buildall.sh script. You can also\nsay \"y\" here to test the nommu codepaths on an mmu system.\n\nA nommu system can't use fork(), it can only vfork() which suspends\nthe parent until the child calls exec() or exits. When a program\nneeds a second instance of itself to run specific code at the same\ntime as the parent, it must use a more complicated approach (such as\nexec(\"/proc/self/exe\") then pass data to the new child through a pipe)\nwhich is larger and slower, especially for things like toysh subshells\nthat need to duplicate a lot of internal state in the child process\nfork() gives you for free.\n\nLibraries like uclibc omit fork() on nommu systems, allowing\ncompile-time probes to select which codepath to use. But musl\nintentionally includes a broken version of fork() that always returns\n-ENOSYS on nommu systems, and goes out of its way to prevent any\ncross-compile compatible compile-time probes for a nommu system.\n(It doesn't even #define __MUSL__ in features.h.) Musl does this\ndespite the fact that a nommu system can't even run standard ELF\nbinaries (requiring specially packaged executables) because it wants\nto force every program to either include all nommu code in every\ninstance ever built, or drop nommu support altogether.\n\nBuilding a toolchain scripts/mcm-buildall.sh patches musl to fix this."
#define HELP_toybox_uid_usr "When commands like useradd/groupadd allocate user IDs, start here."
diff --git a/kconfig/macos_miniconfig b/kconfig/macos_miniconfig
index ac4af149..b9bf6a3a 100644
--- a/kconfig/macos_miniconfig
+++ b/kconfig/macos_miniconfig
@@ -84,7 +84,6 @@ CONFIG_FACTOR=y
CONFIG_FLOCK=y
CONFIG_FMT=y
CONFIG_HELP=y
-CONFIG_HELP_EXTRAS=y
CONFIG_HEXEDIT=y
CONFIG_PRINTENV=y
CONFIG_PWDX=y
diff --git a/lib/env.c b/lib/env.c
index 92cc811f..614a504c 100644
--- a/lib/env.c
+++ b/lib/env.c
@@ -2,7 +2,7 @@
#include "toys.h"
-// In libc, populated by start code,used by getenv() and exec() and friends.
+// In libc, populated by start code, used by getenv() and exec() and friends.
extern char **environ;
// Returns the number of bytes taken by the environment variables. For use
@@ -26,9 +26,8 @@ void xclearenv(void)
int i;
for (i = 0; environ[i]; i++) if (i>=toys.envc) free(environ[i]);
- free(environ);
- }
- toys.envc = 0;
+ } else environ = xmalloc(256*sizeof(char *));
+ toys.envc = 1;
*environ = 0;
}
diff --git a/run-tests-on-android.sh b/run-tests-on-android.sh
index 744fc8b4..d85cca31 100755
--- a/run-tests-on-android.sh
+++ b/run-tests-on-android.sh
@@ -62,12 +62,7 @@ test_toy() {
elif [ "$non_toy" = "true" ]; then
non_toy_failures="$non_toy_failures $toy"
else
- # The chattr tests are currently broken on cuttlefish. Working on it...
- if [[ "$toy" = "chattr" ]]; then
- non_toy_failures="$non_toy_failures $toy"
- else
- failures="$failures $toy"
- fi
+ failures="$failures $toy"
fi
}
diff --git a/scripts/cross.sh b/scripts/cross.sh
index 6dac8ec0..2570713d 100755
--- a/scripts/cross.sh
+++ b/scripts/cross.sh
@@ -35,6 +35,7 @@ then
do
{
export TARGET
+ echo -en "\033]2;$TARGET $*\007"
"$0" $TARGET "$@" 2>&1 || mv cross-log-$TARGET.{txt,failed}
} | tee cross-log-$TARGET.txt
done
diff --git a/scripts/genconfig.sh b/scripts/genconfig.sh
index cc2bd764..b5637f86 100755
--- a/scripts/genconfig.sh
+++ b/scripts/genconfig.sh
@@ -92,7 +92,7 @@ EOF
#include <unistd.h>
int main(int argc, char *argv[]) { return fork(); }
EOF
- echo -e '\tdepends on !TOYBOX_MUSL_NOMMU_IS_BROKEN'
+ echo -e '\tdepends on !TOYBOX_FORCE_NOMMU'
probesymbol TOYBOX_PRLIMIT << EOF
#include <sys/types.h>
diff --git a/scripts/make.sh b/scripts/make.sh
index 538ba121..e4333ba2 100755
--- a/scripts/make.sh
+++ b/scripts/make.sh
@@ -3,10 +3,15 @@
# Grab default values for $CFLAGS and such.
if [ ! -z "$ASAN" ]; then
- # Turn ASan on.
- CFLAGS="-fsanitize=address $CFLAGS"
- # Optional, but effectively necessary if you want useful backtraces.
- CFLAGS="-O1 -g -fno-omit-frame-pointer -fno-optimize-sibling-calls $CFLAGS"
+ echo "Enabling ASan..."
+ # Turn ASan on. Everything except -fsanitize=address is optional, but
+ # but effectively required for useful backtraces.
+ asan_flags="-fsanitize=address \
+ -O1 -g -fno-omit-frame-pointer -fno-optimize-sibling-calls"
+ CFLAGS="$asan_flags $CFLAGS"
+ HOSTCC="$HOSTCC $asan_flags"
+ # Ignore leaks on exit.
+ export ASAN_OPTIONS="detect_leaks=0"
fi
export LANG=c
diff --git a/scripts/mcm-buildall.sh b/scripts/mcm-buildall.sh
index 6e36c7c4..e82ce2d5 100755
--- a/scripts/mcm-buildall.sh
+++ b/scripts/mcm-buildall.sh
@@ -127,6 +127,94 @@ make_tuple()
done
}
+# Packages detect nommu via the absence of fork(). Musl provides a broken fork()
+# on nommu builds that always returns -ENOSYS at runtime. Rip it out.
+# (Currently only for superh/jcore.)
+fix_nommu()
+{
+ # Rich won't merge this
+ sed -i 's/--enable-fdpic$/& --enable-twoprocess/' litecross/Makefile
+
+ PP=patches/musl-"$(sed -n 's/MUSL_VER[ \t]*=[ \t]*//p' Makefile)"
+ mkdir -p "$PP" &&
+ cat > "$PP"/0001-nommu.patch << 'EOF'
+--- a/include/features.h
++++ b/include/features.h
+@@ -3,2 +3,4 @@
+
++#define __MUSL__ 1
++
+ #if defined(_ALL_SOURCE) && !defined(_GNU_SOURCE)
+--- a/src/legacy/daemon.c
++++ b/src/legacy/daemon.c
+@@ -17,3 +17,3 @@
+
+- switch(fork()) {
++ switch(vfork()) {
+ case 0: break;
+@@ -25,3 +25,3 @@
+
+- switch(fork()) {
++ switch(vfork()) {
+ case 0: break;
+--- a/src/misc/forkpty.c
++++ b/src/misc/forkpty.c
+@@ -8,2 +8,3 @@
+
++#ifndef __SH_FDPIC__
+ int forkpty(int *pm, char *name, const struct termios *tio, const struct winsize *ws)
+@@ -57,1 +58,2 @@
+ }
++#endif
+--- a/src/misc/wordexp.c
++++ b/src/misc/wordexp.c
+@@ -25,2 +25,3 @@
+
++#ifndef __SH_FDPIC__
+ static int do_wordexp(const char *s, wordexp_t *we, int flags)
+@@ -177,2 +178,3 @@
+ }
++#endif
+
+--- a/src/process/fork.c
++++ b/src/process/fork.c
+@@ -7,2 +7,3 @@
+
++#ifndef __SH_FDPIC__
+ static void dummy(int x)
+@@ -37,1 +38,2 @@
+ }
++#endif
+--- a/Makefile
++++ b/Makefile
+@@ -100,3 +100,3 @@
+ cp $< $@
+- sed -n -e s/__NR_/SYS_/p < $< >> $@
++ sed -e s/__NR_/SYS_/ < $< >> $@
+
+--- a/arch/sh/bits/syscall.h.in
++++ b/arch/sh/bits/syscall.h.in
+@@ -2,3 +2,5 @@
+ #define __NR_exit 1
++#ifndef __SH_FDPIC__
+ #define __NR_fork 2
++#endif
+ #define __NR_read 3
+EOF
+
+ # I won't sign the FSF's copyright assignment
+ tee $(for i in patches/gcc-*; do echo $i/099-vfork.patch; done) > /dev/null << 'EOF'
+--- gcc-8.3.0/fixincludes/procopen.c 2005-08-14 19:50:43.000000000 -0500
++++ gcc-bak/fixincludes/procopen.c 2020-02-06 23:27:15.408071708 -0600
+@@ -116,3 +116,3 @@
+ */
+- ch_id = fork ();
++ ch_id = vfork ();
+ switch (ch_id)
+EOF
+}
+
+fix_nommu || exit 1
mkdir -p "$OUTPUT"/log
# Make bootstrap compiler (no $TYPE, dynamically linked against host libc)
diff --git a/scripts/mkflags.c b/scripts/mkflags.c
index 93294884..fff9dd4c 100644
--- a/scripts/mkflags.c
+++ b/scripts/mkflags.c
@@ -154,7 +154,7 @@ void octane(char *from)
int main(int argc, char *argv[])
{
- char command[256], flags[1023], allflags[1024];
+ char command[256], flags[1024], allflags[1024];
char *out, *outbuf = malloc(1024*1024);
// Yes, the output buffer is 1 megabyte with no bounds checking.
@@ -162,7 +162,7 @@ int main(int argc, char *argv[])
if (!(out = outbuf)) return 1;
printf("#undef FORCED_FLAG\n#undef FORCED_FLAGLL\n"
- "#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1\n#define FORCED_FLAGLL 1LL\n"
+ "#ifdef FORCE_FLAGS\n#define FORCED_FLAG 1\n#define FORCED_FLAGLL 1ULL\n"
"#else\n#define FORCED_FLAG 0\n#define FORCED_FLAGLL 0\n#endif\n\n");
for (;;) {
@@ -220,7 +220,7 @@ int main(int argc, char *argv[])
out += strlen(out);
while (aflist) {
- char *llstr = bit>31 ? "LL" : "", *s = (char []){0, 0, 0, 0};
+ char *llstr = bit>30 ? "LL" : "", *s = (char []){0, 0, 0, 0};
int enabled = 0;
// Output flag macro for bare longopts
diff --git a/scripts/mkroot.sh b/scripts/mkroot.sh
index d486907e..371ba48f 100755
--- a/scripts/mkroot.sh
+++ b/scripts/mkroot.sh
@@ -43,7 +43,6 @@ rm -rf "$MYBUILD" && mkdir -p "$MYBUILD" || exit 1
if [ ! -z "$CROSS_COMPILE" ]; then
if [ ! -e "$AIRLOCK/toybox" ]; then
echo === Create airlock dir
-
PREFIX="$AIRLOCK" KCONFIG_CONFIG="$TOP"/.airlock CROSS_COMPILE= \
make clean defconfig toybox install_airlock &&
rm "$TOP"/.airlock || exit 1
@@ -59,8 +58,7 @@ chmod a+rwxt "$ROOT"/tmp && ln -s usr/{bin,sbin,lib} "$ROOT" || exit 1
cat > "$ROOT"/init << 'EOF' &&
#!/bin/sh
-export HOME=/home
-export PATH=/bin:/sbin
+export HOME=/home PATH=/bin:/sbin
mountpoint -q proc || mount -t proc proc proc
mountpoint -q sys || mount -t sysfs sys sys
@@ -80,12 +78,9 @@ if [ $$ -eq 1 ]; then
[ "$(date +%s)" -lt 1000 ] && rdate 10.0.2.2 # Ask QEMU what time it is
[ "$(date +%s)" -lt 10000000 ] && ntpd -nq -p north-america.pool.ntp.org
- [ -z "$CONSOLE" ] &&
- CONSOLE="$(sed -n 's@.* console=\(/dev/\)*\([^ ]*\).*@\2@p' /proc/cmdline)"
-
+ [ -z "$CONSOLE" ] && CONSOLE="$(</sys/class/tty/console/active)"
[ -z "$HANDOFF" ] && HANDOFF=/bin/sh && echo Type exit when done.
- [ -z "$CONSOLE" ] && CONSOLE=console
- exec /sbin/oneit -c /dev/"$CONSOLE" $HANDOFF
+ exec /sbin/oneit -c /dev/"${CONSOLE:-console}" $HANDOFF
else
/bin/sh
umount /dev/pts /dev /sys /proc
@@ -100,21 +95,12 @@ guest:x:500:500:guest:/home/guest:/bin/sh
nobody:x:65534:65534:nobody:/proc/self:/dev/null
EOF
echo -e 'root:x:0:\nguest:x:500:\nnobody:x:65534:' > "$ROOT"/etc/group &&
-
-# /etc/resolv.conf using Google's public nameserver. (We could use QEMU's
-# 10.0.2.2 forwarder here, but this way works in both chroot and QEMU.)
+# Google's public nameserver.
echo "nameserver 8.8.8.8" > "$ROOT"/etc/resolv.conf || exit 1
# Build toybox
make clean
-if [ -z .config ]; then
- make defconfig
- # Work around musl-libc design flaw.
- [ "${CROSS_BASE/fdpic//}" != "$CROSS_BASE" ] &&
- sed -i 's/.*\(CONFIG_TOYBOX_MUSL_NOMMU_IS_BROKEN\).*/\1=y/' .config
-else
- make silentoldconfig
-fi
+make $([ -z .config ] && echo defconfig || echo silentoldconfig)
LDFLAGS=--static PREFIX="$ROOT" make toybox install || exit 1
write_miniconfig()
@@ -153,7 +139,7 @@ else
# This could use the same VIRT board as armv7, but let's demonstrate a
# different one requiring a separate device tree binary.
QEMU="arm -M versatilepb -net nic,model=rtl8139 -net user"
- KARCH=arm KARGS="console=ttyAMA0" VMLINUX=arch/arm/boot/zImage
+ KARCH=arm KARGS=ttyAMA0 VMLINUX=arch/arm/boot/zImage
KCONF=CPU_ARM926T,MMU,VFP,ARM_THUMB,AEABI,ARCH_VERSATILE,ATAGS,DEPRECATED_PARAM_STRUCT,ARM_ATAG_DTB_COMPAT,ARM_ATAG_DTB_COMPAT_CMDLINE_EXTEND,SERIAL_AMBA_PL011,SERIAL_AMBA_PL011_CONSOLE,RTC_CLASS,RTC_DRV_PL031,RTC_HCTOSYS,PCI,PCI_VERSATILE,BLK_DEV_SD,SCSI,SCSI_LOWLEVEL,SCSI_SYM53C8XX_2,SCSI_SYM53C8XX_MMIO,NET_VENDOR_REALTEK,8139CP
KERNEL_CONFIG="CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=0"
DTB=arch/arm/boot/dts/versatile-pb.dtb
@@ -164,7 +150,7 @@ else
else
QEMU="arm -M virt" KARCH=arm VMLINUX=arch/arm/boot/zImage
fi
- KARGS="console=ttyAMA0"
+ KARGS=ttyAMA0
KCONF=MMU,ARCH_MULTI_V7,ARCH_VIRT,SOC_DRA7XX,ARCH_OMAP2PLUS_TYPICAL,ARCH_ALPINE,ARM_THUMB,VDSO,CPU_IDLE,ARM_CPUIDLE,KERNEL_MODE_NEON,SERIAL_AMBA_PL011,SERIAL_AMBA_PL011_CONSOLE,RTC_CLASS,RTC_HCTOSYS,RTC_DRV_PL031,NET_CORE,VIRTIO_MENU,VIRTIO_NET,PCI,PCI_HOST_GENERIC,VIRTIO_BLK,VIRTIO_PCI,VIRTIO_MMIO,ATA,ATA_SFF,ATA_BMDMA,ATA_PIIX,PATA_PLATFORM,PATA_OF_PLATFORM,ATA_GENERIC
elif [ "$TARGET" == i486 ] || [ "$TARGET" == i686 ] ||
[ "$TARGET" == x86_64 ] || [ "$TARGET" == x32 ]; then
@@ -176,35 +162,31 @@ else
QEMU=x86_64 KCONF=64BIT
[ "$TARGET" == x32 ] && KCONF=X86_X32
fi
- KARCH=x86 KARGS="console=ttyS0" VMLINUX=arch/x86/boot/bzImage
+ KARCH=x86 KARGS=ttyS0 VMLINUX=arch/x86/boot/bzImage
KCONF=$KCONF,UNWINDER_FRAME_POINTER,PCI,BLK_DEV_SD,ATA,ATA_SFF,ATA_BMDMA,ATA_PIIX,NET_VENDOR_INTEL,E1000,SERIAL_8250,SERIAL_8250_CONSOLE,RTC_CLASS
elif [ "$TARGET" == mips ] || [ "$TARGET" == mipsel ]; then
- QEMU="mips -M malta" KARCH=mips KARGS="console=ttyS0" VMLINUX=vmlinux
+ QEMU="mips -M malta" KARCH=mips KARGS=ttyS0 VMLINUX=vmlinux
KCONF=MIPS_MALTA,CPU_MIPS32_R2,SERIAL_8250,SERIAL_8250_CONSOLE,PCI,BLK_DEV_SD,ATA,ATA_SFF,ATA_BMDMA,ATA_PIIX,NET_VENDOR_AMD,PCNET32,POWER_RESET,POWER_RESET_SYSCON
[ "$TARGET" == mipsel ] && KCONF=$KCONF,CPU_LITTLE_ENDIAN &&
QEMU="mipsel -M malta"
elif [ "$TARGET" == powerpc ]; then
- KARCH=powerpc QEMU="ppc -M g3beige" KARGS="console=ttyS0" VMLINUX=vmlinux
+ KARCH=powerpc QEMU="ppc -M g3beige" KARGS=ttyS0 VMLINUX=vmlinux
KCONF=ALTIVEC,PPC_PMAC,PPC_OF_BOOT_TRAMPOLINE,IDE,IDE_GD,IDE_GD_ATA,BLK_DEV_IDE_PMAC,BLK_DEV_IDE_PMAC_ATA100FIRST,MACINTOSH_DRIVERS,ADB,ADB_CUDA,NET_VENDOR_NATSEMI,NET_VENDOR_8390,NE2K_PCI,SERIO,SERIAL_PMACZILOG,SERIAL_PMACZILOG_TTYS,SERIAL_PMACZILOG_CONSOLE,BOOTX_TEXT
+
elif [ "$TARGET" == powerpc64le ]; then
- KARCH=powerpc QEMU="ppc64 -M pseries -vga none" KARGS="console=/dev/hvc0"
+ KARCH=powerpc QEMU="ppc64 -M pseries -vga none" KARGS=/dev/hvc0
VMLINUX=vmlinux
KCONF=PPC64,PPC_PSERIES,CPU_LITTLE_ENDIAN,PPC_OF_BOOT_TRAMPOLINE,BLK_DEV_SD,SCSI_LOWLEVEL,SCSI_IBMVSCSI,ATA,NET_VENDOR_IBM,IBMVETH,HVC_CONSOLE,PPC_TRANSACTIONAL_MEM,PPC_DISABLE_WERROR,SECTION_MISMATCH_WARN_ONLY
+
elif [ "$TARGET" = s390x ] ; then
QEMU="s390x" KARCH=s390 VMLINUX=arch/s390/boot/bzImage
KCONF=MARCH_Z900,PACK_STACK,NET_CORE,VIRTIO_NET,VIRTIO_BLK,SCLP_TTY,SCLP_CONSOLE,SCLP_VT220_TTY,SCLP_VT220_CONSOLE,S390_GUEST
elif [ "$TARGET" == sh4 ] ; then
QEMU="sh4 -M r2d -serial null -serial mon:stdio" KARCH=sh
- KARGS="console=ttySC1 noiotrap" VMLINUX=arch/sh/boot/zImage
+ KARGS="ttySC1 noiotrap" VMLINUX=arch/sh/boot/zImage
KERNEL_CONFIG="CONFIG_MEMORY_START=0x0c000000"
KCONF=CPU_SUBTYPE_SH7751R,MMU,VSYSCALL,SH_FPU,SH_RTS7751R2D,RTS7751R2D_PLUS,SERIAL_SH_SCI,SERIAL_SH_SCI_CONSOLE,PCI,NET_VENDOR_REALTEK,8139CP,PCI,BLK_DEV_SD,ATA,ATA_SFF,ATA_BMDMA,PATA_PLATFORM,BINFMT_ELF_FDPIC,BINFMT_FLAT
-#CONFIG_SPI=y
-#CONFIG_SPI_SH_SCI=y
-#CONFIG_MFD_SM501=y
-#CONFIG_RTC_CLASS=y
-#CONFIG_RTC_DRV_R9701=y
-#CONFIG_RTC_DRV_SH=y
-#CONFIG_RTC_HCTOSYS=y
+#see also SPI SPI_SH_SCI MFD_SM501 RTC_CLASS RTC_DRV_R9701 RTC_DRV_SH RTC_HCTOSYS
else
echo "Unknown \$TARGET"
exit 1
@@ -213,13 +195,13 @@ else
# Write the qemu launch script
echo "qemu-system-$QEMU" '"$@"' -nographic -no-reboot -m 256 \
"-kernel $(basename "$VMLINUX") -initrd ${CROSS_BASE}root.cpio.gz" \
- "-append \"panic=1 HOST=$TARGET $KARGS \$KARGS\"" \
+ "-append \"panic=1 HOST=$TARGET console=$KARGS \$KARGS\"" \
${DTB:+-dtb "$(basename "$DTB")"} > "$OUTPUT/qemu-$TARGET.sh" &&
chmod +x "$OUTPUT/qemu-$TARGET.sh" &&
echo "Build linux for $KARCH"
+ pushd "$LINUX" && make distclean && popd &&
cp -sfR "$LINUX" "$MYBUILD/linux" && pushd "$MYBUILD/linux" || exit 1
- make distclean &&
write_miniconfig > "$OUTPUT/miniconfig-$TARGET" &&
make ARCH=$KARCH allnoconfig KCONFIG_ALLCONFIG="$OUTPUT/miniconfig-$TARGET" &&
make ARCH=$KARCH CROSS_COMPILE="$CROSS_COMPILE" -j $(nproc) || exit 1
diff --git a/tests/sh.test b/tests/sh.test
index ca6a2831..dd18af71 100755
--- a/tests/sh.test
+++ b/tests/sh.test
@@ -9,9 +9,36 @@
#testing "name" "command" "result" "infile" "stdin"
[ -z "$SH" ] && { [ -z "$TEST_HOST" ] && SH="sh" || export SH="bash" ; }
+
+# Test the sh -c stuff before changing EVAL
+testing '-c "" exit status 0' '$SH -c "" && echo $?' '0\n' '' ''
+testing '-c args' "\$SH -c 'echo \$0,\$1,\$2,\$3' one two three four five" \
+ "one,two,three,four\n" "" ""
+testing '-c arg split' \
+ "$SH -c 'for i in a\"\$@\"b;do echo =\$i=;done;echo \$0' 123 456 789" \
+ "=a456=\n=789b=\n123\n" "" ""
+testing "exec3" '$C -c "{ exec readlink /proc/self/fd/0;} < /proc/self/exe"' \
+ "$(readlink -f $C)\n" "" ""
+
+testing 'exec exitval' "$SH -c 'exec echo hello' && echo \$?" "hello\n0\n" "" ""
+testing 'simple script' '$SH input' 'input\n' 'echo $0' ''
+testing 'simple script2' '$SH ./input two;echo $?' './input+two\n42\n' \
+ '\necho $0+$1\n\nexit 42' ''
+mkdir sub
+echo echo hello > sub/script
+testing 'simple script in PATH' "PATH='$PWD/sub:$PATH' $SH script" \
+ 'hello\n' '' ''
+rm -rf sub
+
+# Change EVAL to call sh -c for us, using "bash" explicitly for the host.
export EVAL="$SH -c"
testing "smoketest" "echo hello" "hello\n" "" ""
+testing "eval" "eval echo hello" "hello\n" "" ""
+testing "eval2" "eval 'echo hello'; echo $?" "hello\n0\n" "" ""
+testing "eval3" 'X="echo hello"; eval "$X"' "hello\n" "" ""
+testing "exec" "exec echo hello" "hello\n" "" ""
+testing "exec2" "exec echo hello; echo $?" "hello\n" "" ""
# ; | && ||
testing "semicolon" "echo one;echo two" "one\ntwo\n" "" ""
@@ -24,11 +51,14 @@ testing "&& ||" "true && false && potato || echo hello" "hello\n" "" ""
# redirection
-testing "" "cat < input" "hello\n" "hello\n" ""
-testing "" "echo blah >out; cat out" "blah\n" "" ""
-testing "" "touch /not/exist 2>out||grep -o /not/exist out" "/not/exist\n" "" ""
-#testing "" 'echo hello | (read i <input; echo $i; read i; echo $i)' \
-# "there\nhello\n" "there\n" ""
+testing "redir1" "cat < input" "hello\n" "hello\n" ""
+testing "redir2" "echo blah >out; cat out" "blah\n" "" ""
+testing "redir3" "echo more >>out; cat out" "blah\nmore\n" "" ""
+testing "redir4" "touch /not/exist 2>out||grep -o /not/exist out" \
+ "/not/exist\n" "" ""
+testing "redir5" "ls out /not/exist &> out2 || wc -l < out2" "2\n" "" ""
+testing "redir6" "ls out /not/exist |& wc -l" "2\n" "" ""
+testing "redir7" 'echo -n $(<input)' "boing" "boing\n" ""
testing "tilde expansion" "echo ~" "$HOME\n" "" ""
testing "tilde2" "echo ~/dir" "$HOME/dir\n" "" ""
@@ -47,22 +77,113 @@ testing "brackets9" 'echo A{B{C,D}E{N,O},F{G,H}I}J{K,L}M' \
for i in /root /var/root /; do [ -e $i ] && EXPECT=$i && break; done
testing "bracket+tilde" "echo {~,~root}/pwd" "$HOME/pwd $EXPECT/pwd\n" "" ""
+#testing "backtick1" 'X=fred; echo `echo $x`' 'fred\n' "" ""
+#testing "backtick2" 'X=fred; echo `x=y; echo $x`' 'y\n' "" ""
+testing '$(( ) )' 'echo $((echo hello) | tr e x)' "hxllo\n" "" ""
+
testing "leading variable assignment" 'abc=def env | grep ^abc=; echo $abc' \
"abc=def\n\n" "" ""
testing "leading variable assignments" \
"abc=def ghi=jkl env | egrep '^(abc|ghi)=' | sort; echo \$abc \$ghi" \
"abc=def\nghi=jkl\n\n" "" ""
+
+#$ IFS=x X=xyxz; for i in abc${X}def; do echo =$i=; done
+#=abc=
+#=y=
+#=zdef=
+
+testing "IFS whitespace before/after" \
+ 'IFS=" x"; A=" x " B=" x" C="x " D=x E=" "; for i in $A $B $C $D L$A L$B L$C L$D $A= $B= $C= $D= L$A= L$B= L$C= L$D=; do echo -n {$i}; done' \
+ "{}{}{}{}{L}{L}{L}{L}{}{=}{}{=}{}{=}{}{=}{L}{=}{L}{=}{L}{=}{L}{=}" "" ""
+testing "quotes and whitespace" \
+ 'A=" abc def "; for i in ""$A""; do echo =$i=; done' \
+ "==\n=abc=\n=def=\n==\n" "" ""
+testing "quotes and whitespace2" \
+ 'A=" abc def "; for i in """"$A""; do echo =$i=; done' \
+ "==\n=abc=\n=def=\n==\n" "" ""
+testing "quotes and whitespace3" \
+ 'A=" abc def "; for i in ""x""$A""; do echo =$i=; done' \
+ "=x=\n=abc=\n=def=\n==\n" "" ""
+
+testing "IFS" 'IFS=x; A=abx; echo -n "$A"' "abx" "" ""
+testing "IFS2" 'IFS=x; A=abx; echo -n $A' "ab" "" ""
+testing "IFS3" 'IFS=x; echo "$(echo abx)"' "abx\n" "" ""
+testing "IFS4" "IFS=x; echo \"\$(echo ab' ')\"" "ab \n" "" ""
+
+testing '$*' 'cc(){ for i in $*;do echo =$i=;done;};cc "" "" "" "" ""' \
+ "" "" ""
+testing '$*2' 'cc(){ for i in "$*";do echo =$i=;done;};cc ""' \
+ "==\n" "" ""
+testing '$*3... Flame. Flames. Flames, on the side of my face...' \
+ 'cc(){ for i in "$*";do echo =$i=;done;};cc "" ""' "= =\n" "" ""
+testing 'why... oh.' \
+ 'cc() { echo ="$*"=; for i in =$*=; do echo -$i-; done;}; cc "" ""; echo and; cc ""' \
+ '= =\n-=-\n-=-\nand\n==\n-==-\n' "" ""
+testing 'really?' 'cc() { for i in $*; do echo -$i-; done;}; cc "" "" ""' \
+ "" "" ""
+testing 'Sigh.' 'cc() { echo =$1$2=;}; cc "" ""' "==\n" "" ""
+testing '$*4' 'cc(){ for i in "$*";do echo =$i=;done;};cc "" "" "" "" ""' \
+ "= =\n" "" ""
+testing '$*5' 'cc(){ for i in "$*";do echo =$i=;done;};cc "" "abc" ""' \
+ "= abc =\n" "" ""
+
+# creating empty arguments without quotes
+testing '$* + IFS' \
+ 'IFS=x; cc(){ for i in $*; do echo =$i=;done;};cc xabcxx' \
+ "==\n=abc=\n==\n" "" ""
+testing '$@' 'cc(){ for i in "$@";do echo =$i=;done;};cc "" "" "" "" ""' \
+ "==\n==\n==\n==\n==\n" "" ""
+testing "IFS10" 'IFS=bcd; A=abcde; for i in $A; do echo =$i=; done' \
+ "=a=\n==\n==\n=e=\n" "" ""
+
+testing "IFS combinations" \
+ 'IFS=" x"; A=" x " B=" x" C="x " D=x E=" "; for i in $A $B $C $D L$A L$B L$C L$D $A= $B= $C= $D= L$A= L$B= L$C= L$D=; do echo -n {$i}; done' \
+ "{}{}{}{}{L}{L}{L}{L}{}{=}{}{=}{}{=}{}{=}{L}{=}{L}{=}{L}{=}{L}{=}" "" ""
+
+testing "! isn't special" "echo !" "!\n" "" ""
+testing "! by itself" '!; echo $?' "1\n" "" ""
+testing "! true" '! true; echo $?' "1\n" "" ""
+testing "! ! true" '! ! true; echo $?' "0\n" "" ""
+
+# The bash man page doesn't say quote removal here, and yet:
+testing "case quoting" 'case a in "a") echo hello;; esac' 'hello\n' "" ""
+
+testing "subshell splitting" 'for i in $(true); do echo =$i=; done' "" "" ""
+#testing "subshell split 2"
+
+# variable assignment argument splitting only performed for "$@"
+testing "assignment splitting" 'X="one two"; Y=$X; echo $Y' "one two\n" "" ""
+testing "argument splitting" \
+ 'chicken() { for i in a"$@"b;do echo =$i=;done;}; chicken 123 456 789' \
+ "=a123=\n=456=\n=789b=\n" "" ""
+testing "assignment splitting2" 'pop(){ X="$@";};pop one two three; echo $X' \
+ "one two three\n" "" ""
+
#testing "leading assignments don't affect current line" \
# 'VAR=12345 echo ${VAR}a' "a\n" "" ""
#testing "can't have space before first : but yes around arguments" \
# 'BLAH=abcdefghi; echo ${BLAH: 1 : 3 }' "bcd\n" "" ""
+testing "subshell exit err" '(exit 42); echo $?' "42\n" "" ""
+
+# Same thing twice, but how do we cmp if exec exited?
+#testing 'exec and $$' testing 'echo $$;exec readlink /proc/self'
+
+X="$(realpath $(which readlink))"
+testing "exec in paren" \
+ '(exec readlink /proc/self/exe);echo hello' "$X\nhello\n" "" ""
+testing "exec in brackets" \
+ "{ exec readlink /proc/self/exe;};echo hi" "$X\n" "" ""
+
NOSPACE=1 testing "curly brackets and pipe" \
'{ echo one; echo two ; } | tee blah.txt; wc blah.txt' \
"one\ntwo\n2 2 8 blah.txt\n" "" ""
NOSPACE=1 testing "parentheses and pipe" \
'(echo two;echo three)|tee blah.txt;wc blah.txt' \
"two\nthree\n2 2 10 blah.txt\n" "" ""
+#testing "pipe into parentheses" \
+# 'echo hello | (read i <input; echo $i; read i; echo $i)' \
+# "there\nhello\n" "there\n" ""
# texpect "name" "command" E/O/I"string"
@@ -77,7 +198,10 @@ txpect "redirect err" "$SH" "E$P" "Iecho > /dev/full\n" "E" "E$P" X0
txpect "wait for <(exit)" "$SH" "E$P" "Icat <(echo hello 1>&2)\n" $'Ehello\n' \
"E$P" X0
-
+# TODO: The txpect plumbing does not work right yet even on TEST_HOST
+#txpect "backtick0" "$SH" "E$P" 'IX=fred; echo `echo \\\\$x`'$'\n' 'Ofred' "E$P" X0
+#txpect "backtick1" "$SH" "E$P" 'IX=fred; echo `echo $x`'$'\n' 'Ofred'$'\n' "E$P" X0
+#txpect "backtick2" "$SH" "E$P" 'IX=fred; echo `x=y; echo $x`' $'Oy\n' "E$P" X0
# $@ $* $# $? $- $$ $! $0
# always exported: PWD SHLVL _
diff --git a/toys/net/ping.c b/toys/net/ping.c
index 9ae7c856..63be72cc 100644
--- a/toys/net/ping.c
+++ b/toys/net/ping.c
@@ -5,7 +5,7 @@
* Not in SUSv4.
*
* Note: ping_group_range should never have existed. To disable it, do:
- * echo 0 $(((1<<31)-1)) > /proc/sys/net/ipv4/ping_group_range
+ * echo 0 999999999 > /proc/sys/net/ipv4/ping_group_range
* (Android does this by default in its init script.)
*
* Yes, I wimped out and capped -s at sizeof(toybuf), waiting for a complaint...
@@ -58,12 +58,13 @@ GLOBALS(
// Print a summary. Called as a single handler or at exit.
static void summary(int sig)
{
- if (!(toys.optflags&FLAG_q) && TT.sent && TT.sa) {
+ if (!FLAG(q) && TT.sent && TT.sa) {
printf("\n--- %s ping statistics ---\n", ntop(TT.sa));
printf("%lu packets transmitted, %lu received, %ld%% packet loss\n",
TT.sent, TT.recv, ((TT.sent-TT.recv)*100)/(TT.sent?TT.sent:1));
- printf("round-trip min/avg/max = %lu/%lu/%lu ms\n",
- TT.min, TT.max, TT.fugit/(TT.recv?TT.recv:1));
+ if (TT.recv)
+ printf("round-trip min/avg/max = %lu/%lu/%lu ms\n",
+ TT.min, TT.fugit/TT.recv, TT.max);
}
TT.sa = 0;
}
@@ -96,10 +97,10 @@ void ping_main(void)
unsigned short seq = 0, pkttime;
// Set nonstatic default values
- if (!(toys.optflags&FLAG_i)) TT.i = (toys.optflags&FLAG_f) ? 200 : 1000;
+ if (!FLAG(i)) TT.i = FLAG(f) ? 200 : 1000;
else if (TT.i<200 && getuid()) error_exit("need root for -i <200");
- if (!(toys.optflags&FLAG_s)) TT.s = 56; // 64-PHDR_LEN
- if ((toys.optflags&(FLAG_f|FLAG_c)) == FLAG_f) TT.c = 15;
+ if (!FLAG(s)) TT.s = 56; // 64-PHDR_LEN
+ if (FLAG(f) && !FLAG(c)) TT.c = 15;
// ipv4 or ipv6? (0 = autodetect if -I or arg have only one address type.)
if (FLAG(6) || strchr(toys.which->name, '6')) family = AF_INET6;
@@ -109,12 +110,10 @@ void ping_main(void)
// If -I srcaddr look it up. Allow numeric address of correct type.
memset(&srcaddr, 0, sizeof(srcaddr));
if (TT.I) {
- if (!(toys.optflags&FLAG_6) && inet_pton(AF_INET, TT.I,
- (void *)&srcaddr.in.sin_addr))
- family = AF_INET;
- else if (!(toys.optflags&FLAG_4) && inet_pton(AF_INET6, TT.I,
- (void *)&srcaddr.in6.sin6_addr))
- family = AF_INET6;
+ if (!FLAG(6) && inet_pton(AF_INET, TT.I, (void *)&srcaddr.in.sin_addr))
+ family = AF_INET;
+ else if (!FLAG(4) && inet_pton(AF_INET6, TT.I, (void *)&srcaddr.in6.sin6_addr))
+ family = AF_INET6;
else if (getifaddrs(&ifa2)) perror_exit("getifaddrs");
}
@@ -150,28 +149,26 @@ void ping_main(void)
if (TT.sock == -1) {
perror_msg("socket SOCK_DGRAM %x", len);
if (errno == EACCES) {
- fprintf(stderr, "Kernel bug workaround (as root):\n");
- fprintf(stderr, "echo 0 9999999 > /proc/sys/net/ipv4/ping_group_range\n");
+ fprintf(stderr, "Kernel bug workaround:\n"
+ "echo 0 99999999 | sudo tee /proc/sys/net/ipv4/ping_group_range\n");
}
xexit();
}
if (TT.I) xbind(TT.sock, sa, sizeof(srcaddr));
- if (toys.optflags&FLAG_m) {
- int mark = TT.m;
-
- xsetsockopt(TT.sock, SOL_SOCKET, SO_MARK, &mark, sizeof(mark));
+ if (FLAG(m)) {
+ len = TT.m;
+ xsetsockopt(TT.sock, SOL_SOCKET, SO_MARK, &len, 4);
}
if (TT.t) {
len = TT.t;
-
if (ai->ai_family == AF_INET)
xsetsockopt(TT.sock, IPPROTO_IP, IP_TTL, &len, 4);
else xsetsockopt(TT.sock, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &len, 4);
}
- if (!(toys.optflags&FLAG_q)) {
+ if (!FLAG(q)) {
printf("Ping %s (%s)", *toys.optargs, ntop(TT.sa));
if (TT.I) {
*toybuf = 0;
@@ -180,6 +177,7 @@ void ping_main(void)
// 20 byte TCP header, 8 byte ICMP header, plus data payload
printf(": %ld(%ld) bytes.\n", TT.s, TT.s+28);
}
+ TT.min = ULONG_MAX;
toys.exitval = 1;
tW = tw = 0;
@@ -214,11 +212,10 @@ void ping_main(void)
ih->un.echo.sequence = ++seq;
if (TT.s >= 4) *(unsigned *)(ih+1) = tnow;
- ih->checksum = 0;
ih->checksum = pingchksum((void *)toybuf, TT.s+sizeof(*ih));
xsendto(TT.sock, toybuf, TT.s+sizeof(*ih), TT.sa);
TT.sent++;
- if ((toys.optflags&(FLAG_f|FLAG_q)) == FLAG_f) xputc('.');
+ if (FLAG(f) && !FLAG(q)) xputc('.');
// last packet?
if (TT.c) if (!--TT.c) {
@@ -238,16 +235,17 @@ void ping_main(void)
TT.recv++;
TT.fugit += (pkttime = millitime()-*(unsigned *)(ih+1));
+ if (pkttime < TT.min) TT.min = pkttime;
+ if (pkttime > TT.max) TT.max = pkttime;
// reply id == 0 for ipv4, 129 for ipv6
- if (!(toys.optflags&FLAG_q)) {
- if (toys.optflags&FLAG_f) xputc('\b');
+ if (!FLAG(q)) {
+ if (FLAG(f)) xputc('\b');
else {
printf("%d bytes from %s: icmp_seq=%d ttl=%d", len, ntop(&srcaddr2.s),
ih->un.echo.sequence, 0);
- if (len >= sizeof(*ih)+4)
- printf(" time=%u ms", pkttime);
+ if (len >= sizeof(*ih)+4) printf(" time=%u ms", pkttime);
xputc('\n');
}
}
diff --git a/toys/other/lsattr.c b/toys/other/lsattr.c
index cd236b9e..3e327920 100644
--- a/toys/other/lsattr.c
+++ b/toys/other/lsattr.c
@@ -67,6 +67,8 @@ GLOBALS(
long p;
long add, rm, set;
+ // !add and !rm tell us whether they were used, but `chattr =` is meaningful.
+ int have_set;
)
#define FS_PROJINHERT_FL 0x20000000 // Linux 4.5
@@ -264,6 +266,7 @@ static void parse_cmdline_arg(char ***argv)
TT.add |= get_flag_val(*ptr);
break;
case '=':
+ TT.have_set = 1;
for (ptr = ++arg; *ptr; ptr++)
TT.set |= get_flag_val(*ptr);
break;
@@ -297,7 +300,7 @@ static int update_attr(struct dirtree *root)
}
// Any potential flag changes?
- if (TT.set | TT.add | TT.set) {
+ if (TT.have_set | TT.add | TT.rm) {
unsigned long orig, new;
// Read current flags.
@@ -308,7 +311,7 @@ static int update_attr(struct dirtree *root)
return DIRTREE_ABORT;
}
// Apply the requested changes.
- if (TT.set) new = TT.set; // '='.
+ if (TT.have_set) new = TT.set; // '='.
else { // '-' and/or '+'.
new = orig;
new &= ~(TT.rm);
@@ -347,10 +350,10 @@ void chattr_main(void)
if (TT.p < 0 || TT.p > UINT_MAX) error_exit("bad projid %lu", TT.p);
if (TT.v < 0 || TT.v > UINT_MAX) error_exit("bad version %ld", TT.v);
if (!*argv) help_exit("no file");
- if (TT.set && (TT.add || TT.rm))
+ if (TT.have_set && (TT.add || TT.rm))
error_exit("no '=' with '-' or '+'");
if (TT.rm & TT.add) error_exit("set/unset same flag");
- if (!(TT.add || TT.rm || TT.set || FLAG(p) || FLAG(v)))
+ if (!(TT.add || TT.rm || TT.have_set || FLAG(p) || FLAG(v)))
error_exit("need '-p', '-v', '=', '-', or '+'");
for (; *argv; argv++) dirtree_read(*argv, update_attr);
}
diff --git a/toys/pending/wget.c b/toys/pending/wget.c
index 16672a24..21d44466 100644
--- a/toys/pending/wget.c
+++ b/toys/pending/wget.c
@@ -144,8 +144,7 @@ void wget_main(void)
if(!toys.optargs[0]) help_exit("no URL");
get_info(toys.optargs[0], hostname, port, path);
-
- sprintf("/%s", TOYBOX_VERSION);
+ sprintf(ua+11, "/%s", TOYBOX_VERSION);
for (;; redirects--) {
sock = conn_svr(hostname, port);
// compose HTTP request
diff --git a/toys/posix/patch.c b/toys/posix/patch.c
index f26e0d70..d3d77792 100644
--- a/toys/posix/patch.c
+++ b/toys/posix/patch.c
@@ -49,9 +49,8 @@ GLOBALS(
char *i, *d;
long p, g, F;
- struct double_list *current_hunk;
- long oldline, oldlen, newline, newlen;
- long linenum;
+ void *current_hunk;
+ long oldline, oldlen, newline, newlen, linenum, outnum;
int context, state, filein, fileout, filepatch, hunknum;
char *tempname;
)
@@ -65,20 +64,17 @@ GLOBALS(
static void do_line(void *data)
{
- struct double_list *dlist = (struct double_list *)data;
+ struct double_list *dlist = data;
- if (TT.state>1 && *dlist->data != TT.state) {
- char *s = dlist->data+(TT.state>3);
- int i = TT.state == 2 ? 2 : TT.fileout;
+ TT.outnum++;
+ if (TT.state>1)
+ if (0>dprintf(TT.state==2 ? 2 : TT.fileout,"%s\n",dlist->data+(TT.state>3)))
+ perror_exit("write");
- xwrite(i, s, strlen(s));
- xwrite(i, "\n", 1);
- }
-
- if (FLAG(x)) fprintf(stderr, "DO %d: %s\n", TT.state, dlist->data);
+ if (FLAG(x))
+ fprintf(stderr, "DO %d %ld: %s\n", TT.state, TT.outnum, dlist->data);
- free(dlist->data);
- free(data);
+ llist_free_double(data);
}
static void finish_oldfile(void)
@@ -121,26 +117,24 @@ static int loosecmp(char *aa, char *bb)
// Given a hunk of a unified diff, make the appropriate change to the file.
// This does not use the location information, but instead treats a hunk
-// as a sort of regex. Copies data from input to output until it finds
+// as a sort of regex. Copies data from input to output until it finds
// the change to be made, then outputs the changed data and returns.
-// (Finding EOF first is an error.) This is a single pass operation, so
+// (Finding EOF first is an error.) This is a single pass operation, so
// multiple hunks must occur in order in the file.
static int apply_one_hunk(void)
{
- struct double_list *plist, *buf = NULL, *check;
- int matcheof, trailing = 0, reverse = FLAG(R), backwarn = 0, allfuzz=0, fuzz;
- int (*lcmp)(char *aa, char *bb);
-
- lcmp = FLAG(l) ? (void *)loosecmp : (void *)strcmp;
- dlist_terminate(TT.current_hunk);
+ struct double_list *plist, *buf = 0, *check;
+ int matcheof, trail = 0, reverse = FLAG(R), backwarn = 0, allfuzz = 0, fuzz,i;
+ int (*lcmp)(char *aa, char *bb) = FLAG(l) ? (void *)loosecmp : (void *)strcmp;
// Match EOF if there aren't as many ending context lines as beginning
+ dlist_terminate(TT.current_hunk);
for (plist = TT.current_hunk; plist; plist = plist->next) {
char c = *plist->data, *s;
- if (c==' ') trailing++;
- else trailing = 0;
+ if (c==' ') trail++;
+ else trail = 0;
// Only allow fuzz if 2 context lines have multiple nonwhitespace chars.
// avoids the "all context was blank or } lines" issue. Removed lines
@@ -153,9 +147,11 @@ static int apply_one_hunk(void)
if (FLAG(x)) fprintf(stderr, "HUNK:%s\n", plist->data);
}
- matcheof = !trailing || trailing < TT.context;
+ matcheof = !trail || trail < TT.context;
if (allfuzz<2) allfuzz = 0;
else allfuzz = FLAG(F) ? TT.F : TT.context ? TT.context-1 : 0;
+ if (allfuzz>=sizeof(toybuf)/sizeof(long))
+ allfuzz = (sizeof(toybuf)/sizeof(long))-1;
if (FLAG(x)) fprintf(stderr,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N');
@@ -163,13 +159,10 @@ static int apply_one_hunk(void)
// lines and all lines to be removed until we've found the end of a
// complete hunk.
plist = TT.current_hunk;
- fuzz = allfuzz;
- buf = NULL;
-
+ fuzz = 0;
for (;;) {
char *data = get_line(TT.filein);
- TT.linenum++;
// Figure out which line of hunk to compare with next. (Skip lines
// of the hunk we'd be adding.)
while (plist && *plist->data == "+-"[reverse]) {
@@ -192,9 +185,11 @@ static int apply_one_hunk(void)
// File ended before we found a place for this hunk.
fail_hunk();
goto done;
- } else if (FLAG(x)) fprintf(stderr, "IN: %s\n", data);
+ } else {
+ TT.linenum++;
+ if (FLAG(x)) fprintf(stderr, "IN: %s\n", data);
+ }
check = dlist_add(&buf, data);
-
// Compare this line with next expected line of hunk.
// A match can fail because the next line doesn't match, or because
@@ -203,11 +198,13 @@ static int apply_one_hunk(void)
// If match failed, flush first line of buffered data and
// recheck buffered data for a new match until we find one or run
// out of buffer.
-
- for (;;) {
+ for (i = 0;; i++) {
if (!plist || lcmp(check->data, plist->data+1)) {
- if (plist && *plist->data == ' ' && fuzz-->0) {
- if (FLAG(x)) fprintf(stderr, "FUZZED: %s\n", plist->data);
+ if (plist && *plist->data == ' ' && fuzz<allfuzz) {
+ if (FLAG(x))
+ fprintf(stderr, "FUZZED: %ld %s\n", TT.linenum, plist->data);
+ ((long *)toybuf)[fuzz++] = TT.outnum+i;
+
goto fuzzed;
}
@@ -226,7 +223,7 @@ static int apply_one_hunk(void)
}
// If this hunk must match start of file, fail if it didn't.
- if (!TT.context || trailing>TT.context) {
+ if (!TT.context || trail>TT.context) {
fail_hunk();
goto done;
}
@@ -234,7 +231,8 @@ static int apply_one_hunk(void)
TT.state = 3;
do_line(check = dlist_pop(&buf));
plist = TT.current_hunk;
- fuzz = allfuzz;
+ memset(toybuf, 0, (fuzz+7)/8);
+ fuzz = 0;
// If we've reached the end of the buffer without confirming a
// match, read more lines.
@@ -254,14 +252,21 @@ fuzzed:
out:
// We have a match. Emit changed data.
TT.state = "-+"[reverse];
- llist_traverse(TT.current_hunk, do_line);
- TT.current_hunk = NULL;
+ allfuzz = 0;
+ while ((plist = dlist_pop(&TT.current_hunk))) {
+ if (TT.state == *plist->data || *plist->data == ' ') {
+ if (((long *)toybuf)[allfuzz] == ++TT.outnum) {
+ dprintf(TT.fileout, "%s\n", buf->data);
+ allfuzz++;
+ } else if (*plist->data == ' ') dprintf(TT.fileout, "%s\n",plist->data+1);
+ llist_free_double(dlist_pop(&buf));
+ } else dprintf(TT.fileout, "%s\n", plist->data+1);
+ llist_free_double(plist);
+ }
+ TT.current_hunk = 0;
TT.state = 1;
done:
- if (buf) {
- dlist_terminate(buf);
- llist_traverse(buf, do_line);
- }
+ llist_traverse(buf, do_line);
return TT.state;
}
@@ -336,7 +341,7 @@ void patch_main(void)
// Are we assembling a hunk?
if (state >= 2) {
if (*patchline==' ' || *patchline=='+' || *patchline=='-') {
- dlist_add(&TT.current_hunk, patchline);
+ dlist_add((void *)&TT.current_hunk, patchline);
if (*patchline != '+') TT.oldlen--;
if (*patchline != '-') TT.newlen--;
@@ -455,8 +460,7 @@ void patch_main(void)
}
if (FLAG(dry_run)) TT.fileout = xopen("/dev/null", O_RDWR);
else TT.fileout = copy_tempfile(TT.filein, name, &TT.tempname);
- TT.linenum = 0;
- TT.hunknum = 0;
+ TT.linenum = TT.outnum = TT.hunknum = 0;
}
}
diff --git a/toys/posix/ps.c b/toys/posix/ps.c
index 0c8e8e81..cd8c73ea 100644
--- a/toys/posix/ps.c
+++ b/toys/posix/ps.c
@@ -311,13 +311,14 @@ struct procpid {
#define XX 64 // force string representation for sorting, etc
// TODO: Android uses -30 for LABEL, but ideally it would auto-size.
+// TODO: ideally, PID and PPID would auto-size too.
struct typography {
char *name, *help;
signed char width, slot;
} static const typos[] = TAGGED_ARRAY(PS,
// Numbers. (What's in slot[] is what's displayed, sorted numerically.)
- {"PID", "Process ID", 5, SLOT_pid},
- {"PPID", "Parent Process ID", 5, SLOT_ppid},
+ {"PID", "Process ID", 6, SLOT_pid},
+ {"PPID", "Parent Process ID", 6, SLOT_ppid},
{"PRI", "Priority (dynamic 0 to 139)", 3, SLOT_priority},
{"NI", "Niceness (static 19 to -20)", 3, SLOT_nice},
{"ADDR", "Instruction pointer", 4+sizeof(long), SLOT_eip},