2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * File: pipe.c $XConsortium: pipe.c /main/4 1996/04/21 19:10:09 drk $
27 * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
29 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
30 * (c) Copyright 1993, 1994 International Business Machines Corp. *
31 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
32 * (c) Copyright 1993, 1994 Novell, Inc. *
35 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
40 /*----------------------------------------------------------------------+*/
41 void pipe_channel_class_init(object_clasp t)
42 /*----------------------------------------------------------------------+*/
44 pipe_channel_clasp c = (pipe_channel_clasp) t;
46 c->new_obj = alloc_channel_object;
48 c->open = open_pipe_channel_object;
49 c->close = close_local_channel_object;
50 c->read = read_pipe_channel_object;
51 c->write = write_local_channel_object;
52 c->reset = reset_pipe_channel_object;
53 c->pre_fork = pre_fork_pipe_channel_object;
54 c->post_fork = post_fork_pipe_channel_object;
55 c->exec_proc = exec_proc_local_channel_object;
56 c->signal = signal_local_channel_object;
57 c->wait_for_termination = local_channel_object_wait_for_termination;
58 c->attach = attach_pipe_channel_object;
59 c->add_input = add_input_pipe_channel_object;
60 c->input = local_channel_object_input_handler;
61 c->remove_logfile = remove_logfile_local_channel_object;
63 /* New B.00 methods */
65 c->send_eof = local_channel_object_send_eof;
66 c->set_termio = set_termio_noio_channel_object;
69 static struct pipe_channel_class pipe_channel_class_struct = {
70 (channel_clasp) &channel_class, /* base class pointer */
71 "pipe_channel", /* class name */
72 pipe_channel_class_init, /* class initialize function */
73 sizeof(SPC_Channel), /* size */
77 pipe_channel_clasp pipe_channel_class = &pipe_channel_class_struct;
79 /*----------------------------------------------------------------------+*/
80 Wire *getpipe(Wire *prevwire)
81 /*----------------------------------------------------------------------+*/
83 Wire *wire_ptr=get_new_wire();
88 wire_ptr->next=prevwire;
89 /* Get file descriptors for pipe */
90 if (pipe(wire_ptr->fd) < OK) {
91 SPC_Error(SPC_No_Pipe);
100 *** Method definitions for pipe channel objects
105 * This routine handles initialization for pipe channels
108 /*----------------------------------------------------------------------+*/
109 SPC_Channel_Ptr open_pipe_channel_object(SPC_Channel_Ptr channel,
112 /*----------------------------------------------------------------------+*/
116 SPC_Channel_Ptr result;
118 call_parent_method(channel, open, (channel, iomode, hostname), result);
120 if(result==SPC_ERROR)
123 if (IS_SPCIO_STDIN(iomode)) {
124 tmpwire=channel->wires[STDIN]=getpipe(NULL);
129 if (IS_SPCIO_STDOUT(iomode)) {
130 tmpwire=channel->wires[STDOUT]=getpipe(tmpwire);
135 if(IS_SPCIO_STDERR(iomode)) {
137 IS_SPCIO_SEPARATE(iomode)) {
138 tmpwire=channel->wires[STDERR]=getpipe(tmpwire);
142 channel->wires[STDERR]=channel->wires[STDOUT];
146 channel->file_descs[STDIN] =(channel->wires[STDIN]) ->fd[WRITE_SIDE];
147 channel->file_descs[STDOUT]=(channel->wires[STDOUT])->fd[READ_SIDE];
148 channel->file_descs[STDERR]=(channel->wires[STDERR])->fd[READ_SIDE];
150 channel->wire_list=tmpwire;
155 /*----------------------------------------------------------------------+*/
156 int read_pipe_channel_object(SPC_Channel_Ptr channel,
157 int connector, /* STDOUT or STDERR */
160 /*----------------------------------------------------------------------+*/
164 call_parent_method(channel,
166 (channel, connector, buffer, nbytes),
169 if(result==Undefined)
173 result = read(channel->file_descs[connector], buffer, nbytes);
174 } while (result<0 && errno == EINTR);
178 SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input);
179 SPC_Change_State(channel, connector, 0, -1);
186 /*----------------------------------------------------------------------+*/
187 int pre_fork_pipe_channel_object(SPC_Channel_Ptr channel)
188 /*----------------------------------------------------------------------+*/
193 call_parent_method(channel, pre_fork, (channel), result);
195 if(result==SPC_ERROR)
201 /*----------------------------------------------------------------------+*/
202 int post_fork_pipe_channel_object(SPC_Channel_Ptr channel,
204 /*----------------------------------------------------------------------+*/
208 call_parent_method(channel, post_fork, (channel, parentp), result);
210 if(result==SPC_ERROR)
214 if (parentp) { /* Master process */
216 spc_close(channel->wires[STDIN]->fd[READ_SIDE]);
217 spc_close(channel->wires[STDOUT]->fd[WRITE_SIDE]);
218 spc_close(channel->wires[STDERR]->fd[WRITE_SIDE]);
220 channel->wires[STDIN]->fd[READ_SIDE] = (-1);
221 channel->wires[STDOUT]->fd[WRITE_SIDE] = (-1);
222 channel->wires[STDERR]->fd[WRITE_SIDE] = (-1);
226 else { /* Slave process */
228 /* Close the "other" side of the pipes */
230 spc_close(channel->wires[STDIN]->fd[WRITE_SIDE]);
231 spc_close(channel->wires[STDOUT]->fd[READ_SIDE]);
232 spc_close(channel->wires[STDERR]->fd[READ_SIDE]);
234 /* Dup the file descriptors to fd's 3, 4, 5.
235 spc_dup2 is used to make sure these guys are hooked to something
236 (/dev/null if necessary). We do this step here just in case any
237 of the source file descriptors are 0, 1, or 2. */
239 spc_dup2(channel->wires[STDIN]->fd[READ_SIDE], 3);
240 spc_dup2(channel->wires[STDOUT]->fd[WRITE_SIDE], 4);
241 spc_dup2(channel->wires[STDERR]->fd[WRITE_SIDE], 5);
243 /* Go to STDIN, STDOUT, STDERR */
249 /* Close any other open file descriptors in the child */
256 /*----------------------------------------------------------------------+*/
257 int reset_pipe_channel_object(SPC_Channel_Ptr channel)
258 /*----------------------------------------------------------------------+*/
261 int iomode=channel->IOMode;
264 call_parent_method(channel, reset, (channel), result);
266 if(result==SPC_ERROR)
269 /* Close the file descriptors */
271 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
272 SPC_XtRemoveInput(&wirelist->read_toolkit_id, SPC_Input);
273 close(wirelist->fd[READ_SIDE]);
274 close(wirelist->fd[WRITE_SIDE]);
275 wirelist->flags &= ~SPCIO_DATA;
278 /* Allocate new file descriptors */
280 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
281 if(pipe(wirelist->fd) < 0) {
282 SPC_Error(SPC_No_Pipe);
287 /* set the file_descs array to the new file descriptors & set up
290 channel->file_descs[STDIN] = (channel->wires[STDIN])->fd[WRITE_SIDE];
291 channel->file_descs[STDOUT] = (channel->wires[STDOUT])->fd[READ_SIDE];
292 channel->file_descs[STDERR] = (channel->wires[STDERR])->fd[READ_SIDE];
294 XeSPCAddInput(channel, NULL, NULL);
300 /*----------------------------------------------------------------------+*/
301 int attach_pipe_channel_object(SPC_Channel_Ptr UNUSED_PARM(channel),
302 int UNUSED_PARM(foo))
303 /*----------------------------------------------------------------------+*/
305 /* It is an error to try to attach to a pipe channel... */
306 SPC_Error(SPC_Bad_Operation);
310 /*----------------------------------------------------------------------+*/
311 int add_input_pipe_channel_object(SPC_Channel_Ptr channel,
312 SbInputHandlerProc handler,
314 /*----------------------------------------------------------------------+*/
317 Wire *wirelist, *stdinwire;
319 call_parent_method(channel, add_input, (channel, handler, data), result);
321 if(result==SPC_ERROR)
324 stdinwire=channel->wires[STDIN];
326 for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
328 if(wirelist == stdinwire)
331 if(wirelist->read_toolkit_id != -1)
334 fd=wirelist->fd[READ_SIDE];
335 SPC_XtAddInput(channel,
336 &wirelist->read_toolkit_id,
338 channel->class_ptr->input,