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