Snap for 8470411 from 52a5af013efa6ca0150d5f07a25cb87361b728a7 to tm-qpr1-release

Change-Id: I9f7fb4d1c5f318d68259fcd1260cad489509710b
diff --git a/.config-device b/.config-device
index 1605d11..196378e 100644
--- a/.config-device
+++ b/.config-device
@@ -8,6 +8,7 @@
 
 CONFIG_TOYBOX=y
 CONFIG_TOYBOX_CONTAINER=y
+# CONFIG_TOYBOX_COPYFILERANGE is not set
 # CONFIG_TOYBOX_DEBUG is not set
 CONFIG_TOYBOX_FALLOCATE=y
 CONFIG_TOYBOX_FIFREEZE=y
diff --git a/.config-linux b/.config-linux
index 937a8eb..0a54259 100644
--- a/.config-linux
+++ b/.config-linux
@@ -8,6 +8,7 @@
 
 # CONFIG_TOYBOX_ANDROID_SCHEDPOLICY is not set
 # CONFIG_TOYBOX_CONTAINER is not set
+# CONFIG_TOYBOX_COPYFILERANGE is not set
 # CONFIG_TOYBOX_DEBUG is not set
 # CONFIG_TOYBOX_FALLOCATE is not set
 # CONFIG_TOYBOX_FIFREEZE is not set
diff --git a/.config-mac b/.config-mac
index dd6a3d9..3770579 100644
--- a/.config-mac
+++ b/.config-mac
@@ -8,6 +8,7 @@
 
 # CONFIG_TOYBOX_ANDROID_SCHEDPOLICY is not set
 # CONFIG_TOYBOX_CONTAINER is not set
+# CONFIG_TOYBOX_COPYFILERANGE is not set
 # CONFIG_TOYBOX_DEBUG is not set
 # CONFIG_TOYBOX_FALLOCATE is not set
 # CONFIG_TOYBOX_FIFREEZE is not set
diff --git a/Config.in b/Config.in
index b626f3c..62185df 100644
--- a/Config.in
+++ b/Config.in
@@ -136,12 +136,6 @@
 	  Enable extra checks for debugging purposes. All of them catch
 	  things that can only go wrong at development time, not runtime.
 
-config TOYBOX_PEDANTIC_ARGS
-	bool "Pedantic argument checking"
-	default n
-	help
-	  Check arguments for commands that have no arguments.
-
 config TOYBOX_UID_SYS
 	int "First system UID"
 	default 100
diff --git a/METADATA b/METADATA
index 500cd28..191882c 100644
--- a/METADATA
+++ b/METADATA
@@ -9,11 +9,11 @@
     type: GIT
     value: "https://github.com/landley/toybox"
   }
-  version: "8a23ac205cb4995d4510a5af880939eda4a5343e"
+  version: "8b97a1fb86b06e329c77c64cdbef29d7738f5840"
   license_type: UNENCUMBERED
   last_upgrade_date {
     year: 2022
-    month: 3
-    day: 16
+    month: 4
+    day: 18
   }
 }
diff --git a/Makefile b/Makefile
index 032e70d..4098702 100644
--- a/Makefile
+++ b/Makefile
@@ -3,7 +3,7 @@
 
 # If people set these on the make command line, use 'em
 # Note that CC defaults to "cc" so the one in configure doesn't get
-# used when scripts/make.sh and care called through "make".
+# used when scripts/make.sh and such called through "make".
 
 HOSTCC?=cc
 
@@ -41,13 +41,13 @@
 bloatcheck: generated/unstripped/toybox_old generated/unstripped/toybox
 	@scripts/bloatcheck generated/unstripped/toybox_old generated/unstripped/toybox
 
-install_flat:
+install_flat: toybox
 	scripts/install.sh --symlink --force
 
-install_airlock:
+install_airlock: toybox
 	scripts/install.sh --symlink --force --airlock
 
-install:
+install: toybox
 	scripts/install.sh --long --symlink --force
 
 uninstall_flat:
@@ -65,7 +65,7 @@
 
 clean::
 	@chmod -fR 700 generated || true
-	@rm -rf toybox generated change .singleconfig*
+	@rm -rf toybox generated change install .singleconfig*
 	@echo cleaned
 
 # If singlemake was in generated/ "make clean; make test_ls" wouldn't work.
diff --git a/android/device/generated/config.h b/android/device/generated/config.h
index 6b15e9f..415d99e 100644
--- a/android/device/generated/config.h
+++ b/android/device/generated/config.h
@@ -2,6 +2,8 @@
 #define USE_TOYBOX(...) __VA_ARGS__
 #define CFG_TOYBOX_CONTAINER 1
 #define USE_TOYBOX_CONTAINER(...) __VA_ARGS__
+#define CFG_TOYBOX_COPYFILERANGE 0
+#define USE_TOYBOX_COPYFILERANGE(...)
 #define CFG_TOYBOX_DEBUG 0
 #define USE_TOYBOX_DEBUG(...)
 #define CFG_TOYBOX_FALLOCATE 1
diff --git a/android/device/generated/flags.h b/android/device/generated/flags.h
index 2140209..ced393d 100644
--- a/android/device/generated/flags.h
+++ b/android/device/generated/flags.h
@@ -1535,9 +1535,9 @@
 #undef FLAG_t
 #endif
 
-// iorenice ?<1>3 ?<1>3
+// iorenice <1>3 <1>3
 #undef OPTSTR_iorenice
-#define OPTSTR_iorenice "?<1>3"
+#define OPTSTR_iorenice "<1>3"
 #ifdef CLEANUP_iorenice
 #undef CLEANUP_iorenice
 #undef FOR_iorenice
@@ -2248,9 +2248,9 @@
 #undef FLAG_n
 #endif
 
-// openvt   c#<1>63sw
+// openvt   ^<1c#<1>63sw
 #undef OPTSTR_openvt
-#define OPTSTR_openvt "c#<1>63sw"
+#define OPTSTR_openvt "^<1c#<1>63sw"
 #ifdef CLEANUP_openvt
 #undef CLEANUP_openvt
 #undef FOR_openvt
@@ -2534,14 +2534,6 @@
 #undef FLAG_n
 #endif
 
-// realpath <1 <1
-#undef OPTSTR_realpath
-#define OPTSTR_realpath "<1"
-#ifdef CLEANUP_realpath
-#undef CLEANUP_realpath
-#undef FOR_realpath
-#endif
-
 // reboot   d:fn
 #undef OPTSTR_reboot
 #define OPTSTR_reboot "d:fn"
@@ -3065,9 +3057,9 @@
 #undef FLAG_f
 #endif
 
-// tar &(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa] &(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]
+// tar &(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa] &(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]
 #undef OPTSTR_tar
-#define OPTSTR_tar "&(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]"
+#define OPTSTR_tar "&(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]"
 #ifdef CLEANUP_tar
 #undef CLEANUP_tar
 #undef FOR_tar
@@ -3105,6 +3097,7 @@
 #undef FLAG_full_time
 #undef FLAG_restrict
 #undef FLAG_selinux
+#undef FLAG_strip_components
 #endif
 
 // taskset <1^pa <1^pa
@@ -3638,12 +3631,13 @@
 #undef FLAG_m
 #endif
 
-// wget   <1>1(max-redirect)#<0=20d(debug)O(output-document):
+// wget   <1>1(max-redirect)#<0=20d(debug)O(output-document):p(post-data):
 #undef OPTSTR_wget
-#define OPTSTR_wget "<1>1(max-redirect)#<0=20d(debug)O(output-document):"
+#define OPTSTR_wget "<1>1(max-redirect)#<0=20d(debug)O(output-document):p(post-data):"
 #ifdef CLEANUP_wget
 #undef CLEANUP_wget
 #undef FOR_wget
+#undef FLAG_p
 #undef FLAG_O
 #undef FLAG_d
 #undef FLAG_max_redirect
@@ -6065,13 +6059,6 @@
 #define FLAG_n (1<<4)
 #endif
 
-#ifdef FOR_realpath
-#define CLEANUP_realpath
-#ifndef TT
-#define TT this.realpath
-#endif
-#endif
-
 #ifdef FOR_reboot
 #define CLEANUP_reboot
 #ifndef TT
@@ -6590,6 +6577,7 @@
 #define FLAG_full_time (1LL<<31)
 #define FLAG_restrict (1LL<<32)
 #define FLAG_selinux (1LL<<33)
+#define FLAG_strip_components (1LL<<34)
 #endif
 
 #ifdef FOR_taskset
@@ -7084,9 +7072,10 @@
 #ifndef TT
 #define TT this.wget
 #endif
-#define FLAG_O (FORCED_FLAG<<0)
-#define FLAG_d (FORCED_FLAG<<1)
-#define FLAG_max_redirect (FORCED_FLAG<<2)
+#define FLAG_p (FORCED_FLAG<<0)
+#define FLAG_O (FORCED_FLAG<<1)
+#define FLAG_d (FORCED_FLAG<<2)
+#define FLAG_max_redirect (FORCED_FLAG<<3)
 #endif
 
 #ifdef FOR_which
diff --git a/android/device/generated/globals.h b/android/device/generated/globals.h
index 844f4d0..403077b 100644
--- a/android/device/generated/globals.h
+++ b/android/device/generated/globals.h
@@ -397,6 +397,12 @@
   char *c;
 };
 
+// toys/other/openvt.c
+
+struct openvt_data {
+  long c;
+};
+
 // toys/other/pwgen.c
 
 struct pwgen_data {
@@ -862,12 +868,6 @@
   int cin_fd;
 };
 
-// toys/pending/openvt.c
-
-struct openvt_data {
-  long c;
-};
-
 // toys/pending/route.c
 
 struct route_data {
@@ -1159,10 +1159,10 @@
 // toys/pending/wget.c
 
 struct wget_data {
-  char *filename;
-  long redirects;
+  char *p, *O;
+  long max_redirect;
 
-  int sock;
+  int sock, https;
   char *url;
 #if CFG_WGET_LIBTLS
   struct tls *tls;
@@ -1549,6 +1549,7 @@
   struct arg_list *T, *X;
   char *I, *to_command, *owner, *group, *mtime, *mode;
   struct arg_list *exclude;
+  long strip_components;
 
   struct double_list *incl, *excl, *seen;
   struct string_list *dirs;
@@ -1678,6 +1679,7 @@
 	struct modinfo_data modinfo;
 	struct nsenter_data nsenter;
 	struct oneit_data oneit;
+	struct openvt_data openvt;
 	struct pwgen_data pwgen;
 	struct readelf_data readelf;
 	struct reboot_data reboot;
@@ -1728,7 +1730,6 @@
 	struct mke2fs_data mke2fs;
 	struct modprobe_data modprobe;
 	struct more_data more;
-	struct openvt_data openvt;
 	struct route_data route;
 	struct sh_data sh;
 	struct strace_data strace;
diff --git a/android/device/generated/help.h b/android/device/generated/help.h
index bc30cd0..04e6212 100644
--- a/android/device/generated/help.h
+++ b/android/device/generated/help.h
@@ -4,8 +4,6 @@
 
 #define HELP_toybox_uid_sys "When commands like useradd/groupadd allocate system IDs, start here."
 
-#define HELP_toybox_pedantic_args "Check arguments for commands that have no arguments."
-
 #define HELP_toybox_debug "Enable extra checks for debugging purposes. All of them catch\nthings that can only go wrong at development time, not runtime."
 
 #define HELP_toybox_norecurse "When one toybox command calls another, usually it just calls the new\ncommand's main() function rather than searching the $PATH and calling\nexec on another file (which is much slower).\n\nThis disables that optimization, so toybox will run external commands\n       even when it has a built-in version of that command. This requires\n       toybox symlinks to be installed in the $PATH, or re-invoking the\n       \"toybox\" multiplexer command by name."
@@ -126,7 +124,7 @@
 
 #define HELP_microcom "usage: microcom [-s SPEED] [-X] DEVICE\n\nSimple serial console.\n\n-s	Set baud rate to SPEED (default 115200)\n-X	Ignore ^@ (send break) and ^] (exit)"
 
-#define HELP_ifconfig "usage: ifconfig [-aS] [INTERFACE [ACTION...]]\n\nDisplay or configure network interface.\n\nWith no arguments, display active interfaces. First argument is interface\nto operate on, one argument by itself displays that interface.\n\n-a	All interfaces displayed, not just active ones\n-S	Short view, one line per interface\n\nStandard ACTIONs to perform on an INTERFACE:\n\nADDR[/MASK]        - set IPv4 address (1.2.3.4/5) and activate interface\nadd|del ADDR[/LEN] - add/remove IPv6 address (1111::8888/128)\nup|down            - activate or deactivate interface\n\nAdvanced ACTIONs (default values usually suffice):\n\ndefault          - remove IPv4 address\nnetmask ADDR     - set IPv4 netmask via 255.255.255.0 instead of /24\ntxqueuelen LEN   - number of buffered packets before output blocks\nmtu LEN          - size of outgoing packets (Maximum Transmission Unit)\nbroadcast ADDR   - Set broadcast address\npointopoint ADDR - PPP and PPPOE use this instead of \"route add default gw\"\nhw TYPE ADDR     - set hardware (mac) address (type = ether|infiniband)\n\nFlags you can set on an interface (or -remove by prefixing with -):\n\narp       - don't use Address Resolution Protocol to map LAN routes\npromisc   - don't discard packets that aren't to this LAN hardware address\nmulticast - force interface into multicast mode if the driver doesn't\nallmulti  - promisc for multicast packets"
+#define HELP_ifconfig "usage: ifconfig [-aS] [INTERFACE [ACTION...]]\n\nDisplay or configure network interface.\n\nWith no arguments, display active interfaces. First argument is interface\nto operate on, one argument by itself displays that interface.\n\n-a	All interfaces displayed, not just active ones\n-S	Short view, one line per interface\n\nStandard ACTIONs to perform on an INTERFACE:\n\nADDR[/MASK]        - set IPv4 address (1.2.3.4/5) and activate interface\nadd|del ADDR[/LEN] - add/remove IPv6 address (1111::8888/128)\nup|down            - activate or deactivate interface\n\nAdvanced ACTIONs (default values usually suffice):\n\ndefault          - remove IPv4 address\nnetmask ADDR     - set IPv4 netmask via 255.255.255.0 instead of /24\ntxqueuelen LEN   - number of buffered packets before output blocks\nmtu LEN          - size of outgoing packets (Maximum Transmission Unit)\nbroadcast ADDR   - Set broadcast address\npointopoint ADDR - PPP and PPPOE use this instead of \"route add default gw\"\nhw TYPE ADDR     - set hardware (mac) address (type = ether|infiniband)\nrename NEWNAME   - rename interface\n\nFlags you can set on an interface (or -remove by prefixing with -):\n\narp       - don't use Address Resolution Protocol to map LAN routes\npromisc   - don't discard packets that aren't to this LAN hardware address\nmulticast - force interface into multicast mode if the driver doesn't\nallmulti  - promisc for multicast packets"
 
 #define HELP_host "usage: host [-v] [-t TYPE] NAME [SERVER]\n\nLook up DNS records for NAME, either domain name or IPv4/IPv6 address to\nreverse lookup, from SERVER or default DNS server(s).\n\n-a	All records\n-t TYPE	Record TYPE (number or ANY A AAAA CNAME MX NS PTR SOA SRV TXT)\n-v	Verbose"
 
@@ -216,6 +214,12 @@
 
 #define HELP_partprobe "usage: partprobe DEVICE...\n\nTell the kernel about partition table changes\n\nAsk the kernel to re-read the partition table on the specified devices."
 
+#define HELP_deallocvt "usage: deallocvt [NUM]\n\nDeallocate unused virtual terminals, either a specific /dev/ttyNUM, or all."
+
+#define HELP_chvt "usage: chvt NUM\n\nChange to virtual terminal number NUM. (This only works in text mode.)\n\nVirtual terminals are the Linux VGA text mode (or framebuffer) displays,\nswitched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch\nfrom X11 to a virtual terminal, and alt-F6 (or F7, or F8) to get back."
+
+#define HELP_openvt "usage: openvt [-c NUM] [-sw] COMMAND...\n\nRun COMMAND on a new virtual terminal.\n\n-c NUM  Use VT NUM\n-s    Switch to the new VT\n-w    Wait for command to exit (with -s, deallocates VT on exit)"
+
 #define HELP_oneit "usage: oneit [-prn3] [-c CONSOLE] [COMMAND...]\n\nSimple init program that runs a single supplied command line with a\ncontrolling tty (so CTRL-C can kill it).\n\n-c	Which console device to use (/dev/console doesn't do CTRL-C, etc)\n-p	Power off instead of rebooting when command exits\n-r	Restart child when it exits\n-n	No reboot, just relaunch command line\n-3	Write 32 bit PID of each exiting reparented process to fd 3 of child\n	(Blocking writes, child must read to avoid eventual deadlock.)\n\nSpawns a single child process (because PID 1 has signals blocked)\nin its own session, reaps zombies until the child exits, then\nreboots the system (or powers off with -p, or restarts the child with -r).\n\nResponds to SIGUSR1 by halting the system, SIGUSR2 by powering off,\nand SIGTERM or SIGINT reboot."
 
 #define HELP_nsenter "usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND...\n\nRun COMMAND in an existing (set of) namespace(s).\n\n-t	PID to take namespaces from    (--target)\n-F	don't fork, even if -p is used (--no-fork)\n\nThe namespaces to switch are:\n\n-i	SysV IPC: message queues, semaphores, shared memory (--ipc)\n-m	Mount/unmount tree (--mount)\n-n	Network address, sockets, routing, iptables (--net)\n-p	Process IDs and init, will fork unless -F is used (--pid)\n-u	Host and domain names (--uts)\n-U	UIDs, GIDs, capabilities (--user)\n\nIf -t isn't specified, each namespace argument must provide a path\nto a namespace file, ala \"-i=/proc/$PID/ns/ipc\""
@@ -312,8 +316,6 @@
 
 #define HELP_clear "Clear the screen."
 
-#define HELP_chvt "usage: chvt N\n\nChange to virtual terminal number N. (This only works in text mode.)\n\nVirtual terminals are the Linux VGA text mode displays, ordinarily\nswitched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch\nfrom X to a virtual terminal, and alt-F6 (or F7, or F8) to get back."
-
 #define HELP_chrt "usage: chrt [-Rmofrbi] {-p PID [PRIORITY] | [PRIORITY COMMAND...]}\n\nGet/set a process' real-time scheduling policy and priority.\n\n-p	Set/query given pid (instead of running COMMAND)\n-R	Set SCHED_RESET_ON_FORK\n-m	Show min/max priorities available\n\nSet policy (default -r):\n\n  -o  SCHED_OTHER    -f  SCHED_FIFO    -r  SCHED_RR\n  -b  SCHED_BATCH    -i  SCHED_IDLE"
 
 #define HELP_chroot "usage: chroot NEWROOT [COMMAND [ARG...]]\n\nRun command within a new root directory. If no command, run /bin/sh."
@@ -348,7 +350,7 @@
 
 #define HELP_wget_libtls "Enable HTTPS support for wget by linking to LibTLS.\nSupports using libtls, libretls or libtls-bearssl."
 
-#define HELP_wget "usage: wget [OPTIONS]... [URL]\n    --max-redirect          maximum redirections allowed\n-d, --debug                 print lots of debugging information\n-O, --output-document=FILE  specify output filename\n\nexamples:\n  wget http://www.example.com"
+#define HELP_wget "usage: wget [OPTIONS]... [URL]\n    --max-redirect          maximum redirections allowed\n-d, --debug                 print lots of debugging information\n-O, --output-document=FILE  specify output filename\n-p, --post-data=DATA        send data in body of POST request\n\nexamples:\n  wget http://www.example.com"
 
 #define HELP_vi "usage: vi [-s script] FILE\n-s script: run script file\nVisual text editor. Predates the existence of standardized cursor keys,\nso the controls are weird and historical."
 
@@ -408,10 +410,6 @@
 
 #define HELP_route "usage: route [-ne] [-A [inet|inet6]] [add|del TARGET [OPTIONS]]\n\nDisplay, add or delete network routes in the \"Forwarding Information Base\",\nwhich send packets out a network interface to an address.\n\n-n	Show numerical addresses (no DNS lookups)\n-e	display netstat fields\n\nAssigning an address to an interface automatically creates an appropriate\nnetwork route (\"ifconfig eth0 10.0.2.15/8\" does \"route add 10.0.0.0/8 eth0\"\nfor you), although some devices (such as loopback) won't show it in the\ntable. For machines more than one hop away, you need to specify a gateway\n(ala \"route add default gw 10.0.2.2\").\n\nThe address \"default\" is a wildcard address (0.0.0.0/0) matching all\npackets without a more specific route.\n\nAvailable OPTIONS include:\nreject   - blocking route (force match failure)\ndev NAME - force matching packets out this interface (ala \"eth0\")\nnetmask  - old way of saying things like ADDR/24\ngw ADDR  - forward packets to gateway ADDR"
 
-#define HELP_deallocvt "usage: deallocvt [NUM]\n\nDeallocate unused virtual terminals, either a specific /dev/ttyNUM, or all."
-
-#define HELP_openvt "usage: openvt [-c NUM] [-sw] [COMMAND...]\n\nStart a program on a new virtual terminal.\n\n-c NUM  Use VT NUM\n-s    Switch to new VT\n-w    Wait for command to exit\n\nTogether -sw switch back to originating VT when command completes."
-
 #define HELP_more "usage: more [FILE...]\n\nView FILE(s) (or stdin) one screenfull at a time."
 
 #define HELP_modprobe "usage: modprobe [-alrqvsDb] [-d DIR] MODULE [symbol=value][...]\n\nmodprobe utility - inserts modules and dependencies.\n\n-a  Load multiple MODULEs\n-b  Apply blacklist to module names too\n-D  Show dependencies\n-d  Load modules from DIR, option may be used multiple times\n-l  List (MODULE is a pattern)\n-q  Quiet\n-r  Remove MODULE (stacks) or do autoclean\n-s  Log to syslog\n-v  Verbose"
@@ -530,7 +528,7 @@
 
 #define HELP_tee "usage: tee [-ai] [FILE...]\n\nCopy stdin to each listed file, and also to stdout.\nFilename \"-\" is a synonym for stdout.\n\n-a	Append to files\n-i	Ignore SIGINT"
 
-#define HELP_tar "usage: tar [-cxt] [-fvohmjkOS] [-XTCf NAME] [--selinux] [FILE...]\n\nCreate, extract, or list files in a .tar (or compressed t?z) file.\n\nOptions:\nc  Create                x  Extract               t  Test (list)\nf  tar FILE (default -)  C  Change to DIR first   v  Verbose display\no  Ignore owner          h  Follow symlinks       m  Ignore mtime\nJ  xz compression        j  bzip2 compression     z  gzip compression\nO  Extract to stdout     X  exclude names in FILE T  include names in FILE\n\n--exclude        FILENAME to exclude    --full-time   Show seconds with -tv\n--mode MODE      Adjust modes           --mtime TIME  Override timestamps\n--owner NAME     Set file owner to NAME --group NAME  Set file group to NAME\n--sparse         Record sparse files    --selinux     Record/restore labels\n--restrict       All archive contents must extract under one subdirectory\n--numeric-owner  Save/use/display uid and gid, not user/group name\n--no-recursion   Don't store directory contents\n-I PROG          Filter through PROG to compress or PROG -d to decompress"
+#define HELP_tar "usage: tar [-cxt] [-fvohmjkOS] [-XTCf NAME] [--selinux] [FILE...]\n\nCreate, extract, or list files in a .tar (or compressed t?z) file.\n\nOptions:\nc  Create                x  Extract               t  Test (list)\nf  tar FILE (default -)  C  Change to DIR first   v  Verbose display\no  Ignore owner          h  Follow symlinks       m  Ignore mtime\nJ  xz compression        j  bzip2 compression     z  gzip compression\nO  Extract to stdout     X  exclude names in FILE T  include names in FILE\n\n--exclude        FILENAME to exclude  --full-time         Show seconds with -tv\n--mode MODE      Adjust permissions   --owner NAME[:UID]  Set file ownership\n--mtime TIME     Override timestamps  --group NAME[:GID]  Set file group\n--sparse         Record sparse files  --selinux           Save/restore labels\n--restrict       All under one dir    --no-recursion      Skip dir contents\n--numeric-owner  Use numeric uid/gid, not user/group names\n--strip-components NUM  Ignore first NUM directory components when extracting\n-I PROG          Filter through PROG to compress or PROG -d to decompress"
 
 #define HELP_tail "usage: tail [-n|c NUMBER] [-f|F] [-s SECONDS] [FILE...]\n\nCopy last lines from files to stdout. If no files listed, copy from\nstdin. Filename \"-\" is a synonym for stdin.\n\n-n	Output the last NUMBER lines (default 10), +X counts from start\n-c	Output the last NUMBER bytes, +NUMBER counts from start\n-f	Follow FILE(s) by descriptor, waiting for more data to be appended\n-F	Follow FILE(s) by filename, waiting for more data, and retrying\n-s	Used with -F, sleep SECONDS between retries (default 1)"
 
diff --git a/android/device/generated/newtoys.h b/android/device/generated/newtoys.h
index ea56d9d..ade8831 100644
--- a/android/device/generated/newtoys.h
+++ b/android/device/generated/newtoys.h
@@ -1,4 +1,4 @@
-USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT))
+USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT|TOYFLAG_NOHELP))
 USE_SH(OLDTOY(-bash, sh, 0))
 USE_SH(OLDTOY(-sh, sh, 0))
 USE_SH(OLDTOY(-toysh, sh, 0))
@@ -137,7 +137,7 @@
 USE_INSMOD(NEWTOY(insmod, "<1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
 USE_INSTALL(NEWTOY(install, "<1cdDpsvt:m:o:g:", TOYFLAG_USR|TOYFLAG_BIN))
 USE_IONICE(NEWTOY(ionice, "^tc#<0>3=2n#<0>7=5p#", TOYFLAG_USR|TOYFLAG_BIN))
-USE_IORENICE(NEWTOY(iorenice, "?<1>3", TOYFLAG_USR|TOYFLAG_BIN))
+USE_IORENICE(NEWTOY(iorenice, "<1>3", TOYFLAG_USR|TOYFLAG_BIN))
 USE_IOTOP(NEWTOY(iotop, ">0AaKO" "Hk*o*p*u*s#<1=7d%<100=3000m#n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
 USE_IP(NEWTOY(ip, NULL, TOYFLAG_SBIN))
 USE_IP(OLDTOY(ipaddr, ip, TOYFLAG_SBIN))
@@ -201,7 +201,7 @@
 USE_NSENTER(NEWTOY(nsenter, "<1F(no-fork)t#<1(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN))
 USE_OD(NEWTOY(od, "j#vw#<1=16N#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN))
 USE_ONEIT(NEWTOY(oneit, "^<1nc:p3[!pn]", TOYFLAG_SBIN))
-USE_OPENVT(NEWTOY(openvt, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+USE_OPENVT(NEWTOY(openvt, "^<1c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
 USE_PARTPROBE(NEWTOY(partprobe, "<1", TOYFLAG_SBIN))
 USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
 USE_PASTE(NEWTOY(paste, "d:s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
@@ -224,7 +224,7 @@
 USE_READAHEAD(NEWTOY(readahead, NULL, TOYFLAG_BIN))
 USE_READELF(NEWTOY(readelf, "<1(dyn-syms)adehlnp:SsWx:", TOYFLAG_USR|TOYFLAG_BIN))
 USE_READLINK(NEWTOY(readlink, "<1nqmef(canonicalize)[-mef]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_REALPATH(NEWTOY(realpath, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_REALPATH(OLDTOY(realpath, readlink, TOYFLAG_USR|TOYFLAG_BIN))
 USE_REBOOT(NEWTOY(reboot, "d:fn", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
 USE_RENICE(NEWTOY(renice, "<1gpun#|", TOYFLAG_USR|TOYFLAG_BIN))
 USE_RESET(NEWTOY(reset, 0, TOYFLAG_USR|TOYFLAG_BIN))
@@ -274,7 +274,7 @@
 USE_SYSLOGD(NEWTOY(syslogd,">0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD", TOYFLAG_SBIN|TOYFLAG_STAYROOT))
 USE_TAC(NEWTOY(tac, NULL, TOYFLAG_USR|TOYFLAG_BIN))
 USE_TAIL(NEWTOY(tail, "?fFs:c(bytes)-n(lines)-[-cn][-fF]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_TAR(NEWTOY(tar, "&(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TAR(NEWTOY(tar, "&(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]", TOYFLAG_USR|TOYFLAG_BIN))
 USE_TASKSET(NEWTOY(taskset, "<1^pa", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
 USE_TCPSVD(NEWTOY(tcpsvd, "^<3c#=30<1C:b#=20<0u:l:hEv", TOYFLAG_USR|TOYFLAG_BIN))
 USE_TEE(NEWTOY(tee, "ia", TOYFLAG_USR|TOYFLAG_BIN))
@@ -321,7 +321,7 @@
 USE_WATCH(NEWTOY(watch, "^<1n%<100=2000tebx", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
 USE_WATCHDOG(NEWTOY(watchdog, "<1>1Ft#=4<1T#=60<1", TOYFLAG_NEEDROOT|TOYFLAG_BIN))
 USE_WC(NEWTOY(wc, "mcwl", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
-USE_WGET(NEWTOY(wget, "<1>1(max-redirect)#<0=20d(debug)O(output-document):", TOYFLAG_USR|TOYFLAG_BIN))
+USE_WGET(NEWTOY(wget, "<1>1(max-redirect)#<0=20d(debug)O(output-document):p(post-data):", TOYFLAG_USR|TOYFLAG_BIN))
 USE_WHICH(NEWTOY(which, "<1a", TOYFLAG_USR|TOYFLAG_BIN))
 USE_WHO(NEWTOY(who, "a", TOYFLAG_USR|TOYFLAG_BIN))
 USE_WHOAMI(OLDTOY(whoami, logname, TOYFLAG_USR|TOYFLAG_BIN))
diff --git a/android/linux/generated/config.h b/android/linux/generated/config.h
index 45d2f91..7d2c730 100644
--- a/android/linux/generated/config.h
+++ b/android/linux/generated/config.h
@@ -2,6 +2,8 @@
 #define USE_TOYBOX_ANDROID_SCHEDPOLICY(...)
 #define CFG_TOYBOX_CONTAINER 0
 #define USE_TOYBOX_CONTAINER(...)
+#define CFG_TOYBOX_COPYFILERANGE 0
+#define USE_TOYBOX_COPYFILERANGE(...)
 #define CFG_TOYBOX_DEBUG 0
 #define USE_TOYBOX_DEBUG(...)
 #define CFG_TOYBOX_FALLOCATE 0
diff --git a/android/linux/generated/flags.h b/android/linux/generated/flags.h
index 7a92c8d..2ab033b 100644
--- a/android/linux/generated/flags.h
+++ b/android/linux/generated/flags.h
@@ -1535,9 +1535,9 @@
 #undef FLAG_t
 #endif
 
-// iorenice   ?<1>3
+// iorenice   <1>3
 #undef OPTSTR_iorenice
-#define OPTSTR_iorenice "?<1>3"
+#define OPTSTR_iorenice "<1>3"
 #ifdef CLEANUP_iorenice
 #undef CLEANUP_iorenice
 #undef FOR_iorenice
@@ -2248,9 +2248,9 @@
 #undef FLAG_n
 #endif
 
-// openvt   c#<1>63sw
+// openvt   ^<1c#<1>63sw
 #undef OPTSTR_openvt
-#define OPTSTR_openvt "c#<1>63sw"
+#define OPTSTR_openvt "^<1c#<1>63sw"
 #ifdef CLEANUP_openvt
 #undef CLEANUP_openvt
 #undef FOR_openvt
@@ -2534,14 +2534,6 @@
 #undef FLAG_n
 #endif
 
-// realpath <1 <1
-#undef OPTSTR_realpath
-#define OPTSTR_realpath "<1"
-#ifdef CLEANUP_realpath
-#undef CLEANUP_realpath
-#undef FOR_realpath
-#endif
-
 // reboot   d:fn
 #undef OPTSTR_reboot
 #define OPTSTR_reboot "d:fn"
@@ -3065,9 +3057,9 @@
 #undef FLAG_f
 #endif
 
-// tar &(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa] &(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]
+// tar &(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa] &(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]
 #undef OPTSTR_tar
-#define OPTSTR_tar "&(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]"
+#define OPTSTR_tar "&(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]"
 #ifdef CLEANUP_tar
 #undef CLEANUP_tar
 #undef FOR_tar
@@ -3105,6 +3097,7 @@
 #undef FLAG_full_time
 #undef FLAG_restrict
 #undef FLAG_selinux
+#undef FLAG_strip_components
 #endif
 
 // taskset   <1^pa
@@ -3638,12 +3631,13 @@
 #undef FLAG_m
 #endif
 
-// wget   <1>1(max-redirect)#<0=20d(debug)O(output-document):
+// wget   <1>1(max-redirect)#<0=20d(debug)O(output-document):p(post-data):
 #undef OPTSTR_wget
-#define OPTSTR_wget "<1>1(max-redirect)#<0=20d(debug)O(output-document):"
+#define OPTSTR_wget "<1>1(max-redirect)#<0=20d(debug)O(output-document):p(post-data):"
 #ifdef CLEANUP_wget
 #undef CLEANUP_wget
 #undef FOR_wget
+#undef FLAG_p
 #undef FLAG_O
 #undef FLAG_d
 #undef FLAG_max_redirect
@@ -6065,13 +6059,6 @@
 #define FLAG_n (1<<4)
 #endif
 
-#ifdef FOR_realpath
-#define CLEANUP_realpath
-#ifndef TT
-#define TT this.realpath
-#endif
-#endif
-
 #ifdef FOR_reboot
 #define CLEANUP_reboot
 #ifndef TT
@@ -6590,6 +6577,7 @@
 #define FLAG_full_time (1LL<<31)
 #define FLAG_restrict (1LL<<32)
 #define FLAG_selinux (1LL<<33)
+#define FLAG_strip_components (1LL<<34)
 #endif
 
 #ifdef FOR_taskset
@@ -7084,9 +7072,10 @@
 #ifndef TT
 #define TT this.wget
 #endif
-#define FLAG_O (FORCED_FLAG<<0)
-#define FLAG_d (FORCED_FLAG<<1)
-#define FLAG_max_redirect (FORCED_FLAG<<2)
+#define FLAG_p (FORCED_FLAG<<0)
+#define FLAG_O (FORCED_FLAG<<1)
+#define FLAG_d (FORCED_FLAG<<2)
+#define FLAG_max_redirect (FORCED_FLAG<<3)
 #endif
 
 #ifdef FOR_which
diff --git a/android/linux/generated/globals.h b/android/linux/generated/globals.h
index 844f4d0..403077b 100644
--- a/android/linux/generated/globals.h
+++ b/android/linux/generated/globals.h
@@ -397,6 +397,12 @@
   char *c;
 };
 
+// toys/other/openvt.c
+
+struct openvt_data {
+  long c;
+};
+
 // toys/other/pwgen.c
 
 struct pwgen_data {
@@ -862,12 +868,6 @@
   int cin_fd;
 };
 
-// toys/pending/openvt.c
-
-struct openvt_data {
-  long c;
-};
-
 // toys/pending/route.c
 
 struct route_data {
@@ -1159,10 +1159,10 @@
 // toys/pending/wget.c
 
 struct wget_data {
-  char *filename;
-  long redirects;
+  char *p, *O;
+  long max_redirect;
 
-  int sock;
+  int sock, https;
   char *url;
 #if CFG_WGET_LIBTLS
   struct tls *tls;
@@ -1549,6 +1549,7 @@
   struct arg_list *T, *X;
   char *I, *to_command, *owner, *group, *mtime, *mode;
   struct arg_list *exclude;
+  long strip_components;
 
   struct double_list *incl, *excl, *seen;
   struct string_list *dirs;
@@ -1678,6 +1679,7 @@
 	struct modinfo_data modinfo;
 	struct nsenter_data nsenter;
 	struct oneit_data oneit;
+	struct openvt_data openvt;
 	struct pwgen_data pwgen;
 	struct readelf_data readelf;
 	struct reboot_data reboot;
@@ -1728,7 +1730,6 @@
 	struct mke2fs_data mke2fs;
 	struct modprobe_data modprobe;
 	struct more_data more;
-	struct openvt_data openvt;
 	struct route_data route;
 	struct sh_data sh;
 	struct strace_data strace;
diff --git a/android/linux/generated/help.h b/android/linux/generated/help.h
index ae7d47c..30c24e9 100644
--- a/android/linux/generated/help.h
+++ b/android/linux/generated/help.h
@@ -4,8 +4,6 @@
 
 #define HELP_toybox_uid_sys "When commands like useradd/groupadd allocate system IDs, start here."
 
-#define HELP_toybox_pedantic_args "Check arguments for commands that have no arguments."
-
 #define HELP_toybox_debug "Enable extra checks for debugging purposes. All of them catch\nthings that can only go wrong at development time, not runtime."
 
 #define HELP_toybox_norecurse "When one toybox command calls another, usually it just calls the new\ncommand's main() function rather than searching the $PATH and calling\nexec on another file (which is much slower).\n\nThis disables that optimization, so toybox will run external commands\n       even when it has a built-in version of that command. This requires\n       toybox symlinks to be installed in the $PATH, or re-invoking the\n       \"toybox\" multiplexer command by name."
@@ -128,7 +126,7 @@
 
 #define HELP_microcom "usage: microcom [-s SPEED] [-X] DEVICE\n\nSimple serial console.\n\n-s	Set baud rate to SPEED (default 115200)\n-X	Ignore ^@ (send break) and ^] (exit)"
 
-#define HELP_ifconfig "usage: ifconfig [-aS] [INTERFACE [ACTION...]]\n\nDisplay or configure network interface.\n\nWith no arguments, display active interfaces. First argument is interface\nto operate on, one argument by itself displays that interface.\n\n-a	All interfaces displayed, not just active ones\n-S	Short view, one line per interface\n\nStandard ACTIONs to perform on an INTERFACE:\n\nADDR[/MASK]        - set IPv4 address (1.2.3.4/5) and activate interface\nadd|del ADDR[/LEN] - add/remove IPv6 address (1111::8888/128)\nup|down            - activate or deactivate interface\n\nAdvanced ACTIONs (default values usually suffice):\n\ndefault          - remove IPv4 address\nnetmask ADDR     - set IPv4 netmask via 255.255.255.0 instead of /24\ntxqueuelen LEN   - number of buffered packets before output blocks\nmtu LEN          - size of outgoing packets (Maximum Transmission Unit)\nbroadcast ADDR   - Set broadcast address\npointopoint ADDR - PPP and PPPOE use this instead of \"route add default gw\"\nhw TYPE ADDR     - set hardware (mac) address (type = ether|infiniband)\n\nFlags you can set on an interface (or -remove by prefixing with -):\n\narp       - don't use Address Resolution Protocol to map LAN routes\npromisc   - don't discard packets that aren't to this LAN hardware address\nmulticast - force interface into multicast mode if the driver doesn't\nallmulti  - promisc for multicast packets"
+#define HELP_ifconfig "usage: ifconfig [-aS] [INTERFACE [ACTION...]]\n\nDisplay or configure network interface.\n\nWith no arguments, display active interfaces. First argument is interface\nto operate on, one argument by itself displays that interface.\n\n-a	All interfaces displayed, not just active ones\n-S	Short view, one line per interface\n\nStandard ACTIONs to perform on an INTERFACE:\n\nADDR[/MASK]        - set IPv4 address (1.2.3.4/5) and activate interface\nadd|del ADDR[/LEN] - add/remove IPv6 address (1111::8888/128)\nup|down            - activate or deactivate interface\n\nAdvanced ACTIONs (default values usually suffice):\n\ndefault          - remove IPv4 address\nnetmask ADDR     - set IPv4 netmask via 255.255.255.0 instead of /24\ntxqueuelen LEN   - number of buffered packets before output blocks\nmtu LEN          - size of outgoing packets (Maximum Transmission Unit)\nbroadcast ADDR   - Set broadcast address\npointopoint ADDR - PPP and PPPOE use this instead of \"route add default gw\"\nhw TYPE ADDR     - set hardware (mac) address (type = ether|infiniband)\nrename NEWNAME   - rename interface\n\nFlags you can set on an interface (or -remove by prefixing with -):\n\narp       - don't use Address Resolution Protocol to map LAN routes\npromisc   - don't discard packets that aren't to this LAN hardware address\nmulticast - force interface into multicast mode if the driver doesn't\nallmulti  - promisc for multicast packets"
 
 #define HELP_host "usage: host [-v] [-t TYPE] NAME [SERVER]\n\nLook up DNS records for NAME, either domain name or IPv4/IPv6 address to\nreverse lookup, from SERVER or default DNS server(s).\n\n-a	All records\n-t TYPE	Record TYPE (number or ANY A AAAA CNAME MX NS PTR SOA SRV TXT)\n-v	Verbose"
 
@@ -218,6 +216,12 @@
 
 #define HELP_partprobe "usage: partprobe DEVICE...\n\nTell the kernel about partition table changes\n\nAsk the kernel to re-read the partition table on the specified devices."
 
+#define HELP_deallocvt "usage: deallocvt [NUM]\n\nDeallocate unused virtual terminals, either a specific /dev/ttyNUM, or all."
+
+#define HELP_chvt "usage: chvt NUM\n\nChange to virtual terminal number NUM. (This only works in text mode.)\n\nVirtual terminals are the Linux VGA text mode (or framebuffer) displays,\nswitched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch\nfrom X11 to a virtual terminal, and alt-F6 (or F7, or F8) to get back."
+
+#define HELP_openvt "usage: openvt [-c NUM] [-sw] COMMAND...\n\nRun COMMAND on a new virtual terminal.\n\n-c NUM  Use VT NUM\n-s    Switch to the new VT\n-w    Wait for command to exit (with -s, deallocates VT on exit)"
+
 #define HELP_oneit "usage: oneit [-prn3] [-c CONSOLE] [COMMAND...]\n\nSimple init program that runs a single supplied command line with a\ncontrolling tty (so CTRL-C can kill it).\n\n-c	Which console device to use (/dev/console doesn't do CTRL-C, etc)\n-p	Power off instead of rebooting when command exits\n-r	Restart child when it exits\n-n	No reboot, just relaunch command line\n-3	Write 32 bit PID of each exiting reparented process to fd 3 of child\n	(Blocking writes, child must read to avoid eventual deadlock.)\n\nSpawns a single child process (because PID 1 has signals blocked)\nin its own session, reaps zombies until the child exits, then\nreboots the system (or powers off with -p, or restarts the child with -r).\n\nResponds to SIGUSR1 by halting the system, SIGUSR2 by powering off,\nand SIGTERM or SIGINT reboot."
 
 #define HELP_nsenter "usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND...\n\nRun COMMAND in an existing (set of) namespace(s).\n\n-t	PID to take namespaces from    (--target)\n-F	don't fork, even if -p is used (--no-fork)\n\nThe namespaces to switch are:\n\n-i	SysV IPC: message queues, semaphores, shared memory (--ipc)\n-m	Mount/unmount tree (--mount)\n-n	Network address, sockets, routing, iptables (--net)\n-p	Process IDs and init, will fork unless -F is used (--pid)\n-u	Host and domain names (--uts)\n-U	UIDs, GIDs, capabilities (--user)\n\nIf -t isn't specified, each namespace argument must provide a path\nto a namespace file, ala \"-i=/proc/$PID/ns/ipc\""
@@ -314,8 +318,6 @@
 
 #define HELP_clear "Clear the screen."
 
-#define HELP_chvt "usage: chvt N\n\nChange to virtual terminal number N. (This only works in text mode.)\n\nVirtual terminals are the Linux VGA text mode displays, ordinarily\nswitched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch\nfrom X to a virtual terminal, and alt-F6 (or F7, or F8) to get back."
-
 #define HELP_chrt "usage: chrt [-Rmofrbi] {-p PID [PRIORITY] | [PRIORITY COMMAND...]}\n\nGet/set a process' real-time scheduling policy and priority.\n\n-p	Set/query given pid (instead of running COMMAND)\n-R	Set SCHED_RESET_ON_FORK\n-m	Show min/max priorities available\n\nSet policy (default -r):\n\n  -o  SCHED_OTHER    -f  SCHED_FIFO    -r  SCHED_RR\n  -b  SCHED_BATCH    -i  SCHED_IDLE"
 
 #define HELP_chroot "usage: chroot NEWROOT [COMMAND [ARG...]]\n\nRun command within a new root directory. If no command, run /bin/sh."
@@ -350,7 +352,7 @@
 
 #define HELP_wget_libtls "Enable HTTPS support for wget by linking to LibTLS.\nSupports using libtls, libretls or libtls-bearssl."
 
-#define HELP_wget "usage: wget [OPTIONS]... [URL]\n    --max-redirect          maximum redirections allowed\n-d, --debug                 print lots of debugging information\n-O, --output-document=FILE  specify output filename\n\nexamples:\n  wget http://www.example.com"
+#define HELP_wget "usage: wget [OPTIONS]... [URL]\n    --max-redirect          maximum redirections allowed\n-d, --debug                 print lots of debugging information\n-O, --output-document=FILE  specify output filename\n-p, --post-data=DATA        send data in body of POST request\n\nexamples:\n  wget http://www.example.com"
 
 #define HELP_vi "usage: vi [-s script] FILE\n-s script: run script file\nVisual text editor. Predates the existence of standardized cursor keys,\nso the controls are weird and historical."
 
@@ -410,10 +412,6 @@
 
 #define HELP_route "usage: route [-ne] [-A [inet|inet6]] [add|del TARGET [OPTIONS]]\n\nDisplay, add or delete network routes in the \"Forwarding Information Base\",\nwhich send packets out a network interface to an address.\n\n-n	Show numerical addresses (no DNS lookups)\n-e	display netstat fields\n\nAssigning an address to an interface automatically creates an appropriate\nnetwork route (\"ifconfig eth0 10.0.2.15/8\" does \"route add 10.0.0.0/8 eth0\"\nfor you), although some devices (such as loopback) won't show it in the\ntable. For machines more than one hop away, you need to specify a gateway\n(ala \"route add default gw 10.0.2.2\").\n\nThe address \"default\" is a wildcard address (0.0.0.0/0) matching all\npackets without a more specific route.\n\nAvailable OPTIONS include:\nreject   - blocking route (force match failure)\ndev NAME - force matching packets out this interface (ala \"eth0\")\nnetmask  - old way of saying things like ADDR/24\ngw ADDR  - forward packets to gateway ADDR"
 
-#define HELP_deallocvt "usage: deallocvt [NUM]\n\nDeallocate unused virtual terminals, either a specific /dev/ttyNUM, or all."
-
-#define HELP_openvt "usage: openvt [-c NUM] [-sw] [COMMAND...]\n\nStart a program on a new virtual terminal.\n\n-c NUM  Use VT NUM\n-s    Switch to new VT\n-w    Wait for command to exit\n\nTogether -sw switch back to originating VT when command completes."
-
 #define HELP_more "usage: more [FILE...]\n\nView FILE(s) (or stdin) one screenfull at a time."
 
 #define HELP_modprobe "usage: modprobe [-alrqvsDb] [-d DIR] MODULE [symbol=value][...]\n\nmodprobe utility - inserts modules and dependencies.\n\n-a  Load multiple MODULEs\n-b  Apply blacklist to module names too\n-D  Show dependencies\n-d  Load modules from DIR, option may be used multiple times\n-l  List (MODULE is a pattern)\n-q  Quiet\n-r  Remove MODULE (stacks) or do autoclean\n-s  Log to syslog\n-v  Verbose"
@@ -532,7 +530,7 @@
 
 #define HELP_tee "usage: tee [-ai] [FILE...]\n\nCopy stdin to each listed file, and also to stdout.\nFilename \"-\" is a synonym for stdout.\n\n-a	Append to files\n-i	Ignore SIGINT"
 
-#define HELP_tar "usage: tar [-cxt] [-fvohmjkOS] [-XTCf NAME] [--selinux] [FILE...]\n\nCreate, extract, or list files in a .tar (or compressed t?z) file.\n\nOptions:\nc  Create                x  Extract               t  Test (list)\nf  tar FILE (default -)  C  Change to DIR first   v  Verbose display\no  Ignore owner          h  Follow symlinks       m  Ignore mtime\nJ  xz compression        j  bzip2 compression     z  gzip compression\nO  Extract to stdout     X  exclude names in FILE T  include names in FILE\n\n--exclude        FILENAME to exclude    --full-time   Show seconds with -tv\n--mode MODE      Adjust modes           --mtime TIME  Override timestamps\n--owner NAME     Set file owner to NAME --group NAME  Set file group to NAME\n--sparse         Record sparse files    --selinux     Record/restore labels\n--restrict       All archive contents must extract under one subdirectory\n--numeric-owner  Save/use/display uid and gid, not user/group name\n--no-recursion   Don't store directory contents\n-I PROG          Filter through PROG to compress or PROG -d to decompress"
+#define HELP_tar "usage: tar [-cxt] [-fvohmjkOS] [-XTCf NAME] [--selinux] [FILE...]\n\nCreate, extract, or list files in a .tar (or compressed t?z) file.\n\nOptions:\nc  Create                x  Extract               t  Test (list)\nf  tar FILE (default -)  C  Change to DIR first   v  Verbose display\no  Ignore owner          h  Follow symlinks       m  Ignore mtime\nJ  xz compression        j  bzip2 compression     z  gzip compression\nO  Extract to stdout     X  exclude names in FILE T  include names in FILE\n\n--exclude        FILENAME to exclude  --full-time         Show seconds with -tv\n--mode MODE      Adjust permissions   --owner NAME[:UID]  Set file ownership\n--mtime TIME     Override timestamps  --group NAME[:GID]  Set file group\n--sparse         Record sparse files  --selinux           Save/restore labels\n--restrict       All under one dir    --no-recursion      Skip dir contents\n--numeric-owner  Use numeric uid/gid, not user/group names\n--strip-components NUM  Ignore first NUM directory components when extracting\n-I PROG          Filter through PROG to compress or PROG -d to decompress"
 
 #define HELP_tail "usage: tail [-n|c NUMBER] [-f|F] [-s SECONDS] [FILE...]\n\nCopy last lines from files to stdout. If no files listed, copy from\nstdin. Filename \"-\" is a synonym for stdin.\n\n-n	Output the last NUMBER lines (default 10), +X counts from start\n-c	Output the last NUMBER bytes, +NUMBER counts from start\n-f	Follow FILE(s) by descriptor, waiting for more data to be appended\n-F	Follow FILE(s) by filename, waiting for more data, and retrying\n-s	Used with -F, sleep SECONDS between retries (default 1)"
 
diff --git a/android/linux/generated/newtoys.h b/android/linux/generated/newtoys.h
index ea56d9d..ade8831 100644
--- a/android/linux/generated/newtoys.h
+++ b/android/linux/generated/newtoys.h
@@ -1,4 +1,4 @@
-USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT))
+USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT|TOYFLAG_NOHELP))
 USE_SH(OLDTOY(-bash, sh, 0))
 USE_SH(OLDTOY(-sh, sh, 0))
 USE_SH(OLDTOY(-toysh, sh, 0))
@@ -137,7 +137,7 @@
 USE_INSMOD(NEWTOY(insmod, "<1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
 USE_INSTALL(NEWTOY(install, "<1cdDpsvt:m:o:g:", TOYFLAG_USR|TOYFLAG_BIN))
 USE_IONICE(NEWTOY(ionice, "^tc#<0>3=2n#<0>7=5p#", TOYFLAG_USR|TOYFLAG_BIN))
-USE_IORENICE(NEWTOY(iorenice, "?<1>3", TOYFLAG_USR|TOYFLAG_BIN))
+USE_IORENICE(NEWTOY(iorenice, "<1>3", TOYFLAG_USR|TOYFLAG_BIN))
 USE_IOTOP(NEWTOY(iotop, ">0AaKO" "Hk*o*p*u*s#<1=7d%<100=3000m#n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
 USE_IP(NEWTOY(ip, NULL, TOYFLAG_SBIN))
 USE_IP(OLDTOY(ipaddr, ip, TOYFLAG_SBIN))
@@ -201,7 +201,7 @@
 USE_NSENTER(NEWTOY(nsenter, "<1F(no-fork)t#<1(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN))
 USE_OD(NEWTOY(od, "j#vw#<1=16N#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN))
 USE_ONEIT(NEWTOY(oneit, "^<1nc:p3[!pn]", TOYFLAG_SBIN))
-USE_OPENVT(NEWTOY(openvt, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+USE_OPENVT(NEWTOY(openvt, "^<1c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
 USE_PARTPROBE(NEWTOY(partprobe, "<1", TOYFLAG_SBIN))
 USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
 USE_PASTE(NEWTOY(paste, "d:s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
@@ -224,7 +224,7 @@
 USE_READAHEAD(NEWTOY(readahead, NULL, TOYFLAG_BIN))
 USE_READELF(NEWTOY(readelf, "<1(dyn-syms)adehlnp:SsWx:", TOYFLAG_USR|TOYFLAG_BIN))
 USE_READLINK(NEWTOY(readlink, "<1nqmef(canonicalize)[-mef]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_REALPATH(NEWTOY(realpath, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_REALPATH(OLDTOY(realpath, readlink, TOYFLAG_USR|TOYFLAG_BIN))
 USE_REBOOT(NEWTOY(reboot, "d:fn", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
 USE_RENICE(NEWTOY(renice, "<1gpun#|", TOYFLAG_USR|TOYFLAG_BIN))
 USE_RESET(NEWTOY(reset, 0, TOYFLAG_USR|TOYFLAG_BIN))
@@ -274,7 +274,7 @@
 USE_SYSLOGD(NEWTOY(syslogd,">0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD", TOYFLAG_SBIN|TOYFLAG_STAYROOT))
 USE_TAC(NEWTOY(tac, NULL, TOYFLAG_USR|TOYFLAG_BIN))
 USE_TAIL(NEWTOY(tail, "?fFs:c(bytes)-n(lines)-[-cn][-fF]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_TAR(NEWTOY(tar, "&(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TAR(NEWTOY(tar, "&(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]", TOYFLAG_USR|TOYFLAG_BIN))
 USE_TASKSET(NEWTOY(taskset, "<1^pa", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
 USE_TCPSVD(NEWTOY(tcpsvd, "^<3c#=30<1C:b#=20<0u:l:hEv", TOYFLAG_USR|TOYFLAG_BIN))
 USE_TEE(NEWTOY(tee, "ia", TOYFLAG_USR|TOYFLAG_BIN))
@@ -321,7 +321,7 @@
 USE_WATCH(NEWTOY(watch, "^<1n%<100=2000tebx", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
 USE_WATCHDOG(NEWTOY(watchdog, "<1>1Ft#=4<1T#=60<1", TOYFLAG_NEEDROOT|TOYFLAG_BIN))
 USE_WC(NEWTOY(wc, "mcwl", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
-USE_WGET(NEWTOY(wget, "<1>1(max-redirect)#<0=20d(debug)O(output-document):", TOYFLAG_USR|TOYFLAG_BIN))
+USE_WGET(NEWTOY(wget, "<1>1(max-redirect)#<0=20d(debug)O(output-document):p(post-data):", TOYFLAG_USR|TOYFLAG_BIN))
 USE_WHICH(NEWTOY(which, "<1a", TOYFLAG_USR|TOYFLAG_BIN))
 USE_WHO(NEWTOY(who, "a", TOYFLAG_USR|TOYFLAG_BIN))
 USE_WHOAMI(OLDTOY(whoami, logname, TOYFLAG_USR|TOYFLAG_BIN))
diff --git a/android/mac/generated/config.h b/android/mac/generated/config.h
index cbb0b43..a9f4bdf 100644
--- a/android/mac/generated/config.h
+++ b/android/mac/generated/config.h
@@ -2,6 +2,8 @@
 #define USE_TOYBOX_ANDROID_SCHEDPOLICY(...)
 #define CFG_TOYBOX_CONTAINER 0
 #define USE_TOYBOX_CONTAINER(...)
+#define CFG_TOYBOX_COPYFILERANGE 0
+#define USE_TOYBOX_COPYFILERANGE(...)
 #define CFG_TOYBOX_DEBUG 0
 #define USE_TOYBOX_DEBUG(...)
 #define CFG_TOYBOX_FALLOCATE 0
diff --git a/android/mac/generated/flags.h b/android/mac/generated/flags.h
index f290c98..516ffc7 100644
--- a/android/mac/generated/flags.h
+++ b/android/mac/generated/flags.h
@@ -1535,9 +1535,9 @@
 #undef FLAG_t
 #endif
 
-// iorenice   ?<1>3
+// iorenice   <1>3
 #undef OPTSTR_iorenice
-#define OPTSTR_iorenice "?<1>3"
+#define OPTSTR_iorenice "<1>3"
 #ifdef CLEANUP_iorenice
 #undef CLEANUP_iorenice
 #undef FOR_iorenice
@@ -2248,9 +2248,9 @@
 #undef FLAG_n
 #endif
 
-// openvt   c#<1>63sw
+// openvt   ^<1c#<1>63sw
 #undef OPTSTR_openvt
-#define OPTSTR_openvt "c#<1>63sw"
+#define OPTSTR_openvt "^<1c#<1>63sw"
 #ifdef CLEANUP_openvt
 #undef CLEANUP_openvt
 #undef FOR_openvt
@@ -2534,14 +2534,6 @@
 #undef FLAG_n
 #endif
 
-// realpath <1 <1
-#undef OPTSTR_realpath
-#define OPTSTR_realpath "<1"
-#ifdef CLEANUP_realpath
-#undef CLEANUP_realpath
-#undef FOR_realpath
-#endif
-
 // reboot   d:fn
 #undef OPTSTR_reboot
 #define OPTSTR_reboot "d:fn"
@@ -3065,9 +3057,9 @@
 #undef FLAG_f
 #endif
 
-// tar &(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa] &(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]
+// tar &(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa] &(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]
 #undef OPTSTR_tar
-#define OPTSTR_tar "&(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]"
+#define OPTSTR_tar "&(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]"
 #ifdef CLEANUP_tar
 #undef CLEANUP_tar
 #undef FOR_tar
@@ -3105,6 +3097,7 @@
 #undef FLAG_full_time
 #undef FLAG_restrict
 #undef FLAG_selinux
+#undef FLAG_strip_components
 #endif
 
 // taskset   <1^pa
@@ -3638,12 +3631,13 @@
 #undef FLAG_m
 #endif
 
-// wget   <1>1(max-redirect)#<0=20d(debug)O(output-document):
+// wget   <1>1(max-redirect)#<0=20d(debug)O(output-document):p(post-data):
 #undef OPTSTR_wget
-#define OPTSTR_wget "<1>1(max-redirect)#<0=20d(debug)O(output-document):"
+#define OPTSTR_wget "<1>1(max-redirect)#<0=20d(debug)O(output-document):p(post-data):"
 #ifdef CLEANUP_wget
 #undef CLEANUP_wget
 #undef FOR_wget
+#undef FLAG_p
 #undef FLAG_O
 #undef FLAG_d
 #undef FLAG_max_redirect
@@ -6065,13 +6059,6 @@
 #define FLAG_n (1<<4)
 #endif
 
-#ifdef FOR_realpath
-#define CLEANUP_realpath
-#ifndef TT
-#define TT this.realpath
-#endif
-#endif
-
 #ifdef FOR_reboot
 #define CLEANUP_reboot
 #ifndef TT
@@ -6590,6 +6577,7 @@
 #define FLAG_full_time (1LL<<31)
 #define FLAG_restrict (1LL<<32)
 #define FLAG_selinux (1LL<<33)
+#define FLAG_strip_components (1LL<<34)
 #endif
 
 #ifdef FOR_taskset
@@ -7084,9 +7072,10 @@
 #ifndef TT
 #define TT this.wget
 #endif
-#define FLAG_O (FORCED_FLAG<<0)
-#define FLAG_d (FORCED_FLAG<<1)
-#define FLAG_max_redirect (FORCED_FLAG<<2)
+#define FLAG_p (FORCED_FLAG<<0)
+#define FLAG_O (FORCED_FLAG<<1)
+#define FLAG_d (FORCED_FLAG<<2)
+#define FLAG_max_redirect (FORCED_FLAG<<3)
 #endif
 
 #ifdef FOR_which
diff --git a/android/mac/generated/globals.h b/android/mac/generated/globals.h
index 844f4d0..403077b 100644
--- a/android/mac/generated/globals.h
+++ b/android/mac/generated/globals.h
@@ -397,6 +397,12 @@
   char *c;
 };
 
+// toys/other/openvt.c
+
+struct openvt_data {
+  long c;
+};
+
 // toys/other/pwgen.c
 
 struct pwgen_data {
@@ -862,12 +868,6 @@
   int cin_fd;
 };
 
-// toys/pending/openvt.c
-
-struct openvt_data {
-  long c;
-};
-
 // toys/pending/route.c
 
 struct route_data {
@@ -1159,10 +1159,10 @@
 // toys/pending/wget.c
 
 struct wget_data {
-  char *filename;
-  long redirects;
+  char *p, *O;
+  long max_redirect;
 
-  int sock;
+  int sock, https;
   char *url;
 #if CFG_WGET_LIBTLS
   struct tls *tls;
@@ -1549,6 +1549,7 @@
   struct arg_list *T, *X;
   char *I, *to_command, *owner, *group, *mtime, *mode;
   struct arg_list *exclude;
+  long strip_components;
 
   struct double_list *incl, *excl, *seen;
   struct string_list *dirs;
@@ -1678,6 +1679,7 @@
 	struct modinfo_data modinfo;
 	struct nsenter_data nsenter;
 	struct oneit_data oneit;
+	struct openvt_data openvt;
 	struct pwgen_data pwgen;
 	struct readelf_data readelf;
 	struct reboot_data reboot;
@@ -1728,7 +1730,6 @@
 	struct mke2fs_data mke2fs;
 	struct modprobe_data modprobe;
 	struct more_data more;
-	struct openvt_data openvt;
 	struct route_data route;
 	struct sh_data sh;
 	struct strace_data strace;
diff --git a/android/mac/generated/help.h b/android/mac/generated/help.h
index ae7d47c..30c24e9 100644
--- a/android/mac/generated/help.h
+++ b/android/mac/generated/help.h
@@ -4,8 +4,6 @@
 
 #define HELP_toybox_uid_sys "When commands like useradd/groupadd allocate system IDs, start here."
 
-#define HELP_toybox_pedantic_args "Check arguments for commands that have no arguments."
-
 #define HELP_toybox_debug "Enable extra checks for debugging purposes. All of them catch\nthings that can only go wrong at development time, not runtime."
 
 #define HELP_toybox_norecurse "When one toybox command calls another, usually it just calls the new\ncommand's main() function rather than searching the $PATH and calling\nexec on another file (which is much slower).\n\nThis disables that optimization, so toybox will run external commands\n       even when it has a built-in version of that command. This requires\n       toybox symlinks to be installed in the $PATH, or re-invoking the\n       \"toybox\" multiplexer command by name."
@@ -128,7 +126,7 @@
 
 #define HELP_microcom "usage: microcom [-s SPEED] [-X] DEVICE\n\nSimple serial console.\n\n-s	Set baud rate to SPEED (default 115200)\n-X	Ignore ^@ (send break) and ^] (exit)"
 
-#define HELP_ifconfig "usage: ifconfig [-aS] [INTERFACE [ACTION...]]\n\nDisplay or configure network interface.\n\nWith no arguments, display active interfaces. First argument is interface\nto operate on, one argument by itself displays that interface.\n\n-a	All interfaces displayed, not just active ones\n-S	Short view, one line per interface\n\nStandard ACTIONs to perform on an INTERFACE:\n\nADDR[/MASK]        - set IPv4 address (1.2.3.4/5) and activate interface\nadd|del ADDR[/LEN] - add/remove IPv6 address (1111::8888/128)\nup|down            - activate or deactivate interface\n\nAdvanced ACTIONs (default values usually suffice):\n\ndefault          - remove IPv4 address\nnetmask ADDR     - set IPv4 netmask via 255.255.255.0 instead of /24\ntxqueuelen LEN   - number of buffered packets before output blocks\nmtu LEN          - size of outgoing packets (Maximum Transmission Unit)\nbroadcast ADDR   - Set broadcast address\npointopoint ADDR - PPP and PPPOE use this instead of \"route add default gw\"\nhw TYPE ADDR     - set hardware (mac) address (type = ether|infiniband)\n\nFlags you can set on an interface (or -remove by prefixing with -):\n\narp       - don't use Address Resolution Protocol to map LAN routes\npromisc   - don't discard packets that aren't to this LAN hardware address\nmulticast - force interface into multicast mode if the driver doesn't\nallmulti  - promisc for multicast packets"
+#define HELP_ifconfig "usage: ifconfig [-aS] [INTERFACE [ACTION...]]\n\nDisplay or configure network interface.\n\nWith no arguments, display active interfaces. First argument is interface\nto operate on, one argument by itself displays that interface.\n\n-a	All interfaces displayed, not just active ones\n-S	Short view, one line per interface\n\nStandard ACTIONs to perform on an INTERFACE:\n\nADDR[/MASK]        - set IPv4 address (1.2.3.4/5) and activate interface\nadd|del ADDR[/LEN] - add/remove IPv6 address (1111::8888/128)\nup|down            - activate or deactivate interface\n\nAdvanced ACTIONs (default values usually suffice):\n\ndefault          - remove IPv4 address\nnetmask ADDR     - set IPv4 netmask via 255.255.255.0 instead of /24\ntxqueuelen LEN   - number of buffered packets before output blocks\nmtu LEN          - size of outgoing packets (Maximum Transmission Unit)\nbroadcast ADDR   - Set broadcast address\npointopoint ADDR - PPP and PPPOE use this instead of \"route add default gw\"\nhw TYPE ADDR     - set hardware (mac) address (type = ether|infiniband)\nrename NEWNAME   - rename interface\n\nFlags you can set on an interface (or -remove by prefixing with -):\n\narp       - don't use Address Resolution Protocol to map LAN routes\npromisc   - don't discard packets that aren't to this LAN hardware address\nmulticast - force interface into multicast mode if the driver doesn't\nallmulti  - promisc for multicast packets"
 
 #define HELP_host "usage: host [-v] [-t TYPE] NAME [SERVER]\n\nLook up DNS records for NAME, either domain name or IPv4/IPv6 address to\nreverse lookup, from SERVER or default DNS server(s).\n\n-a	All records\n-t TYPE	Record TYPE (number or ANY A AAAA CNAME MX NS PTR SOA SRV TXT)\n-v	Verbose"
 
@@ -218,6 +216,12 @@
 
 #define HELP_partprobe "usage: partprobe DEVICE...\n\nTell the kernel about partition table changes\n\nAsk the kernel to re-read the partition table on the specified devices."
 
+#define HELP_deallocvt "usage: deallocvt [NUM]\n\nDeallocate unused virtual terminals, either a specific /dev/ttyNUM, or all."
+
+#define HELP_chvt "usage: chvt NUM\n\nChange to virtual terminal number NUM. (This only works in text mode.)\n\nVirtual terminals are the Linux VGA text mode (or framebuffer) displays,\nswitched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch\nfrom X11 to a virtual terminal, and alt-F6 (or F7, or F8) to get back."
+
+#define HELP_openvt "usage: openvt [-c NUM] [-sw] COMMAND...\n\nRun COMMAND on a new virtual terminal.\n\n-c NUM  Use VT NUM\n-s    Switch to the new VT\n-w    Wait for command to exit (with -s, deallocates VT on exit)"
+
 #define HELP_oneit "usage: oneit [-prn3] [-c CONSOLE] [COMMAND...]\n\nSimple init program that runs a single supplied command line with a\ncontrolling tty (so CTRL-C can kill it).\n\n-c	Which console device to use (/dev/console doesn't do CTRL-C, etc)\n-p	Power off instead of rebooting when command exits\n-r	Restart child when it exits\n-n	No reboot, just relaunch command line\n-3	Write 32 bit PID of each exiting reparented process to fd 3 of child\n	(Blocking writes, child must read to avoid eventual deadlock.)\n\nSpawns a single child process (because PID 1 has signals blocked)\nin its own session, reaps zombies until the child exits, then\nreboots the system (or powers off with -p, or restarts the child with -r).\n\nResponds to SIGUSR1 by halting the system, SIGUSR2 by powering off,\nand SIGTERM or SIGINT reboot."
 
 #define HELP_nsenter "usage: nsenter [-t pid] [-F] [-i] [-m] [-n] [-p] [-u] [-U] COMMAND...\n\nRun COMMAND in an existing (set of) namespace(s).\n\n-t	PID to take namespaces from    (--target)\n-F	don't fork, even if -p is used (--no-fork)\n\nThe namespaces to switch are:\n\n-i	SysV IPC: message queues, semaphores, shared memory (--ipc)\n-m	Mount/unmount tree (--mount)\n-n	Network address, sockets, routing, iptables (--net)\n-p	Process IDs and init, will fork unless -F is used (--pid)\n-u	Host and domain names (--uts)\n-U	UIDs, GIDs, capabilities (--user)\n\nIf -t isn't specified, each namespace argument must provide a path\nto a namespace file, ala \"-i=/proc/$PID/ns/ipc\""
@@ -314,8 +318,6 @@
 
 #define HELP_clear "Clear the screen."
 
-#define HELP_chvt "usage: chvt N\n\nChange to virtual terminal number N. (This only works in text mode.)\n\nVirtual terminals are the Linux VGA text mode displays, ordinarily\nswitched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch\nfrom X to a virtual terminal, and alt-F6 (or F7, or F8) to get back."
-
 #define HELP_chrt "usage: chrt [-Rmofrbi] {-p PID [PRIORITY] | [PRIORITY COMMAND...]}\n\nGet/set a process' real-time scheduling policy and priority.\n\n-p	Set/query given pid (instead of running COMMAND)\n-R	Set SCHED_RESET_ON_FORK\n-m	Show min/max priorities available\n\nSet policy (default -r):\n\n  -o  SCHED_OTHER    -f  SCHED_FIFO    -r  SCHED_RR\n  -b  SCHED_BATCH    -i  SCHED_IDLE"
 
 #define HELP_chroot "usage: chroot NEWROOT [COMMAND [ARG...]]\n\nRun command within a new root directory. If no command, run /bin/sh."
@@ -350,7 +352,7 @@
 
 #define HELP_wget_libtls "Enable HTTPS support for wget by linking to LibTLS.\nSupports using libtls, libretls or libtls-bearssl."
 
-#define HELP_wget "usage: wget [OPTIONS]... [URL]\n    --max-redirect          maximum redirections allowed\n-d, --debug                 print lots of debugging information\n-O, --output-document=FILE  specify output filename\n\nexamples:\n  wget http://www.example.com"
+#define HELP_wget "usage: wget [OPTIONS]... [URL]\n    --max-redirect          maximum redirections allowed\n-d, --debug                 print lots of debugging information\n-O, --output-document=FILE  specify output filename\n-p, --post-data=DATA        send data in body of POST request\n\nexamples:\n  wget http://www.example.com"
 
 #define HELP_vi "usage: vi [-s script] FILE\n-s script: run script file\nVisual text editor. Predates the existence of standardized cursor keys,\nso the controls are weird and historical."
 
@@ -410,10 +412,6 @@
 
 #define HELP_route "usage: route [-ne] [-A [inet|inet6]] [add|del TARGET [OPTIONS]]\n\nDisplay, add or delete network routes in the \"Forwarding Information Base\",\nwhich send packets out a network interface to an address.\n\n-n	Show numerical addresses (no DNS lookups)\n-e	display netstat fields\n\nAssigning an address to an interface automatically creates an appropriate\nnetwork route (\"ifconfig eth0 10.0.2.15/8\" does \"route add 10.0.0.0/8 eth0\"\nfor you), although some devices (such as loopback) won't show it in the\ntable. For machines more than one hop away, you need to specify a gateway\n(ala \"route add default gw 10.0.2.2\").\n\nThe address \"default\" is a wildcard address (0.0.0.0/0) matching all\npackets without a more specific route.\n\nAvailable OPTIONS include:\nreject   - blocking route (force match failure)\ndev NAME - force matching packets out this interface (ala \"eth0\")\nnetmask  - old way of saying things like ADDR/24\ngw ADDR  - forward packets to gateway ADDR"
 
-#define HELP_deallocvt "usage: deallocvt [NUM]\n\nDeallocate unused virtual terminals, either a specific /dev/ttyNUM, or all."
-
-#define HELP_openvt "usage: openvt [-c NUM] [-sw] [COMMAND...]\n\nStart a program on a new virtual terminal.\n\n-c NUM  Use VT NUM\n-s    Switch to new VT\n-w    Wait for command to exit\n\nTogether -sw switch back to originating VT when command completes."
-
 #define HELP_more "usage: more [FILE...]\n\nView FILE(s) (or stdin) one screenfull at a time."
 
 #define HELP_modprobe "usage: modprobe [-alrqvsDb] [-d DIR] MODULE [symbol=value][...]\n\nmodprobe utility - inserts modules and dependencies.\n\n-a  Load multiple MODULEs\n-b  Apply blacklist to module names too\n-D  Show dependencies\n-d  Load modules from DIR, option may be used multiple times\n-l  List (MODULE is a pattern)\n-q  Quiet\n-r  Remove MODULE (stacks) or do autoclean\n-s  Log to syslog\n-v  Verbose"
@@ -532,7 +530,7 @@
 
 #define HELP_tee "usage: tee [-ai] [FILE...]\n\nCopy stdin to each listed file, and also to stdout.\nFilename \"-\" is a synonym for stdout.\n\n-a	Append to files\n-i	Ignore SIGINT"
 
-#define HELP_tar "usage: tar [-cxt] [-fvohmjkOS] [-XTCf NAME] [--selinux] [FILE...]\n\nCreate, extract, or list files in a .tar (or compressed t?z) file.\n\nOptions:\nc  Create                x  Extract               t  Test (list)\nf  tar FILE (default -)  C  Change to DIR first   v  Verbose display\no  Ignore owner          h  Follow symlinks       m  Ignore mtime\nJ  xz compression        j  bzip2 compression     z  gzip compression\nO  Extract to stdout     X  exclude names in FILE T  include names in FILE\n\n--exclude        FILENAME to exclude    --full-time   Show seconds with -tv\n--mode MODE      Adjust modes           --mtime TIME  Override timestamps\n--owner NAME     Set file owner to NAME --group NAME  Set file group to NAME\n--sparse         Record sparse files    --selinux     Record/restore labels\n--restrict       All archive contents must extract under one subdirectory\n--numeric-owner  Save/use/display uid and gid, not user/group name\n--no-recursion   Don't store directory contents\n-I PROG          Filter through PROG to compress or PROG -d to decompress"
+#define HELP_tar "usage: tar [-cxt] [-fvohmjkOS] [-XTCf NAME] [--selinux] [FILE...]\n\nCreate, extract, or list files in a .tar (or compressed t?z) file.\n\nOptions:\nc  Create                x  Extract               t  Test (list)\nf  tar FILE (default -)  C  Change to DIR first   v  Verbose display\no  Ignore owner          h  Follow symlinks       m  Ignore mtime\nJ  xz compression        j  bzip2 compression     z  gzip compression\nO  Extract to stdout     X  exclude names in FILE T  include names in FILE\n\n--exclude        FILENAME to exclude  --full-time         Show seconds with -tv\n--mode MODE      Adjust permissions   --owner NAME[:UID]  Set file ownership\n--mtime TIME     Override timestamps  --group NAME[:GID]  Set file group\n--sparse         Record sparse files  --selinux           Save/restore labels\n--restrict       All under one dir    --no-recursion      Skip dir contents\n--numeric-owner  Use numeric uid/gid, not user/group names\n--strip-components NUM  Ignore first NUM directory components when extracting\n-I PROG          Filter through PROG to compress or PROG -d to decompress"
 
 #define HELP_tail "usage: tail [-n|c NUMBER] [-f|F] [-s SECONDS] [FILE...]\n\nCopy last lines from files to stdout. If no files listed, copy from\nstdin. Filename \"-\" is a synonym for stdin.\n\n-n	Output the last NUMBER lines (default 10), +X counts from start\n-c	Output the last NUMBER bytes, +NUMBER counts from start\n-f	Follow FILE(s) by descriptor, waiting for more data to be appended\n-F	Follow FILE(s) by filename, waiting for more data, and retrying\n-s	Used with -F, sleep SECONDS between retries (default 1)"
 
diff --git a/android/mac/generated/newtoys.h b/android/mac/generated/newtoys.h
index ea56d9d..ade8831 100644
--- a/android/mac/generated/newtoys.h
+++ b/android/mac/generated/newtoys.h
@@ -1,4 +1,4 @@
-USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT))
+USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT|TOYFLAG_NOHELP))
 USE_SH(OLDTOY(-bash, sh, 0))
 USE_SH(OLDTOY(-sh, sh, 0))
 USE_SH(OLDTOY(-toysh, sh, 0))
@@ -137,7 +137,7 @@
 USE_INSMOD(NEWTOY(insmod, "<1", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
 USE_INSTALL(NEWTOY(install, "<1cdDpsvt:m:o:g:", TOYFLAG_USR|TOYFLAG_BIN))
 USE_IONICE(NEWTOY(ionice, "^tc#<0>3=2n#<0>7=5p#", TOYFLAG_USR|TOYFLAG_BIN))
-USE_IORENICE(NEWTOY(iorenice, "?<1>3", TOYFLAG_USR|TOYFLAG_BIN))
+USE_IORENICE(NEWTOY(iorenice, "<1>3", TOYFLAG_USR|TOYFLAG_BIN))
 USE_IOTOP(NEWTOY(iotop, ">0AaKO" "Hk*o*p*u*s#<1=7d%<100=3000m#n#<1bq", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT|TOYFLAG_LOCALE))
 USE_IP(NEWTOY(ip, NULL, TOYFLAG_SBIN))
 USE_IP(OLDTOY(ipaddr, ip, TOYFLAG_SBIN))
@@ -201,7 +201,7 @@
 USE_NSENTER(NEWTOY(nsenter, "<1F(no-fork)t#<1(target)i:(ipc);m:(mount);n:(net);p:(pid);u:(uts);U:(user);", TOYFLAG_USR|TOYFLAG_BIN))
 USE_OD(NEWTOY(od, "j#vw#<1=16N#xsodcbA:t*", TOYFLAG_USR|TOYFLAG_BIN))
 USE_ONEIT(NEWTOY(oneit, "^<1nc:p3[!pn]", TOYFLAG_SBIN))
-USE_OPENVT(NEWTOY(openvt, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+USE_OPENVT(NEWTOY(openvt, "^<1c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
 USE_PARTPROBE(NEWTOY(partprobe, "<1", TOYFLAG_SBIN))
 USE_PASSWD(NEWTOY(passwd, ">1a:dlu", TOYFLAG_STAYROOT|TOYFLAG_USR|TOYFLAG_BIN))
 USE_PASTE(NEWTOY(paste, "d:s", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
@@ -224,7 +224,7 @@
 USE_READAHEAD(NEWTOY(readahead, NULL, TOYFLAG_BIN))
 USE_READELF(NEWTOY(readelf, "<1(dyn-syms)adehlnp:SsWx:", TOYFLAG_USR|TOYFLAG_BIN))
 USE_READLINK(NEWTOY(readlink, "<1nqmef(canonicalize)[-mef]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_REALPATH(NEWTOY(realpath, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_REALPATH(OLDTOY(realpath, readlink, TOYFLAG_USR|TOYFLAG_BIN))
 USE_REBOOT(NEWTOY(reboot, "d:fn", TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
 USE_RENICE(NEWTOY(renice, "<1gpun#|", TOYFLAG_USR|TOYFLAG_BIN))
 USE_RESET(NEWTOY(reset, 0, TOYFLAG_USR|TOYFLAG_BIN))
@@ -274,7 +274,7 @@
 USE_SYSLOGD(NEWTOY(syslogd,">0l#<1>8=8R:b#<0>99=1s#<0=200m#<0>71582787=20O:p:f:a:nSKLD", TOYFLAG_SBIN|TOYFLAG_STAYROOT))
 USE_TAC(NEWTOY(tac, NULL, TOYFLAG_USR|TOYFLAG_BIN))
 USE_TAIL(NEWTOY(tail, "?fFs:c(bytes)-n(lines)-[-cn][-fF]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_TAR(NEWTOY(tar, "&(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TAR(NEWTOY(tar, "&(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]", TOYFLAG_USR|TOYFLAG_BIN))
 USE_TASKSET(NEWTOY(taskset, "<1^pa", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
 USE_TCPSVD(NEWTOY(tcpsvd, "^<3c#=30<1C:b#=20<0u:l:hEv", TOYFLAG_USR|TOYFLAG_BIN))
 USE_TEE(NEWTOY(tee, "ia", TOYFLAG_USR|TOYFLAG_BIN))
@@ -321,7 +321,7 @@
 USE_WATCH(NEWTOY(watch, "^<1n%<100=2000tebx", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
 USE_WATCHDOG(NEWTOY(watchdog, "<1>1Ft#=4<1T#=60<1", TOYFLAG_NEEDROOT|TOYFLAG_BIN))
 USE_WC(NEWTOY(wc, "mcwl", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_LOCALE))
-USE_WGET(NEWTOY(wget, "<1>1(max-redirect)#<0=20d(debug)O(output-document):", TOYFLAG_USR|TOYFLAG_BIN))
+USE_WGET(NEWTOY(wget, "<1>1(max-redirect)#<0=20d(debug)O(output-document):p(post-data):", TOYFLAG_USR|TOYFLAG_BIN))
 USE_WHICH(NEWTOY(which, "<1a", TOYFLAG_USR|TOYFLAG_BIN))
 USE_WHO(NEWTOY(who, "a", TOYFLAG_USR|TOYFLAG_BIN))
 USE_WHOAMI(OLDTOY(whoami, logname, TOYFLAG_USR|TOYFLAG_BIN))
diff --git a/configure b/configure
index 368cf21..c718e83 100755
--- a/configure
+++ b/configure
@@ -15,19 +15,8 @@
 CFLAGS="$CFLAGS -Wall -Wundef -Wno-char-subscripts -Werror=implicit-function-declaration -Wno-char-subscripts -Wno-pointer-sign -Wno-string-plus-int -funsigned-char"
 
 # Set default values if variable not already set
-: ${CC:=cc} ${HOSTCC:=cc} ${GENERATED:=generated} ${KCONFIG_CONFIG:=.config}
-: ${OUTNAME:=toybox${TARGET:+-$TARGET}}
-: ${UNSTRIPPED:=$GENERATED/unstripped/${OUTNAME/*\//}}
+: ${CC:=cc} ${HOSTCC:=cc} ${GENDIR:=generated} ${KCONFIG_CONFIG:=.config}
+: ${UNSTRIPPED:=$GENDIR/unstripped} ${OUTNAME:=toybox${TARGET:+-$TARGET}}
 : ${OPTIMIZE:=-Os -ffunction-sections -fdata-sections -fno-asynchronous-unwind-tables -fno-strict-aliasing}
 
-# set ASAN=1 to enable "address sanitizer" and debuggable backtraces
-[ -z "$ASAN" ] || { CFLAGS="$CFLAGS -O1 -g -fno-omit-frame-pointer -fno-optimize-sibling-calls -fsanitize=address"; NOSTRIP=1; }
-
 # We accept LDFLAGS, but by default don't have anything in it
-if [ "$(uname)" == "Darwin" ]
-then
-  : ${LDOPTIMIZE:=-Wl,-dead_strip} ${STRIP:=strip}
-else
-  : ${LDOPTIMIZE:=-Wl,--gc-sections -Wl,--as-needed} ${STRIP:=strip -s -R .note* -R .comment}
-#  LDASNEEDED="-Wl,--as-needed" # must go at end of compiler command line
-fi
diff --git a/kconfig/kconfig-language.txt b/kconfig/kconfig-language.txt
new file mode 100644
index 0000000..d821369
--- /dev/null
+++ b/kconfig/kconfig-language.txt
@@ -0,0 +1,284 @@
+Linux 2.6.12 Documentation/kbuild/kconfig-language.txt
+
+Introduction
+------------
+
+The configuration database is collection of configuration options
+organized in a tree structure:
+
+	+- Code maturity level options
+	|  +- Prompt for development and/or incomplete code/drivers
+	+- General setup
+	|  +- Networking support
+	|  +- System V IPC
+	|  +- BSD Process Accounting
+	|  +- Sysctl support
+	+- Loadable module support
+	|  +- Enable loadable module support
+	|     +- Set version information on all module symbols
+	|     +- Kernel module loader
+	+- ...
+
+Every entry has its own dependencies. These dependencies are used
+to determine the visibility of an entry. Any child entry is only
+visible if its parent entry is also visible.
+
+Menu entries
+------------
+
+Most entries define a config option, all other entries help to organize
+them. A single configuration option is defined like this:
+
+config MODVERSIONS
+	bool "Set version information on all module symbols"
+	depends MODULES
+	help
+	  Usually, modules have to be recompiled whenever you switch to a new
+	  kernel.  ...
+
+Every line starts with a key word and can be followed by multiple
+arguments.  "config" starts a new config entry. The following lines
+define attributes for this config option. Attributes can be the type of
+the config option, input prompt, dependencies, help text and default
+values. A config option can be defined multiple times with the same
+name, but every definition can have only a single input prompt and the
+type must not conflict.
+
+Menu attributes
+---------------
+
+A menu entry can have a number of attributes. Not all of them are
+applicable everywhere (see syntax).
+
+- type definition: "bool"/"tristate"/"string"/"hex"/"int"
+  Every config option must have a type. There are only two basic types:
+  tristate and string, the other types are based on these two. The type
+  definition optionally accepts an input prompt, so these two examples
+  are equivalent:
+
+	bool "Networking support"
+  and
+	bool
+	prompt "Networking support"
+
+- input prompt: "prompt" <prompt> ["if" <expr>]
+  Every menu entry can have at most one prompt, which is used to display
+  to the user. Optionally dependencies only for this prompt can be added
+  with "if".
+
+- default value: "default" <expr> ["if" <expr>]
+  A config option can have any number of default values. If multiple
+  default values are visible, only the first defined one is active.
+  Default values are not limited to the menu entry, where they are
+  defined, this means the default can be defined somewhere else or be
+  overridden by an earlier definition.
+  The default value is only assigned to the config symbol if no other
+  value was set by the user (via the input prompt above). If an input
+  prompt is visible the default value is presented to the user and can
+  be overridden by him.
+  Optionally dependencies only for this default value can be added with
+  "if".
+
+- dependencies: "depends on"/"requires" <expr>
+  This defines a dependency for this menu entry. If multiple
+  dependencies are defined they are connected with '&&'. Dependencies
+  are applied to all other options within this menu entry (which also
+  accept an "if" expression), so these two examples are equivalent:
+
+	bool "foo" if BAR
+	default y if BAR
+  and
+	depends on BAR
+	bool "foo"
+	default y
+
+- reverse dependencies: "select" <symbol> ["if" <expr>]
+  While normal dependencies reduce the upper limit of a symbol (see
+  below), reverse dependencies can be used to force a lower limit of
+  another symbol. The value of the current menu symbol is used as the
+  minimal value <symbol> can be set to. If <symbol> is selected multiple
+  times, the limit is set to the largest selection.
+  Reverse dependencies can only be used with boolean or tristate
+  symbols.
+
+- numerical ranges: "range" <symbol> <symbol> ["if" <expr>]
+  This allows to limit the range of possible input values for int
+  and hex symbols. The user can only input a value which is larger than
+  or equal to the first symbol and smaller than or equal to the second
+  symbol.
+
+- help text: "help" or "---help---"
+  This defines a help text. The end of the help text is determined by
+  the indentation level, this means it ends at the first line which has
+  a smaller indentation than the first line of the help text.
+  "---help---" and "help" do not differ in behaviour, "---help---" is
+  used to help visually seperate configuration logic from help within
+  the file as an aid to developers.
+
+
+Menu dependencies
+-----------------
+
+Dependencies define the visibility of a menu entry and can also reduce
+the input range of tristate symbols. The tristate logic used in the
+expressions uses one more state than normal boolean logic to express the
+module state. Dependency expressions have the following syntax:
+
+<expr> ::= <symbol>                             (1)
+           <symbol> '=' <symbol>                (2)
+           <symbol> '!=' <symbol>               (3)
+           '(' <expr> ')'                       (4)
+           '!' <expr>                           (5)
+           <expr> '&&' <expr>                   (6)
+           <expr> '||' <expr>                   (7)
+
+Expressions are listed in decreasing order of precedence. 
+
+(1) Convert the symbol into an expression. Boolean and tristate symbols
+    are simply converted into the respective expression values. All
+    other symbol types result in 'n'.
+(2) If the values of both symbols are equal, it returns 'y',
+    otherwise 'n'.
+(3) If the values of both symbols are equal, it returns 'n',
+    otherwise 'y'.
+(4) Returns the value of the expression. Used to override precedence.
+(5) Returns the result of (2-/expr/).
+(6) Returns the result of min(/expr/, /expr/).
+(7) Returns the result of max(/expr/, /expr/).
+
+An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2
+respectively for calculations). A menu entry becomes visible when it's
+expression evaluates to 'm' or 'y'.
+
+There are two types of symbols: constant and nonconstant symbols.
+Nonconstant symbols are the most common ones and are defined with the
+'config' statement. Nonconstant symbols consist entirely of alphanumeric
+characters or underscores.
+Constant symbols are only part of expressions. Constant symbols are
+always surrounded by single or double quotes. Within the quote any
+other character is allowed and the quotes can be escaped using '\'.
+
+Menu structure
+--------------
+
+The position of a menu entry in the tree is determined in two ways. First
+it can be specified explicitly:
+
+menu "Network device support"
+	depends NET
+
+config NETDEVICES
+	...
+
+endmenu
+
+All entries within the "menu" ... "endmenu" block become a submenu of
+"Network device support". All subentries inherit the dependencies from
+the menu entry, e.g. this means the dependency "NET" is added to the
+dependency list of the config option NETDEVICES.
+
+The other way to generate the menu structure is done by analyzing the
+dependencies. If a menu entry somehow depends on the previous entry, it
+can be made a submenu of it. First, the previous (parent) symbol must
+be part of the dependency list and then one of these two conditions
+must be true:
+- the child entry must become invisible, if the parent is set to 'n'
+- the child entry must only be visible, if the parent is visible
+
+config MODULES
+	bool "Enable loadable module support"
+
+config MODVERSIONS
+	bool "Set version information on all module symbols"
+	depends MODULES
+
+comment "module support disabled"
+	depends !MODULES
+
+MODVERSIONS directly depends on MODULES, this means it's only visible if
+MODULES is different from 'n'. The comment on the other hand is always
+visible when MODULES is visible (the (empty) dependency of MODULES is
+also part of the comment dependencies).
+
+
+Kconfig syntax
+--------------
+
+The configuration file describes a series of menu entries, where every
+line starts with a keyword (except help texts). The following keywords
+end a menu entry:
+- config
+- menuconfig
+- choice/endchoice
+- comment
+- menu/endmenu
+- if/endif
+- source
+The first five also start the definition of a menu entry.
+
+config:
+
+	"config" <symbol>
+	<config options>
+
+This defines a config symbol <symbol> and accepts any of above
+attributes as options.
+
+menuconfig:
+	"menuconfig" <symbol>
+	<config options>
+
+This is similiar to the simple config entry above, but it also gives a
+hint to front ends, that all suboptions should be displayed as a
+separate list of options.
+
+choices:
+
+	"choice"
+	<choice options>
+	<choice block>
+	"endchoice"
+
+This defines a choice group and accepts any of above attributes as
+options. A choice can only be of type bool or tristate, while a boolean
+choice only allows a single config entry to be selected, a tristate
+choice also allows any number of config entries to be set to 'm'. This
+can be used if multiple drivers for a single hardware exists and only a
+single driver can be compiled/loaded into the kernel, but all drivers
+can be compiled as modules.
+A choice accepts another option "optional", which allows to set the
+choice to 'n' and no entry needs to be selected.
+
+comment:
+
+	"comment" <prompt>
+	<comment options>
+
+This defines a comment which is displayed to the user during the
+configuration process and is also echoed to the output files. The only
+possible options are dependencies.
+
+menu:
+
+	"menu" <prompt>
+	<menu options>
+	<menu block>
+	"endmenu"
+
+This defines a menu block, see "Menu structure" above for more
+information. The only possible options are dependencies.
+
+if:
+
+	"if" <expr>
+	<if block>
+	"endif"
+
+This defines an if block. The dependency expression <expr> is appended
+to all enclosed menu entries.
+
+source:
+
+	"source" <prompt>
+
+This reads the specified configuration file. This file is always parsed.
diff --git a/lib/args.c b/lib/args.c
index 247c194..2b8da7c 100644
--- a/lib/args.c
+++ b/lib/args.c
@@ -77,6 +77,7 @@
 //     ? Allow unknown arguments (pass them through to command).
 //     & first arg has imaginary dash (ala tar/ps/ar) which sets FLAGS_NODASH
 //     0 Include argv[0] in optargs
+//     note: ^ and ? implied when no options
 //
 //   At the end: [groups] of previously seen options
 //     - Only one in group (switch off)    [-abc] means -ab=-b, -ba=-a, -abc=-c
@@ -254,7 +255,7 @@
 
   // Parse option string into a linked list of options with attributes.
 
-  if (!*options) gof->stopearly++;
+  if (!*options) gof->stopearly++, gof->noerror++;
   while (*options) {
     char *temp;
 
diff --git a/lib/lib.c b/lib/lib.c
index 84af3f4..cf0a958 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -449,9 +449,10 @@
 // Remove trailing \n
 char *chomp(char *s)
 {
-  char *p = strrchr(s, '\n');
+  char *p = s+strlen(s);
 
-  if (p && !p[1]) *p = 0;
+  while (p>=s && (p[-1]=='\r' || p[-1]=='\n')) *--p = 0;
+
   return s;
 }
 
@@ -1251,7 +1252,7 @@
 }
 
 // Return cached passwd entries.
-struct passwd *bufgetpwuid(uid_t uid)
+struct passwd *bufgetpwnamuid(char *name, uid_t uid)
 {
   struct pwuidbuf_list {
     struct pwuidbuf_list *next;
@@ -1263,11 +1264,14 @@
 
   // If we already have this one, return it.
   for (list = pwuidbuf; list; list = list->next)
-    if (list->pw.pw_uid == uid) return &(list->pw);
+    if (name ? !strcmp(name, list->pw.pw_name) : list->pw.pw_uid==uid)
+      return &(list->pw);
 
   for (;;) {
     list = xrealloc(list, size *= 2);
-    errno = getpwuid_r(uid, &list->pw, sizeof(*list)+(char *)list,
+    if (name) errno = getpwnam_r(name, &list->pw, sizeof(*list)+(char *)list,
+      size-sizeof(*list), &temp);
+    else errno = getpwuid_r(uid, &list->pw, sizeof(*list)+(char *)list,
       size-sizeof(*list), &temp);
     if (errno != ERANGE) break;
   }
@@ -1283,8 +1287,13 @@
   return &list->pw;
 }
 
+struct passwd *bufgetpwuid(uid_t uid)
+{
+  return bufgetpwnamuid(0, uid);
+}
+
 // Return cached group entries.
-struct group *bufgetgrgid(gid_t gid)
+struct group *bufgetgrnamgid(char *name, gid_t gid)
 {
   struct grgidbuf_list {
     struct grgidbuf_list *next;
@@ -1295,11 +1304,14 @@
   unsigned size = 256;
 
   for (list = grgidbuf; list; list = list->next)
-    if (list->gr.gr_gid == gid) return &(list->gr);
+    if (name ? !strcmp(name, list->gr.gr_name) : list->gr.gr_gid==gid)
+      return &(list->gr);
 
   for (;;) {
     list = xrealloc(list, size *= 2);
-    errno = getgrgid_r(gid, &list->gr, sizeof(*list)+(char *)list,
+    if (name) errno = getgrnam_r(name, &list->gr, sizeof(*list)+(char *)list,
+      size-sizeof(*list), &temp);
+    else errno = getgrgid_r(gid, &list->gr, sizeof(*list)+(char *)list,
       size-sizeof(*list), &temp);
     if (errno != ERANGE) break;
   }
@@ -1314,6 +1326,12 @@
   return &list->gr;
 }
 
+struct group *bufgetgrgid(gid_t gid)
+{
+  return bufgetgrnamgid(0, gid);
+}
+
+
 // Always null terminates, returns 0 for failure, len for success
 int readlinkat0(int dirfd, char *path, char *buf, int len)
 {
diff --git a/lib/lib.h b/lib/lib.h
index 6e9a264..1721dd6 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -260,7 +260,9 @@
 void create_uuid(char *uuid);
 char *show_uuid(char *uuid);
 char *next_printf(char *s, char **start);
+struct passwd *bufgetpwnamuid(char *name, uid_t uid);
 struct passwd *bufgetpwuid(uid_t uid);
+struct group *bufgetgrnamgid(char *name, gid_t gid);
 struct group *bufgetgrgid(gid_t gid);
 int readlinkat0(int dirfd, char *path, char *buf, int len);
 int readlink0(char *path, char *buf, int len);
diff --git a/lib/portability.c b/lib/portability.c
index 5f98138..89744dd 100644
--- a/lib/portability.c
+++ b/lib/portability.c
@@ -623,26 +623,45 @@
 }
 #endif
 
-// TODO copy_file_range
+static ssize_t copy_file_range_wrap(int infd, off_t *inoff, int outfd,
+    off_t *outoff, size_t len, unsigned flags)
+{
+  // glibc added this constant in git at the end of 2017, shipped in 2018-02.
+#if defined(__NR_copy_file_range)
+  return syscall(__NR_copy_file_range, infd, inoff, outfd, outoff, len, flags);
+#else
+  errno = EINVAL;
+  return -1;
+#endif
+}
+
 // Return bytes copied from in to out. If bytes <0 copy all of in to out.
-// If consuemd isn't null, amount read saved there (return is written or error)
+// If consumed isn't null, amount read saved there (return is written or error)
 long long sendfile_len(int in, int out, long long bytes, long long *consumed)
 {
   long long total = 0, len, ww;
+  int copy_file_range = CFG_TOYBOX_COPYFILERANGE;
 
   if (consumed) *consumed = 0;
   if (in<0) return 0;
   while (bytes != total) {
     ww = 0;
     len = bytes-total;
-    if (bytes<0 || len>sizeof(libbuf)) len = sizeof(libbuf);
 
     errno = 0;
-#if CFG_TOYBOX_COPYFILERANGE
-    len = copy_file_range(in, 0, out, 0, bytes, 0);
-#else
-    ww = len = read(in, libbuf, len);
-#endif
+    if (copy_file_range) {
+      if (bytes<0 || bytes>(1<<30)) len = (1<<30);
+      len = copy_file_range_wrap(in, 0, out, 0, len, 0);
+      if (len < 0 && errno == EINVAL) {
+        copy_file_range = 0;
+
+        continue;
+      }
+    }
+    if (!copy_file_range) {
+      if (bytes<0 || len>sizeof(libbuf)) len = sizeof(libbuf);
+      ww = len = read(in, libbuf, len);
+    }
     if (len<1 && errno==EAGAIN) continue;
     if (len<1) break;
     if (consumed) *consumed += len;
diff --git a/lib/toyflags.h b/lib/toyflags.h
index c883087..0c65735 100644
--- a/lib/toyflags.h
+++ b/lib/toyflags.h
@@ -37,9 +37,3 @@
 
 // Error code to return if argument parsing fails (default 1)
 #define TOYFLAG_ARGFAIL(x) (x<<24)
-
-#if CFG_TOYBOX_PEDANTIC_ARGS
-#define NO_ARGS ">0"
-#else
-#define NO_ARGS 0
-#endif
diff --git a/lib/xwrap.c b/lib/xwrap.c
index f16ebe0..65e9f4f 100644
--- a/lib/xwrap.c
+++ b/lib/xwrap.c
@@ -104,7 +104,12 @@
 // Die unless we can allocate a copy of this string.
 char *xstrdup(char *s)
 {
-  return xstrndup(s, strlen(s));
+  long len = strlen(s);
+  char *c = xmalloc(++len);
+
+  memcpy(c, s, len);
+
+  return c;
 }
 
 void *xmemdup(void *s, long len)
diff --git a/main.c b/main.c
index 95c42fa..9d9d706 100644
--- a/main.c
+++ b/main.c
@@ -82,9 +82,9 @@
   char *s, *ss;
 
   if (!(full&2))
-    fprintf(out, "Toybox %s" USE_TOYBOX(" multicall binary")
-                 ": https://landley.net/toybox"
-                 USE_TOYBOX(" (see toybox --help)") "\n\n", toybox_version);
+    fprintf(out, "Toybox %s"USE_TOYBOX(" multicall binary")"%s\n\n",
+      toybox_version, (CFG_TOYBOX && i) ? " (see toybox --help)"
+      : " (see https://landley.net/toybox)");
 
   if (CFG_TOYBOX_HELP) {
     for (;;) {
@@ -114,8 +114,9 @@
 // Parse --help and --version for (almost) all commands
 void check_help(char **arg)
 {
-  if (!CFG_TOYBOX_HELP_DASHDASH || !*arg || (toys.which->flags&TOYFLAG_NOHELP))
-    return;
+  if (!CFG_TOYBOX_HELP_DASHDASH || !*arg) return;
+  if (!CFG_TOYBOX || toys.which != toy_list)
+    if (toys.which->flags&TOYFLAG_NOHELP) return;
 
   if (!strcmp(*arg, "--help")) {
     if (CFG_TOYBOX && toys.which == toy_list && arg[1])
@@ -164,7 +165,6 @@
   void *oldwhich = toys.which;
 
   // Drop permissions for non-suid commands.
-
   if (CFG_TOYBOX_SUID) {
     if (!toys.which) toys.which = toy_list;
 
@@ -180,6 +180,7 @@
       error_msg("Not installed suid root");
 
     if ((which->flags & TOYFLAG_NEEDROOT) && euid) {
+      toys.which = which;
       check_help(argv+1);
       help_exit("Not root");
     }
@@ -236,12 +237,13 @@
 
   // fast path: try to exec immediately.
   // (Leave toys.which null to disable suid return logic.)
-  // Try dereferencing one layer of symlink
+  // Try dereferencing symlinks until we hit a recognized name
   while (s) {
-    struct toy_list *tl = toy_find(basename(s));
+    char *ss = basename(s);
+    struct toy_list *tl = toy_find(ss);
 
-    if (tl==toy_list && s!=toys.argv[1]) unknown(basename(s));
-    toy_exec_which(toy_find(basename(s)), toys.argv+1);
+    if (tl==toy_list && s!=toys.argv[1]) unknown(ss);
+    toy_exec_which(tl, toys.argv+1);
     s = (0<readlink(s, libbuf, sizeof(libbuf))) ? libbuf : 0;
   }
 
diff --git a/scripts/change.sh b/scripts/change.sh
index 99dcfde..74889aa 100755
--- a/scripts/change.sh
+++ b/scripts/change.sh
@@ -2,8 +2,10 @@
 
 # build each command as a standalone executable
 
+source scripts/portability.sh
+
 NOBUILD=1 scripts/make.sh > /dev/null &&
-${HOSTCC:-cc} -I . scripts/install.c -o generated/instlist &&
+${HOSTCC:-cc} -I . scripts/install.c -o "$UNSTRIPPED"/instlist &&
 export PREFIX=${PREFIX:-change/} &&
 mkdir -p "$PREFIX" || exit 1
 
@@ -12,7 +14,7 @@
 # sh - shell builtins like "cd" and "exit" need the multiplexer
 # help - needs to know what other commands are enabled (use command --help)
 
-for i in $(generated/instlist | egrep -vw "sh|help")
+for i in $("$UNSTRIPPED"/instlist | egrep -vw "sh|help")
 do
   echo -n " $i" &&
   scripts/single.sh $i > /dev/null 2>$PREFIX/${i}.bad &&
diff --git a/scripts/genconfig.sh b/scripts/genconfig.sh
index 01b2eaa..034aa37 100755
--- a/scripts/genconfig.sh
+++ b/scripts/genconfig.sh
@@ -3,10 +3,10 @@
 # This has to be a separate file from scripts/make.sh so it can be called
 # before menuconfig.  (It's called again from scripts/make.sh just to be sure.)
 
-mkdir -p generated
-
 source scripts/portability.sh
 
+mkdir -p "$GENDIR"
+
 probecc()
 {
   ${CROSS_COMPILE}${CC} $CFLAGS $LDFLAGS -xc -o /dev/null - "$@"
@@ -101,10 +101,12 @@
     int main(void) { char buf[100]; getrandom(buf, 100, 0); }
 EOF
 
+  # glibc requires #define GNU to get the wrapper for this Linux system call,
+  # so just use syscall().
   probesymbol TOYBOX_COPYFILERANGE << EOF
     #include <sys/syscall.h>
     #include <unistd.h>
-    int main(void) { copyfilerange(0, 0, 1, 0, 123, 0); }
+    int main(void) { syscall(__NR_copy_file_range, 0, 0, 1, 0, 123, 0); }
 EOF
   probesymbol TOYBOX_HASTIMERS << EOF
     #include <signal.h>
@@ -138,8 +140,8 @@
   done
 }
 
-probeconfig > generated/Config.probed || rm generated/Config.probed
-genconfig > generated/Config.in || rm generated/Config.in
+probeconfig > "$GENDIR"/Config.probed || rm "$GENDIR"/Config.probed
+genconfig > "$GENDIR"/Config.in || rm "$GENDIR"/Config.in
 
 # Find names of commands that can be built standalone in these C files
 toys()
diff --git a/scripts/install.sh b/scripts/install.sh
index d58d075..842ff9b 100755
--- a/scripts/install.sh
+++ b/scripts/install.sh
@@ -2,9 +2,9 @@
 
 # Grab default values for $CFLAGS and such.
 
-source ./configure
+source scripts/portability.sh
 
-[ -z "$PREFIX" ] && PREFIX="/usr/toybox"
+[ -z "$PREFIX" ] && PREFIX="$PWD/install"
 
 # Parse command line arguments.
 
@@ -32,8 +32,8 @@
 echo "Compile instlist..."
 
 NOBUILD=1 scripts/make.sh
-$DEBUG $HOSTCC -I . scripts/install.c -o generated/instlist || exit 1
-COMMANDS="$(generated/instlist $LONG_PATH)"
+$DEBUG $HOSTCC -I . scripts/install.c -o "$UNSTRIPPED"/instlist || exit 1
+COMMANDS="$("$UNSTRIPPED"/instlist $LONG_PATH)"
 
 echo "${UNINSTALL:-Install} commands..."
 
@@ -106,7 +106,7 @@
 # The following are commands toybox should provide, but doesn't yet.
 # For now symlink the host version. This list must go away by 1.0.
 
-PENDING="dd diff expr tr vi wget sh xzcat bc ar gzip   ftpd less awk unxz bison flex make nm"
+PENDING="dd diff expr git tr vi wget bash sh xzcat bc ar gzip   ftpd less awk unxz bison flex make nm"
 
 # "gcc" can go away if the kernel guys merge my patch:
 # http://lkml.iu.edu/hypermail/linux/kernel/2202.0/01505.html
diff --git a/scripts/make.sh b/scripts/make.sh
index 291ff80..b7bb693 100755
--- a/scripts/make.sh
+++ b/scripts/make.sh
@@ -26,9 +26,9 @@
 
 echo "Generate headers from toys/*/*.c..."
 
-mkdir -p generated/unstripped
+mkdir -p "$UNSTRIPPED"
 
-if isnewer generated/Config.in toys || isnewer generated/Config.in Config.in
+if isnewer "$GENDIR"/Config.in toys || isnewer "$GENDIR"/Config.in Config.in
 then
   echo "Extract configuration information from toys/*.c files..."
   scripts/genconfig.sh
@@ -39,14 +39,15 @@
 # first element of the array). The rest must be sorted in alphabetical order
 # for fast binary search.
 
-if isnewer generated/newtoys.h toys
+if isnewer "$GENDIR"/newtoys.h toys
 then
-  echo -n "generated/newtoys.h "
+  echo -n "$GENDIR/newtoys.h "
 
-  echo "USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT))" > generated/newtoys.h
+  echo "USE_TOYBOX(NEWTOY(toybox, NULL, TOYFLAG_STAYROOT|TOYFLAG_NOHELP))" \
+    > "$GENDIR"/newtoys.h
   $SED -n -e 's/^USE_[A-Z0-9_]*(/&/p' toys/*/*.c \
 	| $SED 's/\(.*TOY(\)\([^,]*\),\(.*\)/\2 \1\2,\3/' | sort -s -k 1,1 \
-	| $SED 's/[^ ]* //'  >> generated/newtoys.h
+	| $SED 's/[^ ]* //'  >> "$GENDIR"/newtoys.h
   [ $? -ne 0 ] && exit 1
 fi
 
@@ -55,11 +56,11 @@
 # Extract a list of toys/*/*.c files to compile from the data in $KCONFIG_CONFIG
 # (First command names, then filenames with relevant {NEW,OLD}TOY() macro.)
 
-[ -d ".git" ] && GITHASH="-DTOYBOX_VERSION=\"$(git describe --tags --abbrev=12 2>/dev/null)\""
+[ -d ".git" ] && [ ! -z "$(which git 2>/dev/null)" ] &&
+   GITHASH="-DTOYBOX_VERSION=\"$(git describe --tags --abbrev=12 2>/dev/null)\""
 TOYFILES="$($SED -n 's/^CONFIG_\([^=]*\)=.*/\1/p' "$KCONFIG_CONFIG" | xargs | tr ' [A-Z]' '|[a-z]')"
 TOYFILES="main.c $(egrep -l "TOY[(]($TOYFILES)[ ,]" toys/*/*.c | xargs)"
 BUILD="$(echo ${CROSS_COMPILE}${CC} $CFLAGS -I . $OPTIMIZE $GITHASH)"
-LIBFILES="$(ls lib/*.c)"
 
 if [ "${TOYFILES/pending//}" != "$TOYFILES" ]
 then
@@ -70,12 +71,13 @@
 {
   # Write a canned build line for use on crippled build machines.
 
-  echo -e "#!/bin/sh\n\nPATH='$PATH'\nBUILD='$BUILD'\nLINK='$LINK'\n"
-  echo -e "\$BUILD lib/*.c $TOYFILES \$LINK"
+  LLINK="$(echo $LDOPTIMIZE $LDFLAGS $(cat "$GENDIR"/optlibs.dat))"
+  echo -e "#!/bin/sh\n\nPATH='$PATH'\nBUILD='$BUILD'\nLINK='$LLINK'\n"
+  echo -e "\$BUILD lib/*.c $TOYFILES \$LINK -o $OUTNAME"
 }
 
-if ! cmp -s <(genbuildsh 2>/dev/null | head -n 4 ; echo LINK="'"$LDOPTIMIZE $LDFLAGS) \
-          <(head -n 5 generated/build.sh 2>/dev/null | $SED '5s/ -o .*//')
+if ! cmp -s <(genbuildsh 2>/dev/null | head -n 5) \
+            <(head -n 5 "$GENDIR"/build.sh 2>/dev/null | $SED '5s/ -o .*//')
 then
   echo -n "Library probe"
 
@@ -83,27 +85,24 @@
   # compiler has no way to ignore a library that doesn't exist, so detect
   # and skip nonexistent libraries for it.
 
-  > generated/optlibs.dat
+  > "$GENDIR"/optlibs.dat
   for i in util crypt m resolv selinux smack attr crypto z log iconv tls ssl
   do
     echo "int main(int argc, char *argv[]) {return 0;}" | \
-    ${CROSS_COMPILE}${CC} $CFLAGS $LDFLAGS -xc - -o generated/libprobe -l$i > /dev/null 2>/dev/null &&
-    echo -l$i >> generated/optlibs.dat
+    ${CROSS_COMPILE}${CC} $CFLAGS $LDFLAGS -xc - -o "$GENDIR"/libprobe -l$i > /dev/null 2>/dev/null &&
+    echo -l$i >> "$GENDIR"/optlibs.dat
     echo -n .
   done
-  rm -f generated/libprobe
+  rm -f "$GENDIR"/libprobe
   echo
 fi
 
-# LINK needs optlibs.dat, above
-
-LINK="$(echo $LDOPTIMIZE $LDFLAGS -o "$UNSTRIPPED" $(cat generated/optlibs.dat))"
-genbuildsh > generated/build.sh && chmod +x generated/build.sh || exit 1
+genbuildsh > "$GENDIR"/build.sh && chmod +x "$GENDIR"/build.sh || exit 1
 
 #TODO: "make $SED && make" doesn't regenerate config.h because diff .config
-if true #isnewer generated/config.h "$KCONFIG_CONFIG"
+if true #isnewer "$GENDIR"/config.h "$KCONFIG_CONFIG"
 then
-  echo "Make generated/config.h from $KCONFIG_CONFIG."
+  echo "Make $GENDIR/config.h from $KCONFIG_CONFIG."
 
   # This long and roundabout sed invocation is to make old versions of sed
   # happy. New ones have '\n' so can replace one line with two without all
@@ -128,12 +127,12 @@
     -e 's/.*/#define CFG_& 1/p' \
     -e 'g' \
     -e 's/.*/#define USE_&(...) __VA_ARGS__/p' \
-    $KCONFIG_CONFIG > generated/config.h || exit 1
+    $KCONFIG_CONFIG > "$GENDIR"/config.h || exit 1
 fi
 
-if [ ! -f generated/mkflags ] || [ generated/mkflags -ot scripts/mkflags.c ]
+if [ ! -f "$GENDIR"/mkflags ] || [ "$GENDIR"/mkflags -ot scripts/mkflags.c ]
 then
-  do_loudly $HOSTCC scripts/mkflags.c -o generated/mkflags || exit 1
+  do_loudly $HOSTCC scripts/mkflags.c -o "$UNSTRIPPED"/mkflags || exit 1
 fi
 
 # Process config.h and newtoys.h to generate FLAG_x macros. Note we must
@@ -141,9 +140,9 @@
 # allow multiple NEWTOY() in the same C file. (When disabled the FLAG is 0,
 # so flags&0 becomes a constant 0 allowing dead code elimination.)
 
-if isnewer generated/flags.h toys "$KCONFIG_CONFIG"
+if isnewer "$GENDIR"/flags.h toys "$KCONFIG_CONFIG"
 then
-  echo -n "generated/flags.h "
+  echo -n "$GENDIR/flags.h "
 
   # Parse files through C preprocessor twice, once to get flags for current
   # .config and once to get flags for allyesconfig
@@ -156,12 +155,12 @@
     echo '#define OLDTOY(...)'
     if [ "$I" == A ]
     then
-      cat generated/config.h
+      cat "$GENDIR"/config.h
     else
-      $SED '/USE_.*([^)]*)$/s/$/ __VA_ARGS__/' generated/config.h
+      $SED '/USE_.*([^)]*)$/s/$/ __VA_ARGS__/' "$GENDIR"/config.h
     fi
     echo '#include "lib/toyflags.h"'
-    cat generated/newtoys.h
+    cat "$GENDIR"/newtoys.h
 
     # Run result through preprocessor, glue together " " gaps leftover from USE
     # macros, delete comment lines, print any line with a quoted optstring,
@@ -179,7 +178,7 @@
 
   done | sort -s | $SED -n -e 's/ A / /;t pair;h;s/\([^ ]*\).*/\1 " "/;x' \
     -e 'b single;:pair;h;n;:single;s/[^ ]* B //;H;g;s/\n/ /;p' | \
-    tee generated/flags.raw | generated/mkflags > generated/flags.h || exit 1
+    tee "$GENDIR"/flags.raw | "$UNSTRIPPED"/mkflags > "$GENDIR"/flags.h || exit 1
 fi
 
 # Extract global structure definitions and flag definitions from toys/*/*.c
@@ -197,9 +196,9 @@
   done
 }
 
-if isnewer generated/globals.h toys
+if isnewer "$GENDIR"/globals.h toys
 then
-  echo -n "generated/globals.h "
+  echo -n "$GENDIR/globals.h "
   GLOBSTRUCT="$(getglobals)"
   (
     echo "$GLOBSTRUCT"
@@ -208,30 +207,30 @@
     echo "$GLOBSTRUCT" | \
       $SED -n 's/struct \(.*\)_data {/	struct \1_data \1;/p'
     echo "} this;"
-  ) > generated/globals.h
+  ) > "$GENDIR"/globals.h
 fi
 
-if [ ! -f generated/mktags ] || [ generated/mktags -ot scripts/mktags.c ]
+if [ ! -f "$UNSTRIPPED"/mktags ] || [ "$UNSTRIPPED"/mktags -ot scripts/mktags.c ]
 then
-  do_loudly $HOSTCC scripts/mktags.c -o generated/mktags || exit 1
+  do_loudly $HOSTCC scripts/mktags.c -o "$UNSTRIPPED"/mktags || exit 1
 fi
 
-if isnewer generated/tags.h toys
+if isnewer "$GENDIR"/tags.h toys
 then
-  echo -n "generated/tags.h "
+  echo -n "$GENDIR/tags.h "
 
   $SED -n '/TAGGED_ARRAY(/,/^)/{s/.*TAGGED_ARRAY[(]\([^,]*\),/\1/;p}' \
-    toys/*/*.c lib/*.c | generated/mktags > generated/tags.h
+    toys/*/*.c lib/*.c | "$UNSTRIPPED"/mktags > "$GENDIR"/tags.h
 fi
 
-if [ ! -f generated/config2help ] || [ generated/config2help -ot scripts/config2help.c ]
+if [ ! -f "$UNSTRIPPED"/config2help ] || [ "$UNSTRIPPED"/config2help -ot scripts/config2help.c ]
 then
-  do_loudly $HOSTCC scripts/config2help.c -o generated/config2help || exit 1
+  do_loudly $HOSTCC scripts/config2help.c -o "$UNSTRIPPED"/config2help || exit 1
 fi
-if isnewer generated/help.h generated/Config.in
+if isnewer "$GENDIR"/help.h "$GENDIR"/Config.in
 then
-  echo "generated/help.h"
-  generated/config2help Config.in $KCONFIG_CONFIG > generated/help.h || exit 1
+  echo "$GENDIR/help.h"
+  "$UNSTRIPPED"/config2help Config.in $KCONFIG_CONFIG > "$GENDIR"/help.h || exit 1
 fi
 
 [ ! -z "$NOBUILD" ] && exit 0
@@ -240,16 +239,16 @@
 [ ! -z "$V" ] && echo
 DOTPROG=.
 
-# This is a parallel version of: do_loudly $BUILD $FILES $LINK || exit 1
+# This is a parallel version of: do_loudly $BUILD $FILES $LLINK || exit 1
 
 # Any headers newer than the oldest generated/obj file?
-X="$(ls -1t generated/obj/* 2>/dev/null | tail -n 1)"
+X="$(ls -1t "$GENDIR"/obj/* 2>/dev/null | tail -n 1)"
 # TODO: redo this
 if [ ! -e "$X" ] || [ ! -z "$(find toys -name "*.h" -newer "$X")" ]
 then
-  rm -rf generated/obj && mkdir -p generated/obj || exit 1
+  rm -rf "$GENDIR"/obj && mkdir -p "$GENDIR"/obj || exit 1
 else
-  rm -f generated/obj/{main,lib_help}.o || exit 1
+  rm -f "$GENDIR"/obj/main.o || exit 1
 fi
 
 # build each generated/obj/*.o file in parallel
@@ -258,16 +257,16 @@
 DONE=0
 COUNT=0
 
-for i in $LIBFILES click $TOYFILES
+for i in lib/*.c click $TOYFILES
 do
   [ "$i" == click ] && CLICK=1 && continue
 
   X=${i/lib\//lib_}
   X=${X##*/}
-  OUT="generated/obj/${X%%.c}.o"
+  OUT="$GENDIR/obj/${X%%.c}.o"
   LNKFILES="$LNKFILES $OUT"
 
-  # $LIBFILES don't need to be rebuilt if older than .config, $TOYFILES do
+  # Library files don't need to be rebuilt if older than .config.
   # ($TOYFILES contents can depend on CONFIG symbols, lib/*.c never should.)
 
   [ "$OUT" -nt "$i" ] && [ -z "$CLICK" -o "$OUT" -nt "$KCONFIG_CONFIG" ] &&
@@ -288,7 +287,8 @@
 done
 [ $DONE -ne 0 ] && exit 1
 
-do_loudly $BUILD $LNKFILES $LINK || exit 1
+UNSTRIPPED="$UNSTRIPPED/${OUTNAME/*\//}"
+do_loudly $BUILD $LNKFILES $LLINK -o "$UNSTRIPPED" || exit 1
 if [ ! -z "$NOSTRIP" ] ||
   ! do_loudly ${CROSS_COMPILE}${STRIP} "$UNSTRIPPED" -o "$OUTNAME"
 then
diff --git a/scripts/mkroot.sh b/scripts/mkroot.sh
index f1ddc50..c099bec 100755
--- a/scripts/mkroot.sh
+++ b/scripts/mkroot.sh
@@ -11,7 +11,7 @@
   [ "${i/=/}" != "$i" ] && export "$i" || { [ "$i" != -- ] && PKG="$PKG $i"; }
 done
 
-# Set default values for directories (overrideable from command line)
+# Set default directory locations (overrideable from command line)
 : ${LOG:=${BUILD:=${TOP:=$PWD/root}/build}/log} ${AIRLOCK:=$BUILD/airlock}
 : ${CCC:=$PWD/ccc} ${PKGDIR:=$PWD/scripts/root}
 
@@ -145,8 +145,9 @@
 
 # Build static toybox with existing .config if there is one, else defconfig+sh
 announce toybox
-[ -e .config ] && [ -z "$PENDING" ] && CONF=silentoldconfig || unset CONF
-for i in $PENDING sh route; do XX="$XX"$'\n'CONFIG_${i^^?}=y; done
+[ ! -z "$PENDING" ] && rm -f .config
+[ -e .config ] && CONF=silentoldconfig || unset CONF
+for i in $PENDING sh route wget; do XX="$XX"$'\n'CONFIG_${i^^?}=y; done
 LDFLAGS=--static PREFIX="$ROOT" make clean \
   ${CONF:-defconfig KCONFIG_ALLCONFIG=<(echo "$XX")} toybox install || exit 1
 
@@ -204,7 +205,7 @@
     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" == m68k ]; then
     QEMU="m68k -M q800" KARCH=m68k KARGS=ttyS0 VMLINUX=vmlinux
-    KCONF=MMU,M68040,M68KFPU_EMU,MAC,SCSI_MAC_ESP,MACINTOSH_DRIVERS,ADB,ADB_MACII,NET_CORE,MACSONIC,SERIAL_PMACZILOG,SERIAL_PMACZILOG_TTYS,SERIAL_PMACZILOG_CONSOLE
+    KCONF=MMU,M68040,M68KFPU_EMU,MAC,SCSI_MAC_ESP,MACINTOSH_DRIVERS,ADB,ADB_MACII,NET_CORE,NET_VENDOR_NATSEMI,MACSONIC,SERIAL_PMACZILOG,SERIAL_PMACZILOG_TTYS,SERIAL_PMACZILOG_CONSOLE
   elif [ "$TARGET" == mips ] || [ "$TARGET" == mipsel ]; then
     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
@@ -236,10 +237,11 @@
   # Write the qemu launch script
   if [ -n "$QEMU" ]; then
     [ -z "$BUILTIN" ] && INITRD="-initrd ${CROSS}root.cpio.gz"
-    echo qemu-system-"$QEMU" '"$@"' $QEMU_MORE -nographic -no-reboot -m 256 \
-         -kernel $(basename $VMLINUX) $INITRD \
-         "-append \"panic=1 HOST=$TARGET console=$KARGS \$KARGS\"" \
-         ${DTB:+-dtb "$(basename "$DTB")"} > "$OUTPUT/qemu-$TARGET.sh" &&
+    { echo qemu-system-"$QEMU" '"$@"' $QEMU_MORE -nographic -no-reboot -m 256 \
+        -kernel $(basename $VMLINUX) $INITRD ${DTB:+-dtb "$(basename "$DTB")"} \
+        "-append \"panic=1 HOST=$TARGET console=$KARGS \$KARGS\"" &&
+      echo "echo -e '\\e[?7h'"
+    } > "$OUTPUT/qemu-$TARGET.sh" &&
     chmod +x "$OUTPUT/qemu-$TARGET.sh" || exit 1
   fi
 
diff --git a/scripts/portability.sh b/scripts/portability.sh
index 50793ad..3af2be5 100644
--- a/scripts/portability.sh
+++ b/scripts/portability.sh
@@ -13,20 +13,28 @@
   [ ! -z "$(command -v gsed 2>/dev/null)" ] && SED=gsed || SED=sed
 fi
 
-# Extra debug plumbing the Android guys want
+# Tell linker to do dead code elimination at function level
+if [ "$(uname)" == "Darwin" ]
+then
+  : ${LDOPTIMIZE:=-Wl,-dead_strip} ${STRIP:=strip}
+else
+  : ${LDOPTIMIZE:=-Wl,--gc-sections -Wl,--as-needed} ${STRIP:=strip -s -R .note* -R .comment}
+fi
+
+# Address Sanitizer
 if [ ! -z "$ASAN" ]; then
-  echo "Enabling ASan..."
   # Turn ASan on and disable most optimization to get more readable backtraces.
   # (Technically ASAN is just "-fsanitize=address" and the rest is optional.)
   ASAN_FLAGS="-fsanitize=address -O1 -g -fno-omit-frame-pointer -fno-optimize-sibling-calls"
-  CFLAGS="$ASAN_FLAGS $CFLAGS"
-  # Run this nonsense against temporary build tools that don't ship too
+  CFLAGS="$CFLAGS $ASAN_FLAGS"
   HOSTCC="$HOSTCC $ASAN_FLAGS"
+  NOSTRIP=1
   # Ignore leaks on exit. TODO
   export ASAN_OPTIONS="detect_leaks=0"
+  unset ASAN
 fi
 
-# Centos 7 bug workaround, EOL June 30 2024.
+# Centos 7 bug workaround, EOL June 30 2024. TODO
 DASHN=-n; wait -n 2>/dev/null; [ $? -eq 2 ] && unset DASHN
 
 # If the build is using gnu tools, make them behave less randomly.
diff --git a/tests/tar.test b/tests/tar.test
index 6db3518..034a3bf 100644
--- a/tests/tar.test
+++ b/tests/tar.test
@@ -41,12 +41,12 @@
 # The kernel has two hardwired meaningful UIDs: 0 (root) and 65534 (nobody).
 # (Technically changeable via /proc/sys/*/overflowuid but nobody ever does)
 skipnot id nobody >/dev/null
-testing "pass user" "tar -c --owner nobody --group root --mtime @0 file | LST" \
+testing "pass user" "tar -c --owner nobody:65534 --group root --mtime @0 file | LST" \
   "-rw-rw-r-- nobody/root 0 1970-01-01 00:00 file\n" "" ""
 # (We assume that if we have the nobody user, we also have the group, in the
 # absence of a good portable way to test for the existence of a named group.)
 skipnot id nobody >/dev/null
-testing "pass group" "tar c --owner root --group nobody --mtime @0 file | LST" \
+testing "pass group" "tar c --owner root --group nobody:65534 --mtime @0 file | LST" \
   "-rw-rw-r-- root/nobody 0 1970-01-01 00:00 file\n" "" ""
 
 # Historically we output a "base 256" format that _we_ could decode but that
@@ -210,11 +210,12 @@
   "dir/\ndir/file\ndrwxr-x--- 1494637555 dd/dir\n-rw-r----- 1494637555 dd/dir/file\n" \
   "" ""
 
-yes | (dd bs=$((1<<16)) count=1 status=none; dd bs=8192 seek=14 count=1 status=none; dd bs=4096 seek=64 count=5 status=none) > fweep
+yes | head -n $((1<<18)) > bang
+{ dd bs=$((1<<16)) count=1 status=none; dd bs=8192 seek=14 count=1 status=none; dd bs=4096 seek=64 count=5 status=none; } < bang > fweep
 testing "sparse without overflow" "$TAR --sparse fweep | SUM 3" \
   "e1560110293247934493626d564c8f03c357cec5\n" "" ""
+rm bang fweep
 
-rm fweep
 for i in 1 3 5 7 9 14 27 36 128 256 300 304
 do
   dd if=/dev/zero of=fweep bs=65536 seek=$i count=1 2>/dev/null
@@ -275,6 +276,14 @@
   'hello\n' '' ''
 rm -rf one test.tar
 
+mkdir ..dotsdir
+testing "create ..dotsdir" "$TAR ..dotsdir | SUM 3" \
+  "de99091a91c74ef6b90093e9165b413670730572\n" "" ""
+
+testing "pass ..dotsdir" "$TAR ..dotsdir | LST" \
+  "drwxrwxr-x root/root 0 2009-02-13 23:31 ..dotsdir/\n" "" ""
+rmdir ..dotsdir
+
 if false
 then
 
diff --git a/toys/example/README b/toys/example/README
index 0ebc202..6e73fa1 100644
--- a/toys/example/README
+++ b/toys/example/README
@@ -2,13 +2,22 @@
 
 You probably don't want to deploy any of this.
 
-The hello.c and skeleton.c commands provide templates for new commands:
-hello.c is clean and simple, skeleton.c demonstrates the option parsing
-infrastructure and having multiple commands per file. When writing a new
-command, copying hello.c or skeleton.c to the new name may provide a good
-starting point. (The minimal staring point is toys/posix/false.c)
+The hello.c and skeleton.c commands provide templates for new commands. When
+writing a new command, copying hello.c or skeleton.c to the new name may provide
+a good starting point. (The minimal staring point is toys/posix/false.c)
 
-The demo_* commands demonstrate infrastructure, and do regression testing.
+  - hello.c is clean and simple, and an easy way to check the behavior of
+    toybox library functions running in command context.
 
-Other commands in here are obsolete versions still in some recent Linux systems
-(and often still in posix), but not really useful on modern systems.
+  - skeleton.c demonstrates the option parsing infrastructure and having
+    multiple commands per file.
+
+Some of the commands in here are test infrastructure:
+
+  - logpath.c is optionally used by mkroot.sh and scripts/record-commands
+
+  - demo_* demonstrates infrastructure, allowing tests/demo_*.test to
+    regression test library functions directly.
+
+hostid.c is an obsolete command still in posix and present on some recent
+Linux systems, but not really useful on modern systems.
diff --git a/toys/example/hello.c b/toys/example/hello.c
index 3e68f21..ad74eba 100644
--- a/toys/example/hello.c
+++ b/toys/example/hello.c
@@ -5,7 +5,8 @@
  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/
  * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html
  * See https://www.ietf.org/rfc/rfc3.txt
- * See http://man7.org/linux/man-pages/dir_section_1.html
+ * See https://man7.org/linux/man-pages/man1/intro.1.html
+ * No standard.
 
 USE_HELLO(NEWTOY(hello, 0, TOYFLAG_USR|TOYFLAG_BIN))
 
@@ -33,5 +34,5 @@
   xprintf("Hello world\n");
 
   // Avoid kernel panic if run as init.
-  if (getpid() == 1) wait(&TT.unused);
+  if (getpid() == 1) getchar();
 }
diff --git a/toys/example/skeleton.c b/toys/example/skeleton.c
index d6712b8..5408068 100644
--- a/toys/example/skeleton.c
+++ b/toys/example/skeleton.c
@@ -6,7 +6,8 @@
  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/
  * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/cmdbehav.html
  * See https://www.ietf.org/rfc/rfc3.txt
- * See http://man7.org/linux/man-pages/dir_section_1.html
+ * See https://man7.org/linux/man-pages/man1/intro.1.html
+ * No standard.
 
 // Accept many different kinds of command line argument (see top of lib/args.c)
 // Demonstrate two commands in the same file (see www/documentation.html)
diff --git a/toys/lsb/mount.c b/toys/lsb/mount.c
index 22021ab..10e8e9e 100644
--- a/toys/lsb/mount.c
+++ b/toys/lsb/mount.c
@@ -232,8 +232,7 @@
       i = strlen(type);
       if (i) type[i-1] = 0;
     }
-    if (FLAG(v))
-      printf("try '%s' type '%s' on '%s'\n", dev, type, dir);
+    if (FLAG(v)) printf("try '%s' type '%s' on '%s'\n", dev, type, dir);
     for (;;) {
       rc = mount(dev, dir, type, flags, opts);
       // Did we succeed, fail unrecoverably, or already try read-only?
@@ -354,8 +353,7 @@
           continue;
       } else {
         if (dir && strcmp(dir, mm->dir)) continue;
-        if (dev && strcmp(dev, mm->device) && (dir || strcmp(dev, mm->dir)))
-          continue;
+        if (strcmp(dev, mm->device) && (dir || strcmp(dev, mm->dir))) continue;
       }
 
       // Don't overmount the same dev on the same directory
diff --git a/toys/net/ifconfig.c b/toys/net/ifconfig.c
index e294457..e9671bb 100644
--- a/toys/net/ifconfig.c
+++ b/toys/net/ifconfig.c
@@ -42,6 +42,7 @@
     broadcast ADDR   - Set broadcast address
     pointopoint ADDR - PPP and PPPOE use this instead of "route add default gw"
     hw TYPE ADDR     - set hardware (mac) address (type = ether|infiniband)
+    rename NEWNAME   - rename interface
 
     Flags you can set on an interface (or -remove by prefixing with -):
 
@@ -405,6 +406,7 @@
       {"netmask", 0, SIOCSIFNETMASK},
       {"dstaddr", 0, SIOCSIFDSTADDR},
       {"mtu", IFREQ_OFFSZ(ifr_mtu), SIOCSIFMTU},
+      {"rename", IFREQ_OFFSZ(ifr_newname), SIOCSIFNAME},
       {"keepalive", IFREQ_OFFSZ(ifr_data), SIOCDEVPRIVATE}, // SIOCSKEEPALIVE
       {"outfill", IFREQ_OFFSZ(ifr_data), SIOCDEVPRIVATE+2}, // SIOCSOUTFILL
       {"metric", IFREQ_OFFSZ(ifr_metric), SIOCSIFMETRIC},
@@ -493,6 +495,7 @@
       struct argh *t = try+i;
       int on = t->on, off = t->off;
 
+      // First entry in list assigns address to interface (no command name)
       if (!t->name) {
         if (isdigit(**argv) || !strcmp(*argv, "default")) argv--;
         else continue;
@@ -505,11 +508,12 @@
 
           // Assign value to ifre field and call ioctl? (via IFREQ_OFFSZ.)
           if (on < 0) {
-            long l = strtoul(*argv, 0, 0);
+            void *dest = ((on = -on)>>16)+(char *)&ifre;
 
+            // If we're about to set mem_start/io_addr/irq, get other 2 first
             if (off == SIOCSIFMAP) xioctl(TT.sockfd, SIOCGIFMAP, &ifre);
-            on = -on;
-            poke((on>>16) + (char *)&ifre, l, on&15);
+            if (off == SIOCSIFNAME) xstrncpy(dest, *argv, on&0xffff);
+            else poke(dest, strtoul(*argv, 0, 0), on&15);
             xioctl(TT.sockfd, off, &ifre);
             break;
           } else {
diff --git a/toys/other/chvt.c b/toys/other/chvt.c
deleted file mode 100644
index 7d69f9a..0000000
--- a/toys/other/chvt.c
+++ /dev/null
@@ -1,33 +0,0 @@
-/* chvt.c - switch virtual terminals
- *
- * Copyright (C) 2008 David Anders <danders@amltd.com>
-
-USE_CHVT(NEWTOY(chvt, "<1", TOYFLAG_USR|TOYFLAG_BIN))
-
-config CHVT
-  bool "chvt"
-  default y
-  help
-    usage: chvt N
-
-    Change to virtual terminal number N. (This only works in text mode.)
-
-    Virtual terminals are the Linux VGA text mode displays, ordinarily
-    switched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch
-    from X to a virtual terminal, and alt-F6 (or F7, or F8) to get back.
-*/
-
-#include "toys.h"
-#include <linux/vt.h>
-
-void chvt_main(void)
-{
-  int vt, fd;
-  char *consoles[]={"/dev/console", "/dev/vc/0", "/dev/tty", NULL}, **cc;
-
-  vt = atoi(*toys.optargs);
-  for (cc = consoles; *cc; cc++) if ((fd = open(*cc, O_RDWR)) != -1) break;
-
-  if (fd == -1 || ioctl(fd, VT_ACTIVATE, vt) || ioctl(fd, VT_WAITACTIVE, vt))
-    perror_exit(0);
-}
diff --git a/toys/other/factor.c b/toys/other/factor.c
index f0e69c5..47e1267 100644
--- a/toys/other/factor.c
+++ b/toys/other/factor.c
@@ -2,7 +2,7 @@
  *
  * Copyright 2014 Rob Landley <rob@landley.net>
  *
- * No standard, but it's in coreutils
+ * See https://man7.org/linux/man-pages/man1/factor.1.html
 
 USE_FACTOR(NEWTOY(factor, 0, TOYFLAG_USR|TOYFLAG_BIN))
 
@@ -19,7 +19,7 @@
 
 static void factor(char *s)
 {
-  unsigned long long l, ll;
+  unsigned long long l, ll, lll;
 
   for (;;) {
     char *err = s;
@@ -55,9 +55,8 @@
     }
 
     // test odd numbers until square is > remainder or integer wrap.
-    for (ll=3; ;ll += 2) {
-      long lll = ll*ll;
-
+    for (ll = 3;; ll += 2) {
+      lll = ll*ll;
       if (lll>l || lll<ll) {
         if (l>1) printf(" %llu", l);
         break;
@@ -73,14 +72,11 @@
 
 void factor_main(void)
 {
-  if (toys.optc) {
-    char **ss;
+  char *s = 0, **ss;
+  size_t len = 0;
 
-    for (ss = toys.optargs; *ss; ss++) factor(*ss);
-  } else for (;;) {
-    char *s = 0;
-    size_t len = 0;
-
+  if (toys.optc) for (ss = toys.optargs; *ss; ss++) factor(*ss);
+  else for (;;) {
     if (-1 == getline(&s, &len, stdin)) break;
     factor(s);
   }
diff --git a/toys/other/ionice.c b/toys/other/ionice.c
index 07a212b..db3a6f4 100644
--- a/toys/other/ionice.c
+++ b/toys/other/ionice.c
@@ -6,7 +6,7 @@
  * Documentation/block/ioprio.txt in the linux source.
 
 USE_IONICE(NEWTOY(ionice, "^tc#<0>3=2n#<0>7=5p#", TOYFLAG_USR|TOYFLAG_BIN))
-USE_IORENICE(NEWTOY(iorenice, "?<1>3", TOYFLAG_USR|TOYFLAG_BIN))
+USE_IORENICE(NEWTOY(iorenice, "<1>3", TOYFLAG_USR|TOYFLAG_BIN))
 
 config IONICE
   bool "ionice"
diff --git a/toys/other/openvt.c b/toys/other/openvt.c
new file mode 100644
index 0000000..8210587
--- /dev/null
+++ b/toys/other/openvt.c
@@ -0,0 +1,115 @@
+/* openvt.c - Run a program on a new VT
+ *
+ * Copyright 2008 David Anders <danders@amltd.com>
+ * Copyright 2014 Vivek Kumar Bhagat <vivek.bhagat89@gmail.com>
+ *
+ * No Standard
+
+USE_OPENVT(NEWTOY(openvt, "^<1c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+USE_CHVT(NEWTOY(chvt, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_DEALLOCVT(NEWTOY(deallocvt, ">1", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_NEEDROOT))
+
+config OPENVT
+  bool "openvt"
+  default y
+  help
+    usage: openvt [-c NUM] [-sw] COMMAND...
+
+    Run COMMAND on a new virtual terminal.
+
+    -c NUM  Use VT NUM
+    -s    Switch to the new VT
+    -w    Wait for command to exit (with -s, deallocates VT on exit)
+
+config CHVT
+  bool "chvt"
+  default y
+  help
+    usage: chvt NUM
+
+    Change to virtual terminal number NUM. (This only works in text mode.)
+
+    Virtual terminals are the Linux VGA text mode (or framebuffer) displays,
+    switched between via alt-F1, alt-F2, etc. Use ctrl-alt-F1 to switch
+    from X11 to a virtual terminal, and alt-F6 (or F7, or F8) to get back.
+
+config DEALLOCVT
+  bool "deallocvt"
+  default y
+  help
+    usage: deallocvt [NUM]
+
+    Deallocate unused virtual terminals, either a specific /dev/ttyNUM, or all.
+*/
+
+#define FOR_openvt
+#include "toys.h"
+#include <linux/vt.h>
+#include <linux/kd.h>
+
+GLOBALS(
+  long c;
+)
+
+static int open_console(void)
+{
+  char arg = 0, *console_name[] = {"/dev/tty", "/dev/tty0", "/dev/console"};
+  int i, fd;
+
+  for (i = 0; i < ARRAY_LEN(console_name); i++) {
+    if (0>(fd = open(console_name[i], O_RDWR))) continue;
+    if (!ioctl(fd, KDGKBTYPE, &arg)) return fd;
+    close(fd);
+  }
+  for (fd = 0; fd < 3; fd++) if (!ioctl(fd, KDGKBTYPE, &arg)) return fd;
+  error_exit("can't open console");
+}
+
+static int activate(int fd, int cc)
+{
+  return ioctl(fd, VT_ACTIVATE, cc) || ioctl(fd, VT_WAITACTIVE, cc);
+}
+
+void openvt_main(void)
+{
+  struct vt_stat vstate;
+  int fd, cc = (int)TT.c;
+  pid_t pid;
+
+  // find current console
+  if (-1 == (ioctl(fd = open_console(), VT_GETSTATE, &vstate)) ||
+      (!cc && 0>=(cc = xioctl(fd, VT_OPENQRY, &fd))))
+    perror_exit("can't find open VT");
+
+  sprintf(toybuf, "/dev/tty%d", cc);
+  if (!(pid = XVFORK())) {
+    close(0);  //new vt becomes stdin
+    dup2(dup2(xopen_stdio(toybuf, O_RDWR), 1), 2);
+    if (FLAG(s)) activate(0, cc);
+    setsid();
+    ioctl(0, TIOCSCTTY, 0);
+    if (fd>2) close(fd);
+    xexec(toys.optargs);
+  }
+  if (FLAG(w)) {
+    while (-1 == waitpid(pid, NULL, 0) && errno == EINTR) errno = 0;
+    if (FLAG(s)) {
+      activate(fd, vstate.v_active);
+      dprintf(2, "%d\n", ioctl(fd, VT_DISALLOCATE, cc));
+    }
+  }
+}
+
+void chvt_main(void)
+{
+  if (activate(open_console(), atoi(*toys.optargs)))
+    perror_exit_raw(*toys.optargs);
+}
+
+void deallocvt_main(void)
+{
+  int fd = open_console(), vt_num = 0; // 0 = all
+
+  if (*toys.optargs) vt_num = atolx_range(*toys.optargs, 1, 63);
+  if (-1 == ioctl(fd, VT_DISALLOCATE, vt_num)) perror_exit("%d", vt_num);
+}
diff --git a/toys/other/readlink.c b/toys/other/readlink.c
index 55234cc..3155dcc 100644
--- a/toys/other/readlink.c
+++ b/toys/other/readlink.c
@@ -4,7 +4,7 @@
 
 // -ef positions match ABS_FILE ABS_PATH
 USE_READLINK(NEWTOY(readlink, "<1nqmef(canonicalize)[-mef]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_REALPATH(NEWTOY(realpath, "<1", TOYFLAG_USR|TOYFLAG_BIN))
+USE_REALPATH(OLDTOY(realpath, readlink, TOYFLAG_USR|TOYFLAG_BIN))
 
 config READLINK
   bool "readlink"
@@ -39,6 +39,7 @@
 {
   char **arg, *s;
 
+  if (toys.which->name[3]=='l') toys.optflags |= FLAG_f;
   for (arg = toys.optargs; *arg; arg++) {
     // Calculating full canonical path?
     // Take advantage of flag positions: m = 0, f = ABS_PATH, e = ABS_FILE
@@ -52,9 +53,3 @@
     } else toys.exitval = 1;
   }
 }
-
-void realpath_main(void)
-{
-  toys.optflags = FLAG_f;
-  readlink_main();
-}
diff --git a/toys/pending/openvt.c b/toys/pending/openvt.c
deleted file mode 100644
index 3cc97da..0000000
--- a/toys/pending/openvt.c
+++ /dev/null
@@ -1,102 +0,0 @@
-/* openvt.c - Run a program on a new VT
- *
- * Copyright 2014 Vivek Kumar Bhagat <vivek.bhagat89@gmail.com>
- *
- * No Standard
-
-USE_OPENVT(NEWTOY(openvt, "c#<1>63sw", TOYFLAG_BIN|TOYFLAG_NEEDROOT))
-USE_DEALLOCVT(NEWTOY(deallocvt, ">1", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_NEEDROOT))
-
-config OPENVT
-  bool "openvt"
-  default n
-  depends on TOYBOX_FORK
-  help
-    usage: openvt [-c NUM] [-sw] [COMMAND...]
-
-    Start a program on a new virtual terminal.
-
-    -c NUM  Use VT NUM
-    -s    Switch to new VT
-    -w    Wait for command to exit
-
-    Together -sw switch back to originating VT when command completes.
-
-config DEALLOCVT
-  bool "deallocvt"
-  default n
-  help
-    usage: deallocvt [NUM]
-
-    Deallocate unused virtual terminals, either a specific /dev/ttyNUM, or all.
-*/
-
-#define FOR_openvt
-#include "toys.h"
-#include <linux/vt.h>
-#include <linux/kd.h>
-
-GLOBALS(
-  long c;
-)
-
-int open_console(void)
-{
-  char arg = 0, *console_name[] = {"/dev/tty", "/dev/tty0", "/dev/console"};
-  int i, fd;
-
-  for (i = 0; i < ARRAY_LEN(console_name); i++) {
-    if (0>(fd = open(console_name[i], O_RDWR))) continue;
-    if (!ioctl(fd, KDGKBTYPE, &arg)) return fd;
-    close(fd);
-  }
-  for (fd = 0; fd < 3; fd++) if (!ioctl(fd, KDGKBTYPE, &arg)) return fd;
-  error_exit("can't open console");
-}
-
-void openvt_main(void)
-{
-  struct vt_stat vstate;
-  int fd;
-  pid_t pid;
-
-  // find current console
-  if (-1 == (ioctl(fd = open_console(), VT_GETSTATE, &vstate)) ||
-      (!TT.c && 0>=(TT.c = xioctl(fd, VT_OPENQRY, &fd))))
-    perror_exit("can't find open VT");
-
-  sprintf(toybuf, "/dev/tty%ld", TT.c);
-  close(0);  //new vt becomes stdin
-  dup2(dup2(xopen_stdio(toybuf, O_RDWR), 1), 2);
-  if (FLAG(s)) {
-    ioctl(0, VT_ACTIVATE, (int)TT.c);
-    ioctl(0, VT_WAITACTIVE, (int)TT.c);
-  }
-
-  if (!(pid = xfork())) {
-    setsid();
-    ioctl(0, TIOCSCTTY, 0);
-    if (fd>2) close(fd);
-    xexec(toys.optargs);
-  }
-
-  if (FLAG(w)) {
-    while (-1 == waitpid(pid, NULL, 0) && errno == EINTR);
-    if (FLAG(s)) {
-      ioctl(fd, VT_ACTIVATE, vstate.v_active);
-      ioctl(fd, VT_WAITACTIVE, vstate.v_active);
-      ioctl(fd, VT_DISALLOCATE, (int)TT.c);
-    }
-  }
-  close(fd);
-}
-
-void deallocvt_main(void)
-{
-  int fd, vt_num = 0; // 0 = all
-
-  if (*toys.optargs) vt_num = atolx_range(*toys.optargs, 1, 63);
-  if (-1 == ioctl(fd = open_console(), VT_DISALLOCATE, vt_num))
-    perror_exit("%d", vt_num);
-  close(fd);
-}
diff --git a/toys/pending/sh.c b/toys/pending/sh.c
index 85be826..8f45c17 100644
--- a/toys/pending/sh.c
+++ b/toys/pending/sh.c
@@ -350,6 +350,7 @@
   struct dirent *DE;
   char *s, *ss = 0, buf[4096], *sss = buf;
 
+  if (!X) return;
   for (; (DE = readdir(X));) {
     if (atoi(DE->d_name) == fd) continue;
     s = xreadlink(ss = xmprintf("/proc/self/fd/%s", DE->d_name));
@@ -1547,7 +1548,7 @@
   if (!dt) return arg_add(arg, pattern);
   while (dt) {
     while (dt->child) dt = dt->child;
-    arg_add(arg, dirtree_path(dt, 0));
+    arg_add(arg, push_arg(delete, dirtree_path(dt, 0)));
     do {
       pp = (void *)dt;
       if ((dt = dt->parent)) dt->child = dt->child->next;
@@ -2285,9 +2286,7 @@
   for (j = skip; j<arg->c; j++) {
     int saveclose = 0, bad = 0;
 
-    s = arg->v[j];
-
-    if (!strcmp(s, "!")) {
+    if (!strcmp(s = arg->v[j], "!")) {
       pp->flags ^= PFLAG_NOT;
 
       continue;
@@ -2889,8 +2888,10 @@
 
       // Stop at EOL. Discard blank pipeline segment, else end segment
       if (end == start) done++;
-      if (!pl->type && !arg->c) free_pipeline(dlist_lpop(ppl));
-      else pl->count = -1;
+      if (!pl->type && !arg->c) {
+        free_pipeline(dlist_lpop(ppl));
+        pl = *ppl ? (*ppl)->prev : 0;
+      } else pl->count = -1;
 
       continue;
     }
diff --git a/toys/pending/wget.c b/toys/pending/wget.c
index bcb42f8..9e100e8 100644
--- a/toys/pending/wget.c
+++ b/toys/pending/wget.c
@@ -26,7 +26,7 @@
  * todo: Add support for Transfer Encoding (gzip|deflate)
  * todo: Add support for RFC5987
 
-USE_WGET(NEWTOY(wget, "<1>1(max-redirect)#<0=20d(debug)O(output-document):", TOYFLAG_USR|TOYFLAG_BIN))
+USE_WGET(NEWTOY(wget, "<1>1(max-redirect)#<0=20d(debug)O(output-document):p(post-data):", TOYFLAG_USR|TOYFLAG_BIN))
 
 config WGET
   bool "wget"
@@ -36,6 +36,7 @@
         --max-redirect          maximum redirections allowed
     -d, --debug                 print lots of debugging information
     -O, --output-document=FILE  specify output filename
+    -p, --post-data=DATA        send data in body of POST request
 
     examples:
       wget http://www.example.com
@@ -70,20 +71,14 @@
 #else
 #define WGET_SSL 0
 #endif
+#define HTTPS (WGET_SSL && TT.https)
 
-#define WGET_FILENAME         "Content-Disposition: attachment; filename="
-#define WGET_CHUNKED          "transfer-encoding: chunked"
-#define WGET_LOCATION         "Location: "
-#define WGET_LIBTLS_PROTOCOLS "tlsv1.2"
-
-#define WGET_IS_HTTP  (strncmp(TT.url, "http://", 7) == 0)
-#define WGET_IS_HTTPS (WGET_SSL && (strncmp(TT.url, "https://", 8) == 0))
 
 GLOBALS(
-  char *filename;
-  long redirects;
+  char *p, *O;
+  long max_redirect;
 
-  int sock;
+  int sock, https;
   char *url;
 #if CFG_WGET_LIBTLS
   struct tls *tls;
@@ -93,65 +88,52 @@
 #endif
 )
 
-static char *wget_strncaseafter(char *haystack, char *needle)
-{
-  char *result = strcasestr(haystack, needle);
-  if (result) result = result + strlen(needle);
-  return result;
-}
-
 // get http info in URL
 static void wget_info(char *url, char **host, char **port, char **path)
 {
-  *host = strafter(url, "://");
-  *path = strchr(*host, '/');
+  char *ss = url;
 
-  if ((*path = strchr(*host, '/'))) {
-    **path = '\0';
-    *path = *path + 1;
-  } else {
-    *path = "";
+  // Must start with case insensitive http:// or https://
+  if (strncmp(url, "http", 4)) url = 0;
+  else {
+    url += 4;
+    if ((TT.https = WGET_SSL && toupper(*url=='s'))) url++;
+    if (!strstart(&url, "://")) url = 0;
   }
+  if (!url) error_exit("unsupported protocol: %s", ss);
 
-  if ( *host[0] == '[' && strchr(*host, ']') ) { // IPv6
-    *port = strafter(*host, "]:");
-    *host = *host + 1;
-    strchr(*host, ']')[0] = '\0';
-  } else { // IPv4
-    if ((*port = strchr(*host, ':'))) {
-      **port = '\0';
-      *port = *port + 1;
-    }
-  }
+  if ((*path = strchr(*host = url, '/'))) *((*path)++) = 0;
+  else *path = "";
 
-  if (!*port && WGET_IS_HTTP) *port = "80";
-  else if (!*port && WGET_IS_HTTPS) *port = "443";
-  else if (!*port) error_exit("unsupported protocol");
+  // Get port number and trim literal IPv6 addresses
+  if (**host=='[' && (ss = strchr(++*host, ']'))) {
+    *ss++ = 0;
+    *port = (*ss==':') ? ++ss : 0;
+  } else if ((*port = strchr(*host, ':'))) *(*port++) = 0;
+  if (!*port) *port = HTTPS ? "443" : "80";
 }
 
 static void wget_connect(char *host, char *port)
 {
-  if (WGET_IS_HTTP) {
-    struct addrinfo *a =
-        xgetaddrinfo(host, port, AF_UNSPEC, SOCK_STREAM, 0, 0);
-    TT.sock = xconnectany(a);
-  } else if (WGET_IS_HTTPS) {
+  if (!HTTPS)
+    TT.sock = xconnectany(xgetaddrinfo(host, port, AF_UNSPEC, SOCK_STREAM, 0, 0));
+  else {
 #if CFG_WGET_LIBTLS
     struct tls_config *cfg = NULL;
     uint32_t protocols;
-    if ((TT.tls = tls_client()) == NULL)
+    if (!(TT.tls = tls_client()))
       error_exit("tls_client: %s", tls_error(TT.tls));
-    if ((cfg = tls_config_new()) == NULL)
+    if (!(cfg = tls_config_new()))
       error_exit("tls_config_new: %s", tls_config_error(cfg));
-    if (tls_config_parse_protocols(&protocols, WGET_LIBTLS_PROTOCOLS) != 0)
+    if (tls_config_parse_protocols(&protocols, "tlsv1.2"))
       error_exit("tls_config_parse_protocols");
-    if (tls_config_set_protocols(cfg, protocols) != 0)
+    if (tls_config_set_protocols(cfg, protocols))
       error_exit("tls_config_set_protocols: %s", tls_config_error(cfg));
-    if (tls_configure(TT.tls, cfg) != 0)
+    if (tls_configure(TT.tls, cfg))
       error_exit("tls_configure: %s", tls_error(TT.tls));
     tls_config_free(cfg);
 
-    if (tls_connect(TT.tls, host, port) != 0)
+    if (tls_connect(TT.tls, host, port))
       error_exit("tls_connect: %s", tls_error(TT.tls));
 #elif CFG_WGET_OPENSSL
     SSL_library_init();
@@ -162,9 +144,7 @@
     TT.ctx = SSL_CTX_new(TLS_client_method());
     if (!TT.ctx) error_exit("SSL_CTX_new");
 
-    struct addrinfo *a =
-        xgetaddrinfo(host, port, AF_UNSPEC, SOCK_STREAM, 0, 0);
-    TT.sock = xconnectany(a);
+    TT.sock = xconnectany(xgetaddrinfo(host, port, AF_UNSPEC, SOCK_STREAM, 0, 0));
 
     TT.ssl = SSL_new(TT.ctx);
     if (!TT.ssl)
@@ -180,39 +160,42 @@
 
     if (FLAG(d)) printf("TLS: %s\n", SSL_get_cipher(TT.ssl));
 #endif
-  } else error_exit("unsupported protocol");
+  }
 }
 
 static size_t wget_read(void *buf, size_t len)
 {
-  if (WGET_IS_HTTP) return xread(TT.sock, buf, len);
-  else if (WGET_IS_HTTPS) {
+  if (!HTTPS) return xread(TT.sock, buf, len);
+  else {
+    char *err = 0;
+    int ret;
+
 #if CFG_WGET_LIBTLS
-   ssize_t ret = tls_read(TT.tls, buf, len);
-   if (ret < 0) error_exit("tls_read: %s", tls_error(TT.tls));
-   return ret;
+    if ((ret = tls_read(TT.tls, buf, len))<0) err = tls_error(TT.tls);
 #elif CFG_WGET_OPENSSL
-   int ret = SSL_read(TT.ssl, buf, (int) len);
-   if (ret < 0)
-     error_exit("SSL_read: %s", ERR_error_string(ERR_get_error(), NULL));
-   return ret;
+    if ((ret = SSL_read(TT.ssl, buf, len))<0)
+      err = ERR_error_string(ERR_get_error(), 0);
 #endif
-  } else error_exit("unsupported protocol");
+    if (err) error_exit("https read: %s", err);
+
+    return ret;
+  }
 }
 
 static void wget_write(void *buf, size_t len)
 {
-  if (WGET_IS_HTTP) {
-    xwrite(TT.sock, buf, len);
-  } else if (WGET_IS_HTTPS) {
+  if (!HTTPS) xwrite(TT.sock, buf, len);
+  else {
+    char *err = 0;
+
 #if CFG_WGET_LIBTLS
-    if (len != tls_write(TT.tls, buf, len))
-      error_exit("tls_write: %s", tls_error(TT.tls));
+    if (len != tls_write(TT.tls, buf, len)) err = tls_error(TT.tls);
 #elif CFG_WGET_OPENSSL
-    if (len != SSL_write(TT.ssl, buf, (int) len))
-      error_exit("SSL_write: %s", ERR_error_string(ERR_get_error(), NULL));
+    if (len != SSL_write(TT.ssl, buf, len))
+      err = ERR_error_string(ERR_get_error(), 0);
 #endif
-  } else error_exit("unsupported protocol");
+    if (err) error_exit("https write: %s", err);
+  }
 }
 
 static void wget_close()
@@ -226,120 +209,100 @@
   if (TT.tls) {
     tls_close(TT.tls);
     tls_free(TT.tls);
-    TT.tls = NULL;
+    TT.tls = 0;
   }
 #elif CFG_WGET_OPENSSL
   if (TT.ssl) {
     SSL_shutdown(TT.ssl);
     SSL_free(TT.ssl);
-    TT.ssl = NULL;
+    TT.ssl = 0;
   }
 
   if (TT.ctx) {
     SSL_CTX_free(TT.ctx);
-    TT.ctx = NULL;
+    TT.ctx = 0;
   }
 #endif
 }
 
-static char* wget_find_header(char *header, char *val) {
-  char *v= wget_strncaseafter(header, val);
-  return v;
-}
-
-static int wget_has_header(char *header, char *val)
+static char *wget_find_header(char *header, char *val)
 {
-  return wget_find_header(header, val) != NULL;
-}
+  char *result = strcasestr(header, val);
 
-static char *wget_redirect(char *header)
-{
-  char *redir = wget_find_header(header, WGET_LOCATION);
-  if (!redir) error_exit("could not parse redirect URL");
-  return xstrndup(redir, stridx(redir, '\r'));
-}
+  if (result) {
+    result += strlen(val);
+    result[strcspn(result, "\r\n")] = 0;
+  }
 
-static char *wget_filename(char *header, char *path)
-{
-  char *f = wget_find_header(header, WGET_FILENAME);
-  if (f) strchr(f, '\r')[0] = '\0';
-
-  if (!f && strchr(path, '/')) f = getbasename(path);
-  if (!f || !(*f) ) f = "index.html";
-
-  return f;
+  return result;
 }
 
 void wget_main(void)
 {
   long status = 0;
   size_t len, c_len = 0;
-  int fd, chunked;
-  char *body, *index, *host, *port, *path;
+  int fd = 0;
+  char *body, *index, *host, *port, *path, *chunked, *ss;
   char agent[] = "toybox wget/" TOYBOX_VERSION;
 
-  TT.url = xstrdup(toys.optargs[0]);
+  TT.url = xstrdup(*toys.optargs);
 
-  for (;status != 200; TT.redirects--) {
-    if (TT.redirects < 0) error_exit("Too many redirects");
+  // Ask server for URL, following redirects until success
+  while (status != 200) {
+    if (!TT.max_redirect--) error_exit("Too many redirects");
 
+    // Connect and write request
     wget_info(TT.url, &host, &port, &path);
-
-    sprintf(toybuf, "GET /%s HTTP/1.1\r\nHost: %s\r\n"
-                    "User-Agent: %s\r\nConnection: close\r\n\r\n",
-                    path, host, agent);
-    if (FLAG(d)) printf("--- Request\n%s", toybuf);
-
+    if (TT.p) sprintf(toybuf, "Content-Length: %ld\r\n", strlen(TT.p));
+    ss = xmprintf("%s /%s HTTP/1.1\r\nHost: %s\r\nUser-Agent: %s\r\n"
+                  "Connection: close\r\n%s\r\n%s", FLAG(p) ? "POST" : "GET",
+                  path, host, agent, FLAG(p) ? toybuf : "", FLAG(p)?TT.p:"");
+    if (FLAG(d)) printf("--- Request\n%s", ss);
     wget_connect(host, port);
-    wget_write(toybuf, strlen(toybuf));
+    wget_write(ss, strlen(ss));
+    free(ss);
 
-    // Greedily read the HTTP response until either complete or toybuf is full
-    index = toybuf;
-    while ((len = wget_read(index, sizeof(toybuf) - (index - toybuf))) > 0)
-      index += len;
+    // Read HTTP response into toybuf (probably with some body at end)
+    for (index = toybuf;
+      (len = wget_read(index, sizeof(toybuf)-(index-toybuf)))>0; index += len);
 
-    //Process the response such that
-    //  Valid ranges  toybuf[0...index)      valid length is (index - toybuf)
-    //  Header ranges toybuf[0...body)       header length strlen(toybuf)
-    //  Remnant Body  toybuf[body...index)   valid remnant body length is len
-    //
-    // Per RFC7230 the header cannot contain a NUL octet so we NUL terminate at
-    // the footer of the header. This allows for normal string functions to be
-    // used when processing the header.
-    body = memmem(toybuf, index - toybuf, "\r\n\r\n", 4);
-    if (!body) error_exit("response header too large");
-    body[0] = '\0'; // NUL terminate the headers
-    body += 4; // Skip to the head of body
-    len = index - body; // Adjust len to be body length
+    // Split response into header and body, and null terminate header.
+    // (RFC7230 says header cannot contain NUL.)
+    if (!(body = memmem(ss = toybuf, index-toybuf, "\r\n\r\n", 4)))
+      error_exit("response header too large");
+    *body = 0;
+    body += 4;
+    len = index-body;
     if (FLAG(d)) printf("--- Response\n%s\n\n", toybuf);
 
-    status = strtol(strafter(toybuf, " "), NULL, 10);
+    status = strstart(&ss, "HTTP/1.1 ") ? strtol(ss, 0, 10) : 0;
     if ((status == 301) || (status == 302)) {
+      if (!(ss = wget_find_header(toybuf, "Location: ")))
+        error_exit("bad redirect");
       free(TT.url);
-      TT.url = wget_redirect(toybuf);
+      TT.url = xstrdup(ss);
       wget_close();
     } else if (status != 200) error_exit("response: %ld", status);
   }
 
-  if (!FLAG(O)) {
-    TT.filename = wget_filename(toybuf, path);
-    if (!access(TT.filename, F_OK))
-      error_exit("%s already exists", TT.filename);
+  // Open output file
+  if (TT.O && !strcmp(TT.O, "-")) fd = 1;
+  else if (!TT.O) {
+    ss = wget_find_header(toybuf, "Content-Disposition: attachment; filename=");
+    if (!ss && strchr(path, '/')) ss = getbasename(path);
+    if (!ss || !*ss ) ss = "index.html";
+    if (!access((TT.O = ss), F_OK)) error_exit("%s already exists", TT.O);
   }
-  fd = xcreate(TT.filename, (O_WRONLY|O_CREAT|O_TRUNC), 0644);
-
-  chunked = wget_has_header(toybuf, WGET_CHUNKED);
+  // TODO: don't allow header/basename to write to stdout
+  if (!fd) fd = xcreate(TT.O, (O_WRONLY|O_CREAT|O_TRUNC), 0644);
 
   // If chunked we offset the first buffer by 2 character, meaning it is
   // pointing at half of the header boundary, aka '\r\n'. This simplifies
   // parsing of the first c_len length by allowing the do while loop to fall
   // through on the first iteration and parse the first c_len size.
-  if (chunked) {
-    len = len + 2;
-    memmove(toybuf, body - 2, len);
-  } else {
-    memmove(toybuf, body, len);
-  }
+  chunked = wget_find_header(toybuf, "transfer-encoding: chunked");
+  if (chunked) memmove(toybuf, body-2, len += 2);
+  else memmove(toybuf, body, len);
 
   // len is the size remaining in toybuf
   // c_len is the size of the remaining bytes in the current chunk
@@ -360,7 +323,7 @@
 
       // If len is less than 2 we can't validate the chunk boundary so fall
       // through and go read more into toybuf.
-      if ((c_len == 0) && (len > 2)) {
+      if (!c_len && (len > 2)) {
         char *c;
         if (strncmp(toybuf, "\r\n", 2) != 0) error_exit("chunk boundary");
 
@@ -369,7 +332,7 @@
         c = memmem(toybuf + 2, len - 2, "\r\n",2);
         if (c) {
           c_len = strtol(toybuf + 2, NULL, 16);
-          if (c_len == 0) goto exit; // A c_len of zero means we are complete
+          if (!c_len) break; // A c_len of zero means we are complete
           len = len - (c - toybuf) - 2;
           memmove(toybuf, c + 2, len);
         }
@@ -382,7 +345,6 @@
     }
   } while ((len += wget_read(toybuf + len, sizeof(toybuf) - len)) > 0);
 
-  exit:
   wget_close();
   free(TT.url);
-}
\ No newline at end of file
+}
diff --git a/toys/posix/file.c b/toys/posix/file.c
index 9330da1..2e65bcf 100644
--- a/toys/posix/file.c
+++ b/toys/posix/file.c
@@ -69,15 +69,9 @@
 
   // "x86".
   printf("%s", elf_arch_name(elf_int(toybuf+18, 2)));
-  if (bail) goto bad;
 
   // If what we've seen so far doesn't seem consistent, bail.
-
-  // Parsing ELF means following tables that may point to data earlier in
-  // the file, so sequential reading involves buffering unknown amounts of
-  // data. Just skip it if we can't mmap.
-  if (MAP_FAILED == (map = mmap(0, TT.len, PROT_READ, MAP_SHARED, fd, 0)))
-    goto bad;
+  if (bail) goto bad;
 
   // Stash what we need from the header; it's okay to reuse toybuf after this.
   phentsize = elf_int(toybuf+42+12*bits, 2);
@@ -93,15 +87,24 @@
     printf(", bad phentsize %d?", phentsize);
     goto bad;
   }
+  if (phoff>TT.len || phnum*phentsize>TT.len-phoff) {
+    printf(", bad phoff %lu?", phoff);
+    goto bad;
+  }
+  if (shoff>TT.len || shnum*shsize>TT.len-shoff) {
+    printf(", bad shoff %lu?", phoff);
+    goto bad;
+  }
 
   // Parsing ELF means following tables that may point to data earlier in
   // the file, so sequential reading involves buffering unknown amounts of
   // data. Just skip it if we can't mmap.
-  if (MAP_FAILED == (map = mmap(0, TT.len, PROT_READ, MAP_SHARED, fd, 0)))
+  if (MAP_FAILED == (map = mmap(0, TT.len, PROT_READ, MAP_SHARED, fd, 0))) {
+    perror_msg("mmap");
     goto bad;
+  }
 
   // Read the phdrs for dynamic vs static. (Note: fields reordered on 64 bit)
-  if (phoff>TT.len || phnum*phentsize>TT.len-phoff) goto bad;
   for (i = 0; i<phnum; i++) {
     char *phdr = map+phoff+i*phentsize;
     unsigned p_type = elf_int(phdr, 4);
@@ -113,7 +116,10 @@
     p_offset = elf_int(phdr+(4<<bits), 4<<bits);
     p_filesz = elf_int(phdr+(16<<bits), 4<<bits);
     if (p_type==3) {
-      if (p_filesz>TT.len || p_offset>TT.len-p_filesz) goto bad;
+      if (p_filesz>TT.len || p_offset>TT.len-p_filesz) {
+        printf(", bad phdr %d?", i);
+        goto bad;
+      }
       // TODO: if (int)<0 prints endlessly, could go off end of map?
       printf(", dynamic (%.*s)", (int)p_filesz, map+p_offset);
     }
@@ -123,18 +129,23 @@
   // We need to read the shdrs for stripped/unstripped and any notes.
   // Notes are in program headers *and* section headers, but some files don't
   // contain program headers, so check here. (Note: fields reordered on 64 bit)
-  if (shoff<0 || shoff>TT.len || shnum*shsize>TT.len-shoff) goto bad;
   for (i = 0; i<shnum; i++) {
     char *shdr = map+shoff+i*shsize;
     unsigned long sh_offset;
     int sh_type, sh_size;
 
-    if (shdr>map+TT.len-(8+(4<<bits))) goto bad;
+    if (shdr>map+TT.len-(8+(4<<bits))) {
+      printf(", bad shdr %d?", i);
+      goto bad;
+    }
     sh_type = elf_int(shdr+4, 4);
     sh_offset = elf_int(shdr+8+(8<<bits), 4<<bits);
     sh_size = elf_int(shdr+8+(12<<bits), 4);
     if (sh_type == 8 /*SHT_NOBITS*/) sh_size = 0;
-    if (sh_offset>TT.len || sh_size>TT.len-sh_offset) goto bad;
+    if (sh_offset>TT.len || sh_size>TT.len-sh_offset) {
+      printf(", bad shdr %d?", i);
+      goto bad;
+    }
 
     if (sh_type == 2 /*SHT_SYMTAB*/) {
       stripped = 0;
@@ -149,16 +160,22 @@
       while (sh_size >= 3*4) { // Don't try to read a truncated entry.
         unsigned n_namesz, n_descsz, n_type, notesz;
 
-        if (note>map+TT.len-3*4) goto bad;
+        if (note>map+TT.len-3*4) {
+          printf(", bad note %d?", i);
+          goto bad;
+        }
 
         n_namesz = elf_int(note, 4);
         n_descsz = elf_int(note+4, 4);
         n_type = elf_int(note+8, 4);
         notesz = 3*4 + ((n_namesz+3)&~3) + ((n_descsz+3)&~3);
-        if (notesz<n_namesz || notesz<n_descsz) goto bad;
 
-        // Does the claimed size of this note actually fit in the section?
-        if (notesz > sh_size) goto bad;
+        // Are the name/desc sizes consistent, and does the claimed size of
+        // the note actually fit in the section?
+        if (notesz<n_namesz || notesz<n_descsz || notesz>sh_size) {
+          printf(", bad note %d size?", i);
+          goto bad;
+        }
 
         if (n_namesz==4 && !memcmp(note+12, "GNU", 4) && n_type==3) {
           printf(", BuildID=");
diff --git a/toys/posix/tar.c b/toys/posix/tar.c
index bd68873..9cf1a5c 100644
--- a/toys/posix/tar.c
+++ b/toys/posix/tar.c
@@ -17,7 +17,7 @@
  * Why --exclude pattern but no --include? tar cvzf a.tgz dir --include '*.txt'
  *
 
-USE_TAR(NEWTOY(tar, "&(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_TAR(NEWTOY(tar, "&(strip-components)#(selinux)(restrict)(full-time)(no-recursion)(numeric-owner)(no-same-permissions)(overwrite)(exclude)*(mode):(mtime):(group):(owner):(to-command):o(no-same-owner)p(same-permissions)k(keep-old)c(create)|h(dereference)x(extract)|t(list)|v(verbose)I(use-compress-program):J(xz)j(bzip2)z(gzip)S(sparse)O(to-stdout)P(absolute-names)m(touch)X(exclude-from)*T(files-from)*C(directory):f(file):a[!txc][!jzJa]", TOYFLAG_USR|TOYFLAG_BIN))
 
 config TAR
   bool "tar"
@@ -34,13 +34,13 @@
     J  xz compression        j  bzip2 compression     z  gzip compression
     O  Extract to stdout     X  exclude names in FILE T  include names in FILE
 
-    --exclude        FILENAME to exclude    --full-time   Show seconds with -tv
-    --mode MODE      Adjust modes           --mtime TIME  Override timestamps
-    --owner NAME     Set file owner to NAME --group NAME  Set file group to NAME
-    --sparse         Record sparse files    --selinux     Record/restore labels
-    --restrict       All archive contents must extract under one subdirectory
-    --numeric-owner  Save/use/display uid and gid, not user/group name
-    --no-recursion   Don't store directory contents
+    --exclude        FILENAME to exclude  --full-time         Show seconds with -tv
+    --mode MODE      Adjust permissions   --owner NAME[:UID]  Set file ownership
+    --mtime TIME     Override timestamps  --group NAME[:GID]  Set file group
+    --sparse         Record sparse files  --selinux           Save/restore labels
+    --restrict       All under one dir    --no-recursion      Skip dir contents
+    --numeric-owner  Use numeric uid/gid, not user/group names
+    --strip-components NUM  Ignore first NUM directory components when extracting
     -I PROG          Filter through PROG to compress or PROG -d to decompress
 */
 
@@ -52,6 +52,7 @@
   struct arg_list *T, *X;
   char *I, *to_command, *owner, *group, *mtime, *mode;
   struct arg_list *exclude;
+  long strip_components;
 
   struct double_list *incl, *excl, *seen;
   struct string_list *dirs;
@@ -225,8 +226,12 @@
     if (!(lnk = strstr(lnk, ".."))) break;
     if (lnk == hname || lnk[-1] == '/') {
       if (!lnk[2]) goto done;
-      if (lnk[2]=='/') lnk = hname = lnk+3;
-    } else lnk+= 2;
+      if (lnk[2]=='/') {
+        lnk = hname = lnk+3;
+        continue;
+      }
+    }
+    lnk += 2;
   }
   if (!*hname) goto done;
 
@@ -332,10 +337,10 @@
   if (!FLAG(numeric_owner)) {
     if ((TT.owner || (pw = bufgetpwuid(st->st_uid))) &&
         ascii_fits(st->st_uid, sizeof(hdr.uid)))
-      strncpy(hdr.uname, TT.owner ? TT.owner : pw->pw_name, sizeof(hdr.uname));
+      strncpy(hdr.uname, TT.owner ? : pw->pw_name, sizeof(hdr.uname));
     if ((TT.group || (gr = bufgetgrgid(st->st_gid))) &&
         ascii_fits(st->st_gid, sizeof(hdr.gid)))
-      strncpy(hdr.gname, TT.group ? TT.group : gr->gr_name, sizeof(hdr.gname));
+      strncpy(hdr.gname, TT.group ? : gr->gr_name, sizeof(hdr.gname));
   }
 
   TT.sparselen = 0;
@@ -516,7 +521,15 @@
 static void extract_to_disk(void)
 {
   char *name = TT.hdr.name;
-  int ala = TT.hdr.mode;
+  int ala = TT.hdr.mode, strip;
+
+  for (strip = 0; strip < TT.strip_components; strip++) {
+    char *s = strchr(name, '/');
+
+    if (s && s[1]) name = s+1;
+    else if (S_ISDIR(ala)) return;
+    else break;
+  }
 
   if (dirflush(name, S_ISDIR(ala))) {
     if (S_ISREG(ala) && !TT.hdr.link_target) skippy(TT.hdr.size);
@@ -539,17 +552,16 @@
         return perror_msg("can't link '%s' -> '%s'", name, TT.hdr.link_target);
     // write contents
     } else {
-      int fd = xcreate(name,
-        WARN_ONLY|O_WRONLY|O_CREAT|(FLAG(overwrite)?O_TRUNC:O_EXCL),
-        ala & 07777);
-      if (fd != -1) sendfile_sparse(fd);
+      int fd = WARN_ONLY|O_WRONLY|O_CREAT|(FLAG(overwrite) ? O_TRUNC : O_EXCL);
+
+      if ((fd = xcreate(name, fd, ala&07777)) != -1) sendfile_sparse(fd);
       else return skippy(TT.hdr.size);
     }
   } else if (S_ISDIR(ala)) {
     if ((mkdir(name, 0700) == -1) && errno != EEXIST)
-      return perror_msg("%s: can't create", TT.hdr.name);
+      return perror_msg("%s: can't create", name);
   } else if (S_ISLNK(ala)) {
-    if (symlink(TT.hdr.link_target, TT.hdr.name))
+    if (symlink(TT.hdr.link_target, name))
       return perror_msg("can't link '%s' -> '%s'", name, TT.hdr.link_target);
   } else if (mknod(name, ala, TT.hdr.device))
     return perror_msg("can't create '%s'", name);
@@ -560,20 +572,20 @@
 
     if (TT.owner) TT.hdr.uid = TT.ouid;
     else if (!FLAG(numeric_owner) && *TT.hdr.uname) {
-      struct passwd *pw = getpwnam(TT.hdr.uname);
+      struct passwd *pw = bufgetpwnamuid(TT.hdr.uname, 0);
       if (pw && (TT.owner || !FLAG(numeric_owner))) TT.hdr.uid = pw->pw_uid;
     }
 
     if (TT.group) TT.hdr.gid = TT.ggid;
     else if (!FLAG(numeric_owner) && *TT.hdr.uname) {
-      struct group *gr = getgrnam(TT.hdr.gname);
+      struct group *gr = bufgetgrnamgid(TT.hdr.gname, 0);
       if (gr) TT.hdr.gid = gr->gr_gid;
     }
 
     if (lchown(name, u, g)) perror_msg("chown %d:%d '%s'", u, g, name);;
   }
 
-  if (!S_ISLNK(ala)) chmod(TT.hdr.name, FLAG(p) ? ala : ala&0777);
+  if (!S_ISLNK(ala)) chmod(name, FLAG(p) ? ala : ala&0777);
 
   // Apply mtime.
   if (!FLAG(m)) {
@@ -588,7 +600,7 @@
       strcpy(sl->str+sizeof(long long), name);
       sl->next = TT.dirs;
       TT.dirs = sl;
-    } else wsettime(TT.hdr.name, TT.hdr.mtime);
+    } else wsettime(name, TT.hdr.mtime);
   }
 }
 
@@ -712,18 +724,18 @@
     maj = OTOI(tar.major);
     min = OTOI(tar.minor);
     TT.hdr.device = dev_makedev(maj, min);
-    TT.hdr.uname = xstrndup(TT.owner ? TT.owner : tar.uname, sizeof(tar.uname));
-    TT.hdr.gname = xstrndup(TT.group ? TT.group : tar.gname, sizeof(tar.gname));
+    TT.hdr.uname = xstrndup(TT.owner ? : tar.uname, sizeof(tar.uname));
+    TT.hdr.gname = xstrndup(TT.group ? : tar.gname, sizeof(tar.gname));
 
     if (TT.owner) TT.hdr.uid = TT.ouid;
     else if (!FLAG(numeric_owner)) {
-      struct passwd *pw = getpwnam(TT.hdr.uname);
+      struct passwd *pw = bufgetpwnamuid(TT.hdr.uname, 0);
       if (pw && (TT.owner || !FLAG(numeric_owner))) TT.hdr.uid = pw->pw_uid;
     }
 
     if (TT.group) TT.hdr.gid = TT.ggid;
     else if (!FLAG(numeric_owner)) {
-      struct group *gr = getgrnam(TT.hdr.gname);
+      struct group *gr = bufgetgrnamgid(TT.hdr.gname, 0);
       if (gr) TT.hdr.gid = gr->gr_gid;
     }
 
@@ -857,8 +869,20 @@
 
   // Get possible early errors out of the way
   if (!geteuid()) toys.optflags |= FLAG_p;
-  if (TT.owner) TT.ouid = xgetuid(TT.owner);
-  if (TT.group) TT.ggid = xgetgid(TT.group);
+  if (TT.owner) {
+    if (!(s = strchr(TT.owner, ':'))) TT.ouid = xgetuid(TT.owner);
+    else {
+      TT.owner = xstrndup(TT.owner, s++-TT.owner);
+      TT.ouid = atolx_range(s, 0, INT_MAX);
+    }
+  }
+  if (TT.group) {
+    if (!(s = strchr(TT.group, ':'))) TT.ggid = xgetgid(TT.group);
+    else {
+      TT.group = xstrndup(TT.group, s++-TT.group);
+      TT.ggid = atolx_range(s, 0, INT_MAX);
+    }
+  }
   if (TT.mtime) xparsedate(TT.mtime, &TT.mtt, (void *)&s, 1);
 
   // Collect file list.
diff --git a/www/roadmap.html b/www/roadmap.html
index 865d951..551eb2e 100644
--- a/www/roadmap.html
+++ b/www/roadmap.html
@@ -360,7 +360,7 @@
 <a href=http://landley.net/aboriginal/about.html#hairball>modifying the AOSP build</a>
 to reduce dependencies. (It's fairly likely we'll have to add at least
 a read-only git utility so repo can download the build's source code,
-but that's actually <a href=https://www.youtube.com/watch?v=P7n6G2IL6eo>not
+but that's actually <a href=https://www.youtube.com/watch?v=I-lGyn3PHP4>not
 that hard</a>. We'll probably also need our own "make" at some point after
 1.0, which is its own moving target thanks to cmake and ninja and so on.)
 The ongoing Android <a href=http://lists.landley.net/pipermail/toybox-landley.net/2018-January/009330.html>hermetic build</a> work is already advancing