1 /*
   2  * Copyright (c) 2002, 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.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 /* @test
  25  * @bug 4763384
  26  * @summary Ensure that piped input always works with exec'd processes
  27  */
  28 
  29 import java.io.*;
  30 
  31 
  32 /**
  33  * This class demonstrates a regression in java1.4.1 in the handling of the
  34  * Process OutputStream (exec'd process stdin).  The subprocess completes 100%
  35  * of the time in 1.4, but about only about 50% of the time under 1.4.1.  Issue
  36  * exists for client JVM, Linux Redhat 6.2 not sure about other variants of
  37  * Linux or other OSes, or server JVM.
  38  */
  39 
  40 public class ExecWithInput {
  41 
  42     private static final int N = 200;
  43 
  44     static int go(int i) throws Exception {
  45         /*
  46          * Execute /bin/cat supplying two lines of input. cat should
  47          * read the input lines and copy them to stdout. On completion,
  48          * p.waitFor should return and the exit status is printed and this
  49          * program exits. Under 1.4.1, cat sometimes gets stuck on a pipe
  50          * read and never terminates.
  51          */
  52         Process p = Runtime.getRuntime().exec(UnixCommands.cat());
  53 
  54         String input = i + ": line 1\n" + i + ": line 2\n";
  55         StringBufferInputStream in = new StringBufferInputStream(input);
  56         // create threads to handle I/O streams
  57         IO ioIn = new IO("stdin", in, p.getOutputStream());
  58         IO ioOut = new IO("stdout", p.getInputStream(), System.out);
  59         IO ioErr = new IO("stderr", p.getErrorStream(), System.err);
  60 
  61         // wait for process to exit
  62         return p.waitFor();
  63     }
  64 
  65     public static void main(String[] args) throws Exception {
  66         if (! System.getProperty("os.name").startsWith("Linux")) {
  67             System.err.println("Only for Linux");
  68             return;
  69         }
  70         for (int i = 0; i < N; i++)
  71             go(i);
  72     }
  73 
  74     /**
  75      * Handle IO. Thread is started in constructor.
  76      */
  77     static class IO extends Thread {
  78 
  79         private InputStream in;
  80         private OutputStream out;
  81 
  82         IO(String name, InputStream in, OutputStream out)
  83         {
  84             this.in = in;
  85             this.out = out;
  86             setName(name);
  87             start();
  88         }
  89 
  90         public void run() {
  91             try {
  92                 byte[] buf = new byte[8192];
  93                 int n;
  94                 while ((n = in.read(buf)) != -1) {
  95                     out.write(buf, 0, n);
  96                     out.flush();
  97                 }
  98                 /*
  99                 while ((c = in.read()) != -1) {
 100                     out.write(c);
 101                     if (c == '\n')
 102                         out.flush();
 103                 }
 104                 out.flush();
 105                 */
 106             } catch (IOException e) {
 107                 e.printStackTrace();
 108             } finally {
 109                 if (!System.out.equals(out) && !System.err.equals(out)) {
 110                     // Note: in order to get an exec'd java process to
 111                     // see EOF on input, it is necessary to close stdin
 112                     if (out != null) {
 113                         try { out.close(); } catch (Exception e) {
 114                             e.printStackTrace();
 115                         }
 116                     }
 117                 }
 118             }
 119         }
 120     }
 121 
 122 }