1 /*
   2  * Copyright 2009 Sun Microsystems, Inc.  All Rights Reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Sun designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Sun in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
  22  * CA 95054 USA or visit www.sun.com if you need additional information or
  23  * have any questions.
  24  */
  25 
  26 #include <sys/types.h>
  27 #include <sys/stat.h>
  28 #include <fcntl.h>
  29 #include <stdlib.h>
  30 #include <stdio.h>
  31 #include <signal.h>
  32 #include <dirent.h>
  33 #include <string.h>
  34 #include <errno.h>
  35 #include <limits.h>
  36 #include <unistd.h>
  37 
  38 #include "processutil_md.h"
  39 
  40 /* 
  41  * Utility used by j.l.ProcessBuilder (via UNIXProcess) to launch
  42  * target commands. This (small) binary is launched via posix_spawn.
  43  * It sets up the required environment for the target and then
  44  * execs the target.
  45  * 
  46  * argv[0] target command
  47  * argv[1] working directory for command
  48  * argv[2] = string containing fd numbers of pipes created in the parent
  49  *              in following order:
  50  *              stdinfd stdoutfd stderrfd statuspipe
  51  * argv[3] = "1" redirect stderr to stdout, "0" don't
  52  * argv[4]+  args to target
  53  *
  54  * The std{in,out,err} fds must be moved to their correct numbers first
  55  * and the temporary pipe fd is also moved to position 3
  56  * Then all fds above this are closed.
  57  *
  58  * Target environment (comprising null terminated strings)
  59  * preceded by total byte length and number of strings
  60  * are sent down the pipe. if these two initial vals are -1, then 
  61  * there is no environment.
  62  * 
  63  * Response message sent up pipe to VM, if an error occurs:
  64  *
  65  * - Msg type (4 bytes)
  66  *      1 = chdir error (detail in Field 1)
  67  *      2 = exec error (detail in Field 1)
  68  *      3 = target terminated (exit code in Field 1)
  69  * - Field 1 (4 bytes)
  70  *
  71  * Assuming no error occured, the pipe will be set to close on exec
  72  * and the parent will see EOF on its side of the pipe. This indicates
  73  * a successful launch of the target.
  74  */
  75 
  76 static int stdinfd, stdoutfd, stderrfd, pipefd;
  77 
  78 static void reply (int first, int second) {
  79     int response[2];
  80     response[0] = first; 
  81     response[1] = second;
  82     write (pipefd, &response[0], sizeof(response));
  83 }
  84 
  85 void *jlup_xmalloc (void *env, int size) {
  86     return malloc (size);
  87 }
  88 
  89 int main (int argc, char *argv[]) {
  90    
  91     int err;
  92     int child;
  93     int envL; /* size of child environment */
  94     int nenv; /* number of entries in child environment */
  95     int flags, stderrIsPipe, redirectStderr;
  96     const char **env, *ptr;
  97     char name [256];
  98     const char *nullptr = 0;
  99     struct sigaction sa;
 100     FILE *f;
 101     
 102     jlup_initialize (NULL);
 103     sa.sa_handler = SIG_DFL;
 104     sigemptyset(&sa.sa_mask);
 105     sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
 106     sigaction(SIGCHLD, &sa, NULL);
 107 
 108     if (sscanf (argv[2], "%d %d %d %d", &stdinfd, &stdoutfd, &stderrfd, 
 109                                 &pipefd) != 4) {
 110         reply (2, 0);
 111         exit (0);
 112     }
 113 
 114     if (*argv[1] != 0) {
 115         err = chdir (argv[1]);
 116         if (err != 0) {
 117             reply (1, errno);
 118             exit (0);
 119         }
 120     }
 121   
 122     flags = atoi (argv[3]);
 123     redirectStderr = flags & 0x1;
 124     stderrIsPipe = flags & 0x2;
 125 
 126     argv [3] = argv [0]; /* overwrite the args just handled */
 127 
 128     jlup_moveDescriptor (stdinfd, 0);
 129     jlup_moveDescriptor (stdoutfd, 1);
 130     if (redirectStderr) {
 131         if (stderrIsPipe) {
 132             jlup_closeSafely (stderrfd);
 133         }
 134         dup2 (1, 2);
 135     } else {
 136         jlup_moveDescriptor (stderrfd, 2);
 137     }
 138     jlup_moveDescriptor (pipefd, 3); 
 139     pipefd = 3;
 140 
 141     if (jlup_closeDescriptors(4) ==0) {
 142         reply (2, errno);
 143         exit (0);
 144     }
 145     /* read child's environment */
 146     if (jlup_readFully(pipefd, &envL, sizeof(envL)) != sizeof(envL) ||
 147         jlup_readFully(pipefd, &nenv, sizeof(nenv)) != sizeof(nenv)) {
 148         reply (2, errno);
 149         exit (0);
 150     }
 151 
 152     if (envL == -1) {
 153         /* no environment */
 154         env = 0;
 155     } else if (envL != 0) {
 156         /* at least one entry in environment */
 157         ptr = malloc (envL);
 158         if (jlup_readFully(pipefd, (void *)ptr, envL) != envL) {
 159             reply (2, errno);
 160             exit (0);
 161         }
 162         env = malloc (sizeof(char *) * nenv);
 163         jlup_initVectorFromBlock (env, ptr, nenv);
 164     } else {
 165         /* empty environment */
 166         env = &nullptr;
 167     }
 168     err = fcntl (pipefd, F_SETFD, FD_CLOEXEC);
 169 
 170     jlup_execvpe ((const char * )argv[3], (const char * const*)&argv[3], env);
 171     reply (2, errno);
 172     exit (0);
 173     return 0; /* keep compiler happy */
 174 }