Build with debug symbols enabled.
[oweals/cde.git] / cde / lib / DtSvc / DtEncap / pipe.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
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)
10  * any later version.
11  *
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
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /*
24  * File:         pipe.c $XConsortium: pipe.c /main/4 1996/04/21 19:10:09 drk $
25  * Language:     C
26  *
27  * (c) Copyright 1988, Hewlett-Packard Company, all rights reserved.
28  *
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.                                *
33  */
34
35 #include <bms/sbport.h> /* NOTE: sbport.h must be the first include. */
36 #include <errno.h>
37
38 #include <SPC/spcP.h>
39
40 /*----------------------------------------------------------------------+*/
41 void pipe_channel_class_init(object_clasp t)
42 /*----------------------------------------------------------------------+*/
43 {
44   pipe_channel_clasp c = (pipe_channel_clasp) t;
45   
46   c->new_obj    = alloc_channel_object;
47   
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;
62
63   /* New B.00 methods */
64
65   c->send_eof = local_channel_object_send_eof;
66   c->set_termio = set_termio_noio_channel_object;
67 }
68
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 */
74   0
75   };
76
77 pipe_channel_clasp pipe_channel_class = &pipe_channel_class_struct;
78
79 /*----------------------------------------------------------------------+*/
80 Wire *getpipe(Wire *prevwire)
81 /*----------------------------------------------------------------------+*/
82 {
83   Wire *wire_ptr=get_new_wire();
84
85   if(!wire_ptr)
86     return(SPC_ERROR);
87
88   wire_ptr->next=prevwire;
89   /* Get file descriptors for pipe */
90   if (pipe(wire_ptr->fd) < OK) {
91     SPC_Error(SPC_No_Pipe);
92     return(SPC_ERROR);
93   }
94   return(wire_ptr);
95 }
96
97 /*
98  ***
99  *** Method definitions for pipe channel objects
100  ***
101 */
102
103 /*
104  * This routine handles initialization for pipe channels
105  */
106
107 /*----------------------------------------------------------------------+*/
108 SPC_Channel_Ptr open_pipe_channel_object(SPC_Channel_Ptr channel,
109                                          int iomode,
110                                          XeString hostname)
111 /*----------------------------------------------------------------------+*/
112 {
113
114   Wire *tmpwire=NULL;
115   SPC_Channel_Ptr result;
116   
117   call_parent_method(channel, open, (channel, iomode, hostname), result);
118
119   if(result==SPC_ERROR)
120     return(SPC_ERROR);
121
122   if (IS_SPCIO_STDIN(iomode)) {
123     tmpwire=channel->wires[STDIN]=getpipe(NULL);
124     if(!tmpwire)
125       return(SPC_ERROR);
126   }
127   
128   if (IS_SPCIO_STDOUT(iomode)) {
129     tmpwire=channel->wires[STDOUT]=getpipe(tmpwire);
130     if(!tmpwire)
131       return(SPC_ERROR);
132   }
133
134   if(IS_SPCIO_STDERR(iomode)) {
135     if (!tmpwire ||
136         IS_SPCIO_SEPARATE(iomode)) {
137       tmpwire=channel->wires[STDERR]=getpipe(tmpwire);
138       if(!tmpwire)
139         return(SPC_ERROR);
140     } else {
141       channel->wires[STDERR]=channel->wires[STDOUT];
142     }
143   }
144   
145   channel->file_descs[STDIN] =(channel->wires[STDIN]) ->fd[WRITE_SIDE];
146   channel->file_descs[STDOUT]=(channel->wires[STDOUT])->fd[READ_SIDE];
147   channel->file_descs[STDERR]=(channel->wires[STDERR])->fd[READ_SIDE];
148
149   channel->wire_list=tmpwire;
150   
151   return(channel);
152 }
153
154 /*----------------------------------------------------------------------+*/
155 int read_pipe_channel_object(SPC_Channel_Ptr channel,
156                              int connector,           /* STDOUT or STDERR */
157                              XeString buffer,
158                              int nbytes)
159 /*----------------------------------------------------------------------+*/
160 {
161   int result;
162
163   call_parent_method(channel,
164                      read,
165                      (channel, connector, buffer, nbytes),
166                      result);
167
168   if(result==Undefined)
169     return(Undefined);
170
171   do {
172     result = read(channel->file_descs[connector], buffer, nbytes);
173   } while (result<0 && errno == EINTR);
174
175   if(result == 0) {
176
177     SPC_XtRemoveInput(&channel->wires[connector]->read_toolkit_id, SPC_Input);
178     SPC_Change_State(channel, connector, 0, -1);
179
180   }
181
182   return(result);
183 }
184
185 /*----------------------------------------------------------------------+*/
186 int pre_fork_pipe_channel_object(SPC_Channel_Ptr channel)
187 /*----------------------------------------------------------------------+*/
188 {
189
190   int result;
191   
192   call_parent_method(channel, pre_fork, (channel), result);
193   
194   if(result==SPC_ERROR)
195     return(SPC_ERROR);
196
197   return(TRUE);
198 }
199
200 /*----------------------------------------------------------------------+*/
201 int post_fork_pipe_channel_object(SPC_Channel_Ptr channel,
202                                   int parentp)
203 /*----------------------------------------------------------------------+*/
204 {
205   int result;
206   
207   call_parent_method(channel, post_fork, (channel, parentp), result);
208
209   if(result==SPC_ERROR)
210     return(SPC_ERROR);
211
212   
213   if (parentp) {                /* Master process */
214     
215     spc_close(channel->wires[STDIN]->fd[READ_SIDE]);
216     spc_close(channel->wires[STDOUT]->fd[WRITE_SIDE]);
217     spc_close(channel->wires[STDERR]->fd[WRITE_SIDE]);
218
219     channel->wires[STDIN]->fd[READ_SIDE]   = (-1);
220     channel->wires[STDOUT]->fd[WRITE_SIDE] = (-1);
221     channel->wires[STDERR]->fd[WRITE_SIDE] = (-1);
222
223     return(TRUE);
224   }
225   else {                        /* Slave process */
226     
227     /* Close the "other" side of the pipes */
228     
229     spc_close(channel->wires[STDIN]->fd[WRITE_SIDE]);
230     spc_close(channel->wires[STDOUT]->fd[READ_SIDE]);
231     spc_close(channel->wires[STDERR]->fd[READ_SIDE]);
232
233     /* Dup the file descriptors to fd's 3, 4, 5.
234        spc_dup2 is used to make sure these guys are hooked to something
235        (/dev/null if necessary).  We do this step here just in case any
236        of the source file descriptors are 0, 1, or 2. */
237     
238     spc_dup2(channel->wires[STDIN]->fd[READ_SIDE], 3);
239     spc_dup2(channel->wires[STDOUT]->fd[WRITE_SIDE], 4);
240     spc_dup2(channel->wires[STDERR]->fd[WRITE_SIDE], 5);
241
242     /* Go to STDIN, STDOUT, STDERR */
243     
244     spc_dup2(3, STDIN);
245     spc_dup2(4, STDOUT);
246     spc_dup2(5, STDERR);
247     
248     /* Close any other open file descriptors in the child */
249     SPC_Close_Unused();
250
251     return(TRUE);
252   }
253 }
254
255 /*----------------------------------------------------------------------+*/
256 int reset_pipe_channel_object(SPC_Channel_Ptr channel)
257 /*----------------------------------------------------------------------+*/
258 {
259   int result;  
260   int iomode=channel->IOMode;
261   Wire *wirelist;
262   
263   call_parent_method(channel, reset, (channel), result);
264
265   if(result==SPC_ERROR)
266     return(SPC_ERROR);
267
268   /* Close the file descriptors */
269   
270   for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
271     SPC_XtRemoveInput(&wirelist->read_toolkit_id, SPC_Input);
272     close(wirelist->fd[READ_SIDE]);
273     close(wirelist->fd[WRITE_SIDE]);
274     wirelist->flags &= ~SPCIO_DATA;
275   }
276
277   /* Allocate new file descriptors */
278   
279   for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
280     if(pipe(wirelist->fd) < 0) {
281       SPC_Error(SPC_No_Pipe);
282       return(SPC_ERROR);
283     }
284   }
285
286   /* set the file_descs array to the new file descriptors & set up
287      the new read mask */
288   
289   channel->file_descs[STDIN]  = (channel->wires[STDIN])->fd[WRITE_SIDE];
290   channel->file_descs[STDOUT] = (channel->wires[STDOUT])->fd[READ_SIDE];
291   channel->file_descs[STDERR] = (channel->wires[STDERR])->fd[READ_SIDE];
292
293   XeSPCAddInput(channel, NULL, NULL);
294   
295   return(TRUE);
296   
297 }
298
299 /*----------------------------------------------------------------------+*/
300 int attach_pipe_channel_object(SPC_Channel_Ptr UNUSED_PARM(channel), 
301                                int             UNUSED_PARM(foo))
302 /*----------------------------------------------------------------------+*/
303 {
304   /* It is an error to try to attach to a pipe channel... */
305   SPC_Error(SPC_Bad_Operation);
306   return(SPC_ERROR);
307 }
308
309 /*----------------------------------------------------------------------+*/
310 int add_input_pipe_channel_object(SPC_Channel_Ptr channel,
311                                   SbInputHandlerProc handler, 
312                                   void *data)
313 /*----------------------------------------------------------------------+*/
314 {
315   int result, fd;
316   Wire *wirelist, *stdinwire;
317   
318   call_parent_method(channel, add_input, (channel, handler, data), result);
319
320   if(result==SPC_ERROR)
321     return(SPC_ERROR);
322
323   stdinwire=channel->wires[STDIN];
324   
325   for(wirelist=channel->wire_list; wirelist; wirelist=wirelist->next) {
326     
327     if(wirelist == stdinwire)
328       continue;
329     
330     if(wirelist->read_toolkit_id != -1)
331       continue;
332     
333     fd=wirelist->fd[READ_SIDE];
334     SPC_XtAddInput(channel,
335                    &wirelist->read_toolkit_id,
336                    fd,
337                    channel->class_ptr->input,
338                    SPC_Input);
339
340   }
341   
342   return(TRUE);
343   
344 }