Merge remote-tracking branch 'toybox/master' into HEAD
diff --git a/Makefile b/Makefile
index 2c9a857..d2919e7 100644
--- a/Makefile
+++ b/Makefile
@@ -11,7 +11,7 @@
 	scripts/make.sh
 
 .PHONY: clean distclean baseline bloatcheck install install_flat \
-	uinstall uninstall_flat test tests help toybox_stuff
+	uinstall uninstall_flat test tests help toybox_stuff change
 
 include kconfig/Makefile
 
@@ -46,14 +46,7 @@
 	scripts/install.sh --long --uninstall
 
 change:
-	@NOBUILD=1 scripts/make.sh > /dev/null&& \
-	$(HOSTCC) -I . scripts/install.c -o generated/instlist && \
-	export PREFIX=$${PREFIX:-change/} && \
-	mkdir -p "$$PREFIX" && \
-	for i in $$(generated/instlist); \
-		do echo -n "$$i " && \
-		scripts/single.sh $$i > /dev/null || touch $$PREFIX/$${i}.bad; \
-	done
+	scripts/change.sh
 
 clean::
 	rm -rf toybox toybox_unstripped generated change .singleconfig*
diff --git a/lib/lib.h b/lib/lib.h
index 621ed27..a659b69 100644
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -128,6 +128,7 @@
 long xparsetime(char *arg, long units, long *fraction);
 void xpidfile(char *name);
 void xregcomp(regex_t *preg, char *rexec, int cflags);
+char *xtzset(char *new);
 
 // lib.c
 void verror_msg(char *msg, int err, va_list va);
diff --git a/lib/xwrap.c b/lib/xwrap.c
index cd3c684..0a2b38f 100644
--- a/lib/xwrap.c
+++ b/lib/xwrap.c
@@ -627,3 +627,14 @@
     error_exit("xregcomp: %s", libbuf);
   }
 }
+
+char *xtzset(char *new)
+{
+  char *tz = getenv("TZ");
+
+  if (tz) tz = xstrdup(tz);
+  if (setenv("TZ", new, 1)) perror_exit("setenv");
+  tzset();
+
+  return tz;
+}
diff --git a/main.c b/main.c
index 458d470..a81cfb9 100644
--- a/main.c
+++ b/main.c
@@ -127,15 +127,15 @@
 {
   struct toy_list *which;
 
-  // don't blank old optargs if our new argc lives in the old optargs.
-  if (argv>=toys.optargs && argv<=toys.optargs+toys.optc) toys.optargs = 0;
-
   // Return if we can't find it, or need to re-exec to acquire root,
   // or if stack depth is getting silly.
   if (!(which = toy_find(argv[0]))) return;
   if (toys.recursion && (which->flags & TOYFLAG_ROOTONLY) && getuid()) return;
   if (toys.recursion++ > 5) return;
 
+  // don't blank old optargs if our new argc lives in the old optargs.
+  if (argv>=toys.optargs && argv<=toys.optargs+toys.optc) toys.optargs = 0;
+
   // Run command
   toy_init(which, argv);
   if (toys.which) toys.which->toy_main();
diff --git a/scripts/change.sh b/scripts/change.sh
new file mode 100755
index 0000000..8b8ab92
--- /dev/null
+++ b/scripts/change.sh
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+# build each command as a standalone executable
+
+NOBUILD=1 scripts/make.sh > /dev/null &&
+${HOSTCC:-cc} -I . scripts/install.c -o generated/instlist &&
+export PREFIX=${PREFIX:-change/} &&
+mkdir -p "$PREFIX" || exit 1
+
+# Build all the commands standalone except:
+
+# sh - shell builtins like "cd" and "exit" need the multiplexer
+# help - needs to know what other commands are enabled (use command --help)
+
+for i in $(generated/instlist | egrep -vw "sh|help")
+do
+  echo -n "$i " &&
+  scripts/single.sh $i > /dev/null || touch $PREFIX/${i}.bad
+done
diff --git a/scripts/single.sh b/scripts/single.sh
index ce8695c..a151047 100755
--- a/scripts/single.sh
+++ b/scripts/single.sh
@@ -26,7 +26,7 @@
 
   make allnoconfig > /dev/null &&
   sed -ri -e "s/CONFIG_TOYBOX=y/# CONFIG_TOYBOX is not set/;t" \
-    -e "s/# (CONFIG_(TOYBOX(|_HELP|_I18N|_FLOAT)|$NAME|${NAME}_.*${DEPENDS:+|$DEPENDS})) is not set/\1=y/" \
+    -e "s/# (CONFIG_(TOYBOX(|_HELP.*|_I18N|_FLOAT)|$NAME|${NAME}_.*${DEPENDS:+|$DEPENDS})) is not set/\1=y/" \
     "$KCONFIG_CONFIG" &&
   make &&
   mv toybox $PREFIX$i || exit 1
diff --git a/tests/useradd.test b/tests/useradd.test
index a87da07..61d5e5d 100644
--- a/tests/useradd.test
+++ b/tests/useradd.test
@@ -5,8 +5,12 @@
 
 [ -f testing.sh ] && . testing.sh
 
-# 70 characters long string; hereafter, we will use it as per our need.
-_s70="abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz123456789"
+if [ "$(id -u)" -ne 0 ]
+then
+  echo "SKIPPED: chgrp (not root)"
+  continue 2>/dev/null
+  exit
+fi
 
 # Redirecting all output to /dev/null for grep, adduser and deluser
 arg="&>/dev/null"
@@ -16,75 +20,85 @@
 # Default password for adding user is: 'password'
 pass=`echo -ne 'password\npassword\n'`
 
-testing "adduser user_name (text)" "useradd toyTestUser $arg ||
-   grep '^toyTestUser:' /etc/passwd $arg && test -d /home/toyTestUser &&
-   userdel toyTestUser $arg && rm -rf /home/toyTestUser && echo 'yes'" \
-  "yes\n" "" "$pass"
+user="toyTestUser"
+testing "adduser user_name (text)" "useradd $user $arg || 
+   grep '^$user:' /etc/passwd $arg && [ -d /home/$user ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
-testing "adduser user_name (alphanumeric)" "useradd toy1Test2User3 $arg ||
-   grep '^toy1Test2User3:' /etc/passwd $arg && test -d /home/toy1Test2User3 &&
-   userdel toy1Test2User3 $arg && rm -rf /home/toy1Test2User3 && echo 'yes'" \
-  "yes\n" "" "$pass"
+user="toy1Test2User3"
+testing "adduser user_name (alphanumeric)" "useradd $user $arg ||
+   grep '^$user:' /etc/passwd $arg && [ -d /home/$user ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
-testing "adduser user_name (numeric)" "useradd 987654321 $arg ||
-   grep '^987654321:' /etc/passwd $arg && test -d /home/987654321 &&
-   userdel 987654321 $arg && rm -rf /home/987654321 && echo 'yes'" \
-  "yes\n" "" "$pass"
+user="987654321"
+testing "adduser user_name (numeric)" "useradd $user $arg ||
+   grep '^$user:' /etc/passwd $arg && [ -d /home/$user ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
-testing "adduser user_name (with ./-/_)" "useradd toy.1Test-2User_3 $arg ||
-   grep '^toy.1Test-2User_3:' /etc/passwd $arg &&
-   test -d /home/toy.1Test-2User_3 && userdel toy.1Test-2User_3 $arg &&
-   rm -rf /home/toy.1Test-2User_3 && echo 'yes'" "yes\n" "" "$pass"
+user="toy.1Test-2User_3"
+testing "adduser user_name (with ./-/_)" "useradd $user $arg ||
+   grep '^$user:' /etc/passwd $arg && [ -d /home/$user ] && 
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
-testing "adduser user_name (long string)" "useradd $_s70 $arg ||
-   grep '^$_s70:' /etc/passwd $arg && test -d /home/$_s70 &&
-   userdel $_s70 $arg && rm -rf /home/$_s70 && echo 'yes'" "yes\n" "" "$pass"
+# 70 characters long string; hereafter, we will use it as per our need.
+user="abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrstuvwxyz123456789"
+testing "adduser user_name (long string)" "useradd $user $arg ||
+   grep '^$user:' /etc/passwd $arg && [ -d /home/$user ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
-testing "adduser user_name with dir" "useradd -h $PWD/dir toyTestUser $arg ||
-   grep '^toyTestUser:.*dir' /etc/passwd $arg && test -d $PWD/dir &&
-   userdel toyTestUser $arg && rm -rf $PWD/dir && echo 'yes'" "yes\n" "" "$pass"
+user="toyTestUser"
+testing "adduser user_name with dir" "useradd -h $PWD/dir $user $arg ||
+   grep '^$user:.*dir' /etc/passwd $arg && [ -d $PWD/dir ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
+rm -rf $PWD/dir
 
 gecos="aaa,bbb,ccc,ddd,eee"
-testing "adduser user_name with gecos" "useradd -g '$gecos' toyTestUser $arg ||
-   grep '^toyTestUser:.*$gecos' /etc/passwd $arg && test -d /home/toyTestUser &&
-   userdel toyTestUser $arg && rm -rf /home/toyTestUser && echo 'yes'" \
-  "yes\n" "" "$pass"
+testing "adduser user_name with gecos" "useradd -g '$gecos' $user $arg ||
+   grep '^$user:.*$gecos' /etc/passwd $arg && [ -d /home/$user ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
 shl="/bin/sh"
-testing "adduser user_name with shell" "useradd -s $shl toyTestUser $arg ||
-   grep '^toyTestUser:.*$shl$' /etc/passwd $arg && test -d /home/toyTestUser &&
-   userdel toyTestUser $arg && rm -rf /home/toyTestUser && echo 'yes'" \
-  "yes\n" "" "$pass"
+testing "adduser user_name with shell" "useradd -s $shl $user $arg ||
+   grep '^$user:.*$shl$' /etc/passwd $arg && [ -d /home/$user ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
 g_name="root"
-g_id=`grep $g_name /etc/group | cut -d : -f 3`
-testing "adduser user_name with group" "useradd -G $g_name toyTestUser $arg ||
-   grep '^toyTestUser:.*:.*:$g_id:.*' /etc/passwd $arg &&
-   test -d /home/toyTestUser && userdel toyTestUser $arg &&
-   rm -rf /home/toyTestUser && echo 'yes'" "yes\n" "" "$pass"
+g_id=`grep $g_name':.*:.*' /etc/group | cut -d : -f 3`
+testing "adduser user_name with group" "useradd -G $g_name $user $arg ||
+   grep '^$user:.*:.*:$g_id:.*' /etc/passwd $arg && [ -d /home/$user ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
-testing "adduser user_name (system user)" "useradd -S toyTestUser $arg ||
-   grep '^toyTestUser:.*:.*:.*' /etc/passwd $arg &&
-   test ! -e /home/toyTestUser && userdel toyTestUser $arg && echo 'yes'" \
-  "yes\n" "" "$pass"
+testing "adduser user_name (system user)" "useradd -S $user $arg ||
+   grep '^$user:.*:.*:.*' /etc/passwd $arg && [ ! -e /home/$user ] && 
+   echo 'yes'" "yes\n" "" "$pass"   
+userdel -r $user $arg
 
-testing "adduser user_name with -D" "useradd -D toyTestUser $arg ||
-   grep '^toyTestUser:.*:.*:.*' /etc/passwd $arg && test -d /home/toyTestUser &&
-   userdel toyTestUser $arg && rm -rf /home/toyTestUser && echo 'yes'" \
-  "yes\n" "" "$pass"
+testing "adduser user_name with -D" "useradd -D $user $arg ||
+   grep '^$user:.*:.*:.*' /etc/passwd $arg && [ -d /home/$user ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
-testing "adduser user_name with -H" "useradd -H toyTestUser $arg ||
-   grep '^toyTestUser:.*:.*:.*' /etc/passwd $arg &&
-   test ! -e /home/toyTestUser && userdel toyTestUser $arg && echo 'yes'" \
-  "yes\n" "" "$pass"
+testing "adduser user_name with -H" "useradd -H $user $arg ||
+   grep '^$user:.*:.*:.*' /etc/passwd $arg && [ ! -e /home/$user ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
-testing "adduser user_name with dir and -H" \
-  "useradd -H -h $PWD/dir toyTestUser $arg ||
-   grep '^toyTestUser:.*dir' /etc/passwd $arg && test ! -e $PWD/dir &&
-   userdel toyTestUser $arg && echo 'yes'" "yes\n" "" "$pass"
+testing "adduser user_name with dir and -H" "useradd -H -h $PWD/dir $user $arg ||
+   grep '^$user:.*dir' /etc/passwd $arg && [ ! -e $PWD/dir ] &&
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
-testing "adduser user_name with user_id" "useradd -u 49999 toyTestUser $arg ||
-   grep '^toyTestUser:x:49999:.*' /etc/passwd $arg &&
-   test -d /home/toyTestUser && userdel toyTestUser $arg &&
-   rm -rf /home/toyTestUser && echo 'yes'" "yes\n" "" "$pass"
+testing "adduser user_name with user_id" "useradd -u 49999 $user $arg ||
+   grep '^$user:x:49999:.*' /etc/passwd $arg && [ -d /home/$user ] && 
+   echo 'yes'" "yes\n" "" "$pass"
+userdel -r $user $arg
 
diff --git a/toys/lsb/mktemp.c b/toys/lsb/mktemp.c
index 498f9f1..cc42665 100644
--- a/toys/lsb/mktemp.c
+++ b/toys/lsb/mktemp.c
@@ -4,7 +4,7 @@
  *
  * http://refspecs.linuxfoundation.org/LSB_4.1.0/LSB-Core-generic/LSB-Core-generic/mktemp.html
 
-USE_MKTEMP(NEWTOY(mktemp, ">1q(directory)d(tmpdir)p:", TOYFLAG_BIN))
+USE_MKTEMP(NEWTOY(mktemp, ">1qd(directory)p(tmpdir):", TOYFLAG_BIN))
 
 config MKTEMP
   bool "mktemp"
@@ -40,11 +40,14 @@
   if (!TT.tmpdir) TT.tmpdir = getenv("TMPDIR");
   if (!TT.tmpdir) TT.tmpdir = "/tmp";
 
-  snprintf(toybuf, sizeof(toybuf), "%s/%s", TT.tmpdir, template);
+  template = strchr(template, '/') ? xstrdup(template)
+             : xmprintf("%s/%s", TT.tmpdir, template);
 
-  if (d_flag ? !mkdtemp(toybuf) : mkstemp(toybuf) == -1) {
+  if (d_flag ? !mkdtemp(template) : mkstemp(template) == -1) {
     if (toys.optflags & FLAG_q) toys.exitval = 1;
     else perror_exit("Failed to create %s %s/%s",
                      d_flag ? "directory" : "file", TT.tmpdir, template);
-  } else xputs(toybuf);
+  } else xputs(template);
+
+  if (CFG_TOYBOX_FREE) free(template);
 }
diff --git a/toys/other/dos2unix.c b/toys/other/dos2unix.c
index 690c5a8..021ba38 100644
--- a/toys/other/dos2unix.c
+++ b/toys/other/dos2unix.c
@@ -2,16 +2,25 @@
  *
  * Copyright 2012 Rob Landley <rob@landley.net>
 
-USE_DOS2UNIX(NEWTOY(dos2unix, NULL, TOYFLAG_BIN))
-USE_DOS2UNIX(OLDTOY(unix2dos, dos2unix, TOYFLAG_BIN))
+USE_DOS2UNIX(NEWTOY(dos2unix, 0, TOYFLAG_BIN))
+USE_UNIX2DOS(NEWTOY(unix2dos, 0, TOYFLAG_BIN))
 
 config DOS2UNIX
   bool "dos2unix/unix2dos"
   default y
   help
-    usage: dos2unix/unix2dos [file...]
+    usage: dos2unix [FILE...]
 
-    Convert newline format between dos (\r\n) and unix (just \n)
+    Convert newline format from dos "\r\n" to unix "\n".
+    If no files listed copy from stdin, "-" is a synonym for stdin.
+
+config UNIX2DOS
+  bool "unix2dos"
+  default y
+  help
+    usage: unix2dos [FILE...]
+
+    Convert newline format from unix "\n" to dos "\r\n".
     If no files listed copy from stdin, "-" is a synonym for stdin.
 */
 
@@ -60,3 +69,8 @@
 {
   loopfiles(toys.optargs, do_dos2unix);
 }
+
+void unix2dos_main(void)
+{
+  dos2unix_main();
+}
diff --git a/toys/pending/hwclock.c b/toys/pending/hwclock.c
index 003174f..d9ced6f 100644
--- a/toys/pending/hwclock.c
+++ b/toys/pending/hwclock.c
@@ -2,9 +2,9 @@
  *
  * Copyright 2014 Bilal Qureshi <bilal.jmi@gmail.com>
  *
- * No Standard.
+ * No standard, but see Documentation/rtc.txt in the linux kernel source..
  *
-USE_HWCLOCK(NEWTOY(hwclock, ">0(fast)f(rtc):u(utc)l(localtime)t(systz)w(systohc)s(hctosys)r(show)[!ul][!rsw]", TOYFLAG_USR|TOYFLAG_BIN))
+USE_HWCLOCK(NEWTOY(hwclock, ">0(fast)f(rtc):u(utc)l(localtime)t(systz)s(hctosys)r(show)w(systohc)[-ul][!rtsw]", TOYFLAG_USR|TOYFLAG_BIN))
 
 config HWCLOCK
   bool "hwclock"
@@ -12,7 +12,7 @@
   help
     usage: hwclock [-rswtluf]
 
-    -f FILE Use specified device file instead of /dev/rtc (--show)
+    -f FILE Use specified device file instead of /dev/rtc (--rtc)
     -l      Hardware clock uses localtime (--localtime)
     -r      Show hardware clock time (--show)
     -s      Set system time from hardware clock (--hctosys)
@@ -20,6 +20,7 @@
     -u      Hardware clock uses UTC (--utc)
     -w      Set hardware clock from system time (--systohc)
 */
+
 #define FOR_hwclock
 #include "toys.h"
 #include <linux/rtc.h>
@@ -30,7 +31,7 @@
   int utc;
 )
 
-static int check_hctosys(struct dirtree* node)
+static int rtc_find(struct dirtree* node)
 {
   FILE *fp;
 
@@ -39,148 +40,99 @@
   snprintf(toybuf, sizeof(toybuf), "/sys/class/rtc/%s/hctosys", node->name);
   fp = fopen(toybuf, "r");
   if (fp) {
-    int hctosys = 0;
-    int items = fscanf(fp, "%d", &hctosys);
+    int hctosys = 0, items = fscanf(fp, "%d", &hctosys);
+
     fclose(fp);
     if (items == 1 && hctosys == 1) {
       snprintf(toybuf, sizeof(toybuf), "/dev/%s", node->name);
       TT.fname = toybuf;
+
       return DIRTREE_ABORT;
     }
   }
+
   return 0;
 }
 
-// Search /sys/class/rtc for the RTC that the system clock is set from.
-// See the kernel's Documentation/rtc.txt.
-static int open_wall_clock_rtc(int flag)
-{
-  TT.fname = NULL;
-  dirtree_read("/sys/class/rtc", check_hctosys);
-  return TT.fname ? xopen(TT.fname, flag) : -1;
-}
-
-static int rtc_open(int flag)
-{
-  if (!TT.fname) {
-    int fd; 
-
-    if ((fd = open((TT.fname = "/dev/rtc"), flag)) != -1) return fd;
-    else if ((fd = open_wall_clock_rtc(flag)) != -1) return fd;
-    else TT.fname = "/dev/misc/rtc";
-  }
-  return xopen(TT.fname, flag);
-}
-
-static time_t get_rtc()
-{
-  struct tm time;
-  time_t tm;
-  char *ptz_old = 0;
-  int fd = rtc_open(O_RDONLY);
-
-  xioctl(fd, RTC_RD_TIME, &time);
-  close(fd);
-  if (TT.utc) {
-    ptz_old = getenv("TZ");
-    if (putenv((char*)"TZ=UTC0")) perror_exit("putenv");
-    tzset();
-  }
-  if ((tm = mktime(&time)) < 0) error_exit("mktime failed");
-  if (TT.utc) {
-    if (unsetenv("TZ") < 0) perror_exit("unsetenv");
-    if (ptz_old && putenv(ptz_old - 3)) perror_exit("putenv");
-    tzset();
-  }
-  return tm;
-}
-
-static void set_sysclock_from_hwclock()
-{
-  struct timezone tmzone;
-  struct timeval tmval;
-
-  tmzone.tz_minuteswest = timezone / 60 - 60 * daylight;
-  tmzone.tz_dsttime = 0;
-  tmval.tv_sec = get_rtc();
-  tmval.tv_usec = 0;
-  if (settimeofday(&tmval, &tmzone) < 0) perror_exit("settimeofday");
-}
-
-static void set_hwclock_from_sysclock()
-{
-  struct timeval tmval;
-  struct tm time;
-  int fd = rtc_open(O_WRONLY);
-
-  if (gettimeofday(&tmval, NULL) < 0) perror_exit("gettimeofday");
-  // converting a time value to broken-down UTC time
-  if (TT.utc && !gmtime_r((time_t*)&tmval.tv_sec, &time)) 
-    error_exit("gmtime_r failed");
-  // converting a time value to a broken-down localtime
-  else if (!(localtime_r((time_t*)&tmval.tv_sec, &time)))
-    error_exit("localtime_r failed");
-
-  /* The value of tm_isdst will positive if daylight saving time is in effect,
-   * zero if it is not and negative if the information is not available. 
-   * */
-  time.tm_isdst = 0;
-  xioctl(fd, RTC_SET_TIME, &time);
-  close(fd);
-}
-
-static void set_sysclock_timezone()
-{
-  struct timezone tmzone;
-  struct timeval tmval;
-  struct tm *pb;
-
-  if (gettimeofday(&tmval, NULL) < 0) perror_exit("gettimeofday");
-  if (!(pb = localtime(&tmval.tv_sec))) error_exit("localtime failed");
-  // extern long timezone => defined in header sys/time.h
-  tmzone.tz_minuteswest = timezone / 60;
-  if (pb->tm_isdst) tmzone.tz_minuteswest -= 60;
-  tmzone.tz_dsttime = 0; // daylight saving time is not in effect
-  if (gettimeofday(&tmval, NULL) < 0) perror_exit("gettimeofday");
-  if (!TT.utc) tmval.tv_sec += tmzone.tz_minuteswest * 60;
-  if (settimeofday(&tmval, &tmzone) < 0) perror_exit("settimeofday");
-}
-
 void hwclock_main()
 {
-  // check for UTC
-  if (!(toys.optflags & FLAG_u)) {
-    FILE *fp = fopen("/etc/adjtime", "r");
+  struct timezone tzone;
+  struct timeval timeval;
+  struct tm tm;
+  time_t time;
+  int fd = -1;
 
-    if (fp) {
-      char *line = NULL;
-      size_t st;
+  // check for Grenich Mean Time
+  if (toys.optflags & FLAG_u) TT.utc = 1;
+  else {
+    FILE *fp;
+    char *s = 0;
 
-      while (0 < getline(&line, &st, fp)) {
-        if (!strncmp(line, "UTC", 3)) {
-          TT.utc = 1;
-          break;
-        }
-        free(line);
-      }
-      fclose(fp);
-    }
-  } else TT.utc = 1;
-
-  if (toys.optflags & FLAG_w) set_hwclock_from_sysclock();
-  else if (toys.optflags & FLAG_s) set_sysclock_from_hwclock(); 
-  else if (toys.optflags & FLAG_t) set_sysclock_timezone();
-  else if ((toys.optflags & FLAG_r) || (toys.optflags & FLAG_l) 
-      || !*toys.optargs)
-  {
-    time_t tm = get_rtc();
-    char *s, *pctm = ctime(&tm);
-
-    // ctime() is defined as equivalent to asctime(localtime(t)),
-    // which is defined to overflow its buffer rather than return NULL.
-    // if (!pctm) error_exit("can't happen");
-    if ((s = strrchr(pctm, '\n'))) *s = '\0';
-    // TODO: implement this.
-    xprintf("%s  0.000000 seconds\n", pctm);
+    for (fp = fopen("/etc/adjtime", "r");
+         fp && getline(&s, (void *)toybuf, fp)>0;
+         free(s), s = 0) TT.utc += !strncmp(s, "UTC", 3);
+    if (fp) fclose(fp);
   }
+
+  if (!(toys.optflags&FLAG_t)) {
+    int w = toys.optflags & FLAG_w, flag = O_WRONLY*w;
+
+    // Open /dev/rtc (if your system has no /dev/rtc symlink, search for it).
+    if (!TT.fname && (fd = open("/dev/rtc", flag)) == -1) {
+      dirtree_read("/sys/class/rtc", rtc_find);
+      if (!TT.fname) TT.fname = "/dev/misc/rtc";
+    }
+    if (fd == -1) fd = xopen(TT.fname, flag);
+
+    // Get current time in seconds from rtc device. todo: get subsecond time
+    if (!w) {
+      char *s = s;
+
+      xioctl(fd, RTC_RD_TIME, &tm);
+      if (TT.utc) s = xtzset("UTC0");
+      if ((time = mktime(&tm)) < 0) goto bad;
+      if (TT.utc) {
+        free(xtzset(s));
+        free(s);
+      }
+    }
+  }
+
+  if (toys.optflags & (FLAG_w|FLAG_t))
+    if (gettimeofday(&timeval, 0)
+        || (TT.utc ? gmtime_r : localtime_r)(&timeval.tv_sec, &tm)) goto bad;
+
+  if (toys.optflags & FLAG_w) {
+    /* The value of tm_isdst will positive if daylight saving time is in effect,
+     * zero if it is not and negative if the information is not available. 
+     * todo: so why isn't this negative...? */
+    tm.tm_isdst = 0;
+    xioctl(fd, RTC_SET_TIME, &time);
+  } else if (toys.optflags & FLAG_s) {
+    tzone.tz_minuteswest = timezone / 60 - 60 * daylight;
+    timeval.tv_sec = time;
+    timeval.tv_usec = 0; // todo: fixit
+  } else if (toys.optflags & FLAG_t) {
+    // Adjust seconds for timezone and daylight saving time
+    // extern long timezone is defined in header sys/time.h
+    tzone.tz_minuteswest = timezone / 60;
+    if (tm.tm_isdst) tzone.tz_minuteswest -= 60;
+    if (!TT.utc) timeval.tv_sec += tzone.tz_minuteswest * 60;
+  } else {
+    char *c = ctime(&time), *s = strrchr(c, '\n');
+
+    if (s) *s = '\0';
+    // TODO: implement this.
+    xprintf("%s  0.000000 seconds\n", c);
+  }
+  if (toys.optflags & (FLAG_t|FLAG_s)) {
+    tzone.tz_dsttime = 0;
+    if (settimeofday(&timeval, &tzone)) goto bad;
+  }
+
+  if (fd != -1) close(fd);
+
+  return;
+bad:
+  perror_exit("failed");
 }
diff --git a/toys/posix/cp.c b/toys/posix/cp.c
index c1a438f..3dc6f2a 100644
--- a/toys/posix/cp.c
+++ b/toys/posix/cp.c
@@ -7,7 +7,7 @@
 // This is subtle: MV options shared with CP must be in same order (right to
 // left) as CP for FLAG_X macros to work out right.
 
-USE_CP(NEWTOY(cp, "<2RHLPp"USE_CP_MORE("rdaslvnF")"fi[-HLP"USE_CP_MORE("d")"]"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))
+USE_CP(NEWTOY(cp, "<2RHLPp"USE_CP_MORE("rdaslvnF(remove-destination)")"fi[-HLP"USE_CP_MORE("d")"]"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))
 USE_MV(NEWTOY(mv, "<2"USE_CP_MORE("vnF")"fi"USE_CP_MORE("[-ni]"), TOYFLAG_BIN))
 USE_INSTALL(NEWTOY(install, "<1cdDpsvm:o:g:", TOYFLAG_USR|TOYFLAG_BIN))
 *
@@ -22,7 +22,7 @@
     be a directory.
 
     -f	delete destination files we can't write to
-    -F	delete any existing destination file first (breaks hardlinks)
+    -F	delete any existing destination file first (--remove-destination)
     -i	interactive, prompt before overwriting existing DEST
     -p	preserve timestamps, ownership, and permissions
     -R	recurse into subdirectories (DEST must be a directory)
diff --git a/toys/posix/grep.c b/toys/posix/grep.c
index 18a27e3..61df08e 100644
--- a/toys/posix/grep.c
+++ b/toys/posix/grep.c
@@ -5,8 +5,8 @@
  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/grep.html
 
 USE_GREP(NEWTOY(grep, "ZzEFHabhinorsvwclqe*f*m#x[!wx][!EFw]", TOYFLAG_BIN))
-USE_GREP(OLDTOY(egrep, grep, TOYFLAG_BIN))
-USE_GREP(OLDTOY(fgrep, grep, TOYFLAG_BIN))
+USE_EGREP(OLDTOY(egrep, grep, TOYFLAG_BIN))
+USE_FGREP(OLDTOY(fgrep, grep, TOYFLAG_BIN))
 
 config GREP
   bool "grep"
@@ -36,6 +36,16 @@
     output prefix (default: filename if checking more than 1 file)
     -H  force filename           -b  byte offset of match
     -h  hide filename            -n  line number of match
+
+config EGREP
+  bool
+  default y
+  depends on GREP
+
+config FGREP
+  bool
+  default y
+  depends on GREP
 */
 
 #define FOR_grep