Merge "Add back libcutils dependency."
diff --git a/.config b/.config
index 1a8e396..108f4dc 100644
--- a/.config
+++ b/.config
@@ -127,7 +127,6 @@
 CONFIG_GETCONF=y
 CONFIG_GETENFORCE=y
 CONFIG_GETFATTR=y
-# CONFIG_GETPROP is not set
 # CONFIG_GETTY is not set
 CONFIG_GREP=y
 # CONFIG_GROUPADD is not set
@@ -263,7 +262,6 @@
 CONFIG_SEQ=y
 CONFIG_SETENFORCE=y
 CONFIG_SETFATTR=y
-# CONFIG_SETPROP is not set
 CONFIG_SETSID=y
 CONFIG_SHA1SUM=y
 CONFIG_SHA224SUM=y
@@ -281,9 +279,7 @@
 CONFIG_SORT_FLOAT=y
 CONFIG_SORT=y
 CONFIG_SPLIT=y
-# CONFIG_START is not set
 CONFIG_STAT=y
-# CONFIG_STOP is not set
 CONFIG_STRINGS=y
 CONFIG_STTY=y
 # CONFIG_SU is not set
diff --git a/generated/config.h b/generated/config.h
index 86757e2..c5e2cda 100644
--- a/generated/config.h
+++ b/generated/config.h
@@ -228,8 +228,6 @@
 #define USE_GETENFORCE(...) __VA_ARGS__
 #define CFG_GETFATTR 1
 #define USE_GETFATTR(...) __VA_ARGS__
-#define CFG_GETPROP 0
-#define USE_GETPROP(...)
 #define CFG_GETTY 0
 #define USE_GETTY(...)
 #define CFG_GREP 1
@@ -500,8 +498,6 @@
 #define USE_SETENFORCE(...) __VA_ARGS__
 #define CFG_SETFATTR 1
 #define USE_SETFATTR(...) __VA_ARGS__
-#define CFG_SETPROP 0
-#define USE_SETPROP(...)
 #define CFG_SETSID 1
 #define USE_SETSID(...) __VA_ARGS__
 #define CFG_SHA1SUM 1
@@ -536,12 +532,8 @@
 #define USE_SORT(...) __VA_ARGS__
 #define CFG_SPLIT 1
 #define USE_SPLIT(...) __VA_ARGS__
-#define CFG_START 0
-#define USE_START(...)
 #define CFG_STAT 1
 #define USE_STAT(...) __VA_ARGS__
-#define CFG_STOP 0
-#define USE_STOP(...)
 #define CFG_STRINGS 1
 #define USE_STRINGS(...) __VA_ARGS__
 #define CFG_STTY 1
diff --git a/generated/flags.h b/generated/flags.h
index c7efb83..ee070ae 100644
--- a/generated/flags.h
+++ b/generated/flags.h
@@ -996,15 +996,6 @@
 #undef FLAG_only_values
 #endif
 
-// getprop   >2Z
-#undef OPTSTR_getprop
-#define OPTSTR_getprop ">2Z"
-#ifdef CLEANUP_getprop
-#undef CLEANUP_getprop
-#undef FOR_getprop
-#undef FLAG_Z
-#endif
-
 // getty   <2t#<0H:I:l:f:iwnmLh
 #undef OPTSTR_getty
 #define OPTSTR_getty "<2t#<0H:I:l:f:iwnmLh"
@@ -2442,14 +2433,6 @@
 #undef FLAG_h
 #endif
 
-// setprop   <2>2
-#undef OPTSTR_setprop
-#define OPTSTR_setprop "<2>2"
-#ifdef CLEANUP_setprop
-#undef CLEANUP_setprop
-#undef FOR_setprop
-#endif
-
 // setsid ^<1t ^<1t
 #undef OPTSTR_setsid
 #define OPTSTR_setsid "^<1t"
@@ -2587,14 +2570,6 @@
 #undef FLAG_a
 #endif
 
-// start    
-#undef OPTSTR_start
-#define OPTSTR_start 0
-#ifdef CLEANUP_start
-#undef CLEANUP_start
-#undef FOR_start
-#endif
-
 // stat <1c:(format)fLt <1c:(format)fLt
 #undef OPTSTR_stat
 #define OPTSTR_stat "<1c:(format)fLt"
@@ -2607,14 +2582,6 @@
 #undef FLAG_c
 #endif
 
-// stop    
-#undef OPTSTR_stop
-#define OPTSTR_stop 0
-#ifdef CLEANUP_stop
-#undef CLEANUP_stop
-#undef FOR_stop
-#endif
-
 // strings t:an#=4<1fo t:an#=4<1fo
 #undef OPTSTR_strings
 #define OPTSTR_strings "t:an#=4<1fo"
@@ -4199,13 +4166,6 @@
 #define FLAG_only_values (1<<3)
 #endif
 
-#ifdef FOR_getprop
-#ifndef TT
-#define TT this.getprop
-#endif
-#define FLAG_Z (FORCED_FLAG<<0)
-#endif
-
 #ifdef FOR_getty
 #ifndef TT
 #define TT this.getty
@@ -5409,12 +5369,6 @@
 #define FLAG_h (1<<3)
 #endif
 
-#ifdef FOR_setprop
-#ifndef TT
-#define TT this.setprop
-#endif
-#endif
-
 #ifdef FOR_setsid
 #ifndef TT
 #define TT this.setsid
@@ -5532,12 +5486,6 @@
 #define FLAG_a (1<<2)
 #endif
 
-#ifdef FOR_start
-#ifndef TT
-#define TT this.start
-#endif
-#endif
-
 #ifdef FOR_stat
 #ifndef TT
 #define TT this.stat
@@ -5548,12 +5496,6 @@
 #define FLAG_c (1<<3)
 #endif
 
-#ifdef FOR_stop
-#ifndef TT
-#define TT this.stop
-#endif
-#endif
-
 #ifdef FOR_strings
 #ifndef TT
 #define TT this.strings
diff --git a/generated/globals.h b/generated/globals.h
index ac14272..ac945a1 100644
--- a/generated/globals.h
+++ b/generated/globals.h
@@ -1,11 +1,3 @@
-// toys/android/getprop.c
-
-struct getprop_data {
-  size_t size;
-  char **nv; // name/value pairs: even=name, odd=value
-  struct selabel_handle *handle;
-};
-
 // toys/android/log.c
 
 struct log_data {
@@ -1378,7 +1370,6 @@
 };
 
 extern union global_union {
-	struct getprop_data getprop;
 	struct log_data log;
 	struct demo_number_data demo_number;
 	struct hello_data hello;
diff --git a/generated/help.h b/generated/help.h
index 028c3a2..8bc0e07 100644
--- a/generated/help.h
+++ b/generated/help.h
@@ -34,12 +34,6 @@
 
 #define HELP_toybox "usage: toybox [--long | --help | --version | [command] [arguments...]]\n\nWith no arguments, shows available commands. First argument is\nname of a command to run, followed by any arguments to that command.\n\n--long	Show path to each command\n\nTo install command symlinks, try:\n  for i in $(/bin/toybox --long); do ln -s /bin/toybox $i; done\n\nMost toybox commands also understand the following arguments:\n\n--help		Show command help (only)\n--version	Show toybox version (only)\n\nThe filename \"-\" means stdin/stdout, and \"--\" stops argument parsing.\n\nNumerical arguments accept a single letter suffix for\nkilo, mega, giga, tera, peta, and exabytes, plus an additional\n\"d\" to indicate decimal 1000's instead of 1024.\n\nDurations can be decimal fractions and accept minute (\"m\"), hour (\"h\"),\nor day (\"d\") suffixes (so 0.1m = 6s)."
 
-#define HELP_stop "usage: stop [SERVICE...]\n\nStop the given system service, or netd/surfaceflinger/zygotes."
-
-#define HELP_start "usage: start [SERVICE...]\n\nStarts the given system service, or netd/surfaceflinger/zygotes."
-
-#define HELP_setprop "usage: setprop NAME VALUE\n\nSets an Android system property."
-
 #define HELP_setenforce "usage: setenforce [enforcing|permissive|1|0]\n\nSets whether SELinux is enforcing (1) or permissive (0)."
 
 #define HELP_sendevent "usage: sendevent DEVICE TYPE CODE VALUE\n\nSends a Linux input event."
@@ -52,8 +46,6 @@
 
 #define HELP_load_policy "usage: load_policy FILE\n\nLoad the specified SELinux policy file."
 
-#define HELP_getprop "usage: getprop [NAME [DEFAULT]]\n\nGets an Android system property, or lists them all."
-
 #define HELP_getenforce "usage: getenforce\n\nShows whether SELinux is disabled, enforcing, or permissive."
 
 #define HELP_skeleton_alias "usage: skeleton_alias [-dq] [-b NUMBER]\n\nExample of a second command with different arguments in the same source\nfile as the first. This allows shared infrastructure not added to lib/."
@@ -178,7 +170,7 @@
 
 #define HELP_swapoff "usage: swapoff swapregion\n\nDisable swapping on a given swapregion."
 
-#define HELP_stat "usage: stat [-tfL] [-c FORMAT] FILE...\n\nDisplay status of files or filesystems.\n\n-c	Output specified FORMAT string instead of default\n-f	Display filesystem status instead of file status\n-L	Follow symlinks\n-t	terse (-c \"%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\")\n	      (with -f = -c \"%n %i %l %t %s %S %b %f %a %c %d\")\n\nThe valid format escape sequences for files:\n%a  Access bits (octal) |%A  Access bits (flags)|%b  Size/512\n%B  Bytes per %b (512)  |%d  Device ID (dec)    |%D  Device ID (hex)\n%f  All mode bits (hex) |%F  File type          |%g  Group ID\n%G  Group name          |%h  Hard links         |%i  Inode\n%m  Mount point         |%n  Filename           |%N  Long filename\n%o  I/O block size      |%s  Size (bytes)       |%t  Devtype major (hex)\n%T  Devtype minor (hex) |%u  User ID            |%U  User name\n%x  Access time         |%X  Access unix time   |%y  Modification time\n%Y  Mod unix time       |%z  Creation time      |%Z  Creation unix time\n\nThe valid format escape sequences for filesystems:\n%a  Available blocks    |%b  Total blocks       |%c  Total inodes\n%d  Free inodes         |%f  Free blocks        |%i  File system ID\n%l  Max filename length |%n  File name          |%s  Fragment size\n%S  Best transfer size  |%t  FS type (hex)      |%T  FS type (driver name)"
+#define HELP_stat "usage: stat [-tfL] [-c FORMAT] FILE...\n\nDisplay status of files or filesystems.\n\n-c	Output specified FORMAT string instead of default\n-f	Display filesystem status instead of file status\n-L	Follow symlinks\n-t	terse (-c \"%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\")\n	      (with -f = -c \"%n %i %l %t %s %S %b %f %a %c %d\")\n\nThe valid format escape sequences for files:\n%a  Access bits (octal) |%A  Access bits (flags)|%b  Size/512\n%B  Bytes per %b (512)  |%C  Security context   |%d  Device ID (dec)\n%D  Device ID (hex)     |%f  All mode bits (hex)|%F  File type\n%g  Group ID            |%G  Group name         |%h  Hard links\n%i  Inode               |%m  Mount point        |%n  Filename\n%N  Long filename       |%o  I/O block size     |%s  Size (bytes)\n%t  Devtype major (hex) |%T  Devtype minor (hex)|%u  User ID\n%U  User name           |%x  Access time        |%X  Access unix time\n%y  Modification time   |%Y  Mod unix time      |%z  Creation time\n%Z  Creation unix time\n\nThe valid format escape sequences for filesystems:\n%a  Available blocks    |%b  Total blocks       |%c  Total inodes\n%d  Free inodes         |%f  Free blocks        |%i  File system ID\n%l  Max filename length |%n  File name          |%s  Fragment size\n%S  Best transfer size  |%t  FS type (hex)      |%T  FS type (driver name)"
 
 #define HELP_shred "usage: shred [-fuz] [-n COUNT] [-s SIZE] FILE...\n\nSecurely delete a file by overwriting its contents with random data.\n\n-f		Force (chmod if necessary)\n-n COUNT	Random overwrite iterations (default 1)\n-o OFFSET	Start at OFFSET\n-s SIZE		Use SIZE instead of detecting file size\n-u		Unlink (actually delete file when done)\n-x		Use exact size (default without -s rounds up to next 4k)\n-z		Zero at end\n\nNote: data journaling filesystems render this command useless, you must\noverwrite all free space (fill up disk) to erase old data on those."
 
@@ -476,8 +468,6 @@
 
 #define HELP_tar "usage: tar [-cxt] [-fvohmjkOS] [-XTCf NAME] [FILES]\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--exclude   FILENAME to exclude           --full-time show seconds with -tv\n--mtime     Use TIME for file timestamps  --sparse  Record sparse files\n--owner     Set file owner to NAME        --group   Set file group to NAME\n--restrict       All archive contents must extract under one subdirctory\n--numeric-owner  Save/use/display uid and gid, not user/group name\n--no-recursion   Don't store directory contents"
 
-#define HELP_tail_seek "This version uses lseek, which is faster on large files."
-
 #define HELP_tail "usage: tail [-n|c NUMBER] [-f] [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), waiting for more data to be appended"
 
 #define HELP_strings "usage: strings [-fo] [-t oxd] [-n LEN] [FILE...]\n\nDisplay printable strings in a binary file\n\n-f	Show filename\n-n	At least LEN characters form a string (default 4)\n-o	Show offset (ala -t d)\n-t	Show offset type (o=octal, d=decimal, x=hexadecimal)"
@@ -556,7 +546,7 @@
 
 #define HELP_getconf "usage: getconf -a [PATH] | -l | NAME [PATH]\n\nGet system configuration values. Values from pathconf(3) require a path.\n\n-a	Show all (defaults to \"/\" if no path given)\n-l	List available value names (grouped by source)"
 
-#define HELP_find "usage: find [-HL] [DIR...] [<options>]\n\nSearch directories for matching files.\nDefault: search \".\" match all -print all matches.\n\n-H  Follow command line symlinks         -L  Follow all symlinks\n\nMatch filters:\n-name  PATTERN  filename with wildcards   -iname      case insensitive -name\n-path  PATTERN  path name with wildcards  -ipath      case insensitive -path\n-user  UNAME    belongs to user UNAME     -nouser     user ID not known\n-group GROUP    belongs to group GROUP    -nogroup    group ID not known\n-perm  [-/]MODE permissions (-=min /=any) -prune      ignore contents of dir\n-size  N[c]     512 byte blocks (c=bytes) -xdev       only this filesystem\n-links N        hardlink count            -atime N[u] accessed N units ago\n-ctime N[u]     created N units ago       -mtime N[u] modified N units ago\n-newer FILE     newer mtime than FILE     -mindepth # at least # dirs down\n-depth          ignore contents of dir    -maxdepth # at most # dirs down\n-inum  N        inode number N            -empty      empty files and dirs\n-type [bcdflps]   (block, char, dir, file, symlink, pipe, socket)\n-context PATTERN  security context\n\nNumbers N may be prefixed by a - (less than) or + (greater than). Units for\n-Xtime are d (days, default), h (hours), m (minutes), or s (seconds).\n\nCombine matches with:\n!, -a, -o, ( )    not, and, or, group expressions\n\nActions:\n-print   Print match with newline  -print0    Print match with null\n-exec    Run command with path     -execdir   Run command in file's dir\n-ok      Ask before exec           -okdir     Ask before execdir\n-delete         Remove matching file/dir\n-printf FORMAT  Print using format string\n\nCommands substitute \"{}\" with matched file. End with \";\" to run each file,\nor \"+\" (next argument after \"{}\") to collect and run with multiple files.\n\n-printf FORMAT characters are \\ escapes and:\n%b 512 byte blocks used\n%f  basename            %g  textual gid          %G  numeric gid\n%i  decimal inode       %l  target of symlink    %m  octal mode\n%M  ls format type/mode %p  path to file         %P  path to file minus DIR\n%s  size in bytes       %T@ mod time as unixtime\n%u  username            %U  numeric uid          %Z  security context"
+#define HELP_find "usage: find [-HL] [DIR...] [<options>]\n\nSearch directories for matching files.\nDefault: search \".\", match all, -print matches.\n\n-H  Follow command line symlinks         -L  Follow all symlinks\n\nMatch filters:\n-name  PATTERN   filename with wildcards  (-iname case insensitive)\n-path  PATTERN   path name with wildcards (-ipath case insensitive)\n-user  UNAME     belongs to user UNAME     -nouser     user ID not known\n-group GROUP     belongs to group GROUP    -nogroup    group ID not known\n-perm  [-/]MODE  permissions (-=min /=any) -prune      ignore dir contents\n-size  N[c]      512 byte blocks (c=bytes) -xdev       only this filesystem\n-links N         hardlink count            -atime N[u] accessed N units ago\n-ctime N[u]      created N units ago       -mtime N[u] modified N units ago\n-newer FILE      newer mtime than FILE     -mindepth N at least N dirs down\n-depth           ignore contents of dir    -maxdepth N at most N dirs down\n-inum N          inode number N            -empty      empty files and dirs\n-type [bcdflps]  type is (block, char, dir, file, symlink, pipe, socket)\n-true            always true               -false      always false\n-context PATTERN security context\n\nNumbers N may be prefixed by a - (less than) or + (greater than). Units for\n-Xtime are d (days, default), h (hours), m (minutes), or s (seconds).\n\nCombine matches with:\n!, -a, -o, ( )    not, and, or, group expressions\n\nActions:\n-print  Print match with newline  -print0        Print match with null\n-exec   Run command with path     -execdir       Run command in file's dir\n-ok     Ask before exec           -okdir         Ask before execdir\n-delete Remove matching file/dir  -printf FORMAT Print using format string\n\nCommands substitute \"{}\" with matched file. End with \";\" to run each file,\nor \"+\" (next argument after \"{}\") to collect and run with multiple files.\n\n-printf FORMAT characters are \\ escapes and:\n%b  512 byte blocks used\n%f  basename            %g  textual gid          %G  numeric gid\n%i  decimal inode       %l  target of symlink    %m  octal mode\n%M  ls format type/mode %p  path to file         %P  path to file minus DIR\n%s  size in bytes       %T@ mod time as unixtime\n%u  username            %U  numeric uid          %Z  security context"
 
 #define HELP_file "usage: file [-hL] [file...]\n\nExamine the given files and describe their content types.\n\n-h	Don't follow symlinks (default)\n-L	Follow symlinks"
 
diff --git a/generated/newtoys.h b/generated/newtoys.h
index 4a52530..931a6ce 100644
--- a/generated/newtoys.h
+++ b/generated/newtoys.h
@@ -88,7 +88,6 @@
 USE_GETCONF(NEWTOY(getconf, ">2al", TOYFLAG_USR|TOYFLAG_BIN))
 USE_GETENFORCE(NEWTOY(getenforce, ">0", TOYFLAG_USR|TOYFLAG_SBIN))
 USE_GETFATTR(NEWTOY(getfattr, "(only-values)dhn:", TOYFLAG_USR|TOYFLAG_BIN))
-USE_GETPROP(NEWTOY(getprop, ">2Z", TOYFLAG_USR|TOYFLAG_SBIN))
 USE_GETTY(NEWTOY(getty, "<2t#<0H:I:l:f:iwnmLh",TOYFLAG_SBIN))
 USE_GREP(NEWTOY(grep, "(line-buffered)(color):;(exclude-dir)*S(exclude)*M(include)*ZzEFHIab(byte-offset)h(no-filename)ino(only-matching)rsvwcl(files-with-matches)q(quiet)(silent)e*f*C#B#A#m#x[!wx][!EFw]", TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
 USE_GROUPADD(NEWTOY(groupadd, "<1>2g#<0S", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
@@ -217,7 +216,6 @@
 USE_SEQ(NEWTOY(seq, "<1>3?f:s:w[!fw]", TOYFLAG_USR|TOYFLAG_BIN))
 USE_SETENFORCE(NEWTOY(setenforce, "<1>1", TOYFLAG_USR|TOYFLAG_SBIN))
 USE_SETFATTR(NEWTOY(setfattr, "hn:|v:x:|[!xv]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_SETPROP(NEWTOY(setprop, "<2>2", TOYFLAG_USR|TOYFLAG_SBIN))
 USE_SETSID(NEWTOY(setsid, "^<1t", TOYFLAG_USR|TOYFLAG_BIN))
 USE_SH(NEWTOY(sh, "c:i", TOYFLAG_BIN))
 USE_SHA1SUM(NEWTOY(sha1sum, "bc(check)s(status)[!bc]", TOYFLAG_USR|TOYFLAG_BIN))
@@ -232,9 +230,7 @@
 USE_SNTP(NEWTOY(sntp, "M:m:Sp:asdDqr#<4>17=10[!as]", TOYFLAG_USR|TOYFLAG_BIN))
 USE_SORT(NEWTOY(sort, USE_SORT_FLOAT("g")"S:T:m" "o:k*t:" "xVbMcszdfirun", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_ARGFAIL(2)))
 USE_SPLIT(NEWTOY(split, ">2a#<1=2>9b#<1l#<1[!bl]", TOYFLAG_USR|TOYFLAG_BIN))
-USE_START(NEWTOY(start, "", TOYFLAG_USR|TOYFLAG_SBIN))
 USE_STAT(NEWTOY(stat, "<1c:(format)fLt", TOYFLAG_BIN))
-USE_STOP(NEWTOY(stop, "", TOYFLAG_USR|TOYFLAG_SBIN))
 USE_STRINGS(NEWTOY(strings, "t:an#=4<1fo", TOYFLAG_USR|TOYFLAG_BIN))
 USE_STTY(NEWTOY(stty, "?aF:g[!ag]", TOYFLAG_BIN))
 USE_SU(NEWTOY(su, "^lmpu:g:c:s:[!lmp]", TOYFLAG_BIN|TOYFLAG_ROOTONLY))
diff --git a/kconfig/macos_miniconfig b/kconfig/macos_miniconfig
index ecc4a32..3f782b4 100644
--- a/kconfig/macos_miniconfig
+++ b/kconfig/macos_miniconfig
@@ -105,6 +105,7 @@
 CONFIG_MD5SUM=y
 CONFIG_SHA1SUM=y
 CONFIG_SEQ=y
+CONFIG_TAIL=y
 CONFIG_TOYBOX_SUID=y
 CONFIG_TOYBOX_FLOAT=y
 CONFIG_TOYBOX_HELP=y
diff --git a/lib/lib.c b/lib/lib.c
index ffb24f6..17af3c3 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -454,6 +454,16 @@
   return i;
 }
 
+// If *a starts with b, advance *a past it and return 1, else return 0;
+int strcasestart(char **a, char *b)
+{
+  int len = strlen(b), i = !strncasecmp(*a, b, len);
+
+  if (i) *a += len;
+
+  return i;
+}
+
 // Return how long the file at fd is, if there's any way to determine it.
 off_t fdlength(int fd)
 {
@@ -843,21 +853,22 @@
 #define SIGNIFY(x) {SIG##x, #x}
 
 static struct signame signames[] = {
+  // POSIX
   SIGNIFY(ABRT), SIGNIFY(ALRM), SIGNIFY(BUS),
   SIGNIFY(FPE), SIGNIFY(HUP), SIGNIFY(ILL), SIGNIFY(INT), SIGNIFY(KILL),
   SIGNIFY(PIPE), SIGNIFY(QUIT), SIGNIFY(SEGV), SIGNIFY(TERM),
   SIGNIFY(USR1), SIGNIFY(USR2), SIGNIFY(SYS), SIGNIFY(TRAP),
   SIGNIFY(VTALRM), SIGNIFY(XCPU), SIGNIFY(XFSZ),
+  // Non-POSIX terminal signals
+  SIGNIFY(STKFLT), SIGNIFY(PROF), SIGNIFY(POLL), SIGNIFY(IO), SIGNIFY(PWR),
 
-  // Start of non-terminal signals
-
+  // POSIX non-terminal signals
   SIGNIFY(CHLD), SIGNIFY(CONT), SIGNIFY(STOP), SIGNIFY(TSTP),
-  SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG)
+  SIGNIFY(TTIN), SIGNIFY(TTOU), SIGNIFY(URG),
+  // Non-POSIX non-terminal signals
+  SIGNIFY(WINCH),
 };
 
-// not in posix: SIGNIFY(STKFLT), SIGNIFY(WINCH), SIGNIFY(IO), SIGNIFY(PWR)
-// obsolete: SIGNIFY(PROF) SIGNIFY(POLL)
-
 // Handler that sets toys.signal, and writes to toys.signalfd if set
 void generic_signal(int sig)
 {
@@ -898,22 +909,35 @@
   }
 }
 
-// Convert name to signal number.  If name == NULL print names.
+// Convert a string like "9", "KILL", "SIGHUP", or "SIGRTMIN+2" to a number.
 int sig_to_num(char *pidstr)
 {
-  int i;
+  int i, offset;
+  char *s;
 
-  if (pidstr) {
-    char *s;
+  // Numeric?
+  i = estrtol(pidstr, &s, 10);
+  if (!errno && !*s) return i;
 
-    i = estrtol(pidstr, &s, 10);
-    if (!errno && !*s) return i;
+  // Skip leading "SIG".
+  strcasestart(&pidstr, "sig");
 
-    if (!strncasecmp(pidstr, "sig", 3)) pidstr+=3;
-  }
+  // Named signal?
   for (i=0; i<ARRAY_LEN(signames); i++)
-    if (!pidstr) xputs(signames[i].name);
-    else if (!strcasecmp(pidstr, signames[i].name)) return signames[i].num;
+    if (!strcasecmp(pidstr, signames[i].name)) return signames[i].num;
+
+  // Real-time signal?
+  if (strcasestart(&pidstr, "rtmin")) i = SIGRTMIN;
+  else if (strcasestart(&pidstr, "rtmax")) i = SIGRTMAX;
+  else return -1;
+  // No offset?
+  if (!*pidstr) return i;
+  // We allow any offset that's still a real-time signal: SIGRTMIN+20 is fine.
+  // Others are more restrictive, only accepting what they show with -l.
+  offset = estrtol(pidstr, &s, 10);
+  if (errno || *s) return -1;
+  i += offset;
+  if (i >= SIGRTMIN && i <= SIGRTMAX) return i;
 
   return -1;
 }
@@ -922,11 +946,36 @@
 {
   int i;
 
+  // A named signal?
   for (i=0; i<ARRAY_LEN(signames); i++)
     if (signames[i].num == sig) return signames[i].name;
+
+  // A real-time signal?
+  if (sig == SIGRTMIN) return "RTMIN";
+  if (sig == SIGRTMAX) return "RTMAX";
+  if (sig > SIGRTMIN && sig < SIGRTMAX) {
+    if (sig-SIGRTMIN <= SIGRTMAX-sig) sprintf(libbuf, "RTMIN+%d", sig-SIGRTMIN);
+    else sprintf(libbuf, "RTMAX-%d", SIGRTMAX-sig);
+    return libbuf;
+  }
   return NULL;
 }
 
+// Output a nicely formatted 80-column table of all the signals.
+void list_signals()
+{
+  int i = 0, count = 0;
+  char *name;
+
+  for (; i<=SIGRTMAX; i++) {
+    if ((name = num_to_sig(i))) {
+      printf("%2d) SIG%-9s", i, name);
+      if (++count % 5 == 0) putchar('\n');
+    }
+  }
+  putchar('\n');
+}
+
 // premute mode bits based on posix mode strings.
 mode_t string_to_mode(char *modestr, mode_t mode)
 {
diff --git a/lib/lib.h b/lib/lib.h
index 080c533..7f79bdb 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -229,6 +229,7 @@
 int unescape(char c);
 char *strend(char *str, char *suffix);
 int strstart(char **a, char *b);
+int strcasestart(char **a, char *b);
 off_t fdlength(int fd);
 void loopfiles_rw(char **argv, int flags, int permissions,
   void (*function)(int fd, char *name));
@@ -388,6 +389,7 @@
 void exit_signal(int signal);
 void sigatexit(void *handler);
 int sig_to_num(char *pidstr);
+void list_signals();
 char *num_to_sig(int sig);
 
 mode_t string_to_mode(char *mode_str, mode_t base);
diff --git a/lib/lsm.h b/lib/lsm.h
index 556700c..88bf347 100644
--- a/lib/lsm.h
+++ b/lib/lsm.h
@@ -24,7 +24,6 @@
 #ifndef XATTR_NAME_SMACK
 #define XATTR_NAME_SMACK 0
 #endif
-//ssize_t fgetxattr (int fd, char *name, void *value, size_t size);
 #define smack_smackfs_path(...) (-1)
 #define smack_new_label_from_self(...) (-1)
 #define smack_new_label_from_path(...) (-1)
diff --git a/lib/portability.c b/lib/portability.c
index 726e42a..088b90e 100644
--- a/lib/portability.c
+++ b/lib/portability.c
@@ -46,11 +46,47 @@
   return 1;
 }
 
-// Get a linked list of mount points, with stat information.
+// Get list of mounted filesystems, including stat and statvfs info.
+// Returns a reversed list, which is good for finding overmounts and such.
+
 #if defined(__APPLE__) || defined(__FreeBSD__)
 
-// Not implemented for macOS.
-// See <sys/mount.h>'s getmntinfo(3) for the BSD API.
+#include <sys/mount.h>
+
+struct mtab_list *xgetmountlist(char *path)
+{
+  struct mtab_list *mtlist = 0, *mt;
+  struct statfs *entries;
+  int i, count;
+
+  if (path) error_exit("xgetmountlist");
+  if ((count = getmntinfo(&entries, 0)) == 0) perror_exit("getmntinfo");
+
+  // The "test" part of the loop is done before the first time through and
+  // again after each "increment", so putting the actual load there avoids
+  // duplicating it. If the load was NULL, the loop stops.
+
+  for (i = 0; i < count; ++i) {
+    struct statfs *me = &entries[i];
+
+    mt = xzalloc(sizeof(struct mtab_list) + strlen(me->f_fstypename) +
+      strlen(me->f_mntonname) + strlen(me->f_mntfromname) + strlen("") + 4);
+    dlist_add_nomalloc((void *)&mtlist, (void *)mt);
+
+    // Collect details about mounted filesystem.
+    // Don't report errors, just leave data zeroed.
+    stat(me->f_mntonname, &(mt->stat));
+    statvfs(me->f_mntonname, &(mt->statvfs));
+
+    // Remember information from struct statfs.
+    mt->dir = stpcpy(mt->type, me->f_fstypename)+1;
+    mt->device = stpcpy(mt->dir, me->f_mntonname)+1;
+    mt->opts = stpcpy(mt->device, me->f_mntfromname)+1;
+    strcpy(mt->opts, ""); /* TODO: reverse from f_flags? */
+  }
+
+  return mtlist;
+}
 
 #else
 
@@ -110,9 +146,6 @@
   return !skip;
 }
 
-// Get list of mounted filesystems, including stat and statvfs info.
-// Returns a reversed list, which is good for finding overmounts and such.
-
 struct mtab_list *xgetmountlist(char *path)
 {
   struct mtab_list *mtlist = 0, *mt;
@@ -193,7 +226,7 @@
     if (kevent(not->kq, NULL, 0, &event, 1, NULL) != -1) {
       // We get the fd for free, but still have to search for the path.
       for (i = 0; i<not->count; i++) if (not->fds[i]==event.ident) {
-        *path = paths[i];
+        *path = not->paths[i];
 
         return event.ident;
       }
@@ -247,3 +280,120 @@
 }
 
 #endif
+
+#ifdef __APPLE__
+
+ssize_t xattr_get(const char *path, const char *name, void *value, size_t size)
+{
+  return getxattr(path, name, value, size, 0, 0);
+}
+
+ssize_t xattr_lget(const char *path, const char *name, void *value, size_t size)
+{
+  return getxattr(path, name, value, size, 0, XATTR_NOFOLLOW);
+}
+
+ssize_t xattr_fget(int fd, const char *name, void *value, size_t size)
+{
+  return fgetxattr(fd, name, value, size, 0, 0);
+}
+
+ssize_t xattr_list(const char *path, char *list, size_t size)
+{
+  return listxattr(path, list, size, 0);
+}
+
+ssize_t xattr_llist(const char *path, char *list, size_t size)
+{
+  return listxattr(path, list, size, XATTR_NOFOLLOW);
+}
+
+ssize_t xattr_flist(int fd, char *list, size_t size)
+{
+  return flistxattr(fd, list, size, 0);
+}
+
+ssize_t xattr_set(const char* path, const char* name,
+                  const void* value, size_t size, int flags)
+{
+  return setxattr(path, name, value, size, 0, flags);
+}
+
+ssize_t xattr_lset(const char* path, const char* name,
+                   const void* value, size_t size, int flags)
+{
+  return setxattr(path, name, value, size, 0, flags | XATTR_NOFOLLOW);
+}
+
+ssize_t xattr_fset(int fd, const char* name,
+                   const void* value, size_t size, int flags)
+{
+  return fsetxattr(fd, name, value, size, 0, flags);
+}
+
+#else
+
+ssize_t xattr_get(const char *path, const char *name, void *value, size_t size)
+{
+  return getxattr(path, name, value, size);
+}
+
+ssize_t xattr_lget(const char *path, const char *name, void *value, size_t size)
+{
+  return lgetxattr(path, name, value, size);
+}
+
+ssize_t xattr_fget(int fd, const char *name, void *value, size_t size)
+{
+  return fgetxattr(fd, name, value, size);
+}
+
+ssize_t xattr_list(const char *path, char *list, size_t size)
+{
+  return listxattr(path, list, size);
+}
+
+ssize_t xattr_llist(const char *path, char *list, size_t size)
+{
+  return llistxattr(path, list, size);
+}
+
+ssize_t xattr_flist(int fd, char *list, size_t size)
+{
+  return flistxattr(fd, list, size);
+}
+
+ssize_t xattr_set(const char* path, const char* name,
+                  const void* value, size_t size, int flags)
+{
+  return setxattr(path, name, value, size, flags);
+}
+
+ssize_t xattr_lset(const char* path, const char* name,
+                   const void* value, size_t size, int flags)
+{
+  return lsetxattr(path, name, value, size, flags);
+}
+
+ssize_t xattr_fset(int fd, const char* name,
+                   const void* value, size_t size, int flags)
+{
+  return fsetxattr(fd, name, value, size, flags);
+}
+
+
+#endif
+
+#ifdef __APPLE__
+// In the absence of a mknodat system call, fchdir to dirfd and back
+// around a regular mknod call...
+int mknodat(int dirfd, const char *path, mode_t mode, dev_t dev)
+{
+  int old_dirfd = open(".", O_RDONLY), result;
+
+  if (old_dirfd == -1 || fchdir(dirfd) == -1) return -1;
+  result = mknod(path, mode, dev);
+  if (fchdir(old_dirfd) == -1) perror_exit("mknodat couldn't return");
+  return result;
+}
+#endif
diff --git a/lib/portability.h b/lib/portability.h
index f5f8352..c955edd 100644
--- a/lib/portability.h
+++ b/lib/portability.h
@@ -186,8 +186,24 @@
 #endif
 #endif
 
-#ifndef __FreeBSD__
+#if defined(__APPLE__) || defined(__linux__)
+// Linux and macOS has both have getxattr and friends in <sys/xattr.h>, but
+// they aren't compatible.
 #include <sys/xattr.h>
+ssize_t xattr_get(const char *, const char *, void *, size_t);
+ssize_t xattr_lget(const char *, const char *, void *, size_t);
+ssize_t xattr_fget(int fd, const char *, void *, size_t);
+ssize_t xattr_list(const char *, char *, size_t);
+ssize_t xattr_llist(const char *, char *, size_t);
+ssize_t xattr_flist(int, char *, size_t);
+ssize_t xattr_set(const char*, const char*, const void*, size_t, int);
+ssize_t xattr_lset(const char*, const char*, const void*, size_t, int);
+ssize_t xattr_fset(int, const char*, const void*, size_t, int);
+#endif
+
+// macOS doesn't have mknodat, but we can fake it.
+#ifdef __APPLE__
+int mknodat(int, const char*, mode_t, dev_t);
 #endif
 
 // Android is missing some headers and functions
@@ -251,7 +267,6 @@
 // use toybox before they're ready to switch to host bionic.
 #ifdef __BIONIC__
 #include <android/log.h>
-#include <sys/system_properties.h>
 #else
 typedef enum android_LogPriority {
   ANDROID_LOG_UNKNOWN = 0,
@@ -268,11 +283,6 @@
 {
   return -1;
 }
-#define PROP_VALUE_MAX 92
-static inline int __system_property_set(const char *key, const char *value)
-{
-  return -1;
-}
 #endif
 
 // libprocessgroup is an Android platform library not included in the NDK.
@@ -318,3 +328,7 @@
 struct xnotify *xnotify_init(int max);
 int xnotify_add(struct xnotify *not, int fd, char *path);
 int xnotify_wait(struct xnotify *not, char **path);
+
+#ifdef __APPLE__
+#define f_frsize f_iosize
+#endif
diff --git a/scripts/make.sh b/scripts/make.sh
index bdcfade..6649999 100755
--- a/scripts/make.sh
+++ b/scripts/make.sh
@@ -12,7 +12,8 @@
 UNSTRIPPED="generated/unstripped/$(basename "$OUTNAME")"
 
 # Try to keep one more cc invocation going than we have processors
-[ -z "$CPUS" ] && CPUS=$(($(nproc 2>/dev/null)+1))
+[ -z "$CPUS" ] && \
+  CPUS=$(($(nproc 2>/dev/null || sysctl -n hw.ncpu 2>/dev/null)+1))
 
 # Respond to V= by echoing command lines as well as running them
 DOTPROG=
@@ -296,7 +297,7 @@
   # $LIBFILES doesn't need to be rebuilt if older than .config, $TOYFILES does
   # ($TOYFILES contents can depend on CONFIG symbols, lib/*.c never should.)
 
-  [ "$OUT" -nt "$i" ] && [ -z "$CLICK" -o "$OUT" -ot "$KCONFIG_CONFIG" ] &&
+  [ "$OUT" -nt "$i" ] && [ -z "$CLICK" -o "$OUT" -nt "$KCONFIG_CONFIG" ] &&
     continue
 
   do_loudly $BUILD -c $i -o $OUT &
diff --git a/tests/cp.test b/tests/cp.test
index a720d1f..c7d445c 100755
--- a/tests/cp.test
+++ b/tests/cp.test
@@ -89,6 +89,15 @@
 	"cp -r one/* dir2 && diff -r one dir2 && echo yes" "yes\n" "" ""
 rm -rf one dir dir2
 
+mkdir one; touch one/two; cp one/two one/three
+cp -r one/ one_ # Succeeds twice in a row
+testing "-r dir/." "cp -r one/. one_ && echo yes" "yes\n" "" ""
+rm -rf one one_
+mkdir one; touch one/two; ln -s two one/three
+cp -r one/ one_ # First time ok, but second will fail with "File exists"
+testing "-r dir/. symlink child" "cp -r one/. one_ && echo yes" "yes\n" "" ""
+rm -rf one one_
+
 touch walrus
 chmod 644 walrus
 ln -s walrus woot
@@ -99,7 +108,6 @@
 # cp -r ../source destdir
 # cp -r one/two/three missing
 # cp -r one/two/three two
-# mkdir one; touch one/two; ln -s two one/three
 # cp file1 file2 dir
 # cp file1 missing file2 -> dir
 
diff --git a/tests/find.test b/tests/find.test
index 26ad162..ab84fb0 100755
--- a/tests/find.test
+++ b/tests/find.test
@@ -105,4 +105,7 @@
 testing "-printf .N" "find dir -name file -printf %.2f" "fi" "" ""
 
 
+testing "-false" "find dir -false" "" "" ""
+testing "-true" "find dir/file -true" "dir/file\n" "" ""
+
 rm -rf dir
diff --git a/tests/kill.test b/tests/kill.test
new file mode 100644
index 0000000..a91dd55
--- /dev/null
+++ b/tests/kill.test
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+[ -f testing.sh ] && . testing.sh
+
+#testing "name" "command" "result" "infile" "stdin"
+
+testing "-l HUP" "kill -l HUP" "1\n" "" ""
+testing "-l 1" "kill -l 1" "HUP\n" "" ""
diff --git a/tests/tail.test b/tests/tail.test
index b148aeb..036f433 100755
--- a/tests/tail.test
+++ b/tests/tail.test
@@ -26,7 +26,6 @@
 testing "stdin no trailing newline" "tail -n 1 - " "c" "" "a\nb\nc"
 testing "file no trailing newline" "tail -n 1 input" "c" "a\nb\nc" ""
 
-optional TAIL_SEEK
 testing "noseek -n in bounds" "tail -n 3" "nine\nten\neleven\n" \
 	"" "$BIGTEST"
 testing "noseek -n out of bounds" "tail -n 999" "$BIGTEST" "" "$BIGTEST"
diff --git a/toys/android/getprop.c b/toys/android/getprop.c
deleted file mode 100644
index 51ef7f6..0000000
--- a/toys/android/getprop.c
+++ /dev/null
@@ -1,119 +0,0 @@
-/* getprop.c - Get an Android system property
- *
- * Copyright 2015 The Android Open Source Project
-
-USE_GETPROP(NEWTOY(getprop, ">2Z", TOYFLAG_USR|TOYFLAG_SBIN))
-
-config GETPROP
-  bool "getprop"
-  default y
-  depends on TOYBOX_ON_ANDROID && TOYBOX_SELINUX
-  help
-    usage: getprop [NAME [DEFAULT]]
-
-    Gets an Android system property, or lists them all.
-*/
-
-#define FOR_getprop
-#include "toys.h"
-
-#include <sys/system_properties.h>
-
-#include <selinux/android.h>
-#include <selinux/label.h>
-#include <selinux/selinux.h>
-
-GLOBALS(
-  size_t size;
-  char **nv; // name/value pairs: even=name, odd=value
-  struct selabel_handle *handle;
-)
-
-static char *get_property_context(const char *property)
-{
-  char *context = NULL;
-
-  if (selabel_lookup(TT.handle, &context, property, 1)) {
-    perror_exit("unable to lookup label for \"%s\"", property);
-  }
-  return context;
-}
-
-static void read_callback(void *unused, const char *name, const char *value,
-                          unsigned serial)
-{
-  if (!(TT.size&31)) TT.nv = xrealloc(TT.nv, (TT.size+32)*2*sizeof(char *));
-
-  TT.nv[2*TT.size] = xstrdup((char *)name);
-  if (toys.optflags & FLAG_Z) {
-    TT.nv[1+2*TT.size++] = get_property_context(name);
-  } else {
-    TT.nv[1+2*TT.size++] = xstrdup((char *)value);
-  }
-}
-
-static void add_property(const prop_info *pi, void *unused)
-{
-  __system_property_read_callback(pi, read_callback, NULL);
-}
-
-static void print_callback(void *unused, const char *unused_name, const char *value,
-                           unsigned unused_serial)
-{
-  puts(value);
-}
-
-// Needed to supress extraneous "Loaded property_contexts from" message
-static int selinux_log_callback_local(int type, const char *fmt, ...)
-{
-  va_list ap;
-
-  if (type == SELINUX_INFO) return 0;
-  va_start(ap, fmt);
-  verror_msg((char *)fmt, 0, ap);
-  va_end(ap);
-  return 0;
-}
-
-void getprop_main(void)
-{
-  if (toys.optflags & FLAG_Z) {
-    union selinux_callback cb;
-
-    cb.func_log = selinux_log_callback_local;
-    selinux_set_callback(SELINUX_CB_LOG, cb);
-    TT.handle = selinux_android_prop_context_handle();
-    if (!TT.handle) error_exit("unable to get selinux property context handle");
-  }
-
-  if (*toys.optargs) {
-    if (toys.optflags & FLAG_Z) {
-      char *context = get_property_context(*toys.optargs);
-
-      puts(context);
-      if (CFG_TOYBOX_FREE) free(context);
-    } else {
-      const prop_info* pi = __system_property_find(*toys.optargs);
-      if (pi == NULL) {
-        puts(toys.optargs[1] ? toys.optargs[1] : "");
-      } else {
-        __system_property_read_callback(pi, print_callback, NULL);
-      }
-    }
-  } else {
-    size_t i;
-
-    if (__system_property_foreach(add_property, NULL))
-      error_exit("property_list");
-    qsort(TT.nv, TT.size, 2*sizeof(char *), qstrcmp);
-    for (i = 0; i<TT.size; i++) printf("[%s]: [%s]\n", TT.nv[i*2],TT.nv[1+i*2]);
-    if (CFG_TOYBOX_FREE) {
-      for (i = 0; i<TT.size; i++) {
-        free(TT.nv[i*2]);
-        free(TT.nv[1+i*2]);
-      }
-      free(TT.nv);
-    }
-  }
-  if (CFG_TOYBOX_FREE && (toys.optflags & FLAG_Z)) selabel_close(TT.handle);
-}
diff --git a/toys/android/setprop.c b/toys/android/setprop.c
deleted file mode 100644
index cda34a5..0000000
--- a/toys/android/setprop.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* setprop.c - Set an Android system property
- *
- * Copyright 2015 The Android Open Source Project
-
-USE_SETPROP(NEWTOY(setprop, "<2>2", TOYFLAG_USR|TOYFLAG_SBIN))
-
-config SETPROP
-  bool "setprop"
-  default y
-  depends on TOYBOX_ON_ANDROID
-  help
-    usage: setprop NAME VALUE
-
-    Sets an Android system property.
-*/
-
-#define FOR_setprop
-#include "toys.h"
-
-void setprop_main(void)
-{
-  char *name = toys.optargs[0], *value = toys.optargs[1];
-  char *p;
-  size_t name_len = strlen(name), value_len = strlen(value);
-
-  // property_set doesn't tell us why it failed, and actually can't
-  // recognize most failures (because it doesn't wait for init), so
-  // we duplicate all of init's checks here to help the user.
-
-  if (value_len >= PROP_VALUE_MAX && !strncmp(value, "ro.", 3))
-    error_exit("value '%s' too long; try '%.*s'",
-               value, PROP_VALUE_MAX - 1, value);
-
-  if (*name == '.' || name[name_len - 1] == '.')
-    error_exit("property names must not start or end with '.'");
-  if (strstr(name, ".."))
-    error_exit("'..' is not allowed in a property name");
-  for (p = name; *p; ++p)
-    if (!isalnum(*p) && !strchr(":@_.-", *p))
-      error_exit("invalid character '%c' in name '%s'", *p, name);
-
-  if (__system_property_set(name, value))
-    error_msg("failed to set property '%s' to '%s'", name, value);
-}
diff --git a/toys/android/start.c b/toys/android/start.c
deleted file mode 100644
index 5df847a..0000000
--- a/toys/android/start.c
+++ /dev/null
@@ -1,59 +0,0 @@
-/* start.c - Start/stop system services.
- *
- * Copyright 2016 The Android Open Source Project
-
-USE_START(NEWTOY(start, "", TOYFLAG_USR|TOYFLAG_SBIN))
-USE_STOP(NEWTOY(stop, "", TOYFLAG_USR|TOYFLAG_SBIN))
-
-config START
-  bool "start"
-  depends on TOYBOX_ON_ANDROID
-  default y
-  help
-    usage: start [SERVICE...]
-
-    Starts the given system service, or netd/surfaceflinger/zygotes.
-
-config STOP
-  bool "stop"
-  depends on TOYBOX_ON_ANDROID
-  default y
-  help
-    usage: stop [SERVICE...]
-
-    Stop the given system service, or netd/surfaceflinger/zygotes.
-*/
-
-#define FOR_start
-#include "toys.h"
-
-static void start_stop(int start)
-{
-  char *property = start ? "ctl.start" : "ctl.stop";
-  // null terminated in both directions
-  char *services[] = {0,"netd","surfaceflinger","zygote","zygote_secondary",0},
-       **ss = toys.optargs;
-  int direction = 1;
-
-  if (getuid()) error_exit("must be root");
-
-  if (!*ss) {
-    // If we don't have optargs, iterate through services forward/backward.
-    ss = services+1;
-    if (!start) ss = services+ARRAY_LEN(services)-2, direction = -1;
-  }
-
-  for (; *ss; ss += direction)
-    if (__system_property_set(property, *ss))
-      error_exit("failed to set property '%s' to '%s'", property, *ss);
-}
-
-void start_main(void)
-{
-  start_stop(1);
-}
-
-void stop_main(void)
-{
-  start_stop(0);
-}
diff --git a/toys/lsb/killall.c b/toys/lsb/killall.c
index 8870618..119e01f 100644
--- a/toys/lsb/killall.c
+++ b/toys/lsb/killall.c
@@ -68,7 +68,7 @@
   TT.signum = SIGTERM;
 
   if (toys.optflags & FLAG_l) {
-    sig_to_num(NULL);
+    list_signals();
     return;
   }
 
diff --git a/toys/other/stat.c b/toys/other/stat.c
index 3f1d176..c4c1bf4 100644
--- a/toys/other/stat.c
+++ b/toys/other/stat.c
@@ -20,14 +20,15 @@
 
     The valid format escape sequences for files:
     %a  Access bits (octal) |%A  Access bits (flags)|%b  Size/512
-    %B  Bytes per %b (512)  |%d  Device ID (dec)    |%D  Device ID (hex)
-    %f  All mode bits (hex) |%F  File type          |%g  Group ID
-    %G  Group name          |%h  Hard links         |%i  Inode
-    %m  Mount point         |%n  Filename           |%N  Long filename
-    %o  I/O block size      |%s  Size (bytes)       |%t  Devtype major (hex)
-    %T  Devtype minor (hex) |%u  User ID            |%U  User name
-    %x  Access time         |%X  Access unix time   |%y  Modification time
-    %Y  Mod unix time       |%z  Creation time      |%Z  Creation unix time
+    %B  Bytes per %b (512)  |%C  Security context   |%d  Device ID (dec)
+    %D  Device ID (hex)     |%f  All mode bits (hex)|%F  File type
+    %g  Group ID            |%G  Group name         |%h  Hard links
+    %i  Inode               |%m  Mount point        |%n  Filename
+    %N  Long filename       |%o  I/O block size     |%s  Size (bytes)
+    %t  Devtype major (hex) |%T  Devtype minor (hex)|%u  User ID
+    %U  User name           |%x  Access time        |%X  Access unix time
+    %y  Modification time   |%Y  Mod unix time      |%z  Creation time
+    %Z  Creation unix time
 
     The valid format escape sequences for filesystems:
     %a  Available blocks    |%b  Total blocks       |%c  Total inodes
@@ -82,7 +83,12 @@
     strout(str);
   } else if (type == 'b') out('u', stat->st_blocks);
   else if (type == 'B') out('d', 512);
-  else if (type == 'd') out('d', stat->st_dev);
+  else if (type == 'C') {
+    char *context = NULL;
+
+    strout(lsm_get_context(TT.file, &context) != -1 ? context : "?");
+    free(context);
+  } else if (type == 'd') out('d', stat->st_dev);
   else if (type == 'D') out('x', stat->st_dev);
   else if (type == 'f') out('x', stat->st_mode);
   else if (type == 'F') {
@@ -135,8 +141,15 @@
   else if (type == 'c') out('u', statfs->f_files);
   else if (type == 'd') out('u', statfs->f_ffree);
   else if (type == 'f') out('u', statfs->f_bfree);
-  else if (type == 'l') out('d', statfs->f_namelen);
-  else if (type == 't') out('x', statfs->f_type);
+  else if (type == 'l') {
+#ifdef __APPLE__
+    // TODO: move this into portability.c somehow, or just use this everywhere?
+    // (glibc and bionic will just re-do the statfs and return f_namelen.)
+    out('d', pathconf(TT.file, _PC_NAME_MAX));
+#else
+    out('d', statfs->f_namelen);
+#endif
+  } else if (type == 't') out('x', statfs->f_type);
   else if (type == 'T') {
     char *s = "unknown";
     struct {unsigned num; char *name;} nn[] = {
@@ -155,9 +168,10 @@
       if (nn[i].num == statfs->f_type) s = nn[i].name;
     strout(s);
   } else if (type == 'i') {
+    int *val = (int *) &statfs->f_fsid;
     char buf[32];
 
-    sprintf(buf, "%08x%08x", statfs->f_fsid.__val[0], statfs->f_fsid.__val[1]);
+    sprintf(buf, "%08x%08x", val[0], val[1]);
     strout(buf);
   } else if (type == 's') out('d', statfs->f_frsize);
   else if (type == 'S') out('d', statfs->f_bsize);
diff --git a/toys/posix/cp.c b/toys/posix/cp.c
index 751a718..e37b360 100644
--- a/toys/posix/cp.c
+++ b/toys/posix/cp.c
@@ -278,20 +278,20 @@
 
         // We only copy xattrs for files because there's no flistxattrat()
         if (TT.pflags&(_CP_xattr|_CP_context)) {
-          ssize_t listlen = flistxattr(fdin, 0, 0), len;
+          ssize_t listlen = xattr_flist(fdin, 0, 0), len;
           char *name, *value, *list;
 
           if (listlen>0) {
             list = xmalloc(listlen);
-            flistxattr(fdin, list, listlen);
+            xattr_flist(fdin, list, listlen);
             list[listlen-1] = 0; // I do not trust this API.
             for (name = list; name-list < listlen; name += strlen(name)+1) {
               if (!(TT.pflags&_CP_xattr) && strncmp(name, "security.", 9))
                 continue;
-              if ((len = fgetxattr(fdin, name, 0, 0))>0) {
+              if ((len = xattr_fget(fdin, name, 0, 0))>0) {
                 value = xmalloc(len);
-                if (len == fgetxattr(fdin, name, value, len))
-                  if (fsetxattr(fdout, name, value, len, 0))
+                if (len == xattr_fget(fdin, name, value, len))
+                  if (xattr_fset(fdout, name, value, len, 0))
                     perror_msg("%s setxattr(%s=%s)", catch, name, value);
                 free(value);
               }
diff --git a/toys/posix/find.c b/toys/posix/find.c
index 3f24c0d..5fc9b0c 100644
--- a/toys/posix/find.c
+++ b/toys/posix/find.c
@@ -17,24 +17,25 @@
     usage: find [-HL] [DIR...] [<options>]
 
     Search directories for matching files.
-    Default: search "." match all -print all matches.
+    Default: search ".", match all, -print matches.
 
     -H  Follow command line symlinks         -L  Follow all symlinks
 
     Match filters:
-    -name  PATTERN  filename with wildcards   -iname      case insensitive -name
-    -path  PATTERN  path name with wildcards  -ipath      case insensitive -path
-    -user  UNAME    belongs to user UNAME     -nouser     user ID not known
-    -group GROUP    belongs to group GROUP    -nogroup    group ID not known
-    -perm  [-/]MODE permissions (-=min /=any) -prune      ignore contents of dir
-    -size  N[c]     512 byte blocks (c=bytes) -xdev       only this filesystem
-    -links N        hardlink count            -atime N[u] accessed N units ago
-    -ctime N[u]     created N units ago       -mtime N[u] modified N units ago
-    -newer FILE     newer mtime than FILE     -mindepth # at least # dirs down
-    -depth          ignore contents of dir    -maxdepth # at most # dirs down
-    -inum  N        inode number N            -empty      empty files and dirs
-    -type [bcdflps]   (block, char, dir, file, symlink, pipe, socket)
-    -context PATTERN  security context
+    -name  PATTERN   filename with wildcards  (-iname case insensitive)
+    -path  PATTERN   path name with wildcards (-ipath case insensitive)
+    -user  UNAME     belongs to user UNAME     -nouser     user ID not known
+    -group GROUP     belongs to group GROUP    -nogroup    group ID not known
+    -perm  [-/]MODE  permissions (-=min /=any) -prune      ignore dir contents
+    -size  N[c]      512 byte blocks (c=bytes) -xdev       only this filesystem
+    -links N         hardlink count            -atime N[u] accessed N units ago
+    -ctime N[u]      created N units ago       -mtime N[u] modified N units ago
+    -newer FILE      newer mtime than FILE     -mindepth N at least N dirs down
+    -depth           ignore contents of dir    -maxdepth N at most N dirs down
+    -inum N          inode number N            -empty      empty files and dirs
+    -type [bcdflps]  type is (block, char, dir, file, symlink, pipe, socket)
+    -true            always true               -false      always false
+    -context PATTERN security context
 
     Numbers N may be prefixed by a - (less than) or + (greater than). Units for
     -Xtime are d (days, default), h (hours), m (minutes), or s (seconds).
@@ -43,17 +44,16 @@
     !, -a, -o, ( )    not, and, or, group expressions
 
     Actions:
-    -print   Print match with newline  -print0    Print match with null
-    -exec    Run command with path     -execdir   Run command in file's dir
-    -ok      Ask before exec           -okdir     Ask before execdir
-    -delete         Remove matching file/dir
-    -printf FORMAT  Print using format string
+    -print  Print match with newline  -print0        Print match with null
+    -exec   Run command with path     -execdir       Run command in file's dir
+    -ok     Ask before exec           -okdir         Ask before execdir
+    -delete Remove matching file/dir  -printf FORMAT Print using format string
 
     Commands substitute "{}" with matched file. End with ";" to run each file,
     or "+" (next argument after "{}") to collect and run with multiple files.
 
     -printf FORMAT characters are \ escapes and:
-    %b 512 byte blocks used
+    %b  512 byte blocks used
     %f  basename            %g  textual gid          %G  numeric gid
     %i  decimal inode       %l  target of symlink    %m  octal mode
     %M  ls format type/mode %p  path to file         %P  path to file minus DIR
@@ -305,6 +305,11 @@
     } else if (!strcmp(s, "not")) {
       if (check) not = !not;
       continue;
+    } else if (!strcmp(s, "true")) {
+      if (check) test = 1;
+    } else if (!strcmp(s, "false")) {
+      if (check) test = 0;
+
     // Mostly ignore NOP argument
     } else if (!strcmp(s, "a") || !strcmp(s, "and") || !strcmp(s, "noleaf")) {
       if (not) goto error;
@@ -600,6 +605,11 @@
                 sprintf(buf, "%ld.%ld", new->st.st_mtim.tv_sec,
                              new->st.st_mtim.tv_nsec);
                 ll = (long)buf;
+              } else if (ch == 'Z') {
+                char *path = dirtree_path(new, 0);
+
+                ll = (lsm_get_context(path, &ff) != -1) ? (long)ff : (long)"?";
+                free(path);
               } else error_exit("bad -printf %%%c", ch);
 
               printf(next, ll);
diff --git a/toys/posix/kill.c b/toys/posix/kill.c
index f8e86b6..ee68980 100644
--- a/toys/posix/kill.c
+++ b/toys/posix/kill.c
@@ -67,8 +67,9 @@
       char *s = NULL;
 
       if (signum>=0) s = num_to_sig(signum&127);
-      puts(s ? s : "UNKNOWN");
-    } else sig_to_num(NULL);
+      if (isdigit(**args)) puts(s ? s : "UNKNOWN");
+      else printf("%d\n", signum);
+    } else list_signals();
     return;
   }
 
diff --git a/toys/posix/tail.c b/toys/posix/tail.c
index d49a70c..d716124 100644
--- a/toys/posix/tail.c
+++ b/toys/posix/tail.c
@@ -20,13 +20,6 @@
     -n	Output the last NUMBER lines (default 10), +X counts from start
     -c	Output the last NUMBER bytes, +NUMBER counts from start
     -f	Follow FILE(s), waiting for more data to be appended
-
-config TAIL_SEEK
-  bool "tail seek support"
-  default y
-  depends on TAIL
-  help
-    This version uses lseek, which is faster on large files.
 */
 
 #define FOR_tail
@@ -154,7 +147,7 @@
 
     // The slow codepath is always needed, and can handle all input,
     // so make lseek support optional.
-    if (CFG_TAIL_SEEK && try_lseek(fd, bytes, lines)) return;
+    if (try_lseek(fd, bytes, lines)) return;
 
     // Read data until we run out, keep a trailing buffer
     for (;;) {
diff --git a/www/news.html b/www/news.html
index f824468..a47cec2 100755
--- a/www/news.html
+++ b/www/news.html
@@ -121,8 +121,8 @@
 the old environment variable when it wasn't inherited from exec(). This
 lets long-running loops reset environment variables without memory leaks.</p>
 
-<p>New xnotify() plumbing in lib/portability.c with Linux and BSD versions
-(which should also work on MacOS X).</p>
+<p>New xnotify() plumbing in lib/portability.c with Linux and Mac versions
+(which should also work on BSD).</p>
 
 <p>New xparsedate() and xvali_date() functions allow date, tar --mtime, and
 touch to understand the same date formats,
@@ -156,7 +156,7 @@
 
 <p>A new www/doc/mount.txt file describes how mount works under the covers.</p>
 
-<p.Rob consistently misspelled "canonical" and "millisecond", mountpoint
+<p>Rob consistently misspelled "canonical" and "millisecond", mountpoint
 has a synopsis now,
 Kevin van der Kamp fixed a typo in netstat's help text, and Elliott
 Hughes fixed typos everywhere and made the tense, capitalization, and