xref: /plan9/sys/src/ape/cmd/pdksh/io.c (revision 7dd7cddf99dd7472612f1413b4da293630e6b1bc)
1*7dd7cddfSDavid du Colombier /*
2*7dd7cddfSDavid du Colombier  * shell buffered IO and formatted output
3*7dd7cddfSDavid du Colombier  */
4*7dd7cddfSDavid du Colombier 
5*7dd7cddfSDavid du Colombier #include <ctype.h>
6*7dd7cddfSDavid du Colombier #include "sh.h"
7*7dd7cddfSDavid du Colombier #include "ksh_stat.h"
8*7dd7cddfSDavid du Colombier 
9*7dd7cddfSDavid du Colombier static int initio_done;
10*7dd7cddfSDavid du Colombier 
11*7dd7cddfSDavid du Colombier /*
12*7dd7cddfSDavid du Colombier  * formatted output functions
13*7dd7cddfSDavid du Colombier  */
14*7dd7cddfSDavid du Colombier 
15*7dd7cddfSDavid du Colombier 
16*7dd7cddfSDavid du Colombier /* A shell error occured (eg, syntax error, etc.) */
17*7dd7cddfSDavid du Colombier void
18*7dd7cddfSDavid du Colombier #ifdef HAVE_PROTOTYPES
errorf(const char * fmt,...)19*7dd7cddfSDavid du Colombier errorf(const char *fmt, ...)
20*7dd7cddfSDavid du Colombier #else
21*7dd7cddfSDavid du Colombier errorf(fmt, va_alist)
22*7dd7cddfSDavid du Colombier 	const char *fmt;
23*7dd7cddfSDavid du Colombier 	va_dcl
24*7dd7cddfSDavid du Colombier #endif
25*7dd7cddfSDavid du Colombier {
26*7dd7cddfSDavid du Colombier 	va_list va;
27*7dd7cddfSDavid du Colombier 
28*7dd7cddfSDavid du Colombier 	shl_stdout_ok = 0;	/* debugging: note that stdout not valid */
29*7dd7cddfSDavid du Colombier 	exstat = 1;
30*7dd7cddfSDavid du Colombier 	if (*fmt) {
31*7dd7cddfSDavid du Colombier 		error_prefix(TRUE);
32*7dd7cddfSDavid du Colombier 		SH_VA_START(va, fmt);
33*7dd7cddfSDavid du Colombier 		shf_vfprintf(shl_out, fmt, va);
34*7dd7cddfSDavid du Colombier 		va_end(va);
35*7dd7cddfSDavid du Colombier 		shf_putchar('\n', shl_out);
36*7dd7cddfSDavid du Colombier 	}
37*7dd7cddfSDavid du Colombier 	shf_flush(shl_out);
38*7dd7cddfSDavid du Colombier 	unwind(LERROR);
39*7dd7cddfSDavid du Colombier }
40*7dd7cddfSDavid du Colombier 
41*7dd7cddfSDavid du Colombier /* like errorf(), but no unwind is done */
42*7dd7cddfSDavid du Colombier void
43*7dd7cddfSDavid du Colombier #ifdef HAVE_PROTOTYPES
warningf(int fileline,const char * fmt,...)44*7dd7cddfSDavid du Colombier warningf(int fileline, const char *fmt, ...)
45*7dd7cddfSDavid du Colombier #else
46*7dd7cddfSDavid du Colombier warningf(fileline, fmt, va_alist)
47*7dd7cddfSDavid du Colombier 	int fileline;
48*7dd7cddfSDavid du Colombier 	const char *fmt;
49*7dd7cddfSDavid du Colombier 	va_dcl
50*7dd7cddfSDavid du Colombier #endif
51*7dd7cddfSDavid du Colombier {
52*7dd7cddfSDavid du Colombier 	va_list va;
53*7dd7cddfSDavid du Colombier 
54*7dd7cddfSDavid du Colombier 	error_prefix(fileline);
55*7dd7cddfSDavid du Colombier 	SH_VA_START(va, fmt);
56*7dd7cddfSDavid du Colombier 	shf_vfprintf(shl_out, fmt, va);
57*7dd7cddfSDavid du Colombier 	va_end(va);
58*7dd7cddfSDavid du Colombier 	shf_putchar('\n', shl_out);
59*7dd7cddfSDavid du Colombier 	shf_flush(shl_out);
60*7dd7cddfSDavid du Colombier }
61*7dd7cddfSDavid du Colombier 
62*7dd7cddfSDavid du Colombier /* Used by built-in utilities to prefix shell and utility name to message
63*7dd7cddfSDavid du Colombier  * (also unwinds environments for special builtins).
64*7dd7cddfSDavid du Colombier  */
65*7dd7cddfSDavid du Colombier void
66*7dd7cddfSDavid du Colombier #ifdef HAVE_PROTOTYPES
bi_errorf(const char * fmt,...)67*7dd7cddfSDavid du Colombier bi_errorf(const char *fmt, ...)
68*7dd7cddfSDavid du Colombier #else
69*7dd7cddfSDavid du Colombier bi_errorf(fmt, va_alist)
70*7dd7cddfSDavid du Colombier 	const char *fmt;
71*7dd7cddfSDavid du Colombier 	va_dcl
72*7dd7cddfSDavid du Colombier #endif
73*7dd7cddfSDavid du Colombier {
74*7dd7cddfSDavid du Colombier 	va_list va;
75*7dd7cddfSDavid du Colombier 
76*7dd7cddfSDavid du Colombier 	shl_stdout_ok = 0;	/* debugging: note that stdout not valid */
77*7dd7cddfSDavid du Colombier 	exstat = 1;
78*7dd7cddfSDavid du Colombier 	if (*fmt) {
79*7dd7cddfSDavid du Colombier 		error_prefix(TRUE);
80*7dd7cddfSDavid du Colombier 		/* not set when main() calls parse_args() */
81*7dd7cddfSDavid du Colombier 		if (builtin_argv0)
82*7dd7cddfSDavid du Colombier 			shf_fprintf(shl_out, "%s: ", builtin_argv0);
83*7dd7cddfSDavid du Colombier 		SH_VA_START(va, fmt);
84*7dd7cddfSDavid du Colombier 		shf_vfprintf(shl_out, fmt, va);
85*7dd7cddfSDavid du Colombier 		va_end(va);
86*7dd7cddfSDavid du Colombier 		shf_putchar('\n', shl_out);
87*7dd7cddfSDavid du Colombier 	}
88*7dd7cddfSDavid du Colombier 	shf_flush(shl_out);
89*7dd7cddfSDavid du Colombier 	/* POSIX special builtins and ksh special builtins cause
90*7dd7cddfSDavid du Colombier 	 * non-interactive shells to exit.
91*7dd7cddfSDavid du Colombier 	 * XXX odd use of KEEPASN; also may not want LERROR here
92*7dd7cddfSDavid du Colombier 	 */
93*7dd7cddfSDavid du Colombier 	if ((builtin_flag & SPEC_BI)
94*7dd7cddfSDavid du Colombier 	    || (Flag(FPOSIX) && (builtin_flag & KEEPASN)))
95*7dd7cddfSDavid du Colombier 	{
96*7dd7cddfSDavid du Colombier 		builtin_argv0 = (char *) 0;
97*7dd7cddfSDavid du Colombier 		unwind(LERROR);
98*7dd7cddfSDavid du Colombier 	}
99*7dd7cddfSDavid du Colombier }
100*7dd7cddfSDavid du Colombier 
101*7dd7cddfSDavid du Colombier /* Called when something that shouldn't happen does */
102*7dd7cddfSDavid du Colombier void
103*7dd7cddfSDavid du Colombier #ifdef HAVE_PROTOTYPES
internal_errorf(int jump,const char * fmt,...)104*7dd7cddfSDavid du Colombier internal_errorf(int jump, const char *fmt, ...)
105*7dd7cddfSDavid du Colombier #else
106*7dd7cddfSDavid du Colombier internal_errorf(jump, fmt, va_alist)
107*7dd7cddfSDavid du Colombier 	int jump;
108*7dd7cddfSDavid du Colombier 	const char *fmt;
109*7dd7cddfSDavid du Colombier 	va_dcl
110*7dd7cddfSDavid du Colombier #endif
111*7dd7cddfSDavid du Colombier {
112*7dd7cddfSDavid du Colombier 	va_list va;
113*7dd7cddfSDavid du Colombier 
114*7dd7cddfSDavid du Colombier 	error_prefix(TRUE);
115*7dd7cddfSDavid du Colombier 	shf_fprintf(shl_out, "internal error: ");
116*7dd7cddfSDavid du Colombier 	SH_VA_START(va, fmt);
117*7dd7cddfSDavid du Colombier 	shf_vfprintf(shl_out, fmt, va);
118*7dd7cddfSDavid du Colombier 	va_end(va);
119*7dd7cddfSDavid du Colombier 	shf_putchar('\n', shl_out);
120*7dd7cddfSDavid du Colombier 	shf_flush(shl_out);
121*7dd7cddfSDavid du Colombier 	if (jump)
122*7dd7cddfSDavid du Colombier 		unwind(LERROR);
123*7dd7cddfSDavid du Colombier }
124*7dd7cddfSDavid du Colombier 
125*7dd7cddfSDavid du Colombier /* used by error reporting functions to print "ksh: .kshrc[25]: " */
126*7dd7cddfSDavid du Colombier void
error_prefix(fileline)127*7dd7cddfSDavid du Colombier error_prefix(fileline)
128*7dd7cddfSDavid du Colombier 	int fileline;
129*7dd7cddfSDavid du Colombier {
130*7dd7cddfSDavid du Colombier 	/* Avoid foo: foo[2]: ... */
131*7dd7cddfSDavid du Colombier 	if (!fileline || !source || !source->file
132*7dd7cddfSDavid du Colombier 	    || strcmp(source->file, kshname) != 0)
133*7dd7cddfSDavid du Colombier 		shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
134*7dd7cddfSDavid du Colombier 	if (fileline && source && source->file != NULL) {
135*7dd7cddfSDavid du Colombier 		shf_fprintf(shl_out, "%s[%d]: ", source->file,
136*7dd7cddfSDavid du Colombier 			source->errline > 0 ? source->errline : source->line);
137*7dd7cddfSDavid du Colombier 		source->errline = 0;
138*7dd7cddfSDavid du Colombier 	}
139*7dd7cddfSDavid du Colombier }
140*7dd7cddfSDavid du Colombier 
141*7dd7cddfSDavid du Colombier /* printf to shl_out (stderr) with flush */
142*7dd7cddfSDavid du Colombier void
143*7dd7cddfSDavid du Colombier #ifdef HAVE_PROTOTYPES
shellf(const char * fmt,...)144*7dd7cddfSDavid du Colombier shellf(const char *fmt, ...)
145*7dd7cddfSDavid du Colombier #else
146*7dd7cddfSDavid du Colombier shellf(fmt, va_alist)
147*7dd7cddfSDavid du Colombier 	const char *fmt;
148*7dd7cddfSDavid du Colombier 	va_dcl
149*7dd7cddfSDavid du Colombier #endif
150*7dd7cddfSDavid du Colombier {
151*7dd7cddfSDavid du Colombier 	va_list va;
152*7dd7cddfSDavid du Colombier 
153*7dd7cddfSDavid du Colombier 	if (!initio_done) /* shl_out may not be set up yet... */
154*7dd7cddfSDavid du Colombier 		return;
155*7dd7cddfSDavid du Colombier 	SH_VA_START(va, fmt);
156*7dd7cddfSDavid du Colombier 	shf_vfprintf(shl_out, fmt, va);
157*7dd7cddfSDavid du Colombier 	va_end(va);
158*7dd7cddfSDavid du Colombier 	shf_flush(shl_out);
159*7dd7cddfSDavid du Colombier }
160*7dd7cddfSDavid du Colombier 
161*7dd7cddfSDavid du Colombier /* printf to shl_stdout (stdout) */
162*7dd7cddfSDavid du Colombier void
163*7dd7cddfSDavid du Colombier #ifdef HAVE_PROTOTYPES
shprintf(const char * fmt,...)164*7dd7cddfSDavid du Colombier shprintf(const char *fmt, ...)
165*7dd7cddfSDavid du Colombier #else
166*7dd7cddfSDavid du Colombier shprintf(fmt, va_alist)
167*7dd7cddfSDavid du Colombier 	const char *fmt;
168*7dd7cddfSDavid du Colombier 	va_dcl
169*7dd7cddfSDavid du Colombier #endif
170*7dd7cddfSDavid du Colombier {
171*7dd7cddfSDavid du Colombier 	va_list va;
172*7dd7cddfSDavid du Colombier 
173*7dd7cddfSDavid du Colombier 	if (!shl_stdout_ok)
174*7dd7cddfSDavid du Colombier 		internal_errorf(1, "shl_stdout not valid");
175*7dd7cddfSDavid du Colombier 	SH_VA_START(va, fmt);
176*7dd7cddfSDavid du Colombier 	shf_vfprintf(shl_stdout, fmt, va);
177*7dd7cddfSDavid du Colombier 	va_end(va);
178*7dd7cddfSDavid du Colombier }
179*7dd7cddfSDavid du Colombier 
180*7dd7cddfSDavid du Colombier #ifdef KSH_DEBUG
181*7dd7cddfSDavid du Colombier static struct shf *kshdebug_shf;
182*7dd7cddfSDavid du Colombier 
183*7dd7cddfSDavid du Colombier void
kshdebug_init_()184*7dd7cddfSDavid du Colombier kshdebug_init_()
185*7dd7cddfSDavid du Colombier {
186*7dd7cddfSDavid du Colombier 	if (kshdebug_shf)
187*7dd7cddfSDavid du Colombier 		shf_close(kshdebug_shf);
188*7dd7cddfSDavid du Colombier 	kshdebug_shf = shf_open("/tmp/ksh-debug.log",
189*7dd7cddfSDavid du Colombier 				O_WRONLY|O_APPEND|O_CREAT, 0600,
190*7dd7cddfSDavid du Colombier 				SHF_WR|SHF_MAPHI);
191*7dd7cddfSDavid du Colombier 	if (kshdebug_shf) {
192*7dd7cddfSDavid du Colombier 		shf_fprintf(kshdebug_shf, "\nNew shell[pid %d]\n", getpid());
193*7dd7cddfSDavid du Colombier 		shf_flush(kshdebug_shf);
194*7dd7cddfSDavid du Colombier 	}
195*7dd7cddfSDavid du Colombier }
196*7dd7cddfSDavid du Colombier 
197*7dd7cddfSDavid du Colombier /* print to debugging log */
198*7dd7cddfSDavid du Colombier void
199*7dd7cddfSDavid du Colombier # ifdef HAVE_PROTOTYPES
kshdebug_printf_(const char * fmt,...)200*7dd7cddfSDavid du Colombier kshdebug_printf_(const char *fmt, ...)
201*7dd7cddfSDavid du Colombier # else
202*7dd7cddfSDavid du Colombier kshdebug_printf_(fmt, va_alist)
203*7dd7cddfSDavid du Colombier 	const char *fmt;
204*7dd7cddfSDavid du Colombier 	va_dcl
205*7dd7cddfSDavid du Colombier # endif
206*7dd7cddfSDavid du Colombier {
207*7dd7cddfSDavid du Colombier 	va_list va;
208*7dd7cddfSDavid du Colombier 
209*7dd7cddfSDavid du Colombier 	if (!kshdebug_shf)
210*7dd7cddfSDavid du Colombier 		return;
211*7dd7cddfSDavid du Colombier 	SH_VA_START(va, fmt);
212*7dd7cddfSDavid du Colombier 	shf_fprintf(kshdebug_shf, "[%d] ", getpid());
213*7dd7cddfSDavid du Colombier 	shf_vfprintf(kshdebug_shf, fmt, va);
214*7dd7cddfSDavid du Colombier 	va_end(va);
215*7dd7cddfSDavid du Colombier 	shf_flush(kshdebug_shf);
216*7dd7cddfSDavid du Colombier }
217*7dd7cddfSDavid du Colombier 
218*7dd7cddfSDavid du Colombier void
kshdebug_dump_(str,mem,nbytes)219*7dd7cddfSDavid du Colombier kshdebug_dump_(str, mem, nbytes)
220*7dd7cddfSDavid du Colombier 	const char *str;
221*7dd7cddfSDavid du Colombier 	const void *mem;
222*7dd7cddfSDavid du Colombier 	int nbytes;
223*7dd7cddfSDavid du Colombier {
224*7dd7cddfSDavid du Colombier 	int i, j;
225*7dd7cddfSDavid du Colombier 	int nprow = 16;
226*7dd7cddfSDavid du Colombier 
227*7dd7cddfSDavid du Colombier 	if (!kshdebug_shf)
228*7dd7cddfSDavid du Colombier 		return;
229*7dd7cddfSDavid du Colombier 	shf_fprintf(kshdebug_shf, "[%d] %s:\n", getpid(), str);
230*7dd7cddfSDavid du Colombier 	for (i = 0; i < nbytes; i += nprow) {
231*7dd7cddfSDavid du Colombier 		char c = '\t';
232*7dd7cddfSDavid du Colombier 		for (j = 0; j < nprow && i + j < nbytes; j++) {
233*7dd7cddfSDavid du Colombier 			shf_fprintf(kshdebug_shf, "%c%02x",
234*7dd7cddfSDavid du Colombier 				c, ((const unsigned char *) mem)[i + j]);
235*7dd7cddfSDavid du Colombier 			c = ' ';
236*7dd7cddfSDavid du Colombier 		}
237*7dd7cddfSDavid du Colombier 		shf_fprintf(kshdebug_shf, "\n");
238*7dd7cddfSDavid du Colombier 	}
239*7dd7cddfSDavid du Colombier 	shf_flush(kshdebug_shf);
240*7dd7cddfSDavid du Colombier }
241*7dd7cddfSDavid du Colombier #endif /* KSH_DEBUG */
242*7dd7cddfSDavid du Colombier 
243*7dd7cddfSDavid du Colombier /* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
244*7dd7cddfSDavid du Colombier int
can_seek(fd)245*7dd7cddfSDavid du Colombier can_seek(fd)
246*7dd7cddfSDavid du Colombier 	int fd;
247*7dd7cddfSDavid du Colombier {
248*7dd7cddfSDavid du Colombier 	struct stat statb;
249*7dd7cddfSDavid du Colombier 
250*7dd7cddfSDavid du Colombier 	return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
251*7dd7cddfSDavid du Colombier 		SHF_UNBUF : 0;
252*7dd7cddfSDavid du Colombier }
253*7dd7cddfSDavid du Colombier 
254*7dd7cddfSDavid du Colombier struct shf	shf_iob[3];
255*7dd7cddfSDavid du Colombier 
256*7dd7cddfSDavid du Colombier void
initio()257*7dd7cddfSDavid du Colombier initio()
258*7dd7cddfSDavid du Colombier {
259*7dd7cddfSDavid du Colombier 	shf_fdopen(1, SHF_WR, shl_stdout);	/* force buffer allocation */
260*7dd7cddfSDavid du Colombier 	shf_fdopen(2, SHF_WR, shl_out);
261*7dd7cddfSDavid du Colombier 	shf_fdopen(2, SHF_WR, shl_spare);	/* force buffer allocation */
262*7dd7cddfSDavid du Colombier 	initio_done = 1;
263*7dd7cddfSDavid du Colombier 	kshdebug_init();
264*7dd7cddfSDavid du Colombier }
265*7dd7cddfSDavid du Colombier 
266*7dd7cddfSDavid du Colombier /* A dup2() with error checking */
267*7dd7cddfSDavid du Colombier int
ksh_dup2(ofd,nfd,errok)268*7dd7cddfSDavid du Colombier ksh_dup2(ofd, nfd, errok)
269*7dd7cddfSDavid du Colombier 	int ofd;
270*7dd7cddfSDavid du Colombier 	int nfd;
271*7dd7cddfSDavid du Colombier 	int errok;
272*7dd7cddfSDavid du Colombier {
273*7dd7cddfSDavid du Colombier 	int ret = dup2(ofd, nfd);
274*7dd7cddfSDavid du Colombier 
275*7dd7cddfSDavid du Colombier 	if (ret < 0 && errno != EBADF && !errok)
276*7dd7cddfSDavid du Colombier 		errorf("too many files open in shell");
277*7dd7cddfSDavid du Colombier 
278*7dd7cddfSDavid du Colombier #ifdef DUP2_BROKEN
279*7dd7cddfSDavid du Colombier 	/* Ultrix systems like to preserve the close-on-exec flag */
280*7dd7cddfSDavid du Colombier 	if (ret >= 0)
281*7dd7cddfSDavid du Colombier 		(void) fcntl(nfd, F_SETFD, 0);
282*7dd7cddfSDavid du Colombier #endif /* DUP2_BROKEN */
283*7dd7cddfSDavid du Colombier 
284*7dd7cddfSDavid du Colombier 	return ret;
285*7dd7cddfSDavid du Colombier }
286*7dd7cddfSDavid du Colombier 
287*7dd7cddfSDavid du Colombier /*
288*7dd7cddfSDavid du Colombier  * move fd from user space (0<=fd<10) to shell space (fd>=10),
289*7dd7cddfSDavid du Colombier  * set close-on-exec flag.
290*7dd7cddfSDavid du Colombier  */
291*7dd7cddfSDavid du Colombier int
savefd(fd,noclose)292*7dd7cddfSDavid du Colombier savefd(fd, noclose)
293*7dd7cddfSDavid du Colombier 	int fd;
294*7dd7cddfSDavid du Colombier 	int noclose;
295*7dd7cddfSDavid du Colombier {
296*7dd7cddfSDavid du Colombier 	int nfd;
297*7dd7cddfSDavid du Colombier 
298*7dd7cddfSDavid du Colombier 	if (fd < FDBASE) {
299*7dd7cddfSDavid du Colombier 		nfd = ksh_dupbase(fd, FDBASE);
300*7dd7cddfSDavid du Colombier 		if (nfd < 0)
301*7dd7cddfSDavid du Colombier 			if (errno == EBADF)
302*7dd7cddfSDavid du Colombier 				return -1;
303*7dd7cddfSDavid du Colombier 			else
304*7dd7cddfSDavid du Colombier 				errorf("too many files open in shell");
305*7dd7cddfSDavid du Colombier 		if (!noclose)
306*7dd7cddfSDavid du Colombier 			close(fd);
307*7dd7cddfSDavid du Colombier 	} else
308*7dd7cddfSDavid du Colombier 		nfd = fd;
309*7dd7cddfSDavid du Colombier 	fd_clexec(nfd);
310*7dd7cddfSDavid du Colombier 	return nfd;
311*7dd7cddfSDavid du Colombier }
312*7dd7cddfSDavid du Colombier 
313*7dd7cddfSDavid du Colombier void
restfd(fd,ofd)314*7dd7cddfSDavid du Colombier restfd(fd, ofd)
315*7dd7cddfSDavid du Colombier 	int fd, ofd;
316*7dd7cddfSDavid du Colombier {
317*7dd7cddfSDavid du Colombier 	if (fd == 2)
318*7dd7cddfSDavid du Colombier 		shf_flush(&shf_iob[fd]);
319*7dd7cddfSDavid du Colombier 	if (ofd < 0)		/* original fd closed */
320*7dd7cddfSDavid du Colombier 		close(fd);
321*7dd7cddfSDavid du Colombier 	else {
322*7dd7cddfSDavid du Colombier 		ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */
323*7dd7cddfSDavid du Colombier 		close(ofd);
324*7dd7cddfSDavid du Colombier 	}
325*7dd7cddfSDavid du Colombier }
326*7dd7cddfSDavid du Colombier 
327*7dd7cddfSDavid du Colombier void
openpipe(pv)328*7dd7cddfSDavid du Colombier openpipe(pv)
329*7dd7cddfSDavid du Colombier 	register int *pv;
330*7dd7cddfSDavid du Colombier {
331*7dd7cddfSDavid du Colombier 	if (pipe(pv) < 0)
332*7dd7cddfSDavid du Colombier 		errorf("can't create pipe - try again");
333*7dd7cddfSDavid du Colombier 	pv[0] = savefd(pv[0], 0);
334*7dd7cddfSDavid du Colombier 	pv[1] = savefd(pv[1], 0);
335*7dd7cddfSDavid du Colombier }
336*7dd7cddfSDavid du Colombier 
337*7dd7cddfSDavid du Colombier void
closepipe(pv)338*7dd7cddfSDavid du Colombier closepipe(pv)
339*7dd7cddfSDavid du Colombier 	register int *pv;
340*7dd7cddfSDavid du Colombier {
341*7dd7cddfSDavid du Colombier 	close(pv[0]);
342*7dd7cddfSDavid du Colombier 	close(pv[1]);
343*7dd7cddfSDavid du Colombier }
344*7dd7cddfSDavid du Colombier 
345*7dd7cddfSDavid du Colombier /* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
346*7dd7cddfSDavid du Colombier  * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
347*7dd7cddfSDavid du Colombier  */
348*7dd7cddfSDavid du Colombier int
check_fd(name,mode,emsgp)349*7dd7cddfSDavid du Colombier check_fd(name, mode, emsgp)
350*7dd7cddfSDavid du Colombier 	char *name;
351*7dd7cddfSDavid du Colombier 	int mode;
352*7dd7cddfSDavid du Colombier 	const char **emsgp;
353*7dd7cddfSDavid du Colombier {
354*7dd7cddfSDavid du Colombier 	int fd, fl;
355*7dd7cddfSDavid du Colombier 
356*7dd7cddfSDavid du Colombier 	if (isdigit(name[0]) && !name[1]) {
357*7dd7cddfSDavid du Colombier 		fd = name[0] - '0';
358*7dd7cddfSDavid du Colombier 		if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) {
359*7dd7cddfSDavid du Colombier 			if (emsgp)
360*7dd7cddfSDavid du Colombier 				*emsgp = "bad file descriptor";
361*7dd7cddfSDavid du Colombier 			return -1;
362*7dd7cddfSDavid du Colombier 		}
363*7dd7cddfSDavid du Colombier 		fl &= O_ACCMODE;
364*7dd7cddfSDavid du Colombier #ifdef OS2
365*7dd7cddfSDavid du Colombier 		if (mode == W_OK ) {
366*7dd7cddfSDavid du Colombier 		       if (setmode(fd, O_TEXT) == -1) {
367*7dd7cddfSDavid du Colombier 				if (emsgp)
368*7dd7cddfSDavid du Colombier 					*emsgp = "couldn't set write mode";
369*7dd7cddfSDavid du Colombier 				return -1;
370*7dd7cddfSDavid du Colombier 			}
371*7dd7cddfSDavid du Colombier 		 } else if (mode == R_OK)
372*7dd7cddfSDavid du Colombier 	      		if (setmode(fd, O_BINARY) == -1) {
373*7dd7cddfSDavid du Colombier 				if (emsgp)
374*7dd7cddfSDavid du Colombier 					*emsgp = "couldn't set read mode";
375*7dd7cddfSDavid du Colombier 				return -1;
376*7dd7cddfSDavid du Colombier 			}
377*7dd7cddfSDavid du Colombier #else /* OS2 */
378*7dd7cddfSDavid du Colombier 		/* X_OK is a kludge to disable this check for dups (x<&1):
379*7dd7cddfSDavid du Colombier 		 * historical shells never did this check (XXX don't know what
380*7dd7cddfSDavid du Colombier 		 * posix has to say).
381*7dd7cddfSDavid du Colombier 		 */
382*7dd7cddfSDavid du Colombier 		if (!(mode & X_OK) && fl != O_RDWR
383*7dd7cddfSDavid du Colombier 		    && (((mode & R_OK) && fl != O_RDONLY)
384*7dd7cddfSDavid du Colombier 			|| ((mode & W_OK) && fl != O_WRONLY)))
385*7dd7cddfSDavid du Colombier 		{
386*7dd7cddfSDavid du Colombier 			if (emsgp)
387*7dd7cddfSDavid du Colombier 				*emsgp = (fl == O_WRONLY) ?
388*7dd7cddfSDavid du Colombier 						"fd not open for reading"
389*7dd7cddfSDavid du Colombier 					      : "fd not open for writing";
390*7dd7cddfSDavid du Colombier 			return -1;
391*7dd7cddfSDavid du Colombier 		}
392*7dd7cddfSDavid du Colombier #endif /* OS2 */
393*7dd7cddfSDavid du Colombier 		return fd;
394*7dd7cddfSDavid du Colombier 	}
395*7dd7cddfSDavid du Colombier #ifdef KSH
396*7dd7cddfSDavid du Colombier 	else if (name[0] == 'p' && !name[1])
397*7dd7cddfSDavid du Colombier 		return coproc_getfd(mode, emsgp);
398*7dd7cddfSDavid du Colombier #endif /* KSH */
399*7dd7cddfSDavid du Colombier 	if (emsgp)
400*7dd7cddfSDavid du Colombier 		*emsgp = "illegal file descriptor name";
401*7dd7cddfSDavid du Colombier 	return -1;
402*7dd7cddfSDavid du Colombier }
403*7dd7cddfSDavid du Colombier 
404*7dd7cddfSDavid du Colombier #ifdef KSH
405*7dd7cddfSDavid du Colombier /* Called once from main */
406*7dd7cddfSDavid du Colombier void
coproc_init()407*7dd7cddfSDavid du Colombier coproc_init()
408*7dd7cddfSDavid du Colombier {
409*7dd7cddfSDavid du Colombier 	coproc.read = coproc.readw = coproc.write = -1;
410*7dd7cddfSDavid du Colombier 	coproc.njobs = 0;
411*7dd7cddfSDavid du Colombier 	coproc.id = 0;
412*7dd7cddfSDavid du Colombier }
413*7dd7cddfSDavid du Colombier 
414*7dd7cddfSDavid du Colombier /* Called by c_read() when eof is read - close fd if it is the co-process fd */
415*7dd7cddfSDavid du Colombier void
coproc_read_close(fd)416*7dd7cddfSDavid du Colombier coproc_read_close(fd)
417*7dd7cddfSDavid du Colombier 	int fd;
418*7dd7cddfSDavid du Colombier {
419*7dd7cddfSDavid du Colombier 	if (coproc.read >= 0 && fd == coproc.read) {
420*7dd7cddfSDavid du Colombier 		coproc_readw_close(fd);
421*7dd7cddfSDavid du Colombier 		close(coproc.read);
422*7dd7cddfSDavid du Colombier 		coproc.read = -1;
423*7dd7cddfSDavid du Colombier 	}
424*7dd7cddfSDavid du Colombier }
425*7dd7cddfSDavid du Colombier 
426*7dd7cddfSDavid du Colombier /* Called by c_read() and by iosetup() to close the other side of the
427*7dd7cddfSDavid du Colombier  * read pipe, so reads will actually terminate.
428*7dd7cddfSDavid du Colombier  */
429*7dd7cddfSDavid du Colombier void
coproc_readw_close(fd)430*7dd7cddfSDavid du Colombier coproc_readw_close(fd)
431*7dd7cddfSDavid du Colombier 	int fd;
432*7dd7cddfSDavid du Colombier {
433*7dd7cddfSDavid du Colombier 	if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
434*7dd7cddfSDavid du Colombier 		close(coproc.readw);
435*7dd7cddfSDavid du Colombier 		coproc.readw = -1;
436*7dd7cddfSDavid du Colombier 	}
437*7dd7cddfSDavid du Colombier }
438*7dd7cddfSDavid du Colombier 
439*7dd7cddfSDavid du Colombier /* Called by c_print when a write to a fd fails with EPIPE and by iosetup
440*7dd7cddfSDavid du Colombier  * when co-process input is dup'd
441*7dd7cddfSDavid du Colombier  */
442*7dd7cddfSDavid du Colombier void
coproc_write_close(fd)443*7dd7cddfSDavid du Colombier coproc_write_close(fd)
444*7dd7cddfSDavid du Colombier 	int fd;
445*7dd7cddfSDavid du Colombier {
446*7dd7cddfSDavid du Colombier 	if (coproc.write >= 0 && fd == coproc.write) {
447*7dd7cddfSDavid du Colombier 		close(coproc.write);
448*7dd7cddfSDavid du Colombier 		coproc.write = -1;
449*7dd7cddfSDavid du Colombier 	}
450*7dd7cddfSDavid du Colombier }
451*7dd7cddfSDavid du Colombier 
452*7dd7cddfSDavid du Colombier /* Called to check for existance of/value of the co-process file descriptor.
453*7dd7cddfSDavid du Colombier  * (Used by check_fd() and by c_read/c_print to deal with -p option).
454*7dd7cddfSDavid du Colombier  */
455*7dd7cddfSDavid du Colombier int
coproc_getfd(mode,emsgp)456*7dd7cddfSDavid du Colombier coproc_getfd(mode, emsgp)
457*7dd7cddfSDavid du Colombier 	int mode;
458*7dd7cddfSDavid du Colombier 	const char **emsgp;
459*7dd7cddfSDavid du Colombier {
460*7dd7cddfSDavid du Colombier 	int fd = (mode & R_OK) ? coproc.read : coproc.write;
461*7dd7cddfSDavid du Colombier 
462*7dd7cddfSDavid du Colombier 	if (fd >= 0)
463*7dd7cddfSDavid du Colombier 		return fd;
464*7dd7cddfSDavid du Colombier 	if (emsgp)
465*7dd7cddfSDavid du Colombier 		*emsgp = "no coprocess";
466*7dd7cddfSDavid du Colombier 	return -1;
467*7dd7cddfSDavid du Colombier }
468*7dd7cddfSDavid du Colombier 
469*7dd7cddfSDavid du Colombier /* called to close file descriptors related to the coprocess (if any)
470*7dd7cddfSDavid du Colombier  * Should be called with SIGCHLD blocked.
471*7dd7cddfSDavid du Colombier  */
472*7dd7cddfSDavid du Colombier void
coproc_cleanup(reuse)473*7dd7cddfSDavid du Colombier coproc_cleanup(reuse)
474*7dd7cddfSDavid du Colombier 	int reuse;
475*7dd7cddfSDavid du Colombier {
476*7dd7cddfSDavid du Colombier 	/* This to allow co-processes to share output pipe */
477*7dd7cddfSDavid du Colombier 	if (!reuse || coproc.readw < 0 || coproc.read < 0) {
478*7dd7cddfSDavid du Colombier 		if (coproc.read >= 0) {
479*7dd7cddfSDavid du Colombier 			close(coproc.read);
480*7dd7cddfSDavid du Colombier 			coproc.read = -1;
481*7dd7cddfSDavid du Colombier 		}
482*7dd7cddfSDavid du Colombier 		if (coproc.readw >= 0) {
483*7dd7cddfSDavid du Colombier 			close(coproc.readw);
484*7dd7cddfSDavid du Colombier 			coproc.readw = -1;
485*7dd7cddfSDavid du Colombier 		}
486*7dd7cddfSDavid du Colombier 	}
487*7dd7cddfSDavid du Colombier 	if (coproc.write >= 0) {
488*7dd7cddfSDavid du Colombier 		close(coproc.write);
489*7dd7cddfSDavid du Colombier 		coproc.write = -1;
490*7dd7cddfSDavid du Colombier 	}
491*7dd7cddfSDavid du Colombier }
492*7dd7cddfSDavid du Colombier #endif /* KSH */
493*7dd7cddfSDavid du Colombier 
494*7dd7cddfSDavid du Colombier 
495*7dd7cddfSDavid du Colombier /*
496*7dd7cddfSDavid du Colombier  * temporary files
497*7dd7cddfSDavid du Colombier  */
498*7dd7cddfSDavid du Colombier 
499*7dd7cddfSDavid du Colombier struct temp *
maketemp(ap,type,tlist)500*7dd7cddfSDavid du Colombier maketemp(ap, type, tlist)
501*7dd7cddfSDavid du Colombier 	Area *ap;
502*7dd7cddfSDavid du Colombier 	Temp_type type;
503*7dd7cddfSDavid du Colombier 	struct temp **tlist;
504*7dd7cddfSDavid du Colombier {
505*7dd7cddfSDavid du Colombier 	static unsigned int inc;
506*7dd7cddfSDavid du Colombier 	struct temp *tp;
507*7dd7cddfSDavid du Colombier 	int len;
508*7dd7cddfSDavid du Colombier 	int fd;
509*7dd7cddfSDavid du Colombier 	char *path;
510*7dd7cddfSDavid du Colombier 	const char *dir;
511*7dd7cddfSDavid du Colombier 
512*7dd7cddfSDavid du Colombier 	dir = tmpdir ? tmpdir : "/tmp";
513*7dd7cddfSDavid du Colombier 	/* The 20 + 20 is a paranoid worst case for pid/inc */
514*7dd7cddfSDavid du Colombier 	len = strlen(dir) + 3 + 20 + 20 + 1;
515*7dd7cddfSDavid du Colombier 	tp = (struct temp *) alloc(sizeof(struct temp) + len, ap);
516*7dd7cddfSDavid du Colombier 	tp->name = path = (char *) &tp[1];
517*7dd7cddfSDavid du Colombier 	tp->shf = (struct shf *) 0;
518*7dd7cddfSDavid du Colombier 	tp->type = type;
519*7dd7cddfSDavid du Colombier 	while (1) {
520*7dd7cddfSDavid du Colombier 		/* Note that temp files need to fit 8.3 DOS limits */
521*7dd7cddfSDavid du Colombier 		shf_snprintf(path, len, "%s/sh%05u.%03x",
522*7dd7cddfSDavid du Colombier 			     dir, (unsigned) procpid, inc++);
523*7dd7cddfSDavid du Colombier 		/* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't
524*7dd7cddfSDavid du Colombier 		 * really there.
525*7dd7cddfSDavid du Colombier 		 */
526*7dd7cddfSDavid du Colombier 		fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600);
527*7dd7cddfSDavid du Colombier 		if (fd >= 0) {
528*7dd7cddfSDavid du Colombier 			tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
529*7dd7cddfSDavid du Colombier 			break;
530*7dd7cddfSDavid du Colombier 		}
531*7dd7cddfSDavid du Colombier 		if (errno != EINTR
532*7dd7cddfSDavid du Colombier #ifdef EEXIST
533*7dd7cddfSDavid du Colombier 		    && errno != EEXIST
534*7dd7cddfSDavid du Colombier #endif /* EEXIST */
535*7dd7cddfSDavid du Colombier #ifdef EISDIR
536*7dd7cddfSDavid du Colombier 		    && errno != EISDIR
537*7dd7cddfSDavid du Colombier #endif /* EISDIR */
538*7dd7cddfSDavid du Colombier 			)
539*7dd7cddfSDavid du Colombier 			/* Error must be printed by caller: don't know here if
540*7dd7cddfSDavid du Colombier 			 * errorf() or bi_errorf() should be used.
541*7dd7cddfSDavid du Colombier 			 */
542*7dd7cddfSDavid du Colombier 			break;
543*7dd7cddfSDavid du Colombier 	}
544*7dd7cddfSDavid du Colombier 	tp->next = NULL;
545*7dd7cddfSDavid du Colombier 	tp->pid = procpid;
546*7dd7cddfSDavid du Colombier 
547*7dd7cddfSDavid du Colombier 	tp->next = *tlist;
548*7dd7cddfSDavid du Colombier 	*tlist = tp;
549*7dd7cddfSDavid du Colombier 
550*7dd7cddfSDavid du Colombier 	return tp;
551*7dd7cddfSDavid du Colombier }
552