Merge remote-tracking branch 'toybox/master' into HEAD

Change-Id: If21b4f8a327f584912c9021d9792031e6d79c065
diff --git a/Android.mk b/Android.mk
index 971d873..8f3698d 100644
--- a/Android.mk
+++ b/Android.mk
@@ -67,6 +67,7 @@
     toys/android/setenforce.c \
     toys/android/setprop.c \
     toys/android/start.c \
+    toys/lsb/dmesg.c \
     toys/lsb/hostname.c \
     toys/lsb/killall.c \
     toys/lsb/md5sum.c \
@@ -139,7 +140,6 @@
     toys/other/yes.c \
     toys/pending/dd.c \
     toys/pending/diff.c \
-    toys/pending/dmesg.c \
     toys/pending/expr.c \
     toys/pending/getfattr.c \
     toys/pending/gzip.c \
diff --git a/README b/README
index 5823309..eebe7b7 100644
--- a/README
+++ b/README
@@ -167,12 +167,3 @@
 list) and then be pulled into android's toybox repo from there. (They
 generally resync on fridays). The exception is patches to their build scripts
 (Android.mk and the checked-in generated/* files) which go directly to AOSP.
-
---- Code of conduct
-
-We're using twitter's https://engineering.twitter.com/opensource/code-of-conduct
-except email rob@landley.net with complaints.
-
-(Yes, I try to pay more attention to marginalized programmers, which somehow
-manages to include 51% of the population. If somebody has to be three times as
-good to get half the recognition, why WOULDN'T you adjust for that?)
diff --git a/generated/flags.h b/generated/flags.h
index 6184f35..a240db1 100644
--- a/generated/flags.h
+++ b/generated/flags.h
@@ -354,9 +354,9 @@
 #undef FLAG_preserve
 #endif
 
-// cpio (no-preserve-owner)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF] (no-preserve-owner)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]
+// cpio (no-preserve-owner)(trailer)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF] (no-preserve-owner)(trailer)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]
 #undef OPTSTR_cpio
-#define OPTSTR_cpio "(no-preserve-owner)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]"
+#define OPTSTR_cpio "(no-preserve-owner)(trailer)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]"
 #ifdef CLEANUP_cpio
 #undef CLEANUP_cpio
 #undef FOR_cpio
@@ -371,6 +371,7 @@
 #undef FLAG_u
 #undef FLAG_d
 #undef FLAG_m
+#undef FLAG_trailer
 #undef FLAG_no_preserve_owner
 #endif
 
@@ -572,9 +573,9 @@
 #undef FOR_dirname
 #endif
 
-// dmesg w(follow)CSTtrs#<1n#c[!Ttr][!Cc] w(follow)CSTtrs#<1n#c[!Ttr][!Cc]
+// dmesg w(follow)CSTtrs#<1n#c[!Ttr][!Cc][!Sw] w(follow)CSTtrs#<1n#c[!Ttr][!Cc][!Sw]
 #undef OPTSTR_dmesg
-#define OPTSTR_dmesg "w(follow)CSTtrs#<1n#c[!Ttr][!Cc]"
+#define OPTSTR_dmesg "w(follow)CSTtrs#<1n#c[!Ttr][!Cc][!Sw]"
 #ifdef CLEANUP_dmesg
 #undef CLEANUP_dmesg
 #undef FOR_dmesg
@@ -904,9 +905,9 @@
 #undef FLAG_t
 #endif
 
-// grep C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw] C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]
+// grep S(exclude)*M(include)*C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw] S(exclude)*M(include)*C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]
 #undef OPTSTR_grep
-#define OPTSTR_grep "C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]"
+#define OPTSTR_grep "S(exclude)*M(include)*C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]"
 #ifdef CLEANUP_grep
 #undef CLEANUP_grep
 #undef FOR_grep
@@ -935,6 +936,10 @@
 #undef FLAG_A
 #undef FLAG_B
 #undef FLAG_C
+#undef FLAG_include
+#undef FLAG_M
+#undef FLAG_exclude
+#undef FLAG_S
 #endif
 
 // groupadd   <1>2g#<0S
@@ -3522,7 +3527,8 @@
 #define FLAG_u (1<<7)
 #define FLAG_d (1<<8)
 #define FLAG_m (1<<9)
-#define FLAG_no_preserve_owner (1<<10)
+#define FLAG_trailer (1<<10)
+#define FLAG_no_preserve_owner (1<<11)
 #endif
 
 #ifdef FOR_crond
@@ -4002,6 +4008,10 @@
 #define FLAG_A (1<<22)
 #define FLAG_B (1<<23)
 #define FLAG_C (1<<24)
+#define FLAG_include (1<<25)
+#define FLAG_M (1<<25)
+#define FLAG_exclude (1<<26)
+#define FLAG_S (1<<26)
 #endif
 
 #ifdef FOR_groupadd
diff --git a/generated/globals.h b/generated/globals.h
index d183b1f..00fcc16 100644
--- a/generated/globals.h
+++ b/generated/globals.h
@@ -39,6 +39,16 @@
   int more_globals;
 };
 
+// toys/lsb/dmesg.c
+
+struct dmesg_data {
+  long level;
+  long size;
+
+  int use_color;
+  time_t tea;
+};
+
 // toys/lsb/hostname.c
 
 struct hostname_data {
@@ -549,16 +559,6 @@
   int *offset[2];
 };
 
-// toys/pending/dmesg.c
-
-struct dmesg_data {
-  long level;
-  long size;
-
-  int use_color;
-  struct sysinfo info;
-};
-
 // toys/pending/dumpleases.c
 
 struct dumpleases_data {
@@ -1107,8 +1107,11 @@
   long a;
   long b;
   long c;
+  struct arg_list *M;
+  struct arg_list *S;
 
   char indelim, outdelim;
+  int found;
 };
 
 // toys/posix/head.c
@@ -1393,6 +1396,7 @@
 	struct log_data log;
 	struct hello_data hello;
 	struct skeleton_data skeleton;
+	struct dmesg_data dmesg;
 	struct hostname_data hostname;
 	struct killall_data killall;
 	struct md5sum_data md5sum;
@@ -1449,7 +1453,6 @@
 	struct dhcp6_data dhcp6;
 	struct dhcpd_data dhcpd;
 	struct diff_data diff;
-	struct dmesg_data dmesg;
 	struct dumpleases_data dumpleases;
 	struct expr_data expr;
 	struct fdisk_data fdisk;
diff --git a/generated/help.h b/generated/help.h
index 28582a2..49a14f9 100644
--- a/generated/help.h
+++ b/generated/help.h
@@ -108,6 +108,8 @@
 
 #define HELP_hostname "usage: hostname [-b] [-F FILENAME] [newname]\n\nGet/Set the current hostname\n\n-b	Set hostname to 'localhost' if otherwise unset\n-F	Set hostname to contents of FILENAME\n\n"
 
+#define HELP_dmesg "usage: dmesg [-Cc] [-r|-t|-T] [-n LEVEL] [-s SIZE] [-w]\n\nPrint or control the kernel ring buffer.\n\n-C	Clear ring buffer without printing\n-c	Clear ring buffer after printing\n-n	Set kernel logging LEVEL (1-9)\n-r	Raw output (with <level markers>)\n-S	Use syslog(2) rather than /dev/kmsg\n-s	Show the last SIZE many bytes\n-T	Show human-readable timestamps\n-t	Don't print timestamps\n-w	Keep waiting for more output (aka --follow)\n\n"
+
 #define HELP_tunctl "usage: tunctl [-dtT] [-u USER] NAME\n\nCreate and delete tun/tap virtual ethernet devices.\n\n-T	Use tap (ethernet frames) instead of tun (ip packets)\n-d	Delete tun/tap device\n-t	Create tun/tap device\n-u	Set owner (user who can read/write device without root access)\n\n\n"
 
 #define HELP_rfkill "Usage: rfkill COMMAND [DEVICE]\n\nEnable/disable wireless devices.\n\nCommands:\nlist [DEVICE]   List current state\nblock DEVICE    Disable device\nunblock DEVICE  Enable device\n\nDEVICE is an index number, or one of:\nall, wlan(wifi), bluetooth, uwb(ultrawideband), wimax, wwan, gps, fm.\n\n"
@@ -398,8 +400,6 @@
 
 #define HELP_dumpleases "usage: dumpleases [-r|-a] [-f LEASEFILE]\n\nDisplay DHCP leases granted by udhcpd\n-f FILE,  Lease file\n-r        Show remaining time\n-a        Show expiration time\n\n"
 
-#define HELP_dmesg "usage: dmesg [-Cc] [-r|-t|-T] [-n LEVEL] [-s SIZE] [-w]\n\nPrint or control the kernel ring buffer.\n\n-C	Clear ring buffer without printing\n-c	Clear ring buffer after printing\n-n	Set kernel logging LEVEL (1-9)\n-r	Raw output (with <level markers>)\n-S	Use syslog(2) rather than /dev/kmsg\n-s	Show the last SIZE many bytes\n-T	Show human-readable timestamps\n-t	Don't print timestamps\n-w	Keep waiting for more output (aka --follow)\n\n"
-
 #define HELP_diff "usage: diff [-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2\n\n-a  Treat all files as text\n-b  Ignore changes in the amount of whitespace\n-B  Ignore changes whose lines are all blank\n-d  Try hard to find a smaller set of changes\n-i  Ignore case differences\n-L  Use LABEL instead of the filename in the unified header\n-N  Treat absent files as empty\n-q  Output only whether files differ\n-r  Recurse\n-S  Start with FILE when comparing directories\n-T  Make tabs line up by prefixing a tab when necessary\n-s  Report when two files are the same\n-t  Expand tabs to spaces in output\n-U  Output LINES lines of context\n-w  Ignore all whitespace\n\n"
 
 #define HELP_dhcpd "usage: dhcpd [-46fS] [-i IFACE] [-P N] [CONFFILE]\n\n -f    Run in foreground\n -i Interface to use\n -S    Log to syslog too\n -P N  Use port N (default ipv4 67, ipv6 547)\n -4, -6    Run as a DHCPv4 or DHCPv6 server\n\n"
@@ -480,17 +480,13 @@
 
 #define HELP_pwd "usage: pwd [-L|-P]\n\nPrint working (current) directory.\n\n-L  Use shell's path from $PWD (when applicable)\n-P  Print cannonical absolute path\n\n"
 
-#define HELP_pgkill_common "usage: * [-fnovx] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]\n\n-f	Check full command line for PATTERN\n-G	Match real Group ID(s)\n-g	Match Process Group(s) (0 is current user)\n-n	Newest match only\n-o	Oldest match only\n-P	Match Parent Process ID(s)\n-s	Match Session ID(s) (0 for current)\n-t	Match Terminal(s)\n-U	Match real User ID(s)\n-u	Match effective User ID(s)\n-v	Negate the match\n-x	Match whole command (not substring)\n\n"
+#define HELP_pkill "usage: pkill [-fnovx] [-SIGNAL|-l SIGNAL] [PATTERN] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]\n\n-l	Send SIGNAL (default SIGTERM)\n-V	verbose\n-f	Check full command line for PATTERN\n-G	Match real Group ID(s)\n-g	Match Process Group(s) (0 is current user)\n-n	Newest match only\n-o	Oldest match only\n-P	Match Parent Process ID(s)\n-s	Match Session ID(s) (0 for current)\n-t	Match Terminal(s)\n-U	Match real User ID(s)\n-u	Match effective User ID(s)\n-v	Negate the match\n-x	Match whole command (not substring)\n\n"
 
-#define HELP_pkill "usage: pkill [-SIGNAL|-l SIGNAL] [PATTERN]\n\n-l	Send SIGNAL (default SIGTERM)\n-V	verbose\n\n"
+#define HELP_pgrep "usage: pgrep [-clfnovx] [-d DELIM] [-L SIGNAL] [PATTERN] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]\n\nSearch for process(es). PATTERN is an extended regular expression checked\nagainst command names.\n\n-c	Show only count of matches\n-d	Use DELIM instead of newline\n-L	Send SIGNAL instead of printing name\n-l	Show command name\n-f	Check full command line for PATTERN\n-G	Match real Group ID(s)\n-g	Match Process Group(s) (0 is current user)\n-n	Newest match only\n-o	Oldest match only\n-P	Match Parent Process ID(s)\n-s	Match Session ID(s) (0 for current)\n-t	Match Terminal(s)\n-U	Match real User ID(s)\n-u	Match effective User ID(s)\n-v	Negate the match\n-x	Match whole command (not substring)\n\n"
 
-#define HELP_pgrep "usage: pgrep [-cl] [-d DELIM] [-L SIGNAL] [PATTERN]\n\nSearch for process(es). PATTERN is an extended regular expression checked\nagainst command names.\n\n-c	Show only count of matches\n-d	Use DELIM instead of newline\n-L	Send SIGNAL instead of printing name\n-l	Show command name\n\n"
+#define HELP_iotop "usage: iotop [-AaKObq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]\n\nRank processes by I/O.\n\n-A	All I/O, not just disk\n-a	Accumulated I/O (not percentage)\n-K	Kilobytes\n-k	Fallback sort FIELDS (default -[D]IO,-ETIME,-PID)\n-O	Only show processes doing I/O\n-o	Show FIELDS (default PID,PR,USER,[D]READ,[D]WRITE,SWAP,[D]IO,COMM)\n-s	Sort by field number (0-X, default 6)\n-b	Batch mode (no tty)\n-d	Delay SECONDS between each cycle (default 3)\n-n	Exit after NUMBER iterations\n-p	Show these PIDs\n-u	Show these USERs\n-q	Quiet (no header lines)\n\nCursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force\nupdate, R to reverse sort, Q to exit.\n\n"
 
-#define HELP_top_common "usage: * [-bq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]\n\n-b	Batch mode (no tty)\n-d	Delay SECONDS between each cycle (default 3)\n-n	Exit after NUMBER iterations\n-p	Show these PIDs\n-u	Show these USERs\n-q	Quiet (no header lines)\n\nCursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force\nupdate, R to reverse sort, Q to exit.\n\n"
-
-#define HELP_iotop "usage: iotop [-AaKO]\n\nRank processes by I/O.\n\n-A	All I/O, not just disk\n-a	Accumulated I/O (not percentage)\n-K	Kilobytes\n-k	Fallback sort FIELDS (default -[D]IO,-ETIME,-PID)\n-O	Only show processes doing I/O\n-o	Show FIELDS (default PID,PR,USER,[D]READ,[D]WRITE,SWAP,[D]IO,COMM)\n-s	Sort by field number (0-X, default 6)\n\n"
-
-#define HELP_top "usage: top [-H] [-k FIELD,] [-o FIELD,] [-s SORT]\n\nShow process activity in real time.\n\n-H	Show threads\n-k	Fallback sort FIELDS (default -S,-%CPU,-ETIME,-PID)\n-o	Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)\n-O	Add FIELDS (replacing PR,NI,VIRT,RES,SHR,S from default)\n-s	Sort by field number (1-X, default 9)\n\n"
+#define HELP_top "usage: top [-Hbq] [-k FIELD,] [-o FIELD,] [-s SORT] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]\n\nShow process activity in real time.\n\n-H	Show threads\n-k	Fallback sort FIELDS (default -S,-%CPU,-ETIME,-PID)\n-o	Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)\n-O	Add FIELDS (replacing PR,NI,VIRT,RES,SHR,S from default)\n-s	Sort by field number (1-X, default 9)\n-b	Batch mode (no tty)\n-d	Delay SECONDS between each cycle (default 3)\n-n	Exit after NUMBER iterations\n-p	Show these PIDs\n-u	Show these USERs\n-q	Quiet (no header lines)\n\nCursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force\nupdate, R to reverse sort, Q to exit.\n\n"
 
 #define HELP_ps "usage: ps [-AadefLlnwZ] [-gG GROUP,] [-k FIELD,] [-o FIELD,] [-p PID,] [-t TTY,] [-uU USER,]\n\nList processes.\n\nWhich processes to show (selections may be comma separated lists):\n\n-A	All processes\n-a	Processes with terminals that aren't session leaders\n-d	All processes that aren't session leaders\n-e	Same as -A\n-g	Belonging to GROUPs\n-G	Belonging to real GROUPs (before sgid)\n-p	PIDs (--pid)\n-P	Parent PIDs (--ppid)\n-s	In session IDs\n-t	Attached to selected TTYs\n-T	Show threads\n-u	Owned by USERs\n-U	Owned by real USERs (before suid)\n\nOutput modifiers:\n\n-k	Sort FIELDs in +increasing or -decreasting order (--sort)\n-M	Measure field widths (expanding as necessary)\n-n	Show numeric USER and GROUP\n-w	Wide output (don't truncate fields)\n\nWhich FIELDs to show. (Default = -o PID,TTY,TIME,CMD)\n\n-f	Full listing (-o USER:12=UID,PID,PPID,C,STIME,TTY,TIME,ARGS=CMD)\n-l	Long listing (-o F,S,UID,PID,PPID,C,PRI,NI,ADDR,SZ,WCHAN,TTY,TIME,CMD)\n-o	Output FIELDs instead of defaults, each with optional :size and =title\n-O	Add FIELDS to defaults\n-Z	Include LABEL\n\nCommand line -o fields:\n\n  ARGS     CMDLINE minus initial path     CMD  Command (thread) name (stat[2])\n  CMDLINE  Command line (argv[])          COMM Command filename (/proc/$PID/exe)\n  COMMAND  Command file (/proc/$PID/exe)  NAME Process name (argv[0] of $PID)\n\nProcess attribute -o FIELDs:\n\n  ADDR  Instruction pointer               BIT   Is this process 32 or 64 bits\n  CPU   Which processor running on        ETIME   Elapsed time since PID start\n  F     Flags (1=FORKNOEXEC 4=SUPERPRIV)  GID     Group id\n  GROUP Group name                        LABEL   Security label\n  MAJFL Major page faults                 MINFL   Minor page faults\n  NI    Niceness (lower is faster)\n  PCPU  Percentage of CPU time used       PCY     Android scheduling policy\n  PGID  Process Group ID\n  PID   Process ID                        PPID    Parent Process ID\n  PRI   Priority (higher is faster)       PSR     Processor last executed on\n  RGID  Real (before sgid) group ID       RGROUP  Real (before sgid) group name\n  RSS   Resident Set Size (pages in use)  RTPRIO  Realtime priority\n  RUID  Real (before suid) user ID        RUSER   Real (before suid) user name\n  S     Process state:\n        R (running) S (sleeping) D (device I/O) T (stopped)  t (traced)\n        Z (zombie)  X (deader)   x (dead)       K (wakekill) W (waking)\n  SCHED Scheduling policy (0=other, 1=fifo, 2=rr, 3=batch, 4=iso, 5=idle)\n  STAT  Process state (S) plus:\n        < high priority          N low priority L locked memory\n        s session leader         + foreground   l multithreaded\n  STIME Start time of process in hh:mm (size :19 shows yyyy-mm-dd hh:mm:ss)\n  SZ    Memory Size (4k pages needed to completely swap out process)\n  TCNT  Thread count                      TID     Thread ID\n  TIME  CPU time consumed                 TTY     Controlling terminal\n  UID   User id                           USER    User name\n  VSZ   Virtual memory size (1k units)    %VSZ    VSZ as % of physical memory\n  WCHAN What are we waiting in kernel for\n\n"
 
@@ -536,7 +532,7 @@
 
 #define HELP_head "usage: head [-n number] [file...]\n\nCopy first lines from files to stdout. If no files listed, copy from\nstdin. Filename \"-\" is a synonym for stdin.\n\n-n	Number of lines to copy\n-q	Never print headers\n-v	Always print headers\n\n"
 
-#define HELP_grep "usage: grep [-EFivwcloqsHbhn] [-A NUM] [-m MAX] [-e REGEX]... [-f REGFILE] [FILE]...\n\nShow lines matching regular expressions. If no -e, first argument is\nregular expression to match. With no files (or \"-\" filename) read stdin.\nReturns 0 if matched, 1 if no match found.\n\n-e  Regex to match. (May be repeated.)\n-f  File containing regular expressions to match.\n\nmatch type:\n-A  Show NUM lines after     -B  Show NUM lines before match\n-C  NUM lines context (A+B)  -E  extended regex syntax\n-F  fixed (literal match)    -i  case insensitive\n-m  match MAX many lines     -r  recursive (on dir)\n-v  invert match             -w  whole word (implies -E)\n-x  whole line               -z  input NUL terminated\n\ndisplay modes: (default: matched line)\n-c  count of matching lines  -l  show matching filenames\n-o  only matching part       -q  quiet (errors only)\n-s  silent (no error msg)    -Z  output NUL terminated\n\noutput prefix (default: filename if checking more than 1 file)\n-H  force filename           -b  byte offset of match\n-h  hide filename            -n  line number of match\n\n"
+#define HELP_grep "usage: grep [-EFrivwcloqsHbhn] [-ABC NUM] [-m MAX] [-e REGEX]... [-MS PATTERN]... [-f REGFILE] [FILE]...\n\nShow lines matching regular expressions. If no -e, first argument is\nregular expression to match. With no files (or \"-\" filename) read stdin.\nReturns 0 if matched, 1 if no match found.\n\n-e  Regex to match. (May be repeated.)\n-f  File listing regular expressions to match.\n\nfile search:\n-r  Recurse into subdirectories (defaults FILE to \".\")\n-M  Match filename pattern (--include)\n-S  Skip filename pattern (--exclude)\n\nmatch type:\n-A  Show NUM lines after     -B  Show NUM lines before match\n-C  NUM lines context (A+B)  -E  extended regex syntax\n-F  fixed (literal match)    -i  case insensitive\n-m  match MAX many lines     -v  invert match\n-w  whole word (implies -E)  -x  whole line\n-z  input NUL terminated\n\ndisplay modes: (default: matched line)\n-c  count of matching lines  -l  show matching filenames\n-o  only matching part       -q  quiet (errors only)\n-s  silent (no error msg)    -Z  output NUL terminated\n\noutput prefix (default: filename if checking more than 1 file)\n-H  force filename           -b  byte offset of match\n-h  hide filename            -n  line number of match\n\n"
 
 #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\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\nCommands substitute \"{}\" with matched file. End with \";\" to run each file,\nor \"+\" (next argument after \"{}\") to collect and run with multiple files.\n\n"
 
@@ -560,7 +556,7 @@
 
 #define HELP_cut "usage: cut OPTION... [FILE]...\n\nPrint selected parts of lines from each FILE to standard output.\n\n-b LIST	select only these bytes from LIST\n-c LIST	select only these characters from LIST\n-f LIST	select only these fields\n-d DELIM	use DELIM instead of TAB for field delimiter\n-s	do not print lines not containing delimiters\n-n	don't split multibyte characters (ignored)\n\n"
 
-#define HELP_cpio "usage: cpio -{o|t|i|p DEST} [-v] [--verbose] [-F FILE] [--no-preserve-owner]\n       [ignored: -mdu -H newc]\n\ncopy files into and out of a \"newc\" format cpio archive\n\n-F FILE	use archive FILE instead of stdin/stdout\n-p DEST	copy-pass mode, copy stdin file list to directory DEST\n-i	extract from archive into file system (stdin=archive)\n-o	create archive (stdin=list of files, stdout=archive)\n-t	test files (list only, stdin=archive, stdout=list of files)\n-v	verbose (list files during create/extract)\n--no-preserve-owner (don't set ownership during extract)\n\n"
+#define HELP_cpio "usage: cpio -{o|t|i|p DEST} [-v] [--verbose] [-F FILE] [--no-preserve-owner]\n       [ignored: -mdu -H newc]\n\ncopy files into and out of a \"newc\" format cpio archive\n\n-F FILE	use archive FILE instead of stdin/stdout\n-p DEST	copy-pass mode, copy stdin file list to directory DEST\n-i	extract from archive into file system (stdin=archive)\n-o	create archive (stdin=list of files, stdout=archive)\n-t	test files (list only, stdin=archive, stdout=list of files)\n-v	verbose (list files during create/extract)\n--no-preserve-owner (don't set ownership during extract)\n--trailer Add legacy trailer (prevents concatenation).\n\n"
 
 #define HELP_install "usage: install [-dDpsv] [-o USER] [-g GROUP] [-m MODE] [SOURCE...] DEST\n\nCopy files and set attributes.\n\n-d	Act like mkdir -p\n-D	Create leading directories for DEST\n-g	Make copy belong to GROUP\n-m	Set permissions to MODE\n-o	Make copy belong to USER\n-p	Preserve timestamps\n-s	Call \"strip -p\"\n-v	Verbose\n\n"
 
diff --git a/generated/newtoys.h b/generated/newtoys.h
index d55ca13..fc2811d 100644
--- a/generated/newtoys.h
+++ b/generated/newtoys.h
@@ -35,7 +35,7 @@
 USE_COMPRESS(NEWTOY(compress, "zcd9lrg[-cd][!zgLr]", TOYFLAG_USR|TOYFLAG_BIN))
 USE_COUNT(NEWTOY(count, NULL, TOYFLAG_USR|TOYFLAG_BIN))
 USE_CP(NEWTOY(cp, "<2"USE_CP_PRESERVE("(preserve):;")"RHLPprdaslvnF(remove-destination)fi[-HLPd][-ni]", TOYFLAG_BIN))
-USE_CPIO(NEWTOY(cpio, "(no-preserve-owner)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]", TOYFLAG_BIN))
+USE_CPIO(NEWTOY(cpio, "(no-preserve-owner)(trailer)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]", TOYFLAG_BIN))
 USE_CROND(NEWTOY(crond, "fbSl#<0=8d#<0L:c:[-bf][-LS][-ld]", TOYFLAG_USR|TOYFLAG_SBIN|TOYFLAG_NEEDROOT))
 USE_CRONTAB(NEWTOY(crontab, "c:u:elr[!elr]", TOYFLAG_USR|TOYFLAG_BIN|TOYFLAG_STAYROOT))
 USE_CUT(NEWTOY(cut, "b:|c:|f:|d:sn[!cbf]", TOYFLAG_USR|TOYFLAG_BIN))
@@ -50,7 +50,7 @@
 USE_DHCPD(NEWTOY(dhcpd, ">1P#<0>65535fi:S46[!46]", TOYFLAG_SBIN|TOYFLAG_ROOTONLY))
 USE_DIFF(NEWTOY(diff, "<2>2B(ignore-blank-lines)d(minimal)b(ignore-space-change)ut(expand-tabs)w(ignore-all-space)i(ignore-case)T(initial-tab)s(report-identical-files)q(brief)a(text)L(label)*S(starting-file):N(new-file)r(recursive)U(unified)#<0=3", TOYFLAG_USR|TOYFLAG_BIN))
 USE_DIRNAME(NEWTOY(dirname, "<1", TOYFLAG_USR|TOYFLAG_BIN))
-USE_DMESG(NEWTOY(dmesg, "w(follow)CSTtrs#<1n#c[!Ttr][!Cc]", TOYFLAG_BIN))
+USE_DMESG(NEWTOY(dmesg, "w(follow)CSTtrs#<1n#c[!Ttr][!Cc][!Sw]", TOYFLAG_BIN))
 USE_DOS2UNIX(NEWTOY(dos2unix, 0, TOYFLAG_BIN))
 USE_DU(NEWTOY(du, "d#<0hmlcaHkKLsx[-HL][-kKmh]", TOYFLAG_USR|TOYFLAG_BIN))
 USE_DUMPLEASES(NEWTOY(dumpleases, ">0arf:[!ar]", TOYFLAG_USR|TOYFLAG_BIN))
@@ -82,7 +82,7 @@
 USE_GETFATTR(NEWTOY(getfattr, "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, "C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
+USE_GREP(NEWTOY(grep, "S(exclude)*M(include)*C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
 USE_GROUPADD(NEWTOY(groupadd, "<1>2g#<0S", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
 USE_GROUPDEL(NEWTOY(groupdel, "<1>2", TOYFLAG_NEEDROOT|TOYFLAG_SBIN))
 USE_GROUPS(NEWTOY(groups, NULL, TOYFLAG_USR|TOYFLAG_BIN))
diff --git a/lib/args.c b/lib/args.c
index 20084f3..00932de 100644
--- a/lib/args.c
+++ b/lib/args.c
@@ -136,7 +136,7 @@
   // Did we recognize this option?
   if (!opt) {
     if (gof->noerror) return 1;
-    error_exit("Unknown option %s", gof->arg);
+    help_exit("Unknown option %s", gof->arg);
   }
 
   // Might enabling this switch off something else?
@@ -163,7 +163,7 @@
       if (opt == bad || !(i & toys.optflags)) continue;
       if (toys.optflags & bad->dex[2]) break;
     }
-    if (bad) error_exit("No '%c' with '%c'", opt->c, bad->c);
+    if (bad) help_exit("No '%c' with '%c'", opt->c, bad->c);
   }
 
   // Does this option take an argument?
@@ -187,10 +187,10 @@
       char *s = "Missing argument to ";
       struct longopts *lo;
 
-      if (opt->c != -1) error_exit("%s-%c", s, opt->c);
+      if (opt->c != -1) help_exit("%s-%c", s, opt->c);
 
       for (lo = gof->longopts; lo->opt != opt; lo = lo->next);
-      error_exit("%s--%.*s", s, lo->len, lo->str);
+      help_exit("%s--%.*s", s, lo->len, lo->str);
     }
 
     if (type == ':') *(opt->arg) = (long)arg;
@@ -204,8 +204,8 @@
     } else if (type == '#' || type == '-') {
       long l = atolx(arg);
       if (type == '-' && !ispunct(*arg)) l*=-1;
-      if (l < opt->val[0].l) error_exit("-%c < %ld", opt->c, opt->val[0].l);
-      if (l > opt->val[1].l) error_exit("-%c > %ld", opt->c, opt->val[1].l);
+      if (l < opt->val[0].l) help_exit("-%c < %ld", opt->c, opt->val[0].l);
+      if (l > opt->val[1].l) help_exit("-%c > %ld", opt->c, opt->val[1].l);
 
       *(opt->arg) = l;
     } else if (CFG_TOYBOX_FLOAT && type == '.') {
@@ -213,9 +213,9 @@
 
       *f = strtod(arg, &arg);
       if (opt->val[0].l != LONG_MIN && *f < opt->val[0].f)
-        error_exit("-%c < %lf", opt->c, (double)opt->val[0].f);
+        help_exit("-%c < %lf", opt->c, (double)opt->val[0].f);
       if (opt->val[1].l != LONG_MAX && *f > opt->val[1].f)
-        error_exit("-%c > %lf", opt->c, (double)opt->val[1].f);
+        help_exit("-%c > %lf", opt->c, (double)opt->val[1].f);
     }
 
     if (!gof->nodash_now) gof->arg = "";
@@ -475,10 +475,10 @@
 
   // Sanity check
   if (toys.optc<gof.minargs)
-    error_exit("Need%s %d argument%s", letters[!!(gof.minargs-1)],
+    help_exit("Need%s %d argument%s", letters[!!(gof.minargs-1)],
       gof.minargs, letters[!(gof.minargs-1)]);
   if (toys.optc>gof.maxargs)
-    error_exit("Max %d argument%s", gof.maxargs, letters[!(gof.maxargs-1)]);
+    help_exit("Max %d argument%s", gof.maxargs, letters[!(gof.maxargs-1)]);
   if (gof.requires && !(gof.requires & toys.optflags)) {
     struct opts *req;
     char needs[32], *s = needs;
@@ -487,7 +487,7 @@
       if (req->flags & 1) *(s++) = req->c;
     *s = 0;
 
-    error_exit("Needs %s-%s", s[1] ? "one of " : "", needs);
+    help_exit("Needs %s-%s", s[1] ? "one of " : "", needs);
   }
 
   if (CFG_TOYBOX_FREE) {
diff --git a/lib/lib.c b/lib/lib.c
index b6277f3..ceb1bc7 100644
--- a/lib/lib.c
+++ b/lib/lib.c
@@ -66,7 +66,8 @@
 {
   va_list va;
 
-  if (CFG_TOYBOX_HELP) show_help(stderr);
+  if (CFG_TOYBOX_HELP)
+    fprintf(stderr, "See %s --help\n", toys.which->name);
 
   if (msg) {
     va_start(va, msg);
@@ -392,6 +393,8 @@
   return (idx == -1) ? 0 : to[idx];
 }
 
+// If string ends with suffix return pointer to start of suffix in string,
+// else NULL
 char *strend(char *str, char *suffix)
 {
   long a = strlen(str), b = strlen(suffix);
diff --git a/lib/portability.h b/lib/portability.h
index e62de13..e3e0ef0 100644
--- a/lib/portability.h
+++ b/lib/portability.h
@@ -240,7 +240,7 @@
 //#define strncpy(...) @@strncpyisbadmmkay@@
 //#define strncat(...) @@strncatisbadmmkay@@
 
-#if CFG_TOYBOX_ANDROID_SCHEDPOLICY
+#if CFG_TOYBOX_ANDROID_SCHEDPOLICY && defined(__BIONIC__)
 #include <cutils/sched_policy.h>
 #else
 static inline int get_sched_policy(int tid, void *policy) {return 0;}
diff --git a/scripts/config2help.c b/scripts/config2help.c
index 6ec5e84..575b7b8 100644
--- a/scripts/config2help.c
+++ b/scripts/config2help.c
@@ -1,4 +1,9 @@
-//#include "toys.h"
+/* config2.help.c - config2hep Config.in .config > help.h
+
+   function parse() reads Config.in data into *sym list, then
+   we read .config and set sym->try on each enabled symbol.
+
+*/
 
 #include <ctype.h>
 #include <stdio.h>
@@ -12,6 +17,7 @@
 #include <termios.h>
 #include <poll.h>
 #include <sys/socket.h>
+
 struct statvfs {int i;};
 #include "lib/portability.h"
 #include "lib/lib.h"
@@ -32,7 +38,7 @@
 } *sym;
 
 // remove leading spaces
-char *trim(char *s)
+char *skip_spaces(char *s)
 {
   while (isspace(*s)) s++;
 
@@ -44,11 +50,11 @@
 {
   int len = strlen(name);
 
-  line = trim(line);
+  line = skip_spaces(line);
   if (strncmp(name, line, len)) return 0;
   line += len;
   if (*line && !isspace(*line)) return 0;
-  line = trim(line);
+  line = skip_spaces(line);
 
   return line;
 }
@@ -71,7 +77,7 @@
   while (*help) {
     char *s;
 
-    s = trim((*help)->data);
+    s = skip_spaces((*help)->data);
 
     if (*s) break;
     got++;
@@ -104,7 +110,7 @@
 
   // Find start of dash block. Must be at start or after blank line.
   for (;;) {
-    s = trim((*from)->data);
+    s = skip_spaces((*from)->data);
     if (*s == '-' && s[1] != '-' && !count) break;
 
     if (!*s) count = 0;
@@ -117,7 +123,7 @@
   // If there was whitespace before this, zap it. This can't take out *help
   // because zap_blank_lines skipped blank lines, and we had to have at least
   // one non-blank line (a dash line) to get this far.
-  while (!*trim((*from)->prev->data)) {
+  while (!*skip_spaces((*from)->prev->data)) {
     *from = (*from)->prev;
     free(dlist_zap(from));
   }
@@ -128,7 +134,7 @@
   dd = *from;
   if (*help == *from) *help = 0;
   for (;;) {
-   if (*trim(dd->data) != '-') break;
+   if (*skip_spaces(dd->data) != '-') break;
    count++;
    if (*from == (dd = dd->next)) break;
   }
@@ -140,6 +146,7 @@
   return list;
 }
 
+// Read Config.in (and includes) to populate global struct symbol *sym list.
 void parse(char *filename)
 {
   FILE *fp = xfopen(filename, "r");
@@ -208,6 +215,8 @@
   return strcmp(*a, *b);
 }
 
+// Three stages: read data, collate entries, output results.
+
 int main(int argc, char *argv[])
 {
   FILE *fp;
@@ -217,6 +226,9 @@
     exit(1);
   }
 
+  // Stage 1: read data. Read Config.in to global 'struct symbol *sym' list,
+  // then read .config to set "enabled" member of each enabled symbol.
+
   // Read Config.in
   parse(argv[1]);
 
@@ -241,6 +253,8 @@
     }
   }
 
+  // Stage 2: process data.
+
   // Collate help according to usage, depends, and .config
 
   // Loop through each entry, finding duplicate enabled "usage:" names
@@ -266,7 +280,7 @@
         catch->enabled++;
         while (!isspace(*that) && *that) that++;
         if (!throw) len = that-name;
-        that = trim(that);
+        that = skip_spaces(that);
         if (!throw) {
           throw = catch;
           this = that;
@@ -305,7 +319,7 @@
           }
           while (throw->help && throw->help != tfrom)
             dlist_add(&cfrom, dlist_zap(&throw->help));
-          if (cfrom && cfrom->prev->data && *trim(cfrom->prev->data))
+          if (cfrom && cfrom->prev->data && *skip_spaces(cfrom->prev->data))
             dlist_add(&cfrom, strdup(""));
         }
         if (!anchor) {
@@ -326,7 +340,7 @@
         if (!anchor->data) dlist_zap(&anchor);
 
         // zap whitespace at end of catch help text
-        while (!*trim(anchor->prev->data)) {
+        while (!*skip_spaces(anchor->prev->data)) {
           anchor = anchor->prev;
           free(dlist_zap(&anchor));
         }
@@ -345,8 +359,8 @@
           if (from[ff] == ']' && to[tt] == ']') {
             try = xmprintf("[-%.*s%.*s] ", ff, from, tt, to);
             qsort(try+2, ff+tt, 1, (void *)charsort);
-            this = trim(this+ff+3);
-            that = trim(that+tt+3);
+            this = skip_spaces(this+ff+3);
+            that = skip_spaces(that+tt+3);
           }
         }
 
@@ -375,6 +389,8 @@
     if (!throw) break;
   }
 
+  // Stage 3: output results to stdout.
+
   // Print out help #defines
   while (sym) {
     struct double_list *dd;
diff --git a/toys/lsb/dmesg.c b/toys/lsb/dmesg.c
new file mode 100644
index 0000000..30f90e3
--- /dev/null
+++ b/toys/lsb/dmesg.c
@@ -0,0 +1,182 @@
+/* dmesg.c - display/control kernel ring buffer.
+ *
+ * Copyright 2006, 2007 Rob Landley <rob@landley.net>
+ *
+ * See http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html
+ *
+ * Don't ask me why the horrible new dmesg API is still in "testing":
+ * http://kernel.org/doc/Documentation/ABI/testing/dev-kmsg
+
+// We care that FLAG_c is 1, so keep c at the end.
+USE_DMESG(NEWTOY(dmesg, "w(follow)CSTtrs#<1n#c[!Ttr][!Cc][!Sw]", TOYFLAG_BIN))
+
+config DMESG
+  bool "dmesg"
+  default y
+  help
+    usage: dmesg [-Cc] [-r|-t|-T] [-n LEVEL] [-s SIZE] [-w]
+
+    Print or control the kernel ring buffer.
+
+    -C	Clear ring buffer without printing
+    -c	Clear ring buffer after printing
+    -n	Set kernel logging LEVEL (1-9)
+    -r	Raw output (with <level markers>)
+    -S	Use syslog(2) rather than /dev/kmsg
+    -s	Show the last SIZE many bytes
+    -T	Show human-readable timestamps
+    -t	Don't print timestamps
+    -w	Keep waiting for more output (aka --follow)
+*/
+
+#define FOR_dmesg
+#include "toys.h"
+#include <sys/klog.h>
+
+GLOBALS(
+  long level;
+  long size;
+
+  int use_color;
+  time_t tea;
+)
+
+static void color(int c)
+{
+  if (TT.use_color) printf("\033[%dm", c);
+}
+
+static void format_message(char *msg, int new)
+{
+  unsigned long long time_s, time_us;
+  int facpri, subsystem, pos;
+  char *p, *text;
+
+  // The new /dev/kmsg and the old syslog(2) formats differ slightly.
+  if (new) {
+    if (sscanf(msg, "%u,%*u,%llu,%*[^;]; %n", &facpri, &time_us, &pos) != 2)
+      return;
+
+    time_s = time_us/1000000;
+    time_us %= 1000000;
+  } else if (sscanf(msg, "<%u>[%llu.%llu] %n",
+                    &facpri, &time_s, &time_us, &pos) != 3) return;
+
+  // Drop extras after end of message text.
+  if ((p = strchr(text = msg+pos, '\n'))) *p = 0;
+
+  // Is there a subsystem? (The ": " is just a convention.)
+  p = strstr(text, ": ");
+  subsystem = p ? (p-text) : 0;
+
+  // To get "raw" output for /dev/kmsg we need to add priority to each line
+  if (toys.optflags&FLAG_r) {
+    color(0);
+    printf("<%d>", facpri);
+  }
+
+  // Format the time.
+  if (!(toys.optflags&FLAG_t)) {
+    color(32);
+    if (toys.optflags&FLAG_T) {
+      time_t t = TT.tea+time_s;
+      char *ts = ctime(&t);
+
+      printf("[%.*s] ", (int)(strlen(ts)-1), ts);
+    } else printf("[%5lld.%06lld] ", time_s, time_us);
+  }
+
+  // Errors (or worse) are shown in red, subsystems are shown in yellow.
+  if (subsystem) {
+    color(33);
+    printf("%.*s", subsystem, text);
+    text += subsystem;
+  }
+  color(31*((facpri&7)<=3));
+  xputs(text);
+}
+
+static int xklogctl(int type, char *buf, int len)
+{
+  int rc = klogctl(type, buf, len);
+
+  if (rc<0) perror_exit("klogctl");
+
+  return rc;
+}
+
+static void dmesg_cleanup(void)
+{
+  color(0);
+}
+
+void dmesg_main(void)
+{
+  TT.use_color = isatty(1);
+
+  if (TT.use_color) sigatexit(dmesg_cleanup);
+  // If we're displaying output, is it klogctl or /dev/kmsg?
+  if (toys.optflags & (FLAG_C|FLAG_n)) goto no_output;
+
+  if (toys.optflags&FLAG_T) {
+    struct sysinfo info;
+
+    sysinfo(&info);
+    TT.tea = time(0)-info.uptime;
+  }
+
+  if (!(toys.optflags&FLAG_S)) {
+    char msg[8193]; // CONSOLE_EXT_LOG_MAX+1
+    ssize_t len;
+    int fd;
+
+    // Each read returns one message. By default, we block when there are no
+    // more messages (--follow); O_NONBLOCK is needed for for usual behavior.
+    fd = open("/dev/kmsg", O_RDONLY|(O_NONBLOCK*!(toys.optflags&FLAG_w)));
+    if (fd == -1) goto klogctl_mode;
+
+    // SYSLOG_ACTION_CLEAR(5) doesn't actually remove anything from /dev/kmsg,
+    // you need to seek to the last clear point.
+    lseek(fd, 0, SEEK_DATA);
+
+    for (;;) {
+      // why does /dev/kmesg return EPIPE instead of EAGAIN if oldest message
+      // expires as we read it?
+      if (-1==(len = read(fd, msg, sizeof(msg))) && errno==EPIPE) continue;
+      // read() from kmsg always fails on a pre-3.5 kernel.
+      if (len==-1 && errno==EINVAL) goto klogctl_mode;
+      if (len<1) break;
+
+      msg[len] = 0;
+      format_message(msg, 1);
+    }
+    close(fd);
+  } else {
+    char *data, *to, *from, *end;
+    int size;
+
+klogctl_mode:
+    // Figure out how much data we need, and fetch it.
+    if (!(size = TT.size)) size = xklogctl(10, 0, 0);
+    data = from = xmalloc(size+1);
+    data[size = xklogctl(3+(toys.optflags&FLAG_c), data, size)] = 0;
+
+    // Send each line to format_message.
+    to = data + size;
+    while (from < to) {
+      if (!(end = memchr(from, '\n', to-from))) break;
+      *end = 0;
+      format_message(from, 0);
+      from = end + 1;
+    }
+
+    if (CFG_TOYBOX_FREE) free(data);
+  }
+
+no_output:
+  // Set the log level?
+  if (toys.optflags & FLAG_n) xklogctl(8, 0, TT.level);
+
+  // Clear the buffer?
+  if (toys.optflags & (FLAG_C|FLAG_c)) xklogctl(5, 0, 0);
+}
diff --git a/toys/pending/dmesg.c b/toys/pending/dmesg.c
deleted file mode 100644
index 198f64a..0000000
--- a/toys/pending/dmesg.c
+++ /dev/null
@@ -1,190 +0,0 @@
-/* dmesg.c - display/control kernel ring buffer.
- *
- * Copyright 2006, 2007 Rob Landley <rob@landley.net>
- *
- * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/dmesg.html
-
-// We care that FLAG_c is 1, so keep c at the end.
-USE_DMESG(NEWTOY(dmesg, "w(follow)CSTtrs#<1n#c[!Ttr][!Cc]", TOYFLAG_BIN))
-
-config DMESG
-  bool "dmesg"
-  default n
-  help
-    usage: dmesg [-Cc] [-r|-t|-T] [-n LEVEL] [-s SIZE] [-w]
-
-    Print or control the kernel ring buffer.
-
-    -C	Clear ring buffer without printing
-    -c	Clear ring buffer after printing
-    -n	Set kernel logging LEVEL (1-9)
-    -r	Raw output (with <level markers>)
-    -S	Use syslog(2) rather than /dev/kmsg
-    -s	Show the last SIZE many bytes
-    -T	Show human-readable timestamps
-    -t	Don't print timestamps
-    -w	Keep waiting for more output (aka --follow)
-*/
-
-#define FOR_dmesg
-#include "toys.h"
-#include <sys/klog.h>
-
-GLOBALS(
-  long level;
-  long size;
-
-  int use_color;
-  struct sysinfo info;
-)
-
-static void color(int c)
-{
-  if (TT.use_color) printf("\033[%dm", c);
-}
-
-static void format_message(char *msg, int new) {
-  unsigned long long time_s;
-  unsigned long long time_us;
-  int facpri, subsystem, pos;
-  char *p, *text;
-
-  // The new /dev/kmsg and the old syslog(2) formats differ slightly.
-  if (new) {
-    if (sscanf(msg, "%u,%*u,%llu,%*[^;];%n", &facpri, &time_us, &pos) != 2)
-      return;
-
-    time_s = time_us/1000000;
-    time_us %= 1000000;
-  } else {
-    if (sscanf(msg, "<%u>[%llu.%llu] %n",
-               &facpri, &time_s, &time_us, &pos) != 3)
-      return;
-  }
-
-  // Drop extras after end of message text.
-  text = msg + pos;
-  if ((p = strchr(text, '\n'))) *p = 0;
-
-  // Is there a subsystem? (The ": " is just a convention.)
-  p = strstr(text, ": ");
-  subsystem = p ? (p - text) : 0;
-
-  // "Raw" is a lie for /dev/kmsg. In practice, it just means we show the
-  // syslog facility/priority at the start of each line to emulate the
-  // historical syslog(2) format.
-  if (toys.optflags&FLAG_r) printf("<%d>", facpri);
-
-  // Format the time.
-  if (!(toys.optflags&FLAG_t)) {
-    color(32);
-    if (toys.optflags&FLAG_T) {
-      time_t t = (time(NULL) - TT.info.uptime) + time_s;
-      char *ts = ctime(&t);
-
-      printf("[%.*s] ", (int)(strlen(ts) - 1), ts);
-    } else {
-      printf("[%5lld.%06lld] ", time_s, time_us);
-    }
-    color(0);
-  }
-
-  // Errors (or worse) are shown in red, subsystems are shown in yellow.
-  if (subsystem) {
-    color(33);
-    printf("%.*s", subsystem, text);
-    text += subsystem;
-    color(0);
-  }
-  if (!((facpri&7) <= 3)) xputs(text);
-  else {
-    color(31);
-    printf("%s", text);
-    color(0);
-    xputc('\n');
-  }
-}
-
-static int xklogctl(int type, char *buf, int len)
-{
-  int rc = klogctl(type, buf, len);
-
-  if (rc<0) perror_exit("klogctl");
-
-  return rc;
-}
-
-// Use klogctl for reading if we're on a pre-3.5 kernel.
-static void legacy_mode()
-{
-  char *data, *to, *from;
-  int size;
-
-  // Figure out how much data we need, and fetch it.
-  if (!(size = TT.size)) size = xklogctl(10, 0, 0);
-  data = to = from = xmalloc(size+1);
-  data[size = xklogctl(3 + (toys.optflags & FLAG_c), data, size)] = 0;
-
-  // Break into messages (one per line) and send each one to format_message.
-  to = data + size;
-  while (from < to) {
-    char *msg_end = memchr(from, '\n', (to-from));
-
-    if (!msg_end) break;
-    *msg_end = '\0';
-    format_message(from, 0);
-    from = msg_end + 1;
-  }
-
-  if (CFG_TOYBOX_FREE) free(data);
-}
-
-static void print_all(void)
-{
-  if (toys.optflags&FLAG_T) sysinfo(&TT.info);
-  if (toys.optflags&FLAG_S) return legacy_mode();
-
-  // http://kernel.org/doc/Documentation/ABI/testing/dev-kmsg
-
-  // Each read returns one message. By default, we block when there are no
-  // more messages (--follow); O_NONBLOCK is needed for for usual behavior.
-  int fd = xopen("/dev/kmsg", O_RDONLY | ((toys.optflags&FLAG_w)?0:O_NONBLOCK));
-
-  // With /dev/kmsg, SYSLOG_ACTION_CLEAR (5) doesn't actually remove anything;
-  // you need to seek to the last clear point.
-  lseek(fd, 0, SEEK_DATA);
-
-  while (1) {
-    char msg[8192]; // CONSOLE_EXT_LOG_MAX.
-    ssize_t len;
-
-    // kmsg fails with EPIPE if we try to read while the buffer moves under
-    // us; the next read will succeed and return the next available entry.
-    do {
-      len = read(fd, msg, sizeof(msg));
-    } while (len == -1 && errno == EPIPE);
-    // All reads from kmsg fail if you're on a pre-3.5 kernel.
-    if (len == -1 && errno == EINVAL) {
-      close(fd);
-      return legacy_mode();
-    }
-    if (len <= 0) break;
-
-    msg[len] = 0;
-    format_message(msg, 1);
-  }
-  close(fd);
-}
-
-void dmesg_main(void)
-{
-  TT.use_color = isatty(1);
-
-  if (!(toys.optflags & (FLAG_C|FLAG_n))) print_all();
-
-  // Set the log level?
-  if (toys.optflags & FLAG_n) xklogctl(8, 0, TT.level);
-
-  // Clear the buffer?
-  if (toys.optflags & (FLAG_C|FLAG_c)) xklogctl(5, 0, 0);
-}
diff --git a/toys/posix/cpio.c b/toys/posix/cpio.c
index 5524dba..90c8107 100644
--- a/toys/posix/cpio.c
+++ b/toys/posix/cpio.c
@@ -16,7 +16,7 @@
  * rdevmajor rdevminor namesize check
  * This is the equiavlent of mode -H newc when using GNU CPIO.
 
-USE_CPIO(NEWTOY(cpio, "(no-preserve-owner)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]", TOYFLAG_BIN))
+USE_CPIO(NEWTOY(cpio, "(no-preserve-owner)(trailer)mduH:p:|i|t|F:v(verbose)o|[!pio][!pot][!pF]", TOYFLAG_BIN))
 
 config CPIO
   bool "cpio"
@@ -34,6 +34,7 @@
     -t	test files (list only, stdin=archive, stdout=list of files)
     -v	verbose (list files during create/extract)
     --no-preserve-owner (don't set ownership during extract)
+    --trailer Add legacy trailer (prevents concatenation).
 */
 
 #define FOR_cpio
@@ -113,8 +114,8 @@
     int test = toys.optflags & FLAG_t, err = 0;
 
     // Read header and name.
-    xreadall(afd, toybuf, 110);
-    if (memcmp(toybuf, "070701", 6)) error_exit("bad cpio magic");
+    if (!(size =readall(afd, toybuf, 110))) break;
+    if (size != 110 || memcmp(toybuf, "070701", 6)) error_exit("bad header");
     tofree = name = strpad(afd, x8u(toybuf+94), 110);
     if (!strcmp("TRAILER!!!", name)) {
       if (CFG_TOYBOX_FREE) free(tofree);
@@ -275,9 +276,11 @@
     }
     free(name);
 
-    memset(toybuf, 0, sizeof(toybuf));
-    xwrite(afd, toybuf,
-      sprintf(toybuf, "070701%040X%056X%08XTRAILER!!!", 1, 0x0b, 0)+4);
+    if (FLAG_trailer) {
+      memset(toybuf, 0, sizeof(toybuf));
+      xwrite(afd, toybuf,
+        sprintf(toybuf, "070701%040X%056X%08XTRAILER!!!", 1, 0x0b, 0)+4);
+    }
   }
   if (TT.archive) xclose(afd);
 
diff --git a/toys/posix/grep.c b/toys/posix/grep.c
index a95203a..d1452ce 100644
--- a/toys/posix/grep.c
+++ b/toys/posix/grep.c
@@ -4,9 +4,11 @@
  *
  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html
  *
- * TODO: -ABC
+ * TODO: --color, "Binary file %s matches"
+ *
+ * Posix doesn't even specify -r, documenting deviations from it is silly.
 
-USE_GREP(NEWTOY(grep, "C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
+USE_GREP(NEWTOY(grep, "S(exclude)*M(include)*C#B#A#ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
 USE_EGREP(OLDTOY(egrep, grep, TOYFLAG_BIN))
 USE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN))
 
@@ -14,22 +16,27 @@
   bool "grep"
   default y
   help
-    usage: grep [-EFivwcloqsHbhn] [-A NUM] [-m MAX] [-e REGEX]... [-f REGFILE] [FILE]...
+    usage: grep [-EFrivwcloqsHbhn] [-ABC NUM] [-m MAX] [-e REGEX]... [-MS PATTERN]... [-f REGFILE] [FILE]...
 
     Show lines matching regular expressions. If no -e, first argument is
     regular expression to match. With no files (or "-" filename) read stdin.
     Returns 0 if matched, 1 if no match found.
 
     -e  Regex to match. (May be repeated.)
-    -f  File containing regular expressions to match.
+    -f  File listing regular expressions to match.
+
+    file search:
+    -r  Recurse into subdirectories (defaults FILE to ".")
+    -M  Match filename pattern (--include)
+    -S  Skip filename pattern (--exclude)
 
     match type:
     -A  Show NUM lines after     -B  Show NUM lines before match
     -C  NUM lines context (A+B)  -E  extended regex syntax
     -F  fixed (literal match)    -i  case insensitive
-    -m  match MAX many lines     -r  recursive (on dir)
-    -v  invert match             -w  whole word (implies -E)
-    -x  whole line               -z  input NUL terminated
+    -m  match MAX many lines     -v  invert match
+    -w  whole word (implies -E)  -x  whole line
+    -z  input NUL terminated
 
     display modes: (default: matched line)
     -c  count of matching lines  -l  show matching filenames
@@ -62,8 +69,11 @@
   long a;
   long b;
   long c;
+  struct arg_list *M;
+  struct arg_list *S;
 
   char indelim, outdelim;
+  int found;
 )
 
 // Emit line with various potential prefixes and delimiter
@@ -81,12 +91,18 @@
 static void do_grep(int fd, char *name)
 {
   struct double_list *dlb = 0;
-  FILE *file = xfdopen(fd, "r");
+  FILE *file = fdopen(fd, "r");
   long lcount = 0, mcount = 0, offset = 0, after = 0, before = 0;
   char *bars = 0;
 
   if (!fd) name = "(standard input)";
 
+  if (!file) {
+    perror_msg("%s", name);
+
+    return;
+  }
+
   // Loop through lines of input
   for (;;) {
     char *line = 0, *start;
@@ -96,7 +112,10 @@
     int mmatch = 0;
 
     lcount++;
-    if (0 > (len = getdelim(&line, &unused, TT.indelim, file))) break;
+    errno = 0;
+    len = getdelim(&line, &unused, TT.indelim, file);
+    if (errno) perror_msg("%s", name);
+    if (len<1) break;
     if (line[len-1] == TT.indelim) line[len-1] = 0;
 
     start = line;
@@ -176,8 +195,11 @@
         bars = 0;
       }
       mmatch++;
-      toys.exitval = 0;
-      if (toys.optflags & FLAG_q) xexit();
+      TT.found = 1;
+      if (toys.optflags & FLAG_q) {
+        toys.exitval = 0;
+        xexit();
+      }
       if (toys.optflags & FLAG_l) {
         xprintf("%s%c", name, TT.outdelim);
         free(line);
@@ -315,6 +337,19 @@
 
   if (!dirtree_notdotdot(new)) return 0;
   if (S_ISDIR(new->st.st_mode)) return DIRTREE_RECURSE;
+  if (TT.S || TT.M) {
+    struct arg_list *al;
+
+    for (al = TT.S; al; al = al->next)
+      if (!fnmatch(al->arg, new->name, 0)) return 0;
+
+    if (TT.M) {
+      for (al = TT.M; al; al = al->next)
+        if (!fnmatch(al->arg, new->name, 0)) break;
+
+      if (!al) return 0;
+    }
+  }
 
   // "grep -r onefile" doesn't show filenames, but "grep -r onedir" should.
   if (new->parent && !(toys.optflags & FLAG_h)) toys.optflags |= FLAG_H;
@@ -330,6 +365,9 @@
 {
   char **ss = toys.optargs;
 
+  // Grep exits with 2 for errors
+  toys.exitval = 2;
+
   if (!TT.a) TT.a = TT.c;
   if (!TT.b) TT.b = TT.c;
 
@@ -351,7 +389,6 @@
 
   if (!(toys.optflags & FLAG_h) && toys.optc>1) toys.optflags |= FLAG_H;
 
-  toys.exitval = 1;
   if (toys.optflags & FLAG_s) {
     close(2);
     xopen_stdio("/dev/null", O_RDWR);
@@ -364,4 +401,5 @@
       else dirtree_read(*ss, do_grep_r);
     }
   } else loopfiles_rw(ss, O_RDONLY|WARN_ONLY, 0, do_grep);
+  toys.exitval = !TT.found;
 }
diff --git a/toys/posix/ps.c b/toys/posix/ps.c
index f690671..a0dc53f 100644
--- a/toys/posix/ps.c
+++ b/toys/posix/ps.c
@@ -128,10 +128,9 @@
 
 config TOP
   bool "top"
-  depends on TOP_COMMON
   default y
   help
-    usage: top [-H] [-k FIELD,] [-o FIELD,] [-s SORT]
+    usage: top [-Hbq] [-k FIELD,] [-o FIELD,] [-s SORT] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]
 
     Show process activity in real time.
 
@@ -140,14 +139,22 @@
     -o	Show FIELDS (def PID,USER,PR,NI,VIRT,RES,SHR,S,%CPU,%MEM,TIME+,CMDLINE)
     -O	Add FIELDS (replacing PR,NI,VIRT,RES,SHR,S from default)
     -s	Sort by field number (1-X, default 9)
+    -b	Batch mode (no tty)
+    -d	Delay SECONDS between each cycle (default 3)
+    -n	Exit after NUMBER iterations
+    -p	Show these PIDs
+    -u	Show these USERs
+    -q	Quiet (no header lines)
+
+    Cursor LEFT/RIGHT to change sort, UP/DOWN move list, space to force
+    update, R to reverse sort, Q to exit.
 
 # Requires CONFIG_IRQ_TIME_ACCOUNTING in the kernel for /proc/$$/io
 config IOTOP
   bool "iotop"
-  depends on TOP_COMMON
   default y
   help
-    usage: iotop [-AaKO]
+    usage: iotop [-AaKObq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]
 
     Rank processes by I/O.
 
@@ -158,13 +165,6 @@
     -O	Only show processes doing I/O
     -o	Show FIELDS (default PID,PR,USER,[D]READ,[D]WRITE,SWAP,[D]IO,COMM)
     -s	Sort by field number (0-X, default 6)
-
-config TOP_COMMON
-  bool
-  default y
-  help
-    usage: * [-bq] [-n NUMBER] [-d SECONDS] [-p PID,] [-u USER,]
-
     -b	Batch mode (no tty)
     -d	Delay SECONDS between each cycle (default 3)
     -n	Exit after NUMBER iterations
@@ -178,9 +178,8 @@
 config PGREP
   bool "pgrep"
   default y
-  depends on PGKILL_COMMON
   help
-    usage: pgrep [-cl] [-d DELIM] [-L SIGNAL] [PATTERN]
+    usage: pgrep [-clfnovx] [-d DELIM] [-L SIGNAL] [PATTERN] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]
 
     Search for process(es). PATTERN is an extended regular expression checked
     against command names.
@@ -189,23 +188,27 @@
     -d	Use DELIM instead of newline
     -L	Send SIGNAL instead of printing name
     -l	Show command name
+    -f	Check full command line for PATTERN
+    -G	Match real Group ID(s)
+    -g	Match Process Group(s) (0 is current user)
+    -n	Newest match only
+    -o	Oldest match only
+    -P	Match Parent Process ID(s)
+    -s	Match Session ID(s) (0 for current)
+    -t	Match Terminal(s)
+    -U	Match real User ID(s)
+    -u	Match effective User ID(s)
+    -v	Negate the match
+    -x	Match whole command (not substring)
 
 config PKILL
   bool "pkill"
   default y
-  depends on PGKILL_COMMON
   help
-    usage: pkill [-SIGNAL|-l SIGNAL] [PATTERN]
+    usage: pkill [-fnovx] [-SIGNAL|-l SIGNAL] [PATTERN] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]
 
     -l	Send SIGNAL (default SIGTERM)
     -V	verbose
-
-config PGKILL_COMMON
-  bool
-  default y
-  help
-    usage: * [-fnovx] [-G GID,] [-g PGRP,] [-P PPID,] [-s SID,] [-t TERM,] [-U UID,] [-u EUID,]
-
     -f	Check full command line for PATTERN
     -G	Match real Group ID(s)
     -g	Match Process Group(s) (0 is current user)
diff --git a/www/conduct.html b/www/conduct.html
new file mode 100755
index 0000000..0765895
--- /dev/null
+++ b/www/conduct.html
@@ -0,0 +1,32 @@
+<html><head><title>Toybox Code of Conduct</title>
+<!--#include file="header.html" -->
+
+<p>Toybox's code of conduct used to just link to <a href=https://engineering.twitter.com/opensource/code-of-conduct>twitter's</a>. When that page
+went down we mirrored it here (with different contact info).</p>
+
+<hr>
+
+<p>This code of conduct outlines our expectations for participants within the toybox community, as well as steps to reporting unacceptable behavior. We are committed to providing a welcoming and inspiring community for all and expect our code of conduct to be honored. Anyone who violates this code of conduct may be banned from the community.</p>
+<p>Our open source community strives to:</p>
+<ol><li><p><strong>Be friendly and patient.</strong></p></li>
+<li><p><strong>Be welcoming:</strong> We strive to be a community that welcomes and supports people of all backgrounds and identities. This includes, but is not limited to members of any race, ethnicity, culture, national origin, colour, immigration status, social and economic class, educational level, sex, sexual orientation, gender identity and expression, age, size, family status, political belief, religion, and mental and physical ability.</p></li>
+<li><p><strong>Be considerate:</strong> Your work will be used by other people, and you in turn will depend on the work of others. Any decision you take will affect users and colleagues, and you should take those consequences into account when making decisions. Remember that we're a world-wide community, so you might not be communicating in someone elses primary language.</p></li>
+<li><p><strong>Be respectful:</strong> Not all of us will agree all the time, but disagreement is no excuse for poor behavior and poor manners. We might all experience some frustration now and then, but we cannot allow that frustration to turn into a personal attack. Its important to remember that a community where people feel uncomfortable or threatened is not a productive one.</p></li>
+<li><p><strong>Be careful in the words that you choose:</strong> we are a community of professionals, and we conduct ourselves professionally. Be kind to others. Do not insult or put down other participants. Harassment and other exclusionary behavior arent acceptable. This includes, but is not limited to: Violent threats or language directed against another person, Discriminatory jokes and language, Posting sexually explicit or violent material, Posting (or threatening to post) other peoples personally identifying information (doxing), Personal insults, especially those using racist or sexist terms, Unwelcome sexual attention, Advocating for, or encouraging, any of the above behavior, Repeated harassment of others. In general, if someone asks you to stop, then stop.</p></li>
+<li><p><strong>When we disagree:</strong> try to understand why: Disagreements, both social and technical, happen all the time. It is important that we resolve disagreements and differing views constructively. Remember that were different. The strength of our community comes from its diversity, people from a wide range of backgrounds. Different people have different perspectives on issues. Being unable to understand why someone holds a viewpoint doesnt mean that theyre wrong. Dont forget that it is human to err and blaming each other doesnt get us anywhere. Instead, focus on helping to resolve issues and learning from mistakes.</p></li>
+</ol><p>This code is not exhaustive or complete. It serves to distill our common understanding of a collaborative, shared environment, and goals. We expect it to be followed in spirit as much as in the letter.</p>
+<h5>Diversity Statement</h5>
+<p>We encourage everyone to participate and are committed to building a community for all. Although we may not be able to satisfy everyone, we all agree that everyone is equal. Whenever a participant has made a mistake, we expect them to take responsibility for it. If someone has been harmed or offended, it is our responsibility to listen carefully and respectfully, and do our best to right the wrong.</p>
+<p>Although this list cannot be exhaustive, we explicitly honor diversity in age, gender, gender identity or expression, culture, ethnicity, language, national origin, political beliefs, profession, race, religion, sexual orientation, socioeconomic status, and technical ability. We will not tolerate discrimination based on any of the protected characteristics above, including participants with disabilities.</p>
+<h5>Reporting Issues</h5>
+<p>If you experience or witness unacceptable behavior--or have any other concerns--please report it by contacting the project maintainer (rob@landley.net). All reports will be handled with discretion. In your report please include:</p>
+<ul><li>Your contact information.</li>
+<li>Names (real, nicknames, or pseudonyms) of any individuals involved. If there are additional witnesses, please include them as well. Your account of what occurred, and if you believe the incident is ongoing. If there is a publicly available record (e.g. a mailing list archive or a public IRC logger), please include a link.</li>
+<li>Any additional information that may be helpful.</li>
+</ul><p>After filing a report, a representative will contact you personally. If the person who is harassing you is part of the response team, they will recuse themselves from handling your incident. A representative will then review the incident, follow up with any additional questions, and make a decision as to how to respond. We will respect confidentiality requests for the purpose of protecting victims of abuse.</p>
+<p>Anyone asked to stop unacceptable behavior is expected to comply immediately. If an individual engages in unacceptable behavior, the representative may take any action they deem appropriate, up to and including a permanent ban from our community without warning.</p>
+<ul></ul><h5>Thanks</h5>
+<p>This code of conduct is based on the <a href="https://github.com/todogroup/opencodeofconduct">Open Code of Conduct</a> v1.0.
+We are thankful for their work and all the communities who have paved the way with code of conducts.</p>
+
+<!--#include file="footer.html" -->
diff --git a/www/header.html b/www/header.html
index e3cd2d0..0d5baa9 100644
--- a/www/header.html
+++ b/www/header.html
@@ -37,6 +37,7 @@
     <li><a href="/notes.html">Maintainer's Blog</a></li>
     <li><a href=cleanup.html>Cleanup</a></li>
     <li><a href=http://www.ohloh.net/p/toybox-landley>Statistics</a></li>
+    <li><a href=conduct.html>Code of Conduct</a></li>
   </ul>
 </td>