1 /*
   2  * Copyright (c) 2003, 2010, Oracle and/or its affiliates. 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.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle 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 Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package java.lang;
  27 
  28 import java.io.IOException;
  29 import java.io.FileInputStream;
  30 import java.io.FileOutputStream;
  31 import java.lang.ProcessBuilder.Redirect;
  32 import java.lang.ProcessBuilder.Redirect;
  33 
  34 /**
  35  * This class is for the exclusive use of ProcessBuilder.start() to
  36  * create new processes.
  37  *
  38  * @author Martin Buchholz
  39  * @since   1.5
  40  */
  41 final class ProcessImpl {
  42     private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
  43         = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
  44 
  45     private ProcessImpl() {}    // Not instantiable
  46 
  47     private static byte[] toCString(String s) {
  48         if (s == null)
  49             return null;
  50         byte[] bytes = s.getBytes();
  51         byte[] result = new byte[bytes.length + 1];
  52         System.arraycopy(bytes, 0,
  53                          result, 0,
  54                          bytes.length);
  55         result[result.length-1] = (byte)0;
  56         return result;
  57     }
  58 
  59     // Only for use by ProcessBuilder.start()
  60     static Process start(String[] cmdarray,
  61                          java.util.Map<String,String> environment,
  62                          String dir,
  63                          ProcessBuilder.Redirect[] redirects,
  64                          boolean redirectErrorStream)
  65         throws IOException
  66     {
  67         assert cmdarray != null && cmdarray.length > 0;
  68 
  69         // Convert arguments to a contiguous block; it's easier to do
  70         // memory management in Java than in C.
  71         byte[][] args = new byte[cmdarray.length-1][];
  72         int size = args.length; // For added NUL bytes
  73         for (int i = 0; i < args.length; i++) {
  74             args[i] = cmdarray[i+1].getBytes();
  75             size += args[i].length;
  76         }
  77         byte[] argBlock = new byte[size];
  78         int i = 0;
  79         for (byte[] arg : args) {
  80             System.arraycopy(arg, 0, argBlock, i, arg.length);
  81             i += arg.length + 1;
  82             // No need to write NUL bytes explicitly
  83         }
  84 
  85         int[] envc = new int[1];
  86         byte[] envBlock = ProcessEnvironment.toEnvironmentBlock(environment, envc);
  87 
  88         int[] std_fds;
  89 
  90         FileInputStream  f0 = null;
  91         FileOutputStream f1 = null;
  92         FileOutputStream f2 = null;
  93 
  94         try {
  95             if (redirects == null) {
  96                 std_fds = new int[] { -1, -1, -1 };
  97             } else {
  98                 std_fds = new int[3];
  99 
 100                 if (redirects[0] == Redirect.PIPE)
 101                     std_fds[0] = -1;
 102                 else if (redirects[0] == Redirect.INHERIT)
 103                     std_fds[0] = 0;
 104                 else {
 105                     f0 = new FileInputStream(redirects[0].file());
 106                     std_fds[0] = fdAccess.get(f0.getFD());
 107                 }
 108 
 109                 if (redirects[1] == Redirect.PIPE)
 110                     std_fds[1] = -1;
 111                 else if (redirects[1] == Redirect.INHERIT)
 112                     std_fds[1] = 1;
 113                 else {
 114                     f1 = new FileOutputStream(redirects[1].file(),
 115                                               redirects[1].append());
 116                     std_fds[1] = fdAccess.get(f1.getFD());
 117                 }
 118 
 119                 if (redirects[2] == Redirect.PIPE)
 120                     std_fds[2] = -1;
 121                 else if (redirects[2] == Redirect.INHERIT)
 122                     std_fds[2] = 2;
 123                 else {
 124                     f2 = new FileOutputStream(redirects[2].file(),
 125                                               redirects[2].append());
 126                     std_fds[2] = fdAccess.get(f2.getFD());
 127                 }
 128             }
 129 
 130         return new UNIXProcess
 131             (toCString(cmdarray[0]),
 132              argBlock, args.length,
 133              envBlock, envc[0],
 134              toCString(dir),
 135                  std_fds,
 136              redirectErrorStream);
 137         } finally {
 138             // In theory, close() can throw IOException
 139             // (although it is rather unlikely to happen here)
 140             try { if (f0 != null) f0.close(); }
 141             finally {
 142                 try { if (f1 != null) f1.close(); }
 143                 finally { if (f2 != null) f2.close(); }
 144             }
 145         }
 146     }
 147 }