1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
24 /* Create a coprocess.
25 ** Written by Kiem-Phong Vo.
32 #define EXIT_NOTFOUND 127
40 static char Meta
[1<<CHAR_BIT
], **Path
;
42 /* execute command directly if possible; else use the shell */
44 static void execute(const char* argcmd
)
46 static void execute(argcmd
)
50 reg
char *s
, *cmd
, **argv
, **p
, *interp
;
53 /* define interpreter */
54 if(!(interp
= getenv("SHELL")) || !interp
[0])
57 if(strcmp(interp
,"/bin/sh") != 0 && strcmp(interp
,"/bin/ksh") != 0 )
58 { if(access(interp
,X_OK
) == 0)
60 else interp
= "/bin/sh";
63 /* if there is a meta character, let the shell do it */
64 for(s
= (char*)argcmd
; *s
; ++s
)
68 /* try to construct argv */
69 if(!(cmd
= (char*)malloc(strlen(argcmd
)+1)) )
72 if(!(argv
= (char**)malloc(16*sizeof(char*))) )
74 for(n
= 0, s
= cmd
;; )
75 { while(isspace(s
[0]))
82 if((n
%16) == 0 && !(argv
= (char**)reallocarray(argv
, (n
+ 16), sizeof(char *))) )
85 /* make this into a C string */
86 while(s
[0] && !isspace(s
[0]))
95 /* get the command name */
97 for(s
= cmd
+strlen(cmd
)-1; s
>= cmd
; --s
)
102 /* Non-standard pathnames as in nDFS should be handled by the shell */
103 for(s
= cmd
+strlen(cmd
)-1; s
>= cmd
+2; --s
)
104 if(s
[0] == '.' && s
[-1] == '.' && s
[-2] == '.')
108 (cmd
[0] == '.' && cmd
[1] == '/') ||
109 (cmd
[0] == '.' && cmd
[1] == '.' && cmd
[2] == '/') )
110 { if(access(cmd
,X_OK
) != 0)
112 else execv(cmd
,argv
);
115 { for(p
= Path
; *p
; ++p
)
116 { s
= sfprints("%s/%s", *p
, cmd
);
117 if(access(s
,X_OK
) == 0)
122 /* if get here, let the interpreter do it */
124 for(s
= interp
+strlen(interp
)-1; s
>= interp
; --s
)
127 execl(interp
, s
+1, "-c", argcmd
, NIL(char*));
128 _exit(EXIT_NOTFOUND
);
131 #endif /*_PACKAGE_ast*/
134 Sfio_t
* sfpopen(Sfio_t
* f
, const char* command
, const char* mode
)
136 Sfio_t
* sfpopen(f
,command
,mode
)
138 char* command
; /* command to execute */
139 char* mode
; /* mode of the stream */
149 if (!command
|| !command
[0] || !mode
)
151 sflags
= _sftype(mode
, NiL
, NiL
);
153 if(f
== (Sfio_t
*)(-1))
154 { /* stdio compatibility mode */
161 if (sflags
& SF_READ
)
163 if (sflags
& SF_WRITE
)
167 av
[2] = (char*)command
;
169 if (!(proc
= procopen(0, av
, 0, 0, flags
)))
171 if (!(f
= sfnew(f
, NIL(Void_t
*), (size_t)SF_UNBOUND
,
172 (sflags
&SF_READ
) ? proc
->rfd
: proc
->wfd
, sflags
|((sflags
&SF_RDWR
)?0:SF_READ
))) ||
173 _sfpopen(f
, (sflags
&SF_READ
) ? proc
->wfd
: -1, proc
->pid
, pflags
) < 0)
182 reg
int pid
, fd
, pkeep
, ckeep
, sflags
;
183 int stdio
, parent
[2], child
[2];
186 /* set shell meta characters */
190 for(s
= "!@#$%&*(){}[]:;<>~`'|\"\\"; *s
; ++s
)
191 Meta
[(uchar
)s
[0]] = 1;
194 Path
= _sfgetpath("PATH");
197 if(!command
|| !command
[0] || !mode
)
199 sflags
= _sftype(mode
,NIL(int*),NIL(int*));
202 parent
[0] = parent
[1] = child
[0] = child
[1] = -1;
204 { if(syspipef(parent
) < 0)
206 if((sflags
&SF_RDWR
) == SF_RDWR
&& syspipef(child
) < 0)
210 switch((pid
= fork()) )
212 default : /* in parent process */
214 { pkeep
= READ
; ckeep
= WRITE
; }
215 else { pkeep
= WRITE
; ckeep
= READ
; }
217 if(f
== (Sfio_t
*)(-1))
218 { /* stdio compatibility mode */
224 /* make the streams */
225 if(!(f
= sfnew(f
,NIL(Void_t
*),(size_t)SF_UNBOUND
,parent
[pkeep
],sflags
|((sflags
&SF_RDWR
)?0:SF_READ
))))
228 { CLOSE(parent
[!pkeep
]);
229 SETCLOEXEC(parent
[pkeep
]);
230 if((sflags
&SF_RDWR
) == SF_RDWR
)
231 { CLOSE(child
[!ckeep
]);
232 SETCLOEXEC(child
[ckeep
]);
236 /* save process info */
237 fd
= (sflags
&SF_RDWR
) == SF_RDWR
? child
[ckeep
] : -1;
238 if(_sfpopen(f
,fd
,pid
,stdio
) < 0)
245 case 0 : /* in child process */
246 /* determine what to keep */
248 { pkeep
= WRITE
; ckeep
= READ
; }
249 else { pkeep
= READ
; ckeep
= WRITE
; }
251 /* zap fd that we don't need */
253 { CLOSE(parent
[!pkeep
]);
254 if((sflags
&SF_RDWR
) == SF_RDWR
)
255 CLOSE(child
[!ckeep
]);
258 /* use sfsetfd to make these descriptors the std-ones */
259 SFCLEAR(&sf
,NIL(Vtmutex_t
*));
261 /* must be careful so not to close something useful */
262 if((sflags
&SF_RDWR
) == SF_RDWR
&& pkeep
== child
[ckeep
])
263 if((child
[ckeep
] = sysdupf(pkeep
)) < 0)
264 _exit(EXIT_NOTFOUND
);
267 { if (parent
[pkeep
] != pkeep
)
268 { sf
.file
= parent
[pkeep
];
270 if(sfsetfd(&sf
,pkeep
) != pkeep
)
271 _exit(EXIT_NOTFOUND
);
273 if((sflags
&SF_RDWR
) == SF_RDWR
&& child
[ckeep
] != ckeep
)
274 { sf
.file
= child
[ckeep
];
276 if(sfsetfd(&sf
,ckeep
) != ckeep
)
277 _exit(EXIT_NOTFOUND
);
284 case -1 : /* error */
287 { CLOSE(parent
[0]); CLOSE(parent
[1]); }
289 { CLOSE(child
[0]); CLOSE(child
[1]); }
292 #endif /*_PACKAGE_ast*/