OSDN Git Service

Make defconfig build for nommu.
authorRob Landley <rob@landley.net>
Tue, 29 Sep 2015 10:09:46 +0000 (05:09 -0500)
committerRob Landley <rob@landley.net>
Tue, 29 Sep 2015 10:09:46 +0000 (05:09 -0500)
Adds XVFORK() macro, teaches xpopen_both() to call /proc/self/exe with NULL
argv (and converts cpio -p to use that), adds TOYBOX_FORK guards to some
unconverted commands.

14 files changed:
lib/lib.h
lib/xwrap.c
scripts/config2help.c
toys.h
toys/other/login.c
toys/other/nbd_client.c
toys/other/netcat.c
toys/other/nsenter.c
toys/other/setsid.c
toys/other/timeout.c
toys/pending/arping.c
toys/posix/cpio.c
toys/posix/time.c
toys/posix/xargs.c

index d76dcc0..90f44dc 100644 (file)
--- a/lib/lib.h
+++ b/lib/lib.h
@@ -247,17 +247,8 @@ void mode_to_string(mode_t mode, char *buf);
 char *basename_r(char *name);
 void names_to_pid(char **names, int (*callback)(pid_t pid, char *name));
 
-// Returning from a function can modify a potentially shared stack,
-// so this has to always inline.
-static inline pid_t xvfork(void)
-{
-  pid_t p;
-
-  toys.stacktop = 0;
-  if ((p = vfork()) == -1) perror_exit("vfork");
-
-  return p;
-}
+pid_t xvforkwrap(pid_t pid);
+#define XVFORK() xvforkwrap(vfork())
 
 // Functions in need of further review/cleanup
 #include "lib/pending.h"
index e5dc482..4880bbe 100644 (file)
@@ -129,6 +129,20 @@ void xflush(void)
   if (fflush(stdout) || ferror(stdout)) perror_exit("write");;
 }
 
+// This is called through the XVFORK macro because parent/child of vfork
+// share a stack, so child returning from a function would stomp the return
+// address parent would need. Solution: make vfork() an argument so processes
+// diverge before function gets called.
+pid_t xvforkwrap(pid_t pid)
+{
+  if (pid == -1) perror_exit("vfork");
+
+  // Signal to xexec() and friends that we vforked so can't recurse
+  toys.stacktop = 0;
+
+  return pid;
+}
+
 // Die unless we can exec argv[] (or run builtin command).  Note that anything
 // with a path isn't a builtin, so /bin/sh won't match the builtin sh.
 void xexec(char **argv)
@@ -144,25 +158,27 @@ void xexec(char **argv)
 }
 
 // Spawn child process, capturing stdin/stdout.
-// argv[]: command to exec. If null, child returns to original program.
-// pipes[2]: stdin, stdout of new process. If -1 will not have pipe allocated.
+// argv[]: command to exec. If null, child re-runs original program with
+//         toys.stacktop zeroed.
+// pipes[2]: stdin, stdout of new process, only allocated if zero on way in,
+//           pass NULL to skip pipe allocation entirely.
 // return: pid of child process
 pid_t xpopen_both(char **argv, int *pipes)
 {
   int cestnepasun[4], pid;
 
-  // Make the pipes? Not this won't set either pipe to 0 because if fds are
+  // Make the pipes? Note this won't set either pipe to 0 because if fds are
   // allocated in order and if fd0 was free it would go to cestnepasun[0]
   if (pipes) {
     for (pid = 0; pid < 2; pid++) {
-      if (pipes[pid] == -1) continue;
+      if (pipes[pid] != 0) continue;
       if (pipe(cestnepasun+(2*pid))) perror_exit("pipe");
       pipes[pid] = cestnepasun[pid+1];
     }
   }
 
-  // Child process
-  if (!(pid = xfork())) {
+  // Child process.
+  if (!(pid = CFG_TOYBOX_FORK ? xfork() : XVFORK())) {
     // Dance of the stdin/stdout redirection.
     if (pipes) {
       // if we had no stdin/out, pipe handles could overlap, so test for it
@@ -181,16 +197,31 @@ pid_t xpopen_both(char **argv, int *pipes)
         if (cestnepasun[3] > 2 || !cestnepasun[3]) close(cestnepasun[3]);
       }
     }
-    if (argv) {
-      if (CFG_TOYBOX) toy_exec(argv);
-      execvp(argv[0], argv);
+    if (argv) xexec(argv);
+
+    // In fork() case, force recursion because we know it's us.
+    if (CFG_TOYBOX_FORK) {
+      toy_init(toys.which, toys.argv);
+      toys.stacktop = 0;
+      toys.which->toy_main();
+      xexit();
+    // In vfork() case, exec /proc/self/exe with high bit of first letter set
+    // to tell main() we reentered.
+    } else {
+      char *s = "/proc/self/exe";
+
+      // We did a nommu-friendly vfork but must exec to continue.
+      // setting high bit of argv[0][0] to let new process know
+      **toys.argv |= 0x80;
+      execv(s, toys.argv);
+      perror_msg(s);
+
       _exit(127);
     }
-    return 0;
-
   }
 
   // Parent process
+  if (!CFG_TOYBOX_FORK) **toys.argv &= 0x7f;
   if (pipes) {
     if (pipes[0] != -1) close(cestnepasun[0]);
     if (pipes[1] != -1) close(cestnepasun[3]);
index 2ed189a..f3bb8c3 100644 (file)
@@ -5,6 +5,7 @@ struct toy_context toys;
 char libbuf[4096], toybuf[4096];
 void show_help(FILE *out) {;}
 void toy_exec(char *argv[]) {;}
+void toy_init(struct toy_list *which, char *argv[]) {;}
 
 // Parse config files into data structures.
 
diff --git a/toys.h b/toys.h
index d8efa66..9c33ff2 100644 (file)
--- a/toys.h
+++ b/toys.h
 #include <sys/statfs.h>
 #include <sys/sysinfo.h>
 
+#include "lib/lib.h"
+#include "lib/lsm.h"
+#include "toys/e2fs.h"
+
+// Get list of function prototypes for all enabled command_main() functions.
+
+#define NEWTOY(name, opts, flags) void name##_main(void);
+#define OLDTOY(name, oldname, flags) void oldname##_main(void);
+#include "generated/newtoys.h"
+#include "generated/flags.h"
+#include "generated/globals.h"
+
 // These live in main.c
 
 struct toy_list *toy_find(char *name);
@@ -132,15 +144,3 @@ extern char **environ;
 #define GLOBALS(...)
 
 #define ARRAY_LEN(array) (sizeof(array)/sizeof(*array))
-
-#include "lib/lib.h"
-#include "lib/lsm.h"
-#include "toys/e2fs.h"
-
-// Get list of function prototypes for all enabled command_main() functions.
-
-#define NEWTOY(name, opts, flags) void name##_main(void);
-#define OLDTOY(name, oldname, flags) void oldname##_main(void);
-#include "generated/newtoys.h"
-#include "generated/flags.h"
-#include "generated/globals.h"
index c727bf9..7f9559a 100644 (file)
@@ -159,9 +159,7 @@ void login_main(void)
   syslog(LOG_INFO, "%s logged in on %s %s %s", pwd->pw_name,
     ttyname(tty), hh ? "from" : "", hh ? TT.hostname : "");
 
-  // can't xexec here because name doesn't match argv[0]
-  snprintf(toybuf, sizeof(toybuf)-1, "-%s", basename_r(pwd->pw_shell));
-  toy_exec((char *[]){toybuf, 0});
-  execl(pwd->pw_shell, toybuf, NULL);
-  error_exit("Failed to spawn shell");
+  // not using xexec(), login calls absolute path from filesystem so must exec()
+  execl(pwd->pw_shell, xmprintf("-%s", pwd->pw_shell), (char *)0);
+  perror_exit("exec shell '%s'", pwd->pw_shell);
 }
index a82ff7c..3ad366f 100644 (file)
@@ -12,6 +12,7 @@ USE_NBD_CLIENT(OLDTOY(nbd-client, nbd_client, TOYFLAG_USR|TOYFLAG_BIN))
 
 config NBD_CLIENT
   bool "nbd-client"
+  depends on TOYBOX_FORK
   default y
   help
     usage: nbd-client [-ns] HOST PORT DEVICE
index 3cc3f0a..1c75eb2 100644 (file)
@@ -26,10 +26,10 @@ config NETCAT_LISTEN
   bool "netcat server options (-let)"
   default y
   depends on NETCAT
+  depends on TOYBOX_FORK
   help
-    usage: netcat [-t] [-lL COMMAND...]
+    usage: netcat [-lL COMMAND...]
 
-    -t allocate tty (must come before -l or -L)
     -l listen for one incoming connection.
     -L listen for multiple incoming connections (server mode).
 
@@ -38,6 +38,16 @@ config NETCAT_LISTEN
 
     For a quick-and-dirty server, try something like:
     netcat -s 127.0.0.1 -p 1234 -tL /bin/bash -l
+
+config NETCAT_LISTEN_TTY
+  bool
+  default y
+  depends on NETCAT_LISTEN
+  depends on TOYBOX_FORK
+  help
+    usage: netcat [-t]
+
+    -t allocate tty (must come before -l or -L)
 */
 
 #define FOR_netcat
@@ -139,7 +149,7 @@ void netcat_main(void)
       // Do we need to return immediately because -l has arguments?
 
       if ((toys.optflags & FLAG_l) && toys.optc) {
-        if (xfork()) goto cleanup;
+        if (CFG_TOYBOX_FORK && xfork()) goto cleanup;
         close(0);
         close(1);
         close(2);
@@ -161,7 +171,10 @@ void netcat_main(void)
         // Do we need to fork and/or redirect for exec?
 
         else {
-          if (toys.optflags&FLAG_L) child = fork();
+          if (toys.optflags&FLAG_L) {
+            toys.stacktop = 0;
+            child = vfork();
+          }
           if (!child && toys.optc) {
             int fd = pollfds[0].fd;
 
@@ -183,7 +196,7 @@ void netcat_main(void)
   // (Does not play well with -L, but what _should_ that do?)
   set_alarm(0);
 
-  if (CFG_NETCAT_LISTEN && (toys.optflags&(FLAG_L|FLAG_l) && toys.optc))
+  if (CFG_NETCAT_LISTEN && ((toys.optflags&(FLAG_L|FLAG_l)) && toys.optc))
     xexec(toys.optargs);
 
   // Poll loop copying stdin->socket and socket->stdout.
index 18a2cd2..bda77ac 100644 (file)
@@ -1,14 +1,14 @@
 /* nsenter.c - Enter existing namespaces
  *
- * Copyright 2014 andy Lutomirski <luto@amacapital.net>
+ * Copyright 2014 Andy Lutomirski <luto@amacapital.net>
  *
- * No standard
+ * See http://man7.org/linux/man-pages/man1/nsenter.1.html
  *
  * unshare.c - run command in new context
  *
  * Copyright 2011 Rob Landley <rob@landley.net>
  *
- * No Standard
+ * See http://man7.org/linux/man-pages/man1/unshare.1.html
  *
 
 // Note: flags go in same order (right to left) for shared subset
@@ -149,12 +149,9 @@ void unshare_main(void)
     }
 
     if ((toys.optflags & FLAG_p) && !(toys.optflags & FLAG_F)) {
-      pid_t pid = xfork();
+      toys.exitval = xrun(toys.optargs);
 
-      if (pid) {
-        while (waitpid(pid, 0, 0) == -1 && errno == EINTR);
-        return;
-      }
+      return;
     }
   }
 
index 83db044..9569826 100644 (file)
@@ -19,7 +19,7 @@ config SETSID
 
 void setsid_main(void)
 {
-  while (setsid()<0) if (xvfork()) _exit(0);
+  while (setsid()<0) if (XVFORK()) _exit(0);
   if (toys.optflags) {
     setpgid(0, 0);
     tcsetpgrp(0, getpid());
index bd716e6..0e912f7 100644 (file)
@@ -62,14 +62,10 @@ void timeout_main(void)
   if (TT.s_signal && -1 == (TT.nextsig = sig_to_num(TT.s_signal)))
     error_exit("bad -s: '%s'", TT.s_signal);
 
-  if (!(TT.pid = xvfork())) xexec(toys.optargs+1);
+  if (!(TT.pid = XVFORK())) xexec(toys.optargs+1);
   else {
-    int status;
-
     xsignal(SIGALRM, handler);
     setitimer(ITIMER_REAL, &TT.itv, (void *)toybuf);
-    while (-1 == waitpid(TT.pid, &status, 0) && errno == EINTR);
-    toys.exitval = WIFEXITED(status)
-      ? WEXITSTATUS(status) : WTERMSIG(status) + 127;
+    toys.exitval = xwaitpid(TT.pid);
   }
 }
index 3e522bd..be43cab 100644 (file)
@@ -39,15 +39,9 @@ GLOBALS(
     char *src_ip;
 
     int sockfd;
-    unsigned start;
-    unsigned end;
-    unsigned sent_at;
-    unsigned sent_nr;
-    unsigned rcvd_nr;
-    unsigned brd_sent;
-    unsigned rcvd_req;
-    unsigned brd_rcv;
-    unsigned unicast_flag;
+    unsigned long start, end;
+    unsigned sent_at, sent_nr, rcvd_nr, brd_sent, rcvd_req, brd_rcv,
+             unicast_flag;
 )
 
 struct sockaddr_ll src_pk, dst_pk; 
index 312bb93..a442f0d 100644 (file)
@@ -82,12 +82,15 @@ void cpio_main(void)
   // In passthrough mode, parent stays in original dir and generates archive
   // to pipe, child does chdir to new dir and reads archive from stdin (pipe).
   if (TT.pass) {
-    if (!(pid = xpopen(0, &pipe, 0))) {
+    if (toys.stacktop) {
+      // xpopen() doesn't return from child due to vfork(), instead restarts
+      // with !toys.stacktop
+      pid = xpopen(0, &pipe, 0);
+      afd = pipe;
+    } else {
+      // child
       toys.optflags |= FLAG_i;
       xchdir(TT.pass);
-    } else {
-      toys.optflags |= FLAG_o;
-      afd = pipe;
     }
   }
 
index b3cfd26..2151826 100644 (file)
@@ -28,7 +28,7 @@ void time_main(void)
   struct timeval tv, tv2;
 
   gettimeofday(&tv, NULL);
-  if (!(pid = xvfork())) xexec(toys.optargs);
+  if (!(pid = XVFORK())) xexec(toys.optargs);
   else {
     int stat;
     struct rusage ru;
index 50c4262..b4cb80a 100644 (file)
@@ -111,6 +111,7 @@ void xargs_main(void)
   struct double_list *dlist = NULL, *dtemp;
   int entries, bytes, done = 0, status;
   char *data = NULL, **out;
+  pid_t pid;
 
   if (!(toys.optflags & FLAG_0)) TT.delim = '\n';
 
@@ -168,8 +169,7 @@ void xargs_main(void)
     for (dtemp = dlist; dtemp; dtemp = dtemp->next)
       handle_entries(dtemp->data, out+entries);
 
-    pid_t pid=xvfork();
-    if (!pid) {
+    if (!(pid = XVFORK())) {
       xclose(0);
       open("/dev/null", O_RDONLY);
       xexec(out);