Add basic job support to make.

Change-Id: I0e5640fe2e717dfdd56300e2aecb171aa6803157
diff --git a/job.c b/job.c
index 8124897..d9dec2c 100644
--- a/job.c
+++ b/job.c
@@ -76,6 +76,13 @@
 # define VMS_POSIX_EXIT_MASK (C_FACILITY_NO | 0xA000)
 #endif
 
+#elif defined (__Fuchsia__)
+#include <launchpad/launchpad.h>
+#include <launchpad/vmo.h>
+#include <magenta/syscalls.h>
+
+const char *default_shell = "/boot/bin/sh";
+int batch_mode_shell = 0;
 #else
 
 const char *default_shell = "/bin/sh";
@@ -587,6 +594,10 @@
       pid_t pid;
       int exit_code, exit_sig, coredump;
       struct child *lastc, *c;
+#ifdef __Fuchsia__
+      int mx_status = ERR_TIMED_OUT;
+      mx_signals_t pending_signals = 0;
+#endif
       int child_failed;
       int any_remote, any_local;
       int dontcare;
@@ -670,6 +681,44 @@
               /* A Posix failure can be exactly translated */
               if ((c->cstatus & VMS_POSIX_EXIT_MASK) == VMS_POSIX_EXIT_MASK)
                 status = (c->cstatus >> 3 & 255) << 8;
+#elif defined(__Fuchsia__)
+              status = 0;
+              pid = 0;
+
+              do
+                {
+                  for (c = children; c != 0; c = c->next)
+                    {
+                      mx_status = mx_handle_wait_one
+                                    (c->pid, MX_TASK_TERMINATED, 0,
+                                     &pending_signals);
+
+                      /* If we get any other status, something has gone
+                         wildly off the rails. Unfortunately, the API for
+                         this function doesn't allow us to, for example,
+                         report that the child handle is invalid.  */
+                      assert (mx_status == NO_ERROR
+                              || mx_status == ERR_TIMED_OUT);
+
+                      /* mx_status will always be ERR_TIMED_OUT when
+                         we do a non-blocking wait, so we have to look
+                         at pending_signals to discover an exited
+                         child.  */
+                      if (pending_signals)
+                        {
+                          mx_info_process_t proc_info;
+
+                          mx_status = mx_object_get_info
+                                        (c->pid, MX_INFO_PROCESS, &proc_info,
+                                         sizeof (proc_info), NULL, NULL);
+                          if (mx_status == NO_ERROR)
+                            status = proc_info.return_code;
+
+                          pid = c->pid;
+                          break;
+                        }
+                    }
+                } while (block && !pending_signals);
 #else
 #ifdef WAIT_NOHANG
               if (!block)
@@ -1395,8 +1444,11 @@
       if (child->pid < 0)
         {
           /* Fork failed!  */
+          /* Fuchsia prints an error on failure in child_execute_job.  */
+#ifndef __Fuchsia__
           unblock_sigs ();
           perror_with_name ("fork", "");
+#endif
           goto error;
         }
 #endif /* !VMS */
@@ -2113,6 +2165,100 @@
   return pid;
 }
 
+#elif defined (__Fuchsia__)
+/* Fuchsia:
+   Create a child process executing the command in ARGV.
+   ENVP is the environment of the new program.  Returns the PID or -1.  */
+int
+child_execute_job (struct output *out, int good_stdin, char **argv, char **envp)
+{
+  launchpad_t *lp = NULL;
+  mx_handle_t child_job = MX_HANDLE_INVALID;
+  mx_handle_t this_job = launchpad_get_mxio_job ();
+  mx_status_t status;
+  int argc;
+  mx_handle_t result = -1;
+
+  /* Copy privileges.  */
+  if (this_job != MX_HANDLE_INVALID)
+    mx_handle_duplicate (this_job, MX_RIGHT_SAME_RIGHTS, &child_job);
+
+  status = launchpad_create (child_job, argv[0], &lp);
+  if (status != NO_ERROR)
+    goto done_noalloc;
+
+  status = launchpad_elf_load (lp, launchpad_vmo_from_file (argv[0]));
+  if (status != NO_ERROR)
+    goto done;
+
+  status = launchpad_load_vdso (lp, MX_HANDLE_INVALID);
+  if (status != NO_ERROR)
+    goto done;
+
+  status = launchpad_add_vdso_vmo (lp);
+  if (status != NO_ERROR)
+    goto done;
+
+  /* We have to tell launchpad how many arguments.  */
+  for (argc = 0; argv[argc]; argc++)
+    ;
+
+  status = launchpad_arguments (lp, argc, (const char * const *) argv);
+  if (status != NO_ERROR)
+    goto done;
+
+  status = launchpad_environ (lp, (const char * const *) envp);
+  if (status != NO_ERROR)
+    goto done;
+
+  status = launchpad_clone_mxio_root (lp);
+  if (status != NO_ERROR)
+    goto done;
+
+  status = launchpad_clone_mxio_cwd (lp);
+  if (status != NO_ERROR)
+    goto done;
+
+  /* Copy descriptors, but don't make stdin available to the child.  */
+  if (out && out->syncout)
+    {
+      if (out->out >= 0)
+        status = launchpad_clone_fd (lp, out->out, FD_STDOUT);
+      else
+        status = launchpad_clone_fd (lp, FD_STDOUT, FD_STDOUT);
+
+      if (status != NO_ERROR)
+        goto done;
+
+      if (out->err >= 0)
+        status = launchpad_clone_fd (lp, out->err, FD_STDERR);
+      else
+        status = launchpad_clone_fd (lp, FD_STDERR, FD_STDERR);
+    }
+  else
+    {
+      status = launchpad_clone_fd (lp, FD_STDOUT, FD_STDOUT);
+      if (status != NO_ERROR)
+        goto done;
+
+      status = launchpad_clone_fd (lp, FD_STDERR, FD_STDERR);
+    }
+
+  if (status == NO_ERROR)
+    result = launchpad_start (lp);
+
+done:
+  launchpad_destroy (lp);
+
+done_noalloc:
+  if (status != NO_ERROR)
+    O (error, NILF, _("launchpad: failure to launch"));
+
+  if (result > 0)
+    return (int) result;
+  else
+    return -1;
+}
 #elif !defined (_AMIGA) && !defined (__MSDOS__) && !defined (VMS)
 
 /* POSIX: