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
29import 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
40public 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 (! UnixCommands.isLinux) {
67            System.out.println("For Linux only");
68            return;
69        }
70        UnixCommands.ensureCommandsAvailable("cat");
71
72        for (int i = 0; i < N; i++)
73            go(i);
74    }
75
76    /**
77     * Handle IO. Thread is started in constructor.
78     */
79    static class IO extends Thread {
80
81        private InputStream in;
82        private OutputStream out;
83
84        IO(String name, InputStream in, OutputStream out)
85        {
86            this.in = in;
87            this.out = out;
88            setName(name);
89            start();
90        }
91
92        public void run() {
93            try {
94                byte[] buf = new byte[8192];
95                int n;
96                while ((n = in.read(buf)) != -1) {
97                    out.write(buf, 0, n);
98                    out.flush();
99                }
100                /*
101                while ((c = in.read()) != -1) {
102                    out.write(c);
103                    if (c == '\n')
104                        out.flush();
105                }
106                out.flush();
107                */
108            } catch (IOException e) {
109                e.printStackTrace();
110            } finally {
111                if (!System.out.equals(out) && !System.err.equals(out)) {
112                    // Note: in order to get an exec'd java process to
113                    // see EOF on input, it is necessary to close stdin
114                    if (out != null) {
115                        try { out.close(); } catch (Exception e) {
116                            e.printStackTrace();
117                        }
118                    }
119                }
120            }
121        }
122    }
123
124}
125