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 }