/* * CDE - Common Desktop Environment * * Copyright (c) 1993-2012, The Open Group. All rights reserved. * * These libraries and programs are free software; you can * redistribute them and/or modify them under the terms of the GNU * Lesser General Public License as published by the Free Software * Foundation; either version 2 of the License, or (at your option) * any later version. * * These libraries and programs are distributed in the hope that * they will be useful, but WITHOUT ANY WARRANTY; without even the * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU Lesser General Public License for more * details. * * You should have received a copy of the GNU Lesser General Public * License along with these libraries and programs; if not, write * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth * Floor, Boston, MA 02110-1301 USA */ /* * File: pipe.c $XConsortium: pipe.c /main/4 1996/04/21 19:10:09 drk $ * Language: C * * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved. * * (c) Copyright 1993, 1994 Hewlett-Packard Company * * (c) Copyright 1993, 1994 International Business Machines Corp. * * (c) Copyright 1993, 1994 Sun Microsystems, Inc. * * (c) Copyright 1993, 1994 Novell, Inc. * */ #include /* NOTE: sbport.h must be the first include. */ #include #include /*----------------------------------------------------------------------+*/ void pipe_channel_class_init(object_clasp t) /*----------------------------------------------------------------------+*/ { pipe_channel_clasp c = (pipe_channel_clasp) t; c->new_obj = alloc_channel_object; c->open = open_pipe_channel_object; c->close = close_local_channel_object; c->read = read_pipe_channel_object; c->write = write_local_channel_object; c->reset = reset_pipe_channel_object; c->pre_fork = pre_fork_pipe_channel_object; c->post_fork = post_fork_pipe_channel_object; c->exec_proc = exec_proc_local_channel_object; c->signal = signal_local_channel_object; c->wait_for_termination = local_channel_object_wait_for_termination; c->attach = attach_pipe_channel_object; c->add_input = add_input_pipe_channel_object; c->input = local_channel_object_input_handler; c->remove_logfile = remove_logfile_local_channel_object; /* New B.00 methods */ c->send_eof = local_channel_object_send_eof; c->set_termio = set_termio_noio_channel_object; } static struct pipe_channel_class pipe_channel_class_struct = { (channel_clasp) &channel_class, /* base class pointer */ "pipe_channel", /* class name */ pipe_channel_class_init, /* class initialize function */ sizeof(SPC_Channel), /* size */ 0 }; pipe_channel_clasp pipe_channel_class = &pipe_channel_class_struct; /*----------------------------------------------------------------------+*/ Wire *getpipe(Wire *prevwire) /*----------------------------------------------------------------------+*/ { Wire *wire_ptr=get_new_wire(); if(!wire_ptr) return(SPC_ERROR); wire_ptr->next=prevwire; /* Get file descriptors for pipe */ if (pipe(wire_ptr->fd) < OK) { SPC_Error(SPC_No_Pipe); XeFree(wire_ptr); return(SPC_ERROR); } return(wire_ptr); } /* *** *** Method definitions for pipe channel objects *** */ /* * This routine handles initialization for pipe channels */ /*----------------------------------------------------------------------+*/ SPC_Channel_Ptr open_pipe_channel_object(SPC_Channel_Ptr channel, int iomode, XeString hostname) /*----------------------------------------------------------------------+*/ { Wire *tmpwire=NULL; SPC_Channel_Ptr result; call_parent_method(channel, open, (channel, iomode, hostname), result); if(result==SPC_ERROR) return(SPC_ERROR); if (IS_SPCIO_STDIN(iomode)) { tmpwire=channel->wires[STDIN]=getpipe(NULL); if(!tmpwire) return(SPC_ERROR); } if (IS_SPCIO_STDOUT(iomode)) { tmpwire=channel->wires[STDOUT]=getpipe(tmpwire); if(!tmpwire) return(SPC_ERROR); } if(IS_SPCIO_STDERR(iomode)) { if (!tmpwire || IS_SPCIO_SEPARATE(iomode)) { tmpwire=channel->wires[STDERR]=getpipe(tmpwire); if(!tmpwire) return(SPC_ERROR); } else { channel->wires[STDERR]=channel->wires[STDOUT]; } } channel->file_descs[STDIN] =(channel->wires[STDIN]) ->fd[WRITE_SIDE]; channel->file_descs[STDOUT]=(channel->wires[STDOUT])->fd[READ_SIDE]; channel->file_descs[STDERR]=(channel->wires[STDERR])->fd[READ_SIDE]; channel->wire_list=tmpwire; return(channel); } /*----------------------------------------------------------------------+*/ int read_pipe_channel_object(SPC_Channel_Ptr channel, int connector, /* STDOUT or STDERR */ XeString buffer, int nbytes) /*----------------------------------------------------------------------+*/ { int result; call_parent_method(channel, read, (channel, connector, buffer, nbytes), result); if(result==Undefined) return(Undefined); do { result = read(channel->file_descs[connector], buffer, nbytes); } while (result<0 && errno == EINTR); if(result == 0) { SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input); SPC_Change_State(channel, connector, 0, -1); } return(result); } /*----------------------------------------------------------------------+*/ int pre_fork_pipe_channel_object(SPC_Channel_Ptr channel) /*----------------------------------------------------------------------+*/ { int result; call_parent_method(channel, pre_fork, (channel), result); if(result==SPC_ERROR) return(SPC_ERROR); return(TRUE); } /*----------------------------------------------------------------------+*/ int post_fork_pipe_channel_object(SPC_Channel_Ptr channel, int parentp) /*----------------------------------------------------------------------+*/ { int result; call_parent_method(channel, post_fork, (channel, parentp), result); if(result==SPC_ERROR) return(SPC_ERROR); if (parentp) { /* Master process */ spc_close(channel->wires[STDIN]->fd[READ_SIDE]); spc_close(channel->wires[STDOUT]->fd[WRITE_SIDE]); spc_close(channel->wires[STDERR]->fd[WRITE_SIDE]); channel->wires[STDIN]->fd[READ_SIDE] = (-1); channel->wires[STDOUT]->fd[WRITE_SIDE] = (-1); channel->wires[STDERR]->fd[WRITE_SIDE] = (-1); return(TRUE); } else { /* Slave process */ /* Close the "other" side of the pipes */ spc_close(channel->wires[STDIN]->fd[WRITE_SIDE]); spc_close(channel->wires[STDOUT]->fd[READ_SIDE]); spc_close(channel->wires[STDERR]->fd[READ_SIDE]); /* Dup the file descriptors to fd's 3, 4, 5. spc_dup2 is used to make sure these guys are hooked to something (/dev/null if necessary). We do this step here just in case any of the source file descriptors are 0, 1, or 2. */ spc_dup2(channel->wires[STDIN]->fd[READ_SIDE], 3); spc_dup2(channel->wires[STDOUT]->fd[WRITE_SIDE], 4); spc_dup2(channel->wires[STDERR]->fd[WRITE_SIDE], 5); /* Go to STDIN, STDOUT, STDERR */ spc_dup2(3, STDIN); spc_dup2(4, STDOUT); spc_dup2(5, STDERR); /* Close any other open file descriptors in the child */ SPC_Close_Unused(); return(TRUE); } } /*----------------------------------------------------------------------+*/ int reset_pipe_channel_object(SPC_Channel_Ptr channel) /*----------------------------------------------------------------------+*/ { int result; int iomode=channel->IOMode; Wire *wirelist; call_parent_method(channel, reset, (channel), result); if(result==SPC_ERROR) return(SPC_ERROR); /* Close the file descriptors */ for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) { SPC_XtRemoveInput(&wirelist->read_toolkit_id, SPC_Input); close(wirelist->fd[READ_SIDE]); close(wirelist->fd[WRITE_SIDE]); wirelist->flags &= ~SPCIO_DATA; } /* Allocate new file descriptors */ for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) { if(pipe(wirelist->fd) < 0) { SPC_Error(SPC_No_Pipe); return(SPC_ERROR); } } /* set the file_descs array to the new file descriptors & set up the new read mask */ channel->file_descs[STDIN] = (channel->wires[STDIN])->fd[WRITE_SIDE]; channel->file_descs[STDOUT] = (channel->wires[STDOUT])->fd[READ_SIDE]; channel->file_descs[STDERR] = (channel->wires[STDERR])->fd[READ_SIDE]; XeSPCAddInput(channel, NULL, NULL); return(TRUE); } /*----------------------------------------------------------------------+*/ int attach_pipe_channel_object(SPC_Channel_Ptr UNUSED_PARM(channel), int UNUSED_PARM(foo)) /*----------------------------------------------------------------------+*/ { /* It is an error to try to attach to a pipe channel... */ SPC_Error(SPC_Bad_Operation); return(SPC_ERROR); } /*----------------------------------------------------------------------+*/ int add_input_pipe_channel_object(SPC_Channel_Ptr channel, SbInputHandlerProc handler, void *data) /*----------------------------------------------------------------------+*/ { int result, fd; Wire *wirelist, *stdinwire; call_parent_method(channel, add_input, (channel, handler, data), result); if(result==SPC_ERROR) return(SPC_ERROR); stdinwire=channel->wires[STDIN]; for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) { if(wirelist == stdinwire) continue; if(wirelist->read_toolkit_id != -1) continue; fd=wirelist->fd[READ_SIDE]; SPC_XtAddInput(channel, &wirelist->read_toolkit_id, fd, channel->class_ptr->input, SPC_Input); } return(TRUE); }