Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4039120

Pipes don't work with child processes under certain circumstances

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P3 P3
    • None
    • 1.1
    • core-libs
    • None
    • x86
    • windows_nt

      Name: mc57594 Date: 03/14/97


      There are two related problems here. The first is that pipes to
      and from child processes don't work. The second is ( I believe)
      related. The first is described in comments in the code.
      CommandStreamEditor.doPipe is the method to look at.

      The second problem is that when a command shell is launched as a
      child, and used to launch another child
      ( something like cmd /c tar --help ), the command processor opens
      a fullscreen window and sends stdout to the window. The window closes
      and nothing comes back to the parent of the command shell. After
      doing some MSVC ( ewww ) research, I thought
      this may be because the command shell is launched with options
      indicating that handles should be non-inheritable.

      You can see this by doing something like

      dir | java CommandStreamEditor

      or

      java CommandStreamEditor someparam

      then type in the name of an executable on the path that writes to stdout.

      I've set it up so that if there's nothing in the lower window,
      nothing will be sent to the child process. That seems to be
      part of the problem - see the comments.

      Anyways, here's the source:

      =======================================
      import java.awt.*;
      import java.io.*;

      /**
      This class reads from stdin, displays what's there in
      an editable window. When the window is closed, the contents
      are sent to stdout.
      */
      class BasicStreamEditor extends Frame
      {
      private TextArea editWindow;
      protected String args[];

      public BasicStreamEditor ( String someArgs[] )
      {
      super();
      args = someArgs;
      setTitle ( getClass().getName() );
      createLayout();
      }

      protected void createLayout()
      {
      // make the area where input is displayed
      // and which can be edited for the output
      editWindow = new TextArea();
      editWindow.setForeground ( SystemColor.textText );
      editWindow.setBackground ( SystemColor.text );
      editWindow.setFont ( new Font ( "Dauphin", Font.PLAIN, 20 ) );
      add ( "Center", editWindow );
      }

      public boolean handleEvent(Event event)
      {
      if (event.id == Event.WINDOW_DESTROY)
      {
      // send the contents of the edit area to stdout
      System.out.print ( getContents() );
      System.exit(0);
      }
      return super.handleEvent(event);
          }

      public void setContents ( Reader anInput )
      throws IOException
      {
      BufferedReader input = new BufferedReader ( anInput );

      StringBuffer buffer = new StringBuffer ( "" );
      String next;

      // can't use input.ready() or input.available here
      while ( ( next = input.readLine() ) != null )
      {
      buffer.append ( input.readLine() );
      buffer.append ( "\n" );
      }
      editWindow.setText ( buffer.toString() );
      }

      // convenience method for InputStream, rather than Reader.
      // Silly dichotomy that... ;-)
      public void setContents ( InputStream anInput )
      {
      try
      {
      setContents ( new BufferedReader ( new InputStreamReader ( anInput ) ) );
      }
      catch ( IOException exception )
      {
      editWindow.setText ( "Error\n" );
      }
      }

      public String getContents()
      {
      return editWindow.getText();
      }

      public void startEditor()
      {
      if ( args.length == 0 )
      {
      try
      {
      setContents ( System.in );
      }
      catch ( Exception exception )
      {
      System.err.println ( exception.getMessage() );
      exception.printStackTrace();
      System.exit(0);
      }
      }

      pack();
      show();
      // put the cursor in the edit area
      editWindow.requestFocus();
      }

      // if there are no arguments then stdin is read. Otherwise
      // not. This is mainly to allow for debugging.
      public static void main ( String args[] )
      throws IOException
      {
      BasicStreamEditor instance = new BasicStreamEditor( args );
      instance.startEditor();
      }
      }
      =======================================
      import java.awt.*;
      import java.awt.event.*;
      import java.io.*;
      import java.util.*;

      class CommandStreamEditor
      extends BasicStreamEditor
      implements ActionListener
      {
      private TextField commandLine;
      private Process child;

      public CommandStreamEditor ( String someArgs[] )
      {
      super ( someArgs );
      }

      protected void createLayout()
      {
      super.createLayout();

      // make the text field into which commands can be typed
      commandLine = new TextField();
      commandLine.addActionListener ( this );
      commandLine.setForeground ( SystemColor.textText );
      commandLine.setBackground ( SystemColor.text );
      commandLine.setFont ( new Font ( "Lucida Console", Font.PLAIN, 10 ) );
      add ( "North", commandLine );
      }

      public void actionPerformed ( ActionEvent event)
      {
      // catch the enter pressed
      doPipe();
      }

      // make a child process. Send the contents of the edit window
      // to the stdin of the process, and retrieve the stdout of the
      // process. Replace the contents of the edit window with the
      // contents of stdout from the process.
      protected void doPipe()
      {
      try
      {
      // get the string that allows child processes and
      // shell commands to be executed
      /*
      Properties localProperties = new Properties();
      localProperties.load ( new FileInputStream ( "properties" ) );
      // run the specified child command
      child = Runtime.getRuntime().exec (
      localProperties.getProperty( "shellExecChild" ) + " " + commandLine.getText()
      );
      */
      // Does this exec allow children of child to inherit
      // child's file handles ( stdin stdout and stderr) ?
      // It seems not because a command shell ( cmd.exe or 4nt.exe ) // trying to execute its own child
      // process seems to always open its own window. The std out from that child
      // process always appears ( briefly ) in the window,
      // but never gets back to here.
      // This bug also affects the CgiServlet in Java Server.
      child = Runtime.getRuntime().exec ( commandLine.getText() );

      if ( getContents().length() != 0 )
      {
      try
      {
      // send the contents of the TextArea to the child command
      System.err.println ( "make toChild" );
      OutputStreamWriter toChild = new OutputStreamWriter ( child.getOutputStream() );
      System.err.println ( "send contents" );
      toChild.write ( getContents() );

      // make sure the child knows where the pipe ends
      System.err.println ( "Flushing..." );
      // it stops and waits forever here if the child process
      // is ignoring stdin
      // But if the child process is killed from somewhere else
      // this thread keeps going...
      toChild.flush();
      System.err.println ( "closing..." );
      toChild.close();
      System.err.println ( "closed" );
      }
      catch ( IOException e )
      {
      System.err.println ( "Error sending contents" );
      }
      }

      // get the output from the child command
      System.err.println ( "getting input..." );

      // if a process does accept input from stdin,
      // then we wait here forever.
      // But: if no attempt is made to send input to the
      // child, this line works OK.
      // If the child process is killed from somewhere else
      // most of its ouput is picked up.
      setContents ( child.getInputStream() );
      System.err.println ( "got input" );

      // make sure gc happens
      child = null;
      }
      catch ( IOException exception )
      {
      exception.printStackTrace();
      }
      }

      // override this to get focus to the right component
      public void startEditor()
      {
      super.startEditor();
      commandLine.requestFocus();
      }

      static public void main ( String args[] )
      {
      CommandStreamEditor instance = new CommandStreamEditor ( args );

      instance.startEditor();
      }
      }

      company - Semiosix , email - ###@###.###
      ======================================================================

            hongzh Hong Zhang
            mchamnessunw Mark Chamness (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: