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

Change-Id: I6ba143f54cdea32f90c0c4ccc262058104a13180
diff --git a/generated/flags.h b/generated/flags.h
index 774078a..bef3806 100644
--- a/generated/flags.h
+++ b/generated/flags.h
@@ -1892,12 +1892,13 @@
 #undef FLAG_n
 #endif
 
-// netcat ^tlLw#<1W#<1p#<1>65535q#<1s:f:46u[!tlL][!Lw][!46] ^tlLw#<1W#<1p#<1>65535q#<1s:f:46u[!tlL][!Lw][!46]
+// netcat ^tlLw#<1W#<1p#<1>65535q#<1s:f:46uU[!tlL][!Lw][!46U] ^tlLw#<1W#<1p#<1>65535q#<1s:f:46uU[!tlL][!Lw][!46U]
 #undef OPTSTR_netcat
-#define OPTSTR_netcat "^tlLw#<1W#<1p#<1>65535q#<1s:f:46u[!tlL][!Lw][!46]"
+#define OPTSTR_netcat "^tlLw#<1W#<1p#<1>65535q#<1s:f:46uU[!tlL][!Lw][!46U]"
 #ifdef CLEANUP_netcat
 #undef CLEANUP_netcat
 #undef FOR_netcat
+#undef FLAG_U
 #undef FLAG_u
 #undef FLAG_6
 #undef FLAG_4
@@ -4922,18 +4923,19 @@
 #ifndef TT
 #define TT this.netcat
 #endif
-#define FLAG_u (1<<0)
-#define FLAG_6 (1<<1)
-#define FLAG_4 (1<<2)
-#define FLAG_f (1<<3)
-#define FLAG_s (1<<4)
-#define FLAG_q (1<<5)
-#define FLAG_p (1<<6)
-#define FLAG_W (1<<7)
-#define FLAG_w (1<<8)
-#define FLAG_L (1<<9)
-#define FLAG_l (1<<10)
-#define FLAG_t (1<<11)
+#define FLAG_U (1<<0)
+#define FLAG_u (1<<1)
+#define FLAG_6 (1<<2)
+#define FLAG_4 (1<<3)
+#define FLAG_f (1<<4)
+#define FLAG_s (1<<5)
+#define FLAG_q (1<<6)
+#define FLAG_p (1<<7)
+#define FLAG_W (1<<8)
+#define FLAG_w (1<<9)
+#define FLAG_L (1<<10)
+#define FLAG_l (1<<11)
+#define FLAG_t (1<<12)
 #endif
 
 #ifdef FOR_netstat
diff --git a/generated/help.h b/generated/help.h
index 7466a97..65c49d5 100644
--- a/generated/help.h
+++ b/generated/help.h
@@ -122,7 +122,7 @@
 
 #define HELP_netstat "usage: netstat [-pWrxwutneal]\n\nDisplay networking information. Default is netstat -tuwx\n\n-r	Routing table\n-a	All sockets (not just connected)\n-l	Listening server sockets\n-t	TCP sockets\n-u	UDP sockets\n-w	Raw sockets\n-x	Unix sockets\n-e	Extended info\n-n	Don't resolve names\n-W	Wide display\n-p	Show PID/program name of sockets"
 
-#define HELP_netcat "usage: netcat [-46t] [-lL COMMAND...] [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}\n\nForward stdin/stdout to a file or network connection.\n\n-4	Force IPv4\n-6	Force IPv6\n-L	Listen for multiple incoming connections (server mode)\n-W	SECONDS timeout for more data on an idle connection\n-f	Use FILENAME (ala /dev/ttyS0) instead of network\n-l	Listen for one incoming connection\n-p	Local port number\n-q	Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet\n-s	Local source address\n-t	Allocate tty (must come before -l or -L)\n-u	Use UDP\n-w	SECONDS timeout to establish connection\n\nUse \"stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho\" with\nnetcat -f to connect to a serial port.\n\nThe command line after -l or -L is executed (as a child process) to handle\neach incoming connection. If blank -l waits for a connection and forwards\nit to stdin/stdout. If no -p specified, -l prints port it bound to and\nbackgrounds itself (returning immediately).\n\nFor a quick-and-dirty server, try something like:\nnetcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l"
+#define HELP_netcat "usage: netcat [-46Ut] [-lL COMMAND...] [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}\n\nForward stdin/stdout to a file or network connection.\n\n-4	Force IPv4\n-6	Force IPv6\n-L	Listen for multiple incoming connections (server mode)\n-U	Use a UNIX domain socket\n-W	SECONDS timeout for more data on an idle connection\n-f	Use FILENAME (ala /dev/ttyS0) instead of network\n-l	Listen for one incoming connection\n-p	Local port number\n-q	Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet\n-s	Local source address\n-t	Allocate tty (must come before -l or -L)\n-u	Use UDP\n-w	SECONDS timeout to establish connection\n\nUse \"stty 115200 -F /dev/ttyS0 && stty raw -echo -ctlecho\" with\nnetcat -f to connect to a serial port.\n\nThe command line after -l or -L is executed (as a child process) to handle\neach incoming connection. If blank -l waits for a connection and forwards\nit to stdin/stdout. If no -p specified, -l prints port it bound to and\nbackgrounds itself (returning immediately).\n\nFor a quick-and-dirty server, try something like:\nnetcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l"
 
 #define HELP_microcom "usage: microcom [-s SPEED] [-X] DEVICE\n\nSimple serial console.\n\n-s	Set baud rate to SPEED\n-X	Ignore ^@ (send break) and ^] (exit)"
 
diff --git a/generated/newtoys.h b/generated/newtoys.h
index 0662f39..0b93d2f 100644
--- a/generated/newtoys.h
+++ b/generated/newtoys.h
@@ -169,7 +169,7 @@
 USE_NBD_CLIENT(OLDTOY(nbd-client, nbd_client, TOYFLAG_USR|TOYFLAG_BIN))
 USE_NBD_CLIENT(NEWTOY(nbd_client, "<3>3ns", 0))
 USE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN))
-USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46u"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46]", TOYFLAG_BIN))
+USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46uU"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46U]", TOYFLAG_BIN))
 USE_NETSTAT(NEWTOY(netstat, "pWrxwutneal", TOYFLAG_BIN))
 USE_NICE(NEWTOY(nice, "^<1n#", TOYFLAG_BIN))
 USE_NL(NEWTOY(nl, "v#<1=1l#w#<0=6Eb:n:s:", TOYFLAG_USR|TOYFLAG_BIN))
diff --git a/toys/net/netcat.c b/toys/net/netcat.c
index 833d32a..65c41ac 100644
--- a/toys/net/netcat.c
+++ b/toys/net/netcat.c
@@ -7,13 +7,13 @@
  * netcat -L zombies
 
 USE_NETCAT(OLDTOY(nc, netcat, TOYFLAG_USR|TOYFLAG_BIN))
-USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46u"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46]", TOYFLAG_BIN))
+USE_NETCAT(NEWTOY(netcat, USE_NETCAT_LISTEN("^tlL")"w#<1W#<1p#<1>65535q#<1s:f:46uU"USE_NETCAT_LISTEN("[!tlL][!Lw]")"[!46U]", TOYFLAG_BIN))
 
 config NETCAT
   bool "netcat"
   default y
   help
-    usage: netcat [-46] [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}
+    usage: netcat [-46U] [-u] [-wpq #] [-s addr] {IPADDR PORTNUM|-f FILENAME}
 
     Forward stdin/stdout to a file or network connection.
 
@@ -24,6 +24,7 @@
     -q	Quit SECONDS after EOF on stdin, even if stdout hasn't closed yet
     -s	Local source address
     -u	Use UDP
+    -U	Use a UNIX domain socket
     -w	SECONDS timeout to establish connection
     -W	SECONDS timeout for more data on an idle connection
 
@@ -85,11 +86,13 @@
   // The argument parsing logic can't make "<2" conditional on other
   // arguments like -f and -l, so do it by hand here.
   if ((toys.optflags&FLAG_f) ? toys.optc :
-      (!(toys.optflags&(FLAG_l|FLAG_L)) && toys.optc!=2))
+      (!(toys.optflags&(FLAG_l|FLAG_L)) &&
+       toys.optc!=(toys.optflags&FLAG_U?1:2)))
         help_exit("bad argument count");
 
   if (toys.optflags&FLAG_4) family = AF_INET;
   else if (toys.optflags&FLAG_6) family = AF_INET6;
+  else if (toys.optflags&FLAG_U) family = AF_UNIX;
 
   if (toys.optflags&FLAG_u) type = SOCK_DGRAM;
 
@@ -97,9 +100,28 @@
   else {
     // Setup socket
     if (!(toys.optflags&(FLAG_L|FLAG_l))) {
-      struct addrinfo *addr = xgetaddrinfo(toys.optargs[0], toys.optargs[1],
-                                           family, type, 0, 0);
-      sockfd = xconnect(addr);
+      if (toys.optflags&FLAG_U) {
+        struct sockaddr_un sockaddr;
+
+        memset(&sockaddr, 0, sizeof(struct sockaddr_un));
+
+        if (strlen(toys.optargs[0]) + 1 > sizeof(sockaddr.sun_path))
+          error_exit("socket path too long %s", toys.optargs[0]);
+        strcpy(sockaddr.sun_path, toys.optargs[0]);
+        sockaddr.sun_family = AF_UNIX;
+
+        sockfd = xsocket(AF_UNIX, type | SOCK_CLOEXEC, 0);
+        if (connect(sockfd, (struct sockaddr*)&sockaddr,
+                    sizeof(sockaddr)) != 0) {
+          perror_exit("could not bind to unix domain socket");
+        }
+
+      } else {
+        struct addrinfo *addr = xgetaddrinfo(toys.optargs[0], toys.optargs[1],
+                                             family, type, 0, 0);
+
+        sockfd = xconnect(addr);
+      }
 
       // We have a connection. Disarm timeout.
       set_alarm(0);
@@ -109,14 +131,33 @@
       pollinate(in1, in2, out1, out2, TT.W, TT.q);
     } else {
       // Listen for incoming connections
-      struct sockaddr* address = (void*)toybuf;
-      socklen_t len = sizeof(struct sockaddr_storage);
+      if (toys.optflags&FLAG_U) {
+        struct sockaddr_un sockaddr;
 
-      sprintf(toybuf, "%ld", TT.p);
-      sockfd = xbind(xgetaddrinfo(TT.s, toybuf, family, type, 0, 0));
+        memset(&sockaddr, 0, sizeof(struct sockaddr_un));
+
+        if (!(toys.optflags&FLAG_s))
+          error_exit("-s must be provided if using -U with -L/-l");
+
+        if (strlen(TT.s) + 1 > sizeof(sockaddr.sun_path))
+          error_exit("socket path too long %s", TT.s);
+        strcpy(sockaddr.sun_path, TT.s);
+        sockaddr.sun_family = AF_UNIX;
+
+        sockfd = xsocket(AF_UNIX, type | SOCK_CLOEXEC, 0);
+        if (bind(sockfd, (struct sockaddr*)&sockaddr,
+                 sizeof(struct sockaddr_un)) != 0) {
+          perror_exit("unable to bind to UNIX domain socket");
+        }
+      } else {
+        sprintf(toybuf, "%ld", TT.p);
+        sockfd = xbind(xgetaddrinfo(TT.s, toybuf, family, type, 0, 0));
+      }
 
       if (listen(sockfd, 5)) error_exit("listen");
-      if (!TT.p) {
+      if (!TT.p && !(toys.optflags&FLAG_U)) {
+        struct sockaddr* address = (void*)toybuf;
+        socklen_t len = sizeof(struct sockaddr_storage);
         short port_be;
 
         getsockname(sockfd, address, &len);
@@ -136,7 +177,7 @@
 
       do {
         child = 0;
-        in1 = out2 = accept(sockfd, (struct sockaddr *)address, &len);
+        in1 = out2 = accept(sockfd, NULL, NULL);
         if (in1<0) perror_exit("accept");
 
         // We have a connection. Disarm timeout.
diff --git a/toys/pending/sh.c b/toys/pending/sh.c
index 8c898cd..e8a11ce 100644
--- a/toys/pending/sh.c
+++ b/toys/pending/sh.c
@@ -184,7 +184,7 @@
     pipe[0] = 0;
     pipe[1] = 1;
     if (-1 == (pp->pid = xpopen_both(pp->arg.v, pipe)))
-      perror_msg("%s: not found", *pp->arg.v);
+      perror_msg("%s: vfork", *pp->arg.v);
     else pp->exit = xpclose_both(pp->pid, 0);
   }
 
@@ -290,7 +290,7 @@
 // pointer to start of unused part of line if it needs another line of input.
 static char *parse_line(char *line, struct double_list **pipeline)
 {
-  char *start = line, *end, *s;
+  char *start = line, *end, *s, *ex, *add;
   struct sh_arg *arg = 0;
   struct double_list *pl, *expect = 0;
   unsigned i, paren = 0;
@@ -350,40 +350,81 @@
   for (pl = *pipeline; pl ; pl = (pl->next == *pipeline) ? 0 : pl->next) {
     arg = (void *)pl->data;
     if (!arg->c) continue;
+    add = 0;
 
     // parse flow control statements in this command line
-    for (i = 0; i<arg->c; i++) {
-      char *ex = expect ? expect->prev->data : 0;
-
+    for (i = 0; ; i++) {
+      ex = expect ? expect->prev->data : 0;
       s = arg->v[i];
-      if (!strcmp(s, "if")) ex = "then";
-      else if (!strcmp(s, "for") || !strcmp(s, "select")
-          || !strcmp(s, "while") || !strcmp(s, "until")) ex = "do";
-      else if (!strcmp(s, "case")) ex = "esac";
-      else if (!strcmp(s, "{")) ex = "}";
-      else if (!strcmp(s, "[[")) ex = "]]";
 
-      // If we expect a non-flow-control command, eat rest of line
-      else if (expect && !ex) {
+      // push word to expect to end this block, and expect a command first
+      if (add) {
+        dlist_add(&expect, add);
+        dlist_add(&expect, add = 0);
+      }
+
+      // end of statement?
+      if (i == arg->c) break;
+
+      // When waiting for { it must be next symbol, but can be on a new line.
+      if (ex && !strcmp(ex, "{") && (strcmp(s, "{") || (!i && end))) {
+        syntax_err("need {");
+        goto flush;
+      }
+
+      if (!strcmp(s, "if")) add = "then";
+      else if (!strcmp(s, "for") || !strcmp(s, "select")
+          || !strcmp(s, "while") || !strcmp(s, "until")) add = "do";
+      else if (!strcmp(s, "case")) add = "esac";
+      else if (!strcmp(s, "{")) add = "}";
+      else if (!strcmp(s, "[[")) add = "]]";
+
+      // function NAME () [nl] { [nl] body ; }
+      // Why can you to declare functions inside other functions?
+      else if (arg->c>i+1 && !strcmp(arg->v[i+1], "(")) goto funky;
+      else if (!strcmp(s, "function")) {
+        i++;
+funky:
+        // At this point we can only have a function: barf if it's invalid
+        if (arg->c<i+3 || !strcmp(arg->v[i+1], "(")
+            || !strcmp(arg->v[i+2], ")"))
+        {
+          syntax_err("bad function ()");
+          goto flush;
+        }
+        dlist_add(&expect, "}");
+        dlist_add(&expect, 0);
+        dlist_add(&expect, "{");
+
+      // Expecting NULL will take any otherwise unrecognized word
+      } else if (expect && !ex) {
         free(dlist_pop(&expect));
         continue;
 
-      // Did we find a specific word we were waiting for?
-      } else if (ex && !strcmp(arg->v[i], ex)) {
+      // If we expect nothing and didn't just start a new flow control block,
+      // rest of statement is a command and arguments, so stop now
+      } else if (!ex) break;
+
+      if (add) continue;
+
+      // If we got here we expect a word to end this block: is this it?
+      if (!strcmp(arg->v[i], ex)) {
         free(dlist_pop(&expect));
+
+        // can't "if | then" or "while && do", only ; or newline works
         if (end && !strcmp(end, ";")) {
-          // can't if | then or while && do, only ; or newline counts
           syntax_err("bad %s", end);
           goto flush;
         }
-        if (!strcmp(s, "do")) dlist_add(&expect, "done");
-        else if (!strcmp(s, "then")) dlist_add(&expect, "fi\0A");
-        break;
+
+        // if it's a multipart block, what comes next?
+        if (!strcmp(s, "do")) ex = "done";
+        else if (!strcmp(s, "then")) add = "fi\0A";
       // fi could have elif, which queues a then.
-      } else if (ex && !strcmp(ex, "fi")) {
+      } else if (!strcmp(ex, "fi")) {
         if (!strcmp(s, "elif")) {
           free(dlist_pop(&expect));
-          dlist_add(&expect, "then");
+          add = "then";
         // catch duplicate else while we're here
         } else if (!strcmp(s, "else")) {
           if (ex[3] != 'A') {
@@ -391,23 +432,21 @@
             goto flush;
           }
           free(dlist_pop(&expect));
-          dlist_add(&expect, "fi\0B");
+          add = "fi\0B";
         }
-      } else break;
-
-      dlist_add(&expect, ex);
+      }
     }
-    // Record how the previous stanza ended
+    // Record how the previous stanza ended: ; | & ;; || && ;& ;;& |& NULL
     end = arg->v[arg->c];
   }
 
-  // If we need more lines to finish flow control...
-  // TODO: functions
-  if (expect) {
+  // Do we need more lines to finish a flow control statement?
+  if (expect || paren) {
     llist_traverse(expect, free);
     return start;
   }
 
+  // iterate through the commands running each one
   for (pl = *pipeline; pl ; pl = (pl->next == *pipeline) ? 0 : pl->next) {
     struct sh_process *pp = xzalloc(sizeof(struct sh_process));
 
@@ -445,7 +484,12 @@
     size_t linelen = 0;
 
     // Prompt and read line
-    if (!f) do_prompt(getenv(command ? "PS2" : "PS1"));
+    if (!f) {
+      char *s = getenv(command ? "PS2" : "PS1");
+
+      if (!s) s = command ? "> " : (getpid() ? "\\$ " : "# ");
+      do_prompt(s);
+    }
     if (1 > getline(&new, &linelen, f ? f : stdin)) break;
     if (f) TT.lineno++;