Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / lib / libast / sfio / sfpopen.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 /* $XConsortium: sfpopen.c /main/3 1995/11/01 18:33:06 rswiston $ */
24 /***************************************************************
25 *                                                              *
26 *                      AT&T - PROPRIETARY                      *
27 *                                                              *
28 *         THIS IS PROPRIETARY SOURCE CODE LICENSED BY          *
29 *                          AT&T CORP.                          *
30 *                                                              *
31 *                Copyright (c) 1995 AT&T Corp.                 *
32 *                     All Rights Reserved                      *
33 *                                                              *
34 *           This software is licensed by AT&T Corp.            *
35 *       under the terms and conditions of the license in       *
36 *       http://www.research.att.com/orgs/ssr/book/reuse        *
37 *                                                              *
38 *               This software was created by the               *
39 *           Software Engineering Research Department           *
40 *                    AT&T Bell Laboratories                    *
41 *                                                              *
42 *               For further information contact                *
43 *                     gsf@research.att.com                     *
44 *                                                              *
45 ***************************************************************/
46 #include        "sfhdr.h"
47
48 #if _PACKAGE_ast
49
50 #include        <proc.h>
51
52 #else
53
54 #if _lib_vfork
55 #define fork    vfork
56 #if _hdr_vfork
57 #include        <vfork.h>
58 #endif
59 #if _sys_vfork
60 #include        <sys/vfork.h>
61 #endif
62 #endif
63
64 #include        <signal.h>
65 typedef void(*Handler_t)_ARG_((int));
66 #define EXIT_NOTFOUND   127
67
68 _BEGIN_EXTERNS_
69 extern int      fork _ARG_((void));
70 extern int      waitpid _ARG_((int, int*, int));
71 extern int      wait _ARG_((int*));
72 extern int      pipe _ARG_((int*));
73 extern int      execl _ARG_((char*,char*,...));
74 _END_EXTERNS_
75
76 /* pipe ends */
77 #define READ    0
78 #define WRITE   1
79
80 #endif /*_PACKAGE_ast*/
81
82 #if __STD_C
83 Sfio_t *sfpopen(Sfio_t* f, const char* command, const char* mode)
84 #else
85 Sfio_t *sfpopen(f,command,mode)
86 Sfio_t  *f;
87 char    *command;       /* command to execute */
88 char    *mode;          /* mode of the stream */
89 #endif
90 {
91 #if _PACKAGE_ast
92         reg Proc_t*     proc;
93         reg int         sflags;
94         reg long        flags = PROC_IGNORE;
95         char*           av[4];
96
97         if (!command || !command[0] || !(sflags = _sftype(mode, NiL)))
98                 return 0;
99         if (sflags & SF_READ)
100                 flags |= PROC_READ;
101         if (sflags & SF_WRITE)
102                 flags |= PROC_WRITE;
103         av[0] = "sh";
104         av[1] = "-c";
105         av[2] = (char*)command;
106         av[3] = 0;
107         if (!(proc = procopen(NiL, av, NiL, NiL, flags)))
108                 return 0;
109         if (!(f = sfnew(f, NiL, -1, (sflags&SF_READ) ? proc->rfd : proc->wfd, sflags)) ||
110             _sfpopen(f, (sflags&SF_READ) ? proc->wfd : -1, proc->pid) < 0)
111         {
112                 if (f) sfclose(f);
113                 procclose(proc);
114                 return 0;
115         }
116         procfree(proc);
117         return f;
118 #else
119         reg int         pid, pkeep, ckeep, sflags;
120         int             parent[2], child[2];
121         Sfio_t          sf;
122         Handler_t       sig;
123
124         /* sanity check */
125         if(!command || !command[0] || !(sflags = _sftype(mode,NIL(int*))))
126                 return NIL(Sfio_t*);
127
128         /* make pipes */
129         parent[0] = parent[1] = child[0] = child[1] = -1;
130         if(pipe(parent) < 0)
131                 goto error;
132         if((sflags&SF_RDWR) == SF_RDWR && pipe(child) < 0)
133                 goto error;
134
135         switch(pid = fork())
136         {
137         default :       /* in parent process */
138                 if(sflags&SF_READ)
139                         { pkeep = READ; ckeep = WRITE; }
140                 else    { pkeep = WRITE; ckeep = READ; }
141
142                 /* make the streams */
143                 if(!(f = sfnew(f,NIL(char*),-1,parent[pkeep],sflags)))
144                         goto error;
145                 CLOSE(parent[!pkeep]);
146
147                 if((sflags&SF_RDWR) == SF_RDWR)
148                         CLOSE(child[!ckeep]);
149
150                 /* save process info */
151                 if(_sfpopen(f,(sflags&SF_RDWR) == SF_RDWR ? child[ckeep] : -1,pid) < 0)
152                 {       (void)sfclose(f);
153                         goto error;
154                 }
155
156 #ifdef SIGPIPE  /* protect from broken pipe signal */
157                 if((sflags&SF_WRITE) &&
158                    (sig = signal(SIGPIPE,SIG_IGN)) != SIG_DFL && sig != SIG_IGN)
159                         signal(SIGPIPE,sig);
160 #endif
161
162                 return f;
163
164         case 0 :        /* in child process */
165                 (void)_sfpclose(NIL(Sfio_t*));
166
167                 /* determine what to keep */
168                 if(sflags&SF_READ)
169                         { pkeep = WRITE; ckeep = READ; }
170                 else    { pkeep = READ; ckeep = WRITE; }
171
172                 /* zap fd that we don't need */
173                 CLOSE(parent[!pkeep]);
174                 if((sflags&SF_RDWR) == SF_RDWR)
175                         CLOSE(child[!ckeep]);
176
177                 /* use sfsetfd to make these descriptors the std-ones */
178                 SFCLEAR(&sf);
179
180                 /* must be careful so not to close something useful */
181                 if((sflags&SF_RDWR) == SF_RDWR && pkeep == child[ckeep])
182                         if((child[ckeep] = dup(pkeep)) < 0)
183                                 _exit(EXIT_NOTFOUND);
184
185                 if(parent[pkeep] != pkeep)
186                 {       sf.file = parent[pkeep];
187                         CLOSE(pkeep);
188                         if(sfsetfd(&sf,pkeep) != pkeep)
189                                 _exit(EXIT_NOTFOUND);
190                 }
191
192                 if((sflags&SF_RDWR) == SF_RDWR && child[ckeep] != ckeep)
193                 {       sf.file = child[ckeep];
194                         CLOSE(ckeep);
195                         if(sfsetfd(&sf,ckeep) != ckeep)
196                                 _exit(EXIT_NOTFOUND);
197                 }
198
199                 /* now exec the command */
200                 execl("/bin/sh", "sh", "-c", command, NIL(char*));
201                 _exit(EXIT_NOTFOUND);
202                 return NIL(Sfio_t*);
203
204         case -1 :       /* error */
205         error:
206                 if(parent[0] >= 0)
207                         { CLOSE(parent[0]); CLOSE(parent[1]); }
208                 if(child[0] >= 0)
209                         { CLOSE(child[0]); CLOSE(child[1]); }
210                 return NIL(Sfio_t*);
211         }
212 #endif /*_PACKAGE_ast*/
213 }