xref: /openbsd/bin/ksh/io.c (revision 18bbba6b)
1*18bbba6bSmillert /*	$OpenBSD: io.c,v 1.7 1999/01/10 17:55:02 millert Exp $	*/
27cb960a2Sdownsj 
37cb960a2Sdownsj /*
47cb960a2Sdownsj  * shell buffered IO and formatted output
57cb960a2Sdownsj  */
67cb960a2Sdownsj 
77cb960a2Sdownsj #include <ctype.h>
87cb960a2Sdownsj #include "sh.h"
97cb960a2Sdownsj #include "ksh_stat.h"
107cb960a2Sdownsj 
113b015934Smillert static int initio_done;
123b015934Smillert 
137cb960a2Sdownsj /*
147cb960a2Sdownsj  * formatted output functions
157cb960a2Sdownsj  */
167cb960a2Sdownsj 
177cb960a2Sdownsj 
187cb960a2Sdownsj /* A shell error occured (eg, syntax error, etc.) */
197cb960a2Sdownsj void
207cb960a2Sdownsj #ifdef HAVE_PROTOTYPES
217cb960a2Sdownsj errorf(const char *fmt, ...)
227cb960a2Sdownsj #else
237cb960a2Sdownsj errorf(fmt, va_alist)
247cb960a2Sdownsj 	const char *fmt;
257cb960a2Sdownsj 	va_dcl
267cb960a2Sdownsj #endif
277cb960a2Sdownsj {
287cb960a2Sdownsj 	va_list va;
297cb960a2Sdownsj 
307cb960a2Sdownsj 	shl_stdout_ok = 0;	/* debugging: note that stdout not valid */
317cb960a2Sdownsj 	exstat = 1;
327cb960a2Sdownsj 	if (*fmt) {
337cb960a2Sdownsj 		error_prefix(TRUE);
347cb960a2Sdownsj 		SH_VA_START(va, fmt);
357cb960a2Sdownsj 		shf_vfprintf(shl_out, fmt, va);
367cb960a2Sdownsj 		va_end(va);
377cb960a2Sdownsj 		shf_putchar('\n', shl_out);
387cb960a2Sdownsj 	}
397cb960a2Sdownsj 	shf_flush(shl_out);
407cb960a2Sdownsj 	unwind(LERROR);
417cb960a2Sdownsj }
427cb960a2Sdownsj 
437cb960a2Sdownsj /* like errorf(), but no unwind is done */
447cb960a2Sdownsj void
457cb960a2Sdownsj #ifdef HAVE_PROTOTYPES
467cb960a2Sdownsj warningf(int fileline, const char *fmt, ...)
477cb960a2Sdownsj #else
487cb960a2Sdownsj warningf(fileline, fmt, va_alist)
497cb960a2Sdownsj 	int fileline;
507cb960a2Sdownsj 	const char *fmt;
517cb960a2Sdownsj 	va_dcl
527cb960a2Sdownsj #endif
537cb960a2Sdownsj {
547cb960a2Sdownsj 	va_list va;
557cb960a2Sdownsj 
567cb960a2Sdownsj 	error_prefix(fileline);
577cb960a2Sdownsj 	SH_VA_START(va, fmt);
587cb960a2Sdownsj 	shf_vfprintf(shl_out, fmt, va);
597cb960a2Sdownsj 	va_end(va);
607cb960a2Sdownsj 	shf_putchar('\n', shl_out);
617cb960a2Sdownsj 	shf_flush(shl_out);
627cb960a2Sdownsj }
637cb960a2Sdownsj 
647cb960a2Sdownsj /* Used by built-in utilities to prefix shell and utility name to message
657cb960a2Sdownsj  * (also unwinds environments for special builtins).
667cb960a2Sdownsj  */
677cb960a2Sdownsj void
687cb960a2Sdownsj #ifdef HAVE_PROTOTYPES
697cb960a2Sdownsj bi_errorf(const char *fmt, ...)
707cb960a2Sdownsj #else
717cb960a2Sdownsj bi_errorf(fmt, va_alist)
727cb960a2Sdownsj 	const char *fmt;
737cb960a2Sdownsj 	va_dcl
747cb960a2Sdownsj #endif
757cb960a2Sdownsj {
767cb960a2Sdownsj 	va_list va;
777cb960a2Sdownsj 
787cb960a2Sdownsj 	shl_stdout_ok = 0;	/* debugging: note that stdout not valid */
797cb960a2Sdownsj 	exstat = 1;
807cb960a2Sdownsj 	if (*fmt) {
817cb960a2Sdownsj 		error_prefix(TRUE);
827cb960a2Sdownsj 		/* not set when main() calls parse_args() */
837cb960a2Sdownsj 		if (builtin_argv0)
847cb960a2Sdownsj 			shf_fprintf(shl_out, "%s: ", builtin_argv0);
857cb960a2Sdownsj 		SH_VA_START(va, fmt);
867cb960a2Sdownsj 		shf_vfprintf(shl_out, fmt, va);
877cb960a2Sdownsj 		va_end(va);
887cb960a2Sdownsj 		shf_putchar('\n', shl_out);
897cb960a2Sdownsj 	}
907cb960a2Sdownsj 	shf_flush(shl_out);
917cb960a2Sdownsj 	/* POSIX special builtins and ksh special builtins cause
927cb960a2Sdownsj 	 * non-interactive shells to exit.
937cb960a2Sdownsj 	 * XXX odd use of KEEPASN; also may not want LERROR here
947cb960a2Sdownsj 	 */
957cb960a2Sdownsj 	if ((builtin_flag & SPEC_BI)
967cb960a2Sdownsj 	    || (Flag(FPOSIX) && (builtin_flag & KEEPASN)))
977cb960a2Sdownsj 	{
984c69a2c1Skstailey 		builtin_argv0 = (char *) 0;
997cb960a2Sdownsj 		unwind(LERROR);
1007cb960a2Sdownsj 	}
1017cb960a2Sdownsj }
1027cb960a2Sdownsj 
1037cb960a2Sdownsj /* Called when something that shouldn't happen does */
1047cb960a2Sdownsj void
1057cb960a2Sdownsj #ifdef HAVE_PROTOTYPES
1067cb960a2Sdownsj internal_errorf(int jump, const char *fmt, ...)
1077cb960a2Sdownsj #else
1087cb960a2Sdownsj internal_errorf(jump, fmt, va_alist)
1097cb960a2Sdownsj 	int jump;
1107cb960a2Sdownsj 	const char *fmt;
1117cb960a2Sdownsj 	va_dcl
1127cb960a2Sdownsj #endif
1137cb960a2Sdownsj {
1147cb960a2Sdownsj 	va_list va;
1157cb960a2Sdownsj 
1167cb960a2Sdownsj 	error_prefix(TRUE);
1177cb960a2Sdownsj 	shf_fprintf(shl_out, "internal error: ");
1187cb960a2Sdownsj 	SH_VA_START(va, fmt);
1197cb960a2Sdownsj 	shf_vfprintf(shl_out, fmt, va);
1207cb960a2Sdownsj 	va_end(va);
1217cb960a2Sdownsj 	shf_putchar('\n', shl_out);
1227cb960a2Sdownsj 	shf_flush(shl_out);
1237cb960a2Sdownsj 	if (jump)
1247cb960a2Sdownsj 		unwind(LERROR);
1257cb960a2Sdownsj }
1267cb960a2Sdownsj 
1277cb960a2Sdownsj /* used by error reporting functions to print "ksh: .kshrc[25]: " */
1287cb960a2Sdownsj void
1297cb960a2Sdownsj error_prefix(fileline)
1307cb960a2Sdownsj 	int fileline;
1317cb960a2Sdownsj {
1323b015934Smillert 	/* Avoid foo: foo[2]: ... */
1333b015934Smillert 	if (!fileline || !source || !source->file
1343b015934Smillert 	    || strcmp(source->file, kshname) != 0)
1357cb960a2Sdownsj 		shf_fprintf(shl_out, "%s: ", kshname + (*kshname == '-'));
1367cb960a2Sdownsj 	if (fileline && source && source->file != NULL) {
1377cb960a2Sdownsj 		shf_fprintf(shl_out, "%s[%d]: ", source->file,
1387cb960a2Sdownsj 			source->errline > 0 ? source->errline : source->line);
1397cb960a2Sdownsj 		source->errline = 0;
1407cb960a2Sdownsj 	}
1417cb960a2Sdownsj }
1427cb960a2Sdownsj 
1437cb960a2Sdownsj /* printf to shl_out (stderr) with flush */
1447cb960a2Sdownsj void
1457cb960a2Sdownsj #ifdef HAVE_PROTOTYPES
1467cb960a2Sdownsj shellf(const char *fmt, ...)
1477cb960a2Sdownsj #else
1487cb960a2Sdownsj shellf(fmt, va_alist)
1497cb960a2Sdownsj 	const char *fmt;
1507cb960a2Sdownsj 	va_dcl
1517cb960a2Sdownsj #endif
1527cb960a2Sdownsj {
1537cb960a2Sdownsj 	va_list va;
1547cb960a2Sdownsj 
1553b015934Smillert 	if (!initio_done) /* shl_out may not be set up yet... */
1563b015934Smillert 		return;
1577cb960a2Sdownsj 	SH_VA_START(va, fmt);
1587cb960a2Sdownsj 	shf_vfprintf(shl_out, fmt, va);
1597cb960a2Sdownsj 	va_end(va);
1607cb960a2Sdownsj 	shf_flush(shl_out);
1617cb960a2Sdownsj }
1627cb960a2Sdownsj 
1637cb960a2Sdownsj /* printf to shl_stdout (stdout) */
1647cb960a2Sdownsj void
1657cb960a2Sdownsj #ifdef HAVE_PROTOTYPES
1667cb960a2Sdownsj shprintf(const char *fmt, ...)
1677cb960a2Sdownsj #else
1687cb960a2Sdownsj shprintf(fmt, va_alist)
1697cb960a2Sdownsj 	const char *fmt;
1707cb960a2Sdownsj 	va_dcl
1717cb960a2Sdownsj #endif
1727cb960a2Sdownsj {
1737cb960a2Sdownsj 	va_list va;
1747cb960a2Sdownsj 
1757cb960a2Sdownsj 	if (!shl_stdout_ok)
1767cb960a2Sdownsj 		internal_errorf(1, "shl_stdout not valid");
1777cb960a2Sdownsj 	SH_VA_START(va, fmt);
1787cb960a2Sdownsj 	shf_vfprintf(shl_stdout, fmt, va);
1797cb960a2Sdownsj 	va_end(va);
1807cb960a2Sdownsj }
1817cb960a2Sdownsj 
182945abdecSmillert #ifdef KSH_DEBUG
183945abdecSmillert static struct shf *kshdebug_shf;
184945abdecSmillert 
185945abdecSmillert void
186945abdecSmillert kshdebug_init_()
187945abdecSmillert {
188945abdecSmillert 	if (kshdebug_shf)
189945abdecSmillert 		shf_close(kshdebug_shf);
190945abdecSmillert 	kshdebug_shf = shf_open("/tmp/ksh-debug.log",
191945abdecSmillert 				O_WRONLY|O_APPEND|O_CREAT, 0600,
192945abdecSmillert 				SHF_WR|SHF_MAPHI);
193945abdecSmillert 	if (kshdebug_shf) {
194945abdecSmillert 		shf_fprintf(kshdebug_shf, "\nNew shell[pid %d]\n", getpid());
195945abdecSmillert 		shf_flush(kshdebug_shf);
196945abdecSmillert 	}
197945abdecSmillert }
198945abdecSmillert 
199945abdecSmillert /* print to debugging log */
200945abdecSmillert void
201945abdecSmillert # ifdef HAVE_PROTOTYPES
202945abdecSmillert kshdebug_printf_(const char *fmt, ...)
203945abdecSmillert # else
204945abdecSmillert kshdebug_printf_(fmt, va_alist)
205945abdecSmillert 	const char *fmt;
206945abdecSmillert 	va_dcl
207945abdecSmillert # endif
208945abdecSmillert {
209945abdecSmillert 	va_list va;
210945abdecSmillert 
211945abdecSmillert 	if (!kshdebug_shf)
212945abdecSmillert 		return;
213945abdecSmillert 	SH_VA_START(va, fmt);
214945abdecSmillert 	shf_fprintf(kshdebug_shf, "[%d] ", getpid());
215945abdecSmillert 	shf_vfprintf(kshdebug_shf, fmt, va);
216945abdecSmillert 	va_end(va);
217945abdecSmillert 	shf_flush(kshdebug_shf);
218945abdecSmillert }
219945abdecSmillert 
220945abdecSmillert void
221945abdecSmillert kshdebug_dump_(str, mem, nbytes)
222945abdecSmillert 	const char *str;
223945abdecSmillert 	const void *mem;
224945abdecSmillert 	int nbytes;
225945abdecSmillert {
226945abdecSmillert 	int i, j;
227945abdecSmillert 	int nprow = 16;
228945abdecSmillert 
229945abdecSmillert 	if (!kshdebug_shf)
230945abdecSmillert 		return;
231945abdecSmillert 	shf_fprintf(kshdebug_shf, "[%d] %s:\n", getpid(), str);
232945abdecSmillert 	for (i = 0; i < nbytes; i += nprow) {
233945abdecSmillert 		char c = '\t';
234945abdecSmillert 		for (j = 0; j < nprow && i + j < nbytes; j++) {
235945abdecSmillert 			shf_fprintf(kshdebug_shf, "%c%02x",
236945abdecSmillert 				c, ((const unsigned char *) mem)[i + j]);
237945abdecSmillert 			c = ' ';
238945abdecSmillert 		}
239945abdecSmillert 		shf_fprintf(kshdebug_shf, "\n");
240945abdecSmillert 	}
241945abdecSmillert 	shf_flush(kshdebug_shf);
242945abdecSmillert }
243945abdecSmillert #endif /* KSH_DEBUG */
244945abdecSmillert 
2457cb960a2Sdownsj /* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
2467cb960a2Sdownsj int
2477cb960a2Sdownsj can_seek(fd)
2487cb960a2Sdownsj 	int fd;
2497cb960a2Sdownsj {
2507cb960a2Sdownsj 	struct stat statb;
2517cb960a2Sdownsj 
2527cb960a2Sdownsj 	return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
2537cb960a2Sdownsj 		SHF_UNBUF : 0;
2547cb960a2Sdownsj }
2557cb960a2Sdownsj 
2567cb960a2Sdownsj struct shf	shf_iob[3];
2577cb960a2Sdownsj 
2587cb960a2Sdownsj void
2597cb960a2Sdownsj initio()
2607cb960a2Sdownsj {
2617cb960a2Sdownsj 	shf_fdopen(1, SHF_WR, shl_stdout);	/* force buffer allocation */
2627cb960a2Sdownsj 	shf_fdopen(2, SHF_WR, shl_out);
2637cb960a2Sdownsj 	shf_fdopen(2, SHF_WR, shl_spare);	/* force buffer allocation */
2643b015934Smillert 	initio_done = 1;
265945abdecSmillert 	kshdebug_init();
2667cb960a2Sdownsj }
2677cb960a2Sdownsj 
2687cb960a2Sdownsj /* A dup2() with error checking */
2697cb960a2Sdownsj int
2707cb960a2Sdownsj ksh_dup2(ofd, nfd, errok)
2717cb960a2Sdownsj 	int ofd;
2727cb960a2Sdownsj 	int nfd;
2737cb960a2Sdownsj 	int errok;
2747cb960a2Sdownsj {
2757cb960a2Sdownsj 	int ret = dup2(ofd, nfd);
2767cb960a2Sdownsj 
2777cb960a2Sdownsj 	if (ret < 0 && errno != EBADF && !errok)
2787cb960a2Sdownsj 		errorf("too many files open in shell");
2797cb960a2Sdownsj 
2807cb960a2Sdownsj #ifdef DUP2_BROKEN
2817cb960a2Sdownsj 	/* Ultrix systems like to preserve the close-on-exec flag */
2827cb960a2Sdownsj 	if (ret >= 0)
2837cb960a2Sdownsj 		(void) fcntl(nfd, F_SETFD, 0);
2847cb960a2Sdownsj #endif /* DUP2_BROKEN */
2857cb960a2Sdownsj 
2867cb960a2Sdownsj 	return ret;
2877cb960a2Sdownsj }
2887cb960a2Sdownsj 
2897cb960a2Sdownsj /*
2907cb960a2Sdownsj  * move fd from user space (0<=fd<10) to shell space (fd>=10),
2917cb960a2Sdownsj  * set close-on-exec flag.
2927cb960a2Sdownsj  */
2937cb960a2Sdownsj int
2947cb960a2Sdownsj savefd(fd, noclose)
2957cb960a2Sdownsj 	int fd;
2967cb960a2Sdownsj 	int noclose;
2977cb960a2Sdownsj {
2987cb960a2Sdownsj 	int nfd;
2997cb960a2Sdownsj 
3007cb960a2Sdownsj 	if (fd < FDBASE) {
3017cb960a2Sdownsj 		nfd = ksh_dupbase(fd, FDBASE);
302*18bbba6bSmillert 		if (nfd < 0) {
3037cb960a2Sdownsj 			if (errno == EBADF)
3047cb960a2Sdownsj 				return -1;
3057cb960a2Sdownsj 			else
3067cb960a2Sdownsj 				errorf("too many files open in shell");
307*18bbba6bSmillert 		}
3087cb960a2Sdownsj 		if (!noclose)
3097cb960a2Sdownsj 			close(fd);
3107cb960a2Sdownsj 	} else
3117cb960a2Sdownsj 		nfd = fd;
3127cb960a2Sdownsj 	fd_clexec(nfd);
3137cb960a2Sdownsj 	return nfd;
3147cb960a2Sdownsj }
3157cb960a2Sdownsj 
3167cb960a2Sdownsj void
3177cb960a2Sdownsj restfd(fd, ofd)
3187cb960a2Sdownsj 	int fd, ofd;
3197cb960a2Sdownsj {
3207cb960a2Sdownsj 	if (fd == 2)
3217cb960a2Sdownsj 		shf_flush(&shf_iob[fd]);
3227cb960a2Sdownsj 	if (ofd < 0)		/* original fd closed */
3237cb960a2Sdownsj 		close(fd);
3247cb960a2Sdownsj 	else {
3257cb960a2Sdownsj 		ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */
3267cb960a2Sdownsj 		close(ofd);
3277cb960a2Sdownsj 	}
3287cb960a2Sdownsj }
3297cb960a2Sdownsj 
3307cb960a2Sdownsj void
3317cb960a2Sdownsj openpipe(pv)
3327cb960a2Sdownsj 	register int *pv;
3337cb960a2Sdownsj {
3347cb960a2Sdownsj 	if (pipe(pv) < 0)
3357cb960a2Sdownsj 		errorf("can't create pipe - try again");
3367cb960a2Sdownsj 	pv[0] = savefd(pv[0], 0);
3377cb960a2Sdownsj 	pv[1] = savefd(pv[1], 0);
3387cb960a2Sdownsj }
3397cb960a2Sdownsj 
3407cb960a2Sdownsj void
3417cb960a2Sdownsj closepipe(pv)
3427cb960a2Sdownsj 	register int *pv;
3437cb960a2Sdownsj {
3447cb960a2Sdownsj 	close(pv[0]);
3457cb960a2Sdownsj 	close(pv[1]);
3467cb960a2Sdownsj }
3477cb960a2Sdownsj 
3487cb960a2Sdownsj /* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
3497cb960a2Sdownsj  * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
3507cb960a2Sdownsj  */
3517cb960a2Sdownsj int
3527cb960a2Sdownsj check_fd(name, mode, emsgp)
3537cb960a2Sdownsj 	char *name;
3547cb960a2Sdownsj 	int mode;
3557cb960a2Sdownsj 	const char **emsgp;
3567cb960a2Sdownsj {
3577cb960a2Sdownsj 	int fd, fl;
3587cb960a2Sdownsj 
3597cb960a2Sdownsj 	if (isdigit(name[0]) && !name[1]) {
3607cb960a2Sdownsj 		fd = name[0] - '0';
3617cb960a2Sdownsj 		if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) {
3627cb960a2Sdownsj 			if (emsgp)
3637cb960a2Sdownsj 				*emsgp = "bad file descriptor";
3647cb960a2Sdownsj 			return -1;
3657cb960a2Sdownsj 		}
3667cb960a2Sdownsj 		fl &= O_ACCMODE;
3677cb960a2Sdownsj #ifdef OS2
3687cb960a2Sdownsj 		if (mode == W_OK ) {
3697cb960a2Sdownsj 		       if (setmode(fd, O_TEXT) == -1) {
3707cb960a2Sdownsj 				if (emsgp)
3717cb960a2Sdownsj 					*emsgp = "couldn't set write mode";
3727cb960a2Sdownsj 				return -1;
3737cb960a2Sdownsj 			}
3747cb960a2Sdownsj 		 } else if (mode == R_OK)
3757cb960a2Sdownsj 	      		if (setmode(fd, O_BINARY) == -1) {
3767cb960a2Sdownsj 				if (emsgp)
3777cb960a2Sdownsj 					*emsgp = "couldn't set read mode";
3787cb960a2Sdownsj 				return -1;
3797cb960a2Sdownsj 			}
3807cb960a2Sdownsj #else /* OS2 */
3817cb960a2Sdownsj 		/* X_OK is a kludge to disable this check for dups (x<&1):
3827cb960a2Sdownsj 		 * historical shells never did this check (XXX don't know what
3837cb960a2Sdownsj 		 * posix has to say).
3847cb960a2Sdownsj 		 */
3857cb960a2Sdownsj 		if (!(mode & X_OK) && fl != O_RDWR
3867cb960a2Sdownsj 		    && (((mode & R_OK) && fl != O_RDONLY)
3877cb960a2Sdownsj 			|| ((mode & W_OK) && fl != O_WRONLY)))
3887cb960a2Sdownsj 		{
3897cb960a2Sdownsj 			if (emsgp)
3907cb960a2Sdownsj 				*emsgp = (fl == O_WRONLY) ?
3917cb960a2Sdownsj 						"fd not open for reading"
3927cb960a2Sdownsj 					      : "fd not open for writing";
3937cb960a2Sdownsj 			return -1;
3947cb960a2Sdownsj 		}
3957cb960a2Sdownsj #endif /* OS2 */
3967cb960a2Sdownsj 		return fd;
3977cb960a2Sdownsj 	}
3987cb960a2Sdownsj #ifdef KSH
3997cb960a2Sdownsj 	else if (name[0] == 'p' && !name[1])
400dcacb757Sdownsj 		return coproc_getfd(mode, emsgp);
4017cb960a2Sdownsj #endif /* KSH */
4027cb960a2Sdownsj 	if (emsgp)
4037cb960a2Sdownsj 		*emsgp = "illegal file descriptor name";
4047cb960a2Sdownsj 	return -1;
4057cb960a2Sdownsj }
4067cb960a2Sdownsj 
4077cb960a2Sdownsj #ifdef KSH
4087cb960a2Sdownsj /* Called once from main */
4097cb960a2Sdownsj void
4107cb960a2Sdownsj coproc_init()
4117cb960a2Sdownsj {
4127cb960a2Sdownsj 	coproc.read = coproc.readw = coproc.write = -1;
413dcacb757Sdownsj 	coproc.njobs = 0;
414dcacb757Sdownsj 	coproc.id = 0;
4157cb960a2Sdownsj }
4167cb960a2Sdownsj 
4177cb960a2Sdownsj /* Called by c_read() when eof is read - close fd if it is the co-process fd */
4187cb960a2Sdownsj void
4197cb960a2Sdownsj coproc_read_close(fd)
4207cb960a2Sdownsj 	int fd;
4217cb960a2Sdownsj {
4227cb960a2Sdownsj 	if (coproc.read >= 0 && fd == coproc.read) {
423dcacb757Sdownsj 		coproc_readw_close(fd);
4247cb960a2Sdownsj 		close(coproc.read);
4257cb960a2Sdownsj 		coproc.read = -1;
4267cb960a2Sdownsj 	}
4277cb960a2Sdownsj }
4287cb960a2Sdownsj 
4297cb960a2Sdownsj /* Called by c_read() and by iosetup() to close the other side of the
4307cb960a2Sdownsj  * read pipe, so reads will actually terminate.
4317cb960a2Sdownsj  */
4327cb960a2Sdownsj void
4337cb960a2Sdownsj coproc_readw_close(fd)
4347cb960a2Sdownsj 	int fd;
4357cb960a2Sdownsj {
436dcacb757Sdownsj 	if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
4377cb960a2Sdownsj 		close(coproc.readw);
4387cb960a2Sdownsj 		coproc.readw = -1;
4397cb960a2Sdownsj 	}
4407cb960a2Sdownsj }
4417cb960a2Sdownsj 
4427cb960a2Sdownsj /* Called by c_print when a write to a fd fails with EPIPE and by iosetup
4437cb960a2Sdownsj  * when co-process input is dup'd
4447cb960a2Sdownsj  */
4457cb960a2Sdownsj void
4467cb960a2Sdownsj coproc_write_close(fd)
4477cb960a2Sdownsj 	int fd;
4487cb960a2Sdownsj {
4497cb960a2Sdownsj 	if (coproc.write >= 0 && fd == coproc.write) {
4507cb960a2Sdownsj 		close(coproc.write);
4517cb960a2Sdownsj 		coproc.write = -1;
4527cb960a2Sdownsj 	}
4537cb960a2Sdownsj }
4547cb960a2Sdownsj 
4557cb960a2Sdownsj /* Called to check for existance of/value of the co-process file descriptor.
4567cb960a2Sdownsj  * (Used by check_fd() and by c_read/c_print to deal with -p option).
4577cb960a2Sdownsj  */
4587cb960a2Sdownsj int
459dcacb757Sdownsj coproc_getfd(mode, emsgp)
4607cb960a2Sdownsj 	int mode;
4617cb960a2Sdownsj 	const char **emsgp;
4627cb960a2Sdownsj {
4637cb960a2Sdownsj 	int fd = (mode & R_OK) ? coproc.read : coproc.write;
4647cb960a2Sdownsj 
4657cb960a2Sdownsj 	if (fd >= 0)
4667cb960a2Sdownsj 		return fd;
4677cb960a2Sdownsj 	if (emsgp)
4687cb960a2Sdownsj 		*emsgp = "no coprocess";
4697cb960a2Sdownsj 	return -1;
4707cb960a2Sdownsj }
4717cb960a2Sdownsj 
472dcacb757Sdownsj /* called to close file descriptors related to the coprocess (if any)
473dcacb757Sdownsj  * Should be called with SIGCHLD blocked.
474dcacb757Sdownsj  */
4757cb960a2Sdownsj void
476dcacb757Sdownsj coproc_cleanup(reuse)
4777cb960a2Sdownsj 	int reuse;
4787cb960a2Sdownsj {
4797cb960a2Sdownsj 	/* This to allow co-processes to share output pipe */
4807cb960a2Sdownsj 	if (!reuse || coproc.readw < 0 || coproc.read < 0) {
4817cb960a2Sdownsj 		if (coproc.read >= 0) {
4827cb960a2Sdownsj 			close(coproc.read);
4837cb960a2Sdownsj 			coproc.read = -1;
4847cb960a2Sdownsj 		}
4857cb960a2Sdownsj 		if (coproc.readw >= 0) {
4867cb960a2Sdownsj 			close(coproc.readw);
4877cb960a2Sdownsj 			coproc.readw = -1;
4887cb960a2Sdownsj 		}
4897cb960a2Sdownsj 	}
4907cb960a2Sdownsj 	if (coproc.write >= 0) {
4917cb960a2Sdownsj 		close(coproc.write);
4927cb960a2Sdownsj 		coproc.write = -1;
4937cb960a2Sdownsj 	}
4947cb960a2Sdownsj }
4957cb960a2Sdownsj #endif /* KSH */
4967cb960a2Sdownsj 
4977cb960a2Sdownsj /*
4987cb960a2Sdownsj  * temporary files
4997cb960a2Sdownsj  */
5007cb960a2Sdownsj 
5017cb960a2Sdownsj struct temp *
5027cb960a2Sdownsj maketemp(ap)
5037cb960a2Sdownsj 	Area *ap;
5047cb960a2Sdownsj {
5057cb960a2Sdownsj 	static unsigned int inc;
5067cb960a2Sdownsj 	struct temp *tp;
5077cb960a2Sdownsj 	int len;
5087cb960a2Sdownsj 	int fd;
5097cb960a2Sdownsj 	char *path;
5107cb960a2Sdownsj 	const char *tmp;
5117cb960a2Sdownsj 
5127cb960a2Sdownsj 	tmp = tmpdir ? tmpdir : "/tmp";
5137cb960a2Sdownsj 	/* The 20 + 20 is a paranoid worst case for pid/inc */
5147cb960a2Sdownsj 	len = strlen(tmp) + 3 + 20 + 20 + 1;
5157cb960a2Sdownsj 	tp = (struct temp *) alloc(sizeof(struct temp) + len, ap);
5167cb960a2Sdownsj 	tp->name = path = (char *) &tp[1];
5174c69a2c1Skstailey 	tp->shf = (struct shf *) 0;
5187cb960a2Sdownsj 	while (1) {
5197cb960a2Sdownsj 		/* Note that temp files need to fit 8.3 DOS limits */
5207cb960a2Sdownsj 		shf_snprintf(path, len, "%s/sh%05u.%03x",
5217cb960a2Sdownsj 			tmp, (unsigned) procpid, inc++);
5227cb960a2Sdownsj 		/* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't
5237cb960a2Sdownsj 		 * really there.
5247cb960a2Sdownsj 		 */
5257cb960a2Sdownsj 		fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600);
5267cb960a2Sdownsj 		if (fd >= 0) {
5274c69a2c1Skstailey 			tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
5287cb960a2Sdownsj 			break;
5297cb960a2Sdownsj 		}
5307cb960a2Sdownsj 		if (errno != EINTR
5317cb960a2Sdownsj #ifdef EEXIST
5327cb960a2Sdownsj 		    && errno != EEXIST
5337cb960a2Sdownsj #endif /* EEXIST */
5347cb960a2Sdownsj #ifdef EISDIR
5357cb960a2Sdownsj 		    && errno != EISDIR
5367cb960a2Sdownsj #endif /* EISDIR */
5377cb960a2Sdownsj 			)
5387cb960a2Sdownsj 			/* Error must be printed by called: don't know here if
5397cb960a2Sdownsj 			 * errorf() or bi_errorf() should be used.
5407cb960a2Sdownsj 			 */
5417cb960a2Sdownsj 			break;
5427cb960a2Sdownsj 	}
5437cb960a2Sdownsj 	tp->next = NULL;
5447cb960a2Sdownsj 	tp->pid = procpid;
5457cb960a2Sdownsj 	return tp;
5467cb960a2Sdownsj }
547