Home | History | Annotate | Line # | Download | only in ksh
io.c revision 1.2
      1 /*	$NetBSD: io.c,v 1.2 1997/01/12 19:11:53 tls 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 		if (!noclose)
    236 			close(fd);
    237 	} else
    238 		nfd = fd;
    239 	fd_clexec(nfd);
    240 	return nfd;
    241 }
    242 
    243 void
    244 restfd(fd, ofd)
    245 	int fd, ofd;
    246 {
    247 	if (fd == 2)
    248 		shf_flush(&shf_iob[fd]);
    249 	if (ofd < 0)		/* original fd closed */
    250 		close(fd);
    251 	else {
    252 		ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */
    253 		close(ofd);
    254 	}
    255 }
    256 
    257 void
    258 openpipe(pv)
    259 	register int *pv;
    260 {
    261 	if (pipe(pv) < 0)
    262 		errorf("can't create pipe - try again");
    263 	pv[0] = savefd(pv[0], 0);
    264 	pv[1] = savefd(pv[1], 0);
    265 }
    266 
    267 void
    268 closepipe(pv)
    269 	register int *pv;
    270 {
    271 	close(pv[0]);
    272 	close(pv[1]);
    273 }
    274 
    275 /* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
    276  * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
    277  */
    278 int
    279 check_fd(name, mode, emsgp)
    280 	char *name;
    281 	int mode;
    282 	const char **emsgp;
    283 {
    284 	int fd, fl;
    285 
    286 	if (isdigit(name[0]) && !name[1]) {
    287 		fd = name[0] - '0';
    288 		if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) {
    289 			if (emsgp)
    290 				*emsgp = "bad file descriptor";
    291 			return -1;
    292 		}
    293 		fl &= O_ACCMODE;
    294 #ifdef OS2
    295 		if (mode == W_OK ) {
    296 		       if (setmode(fd, O_TEXT) == -1) {
    297 				if (emsgp)
    298 					*emsgp = "couldn't set write mode";
    299 				return -1;
    300 			}
    301 		 } else if (mode == R_OK)
    302 	      		if (setmode(fd, O_BINARY) == -1) {
    303 				if (emsgp)
    304 					*emsgp = "couldn't set read mode";
    305 				return -1;
    306 			}
    307 #else /* OS2 */
    308 		/* X_OK is a kludge to disable this check for dups (x<&1):
    309 		 * historical shells never did this check (XXX don't know what
    310 		 * posix has to say).
    311 		 */
    312 		if (!(mode & X_OK) && fl != O_RDWR
    313 		    && (((mode & R_OK) && fl != O_RDONLY)
    314 			|| ((mode & W_OK) && fl != O_WRONLY)))
    315 		{
    316 			if (emsgp)
    317 				*emsgp = (fl == O_WRONLY) ?
    318 						"fd not open for reading"
    319 					      : "fd not open for writing";
    320 			return -1;
    321 		}
    322 #endif /* OS2 */
    323 		return fd;
    324 	}
    325 #ifdef KSH
    326 	else if (name[0] == 'p' && !name[1])
    327 		return coproc_getfd(mode, emsgp);
    328 #endif /* KSH */
    329 	if (emsgp)
    330 		*emsgp = "illegal file descriptor name";
    331 	return -1;
    332 }
    333 
    334 #ifdef KSH
    335 /* Called once from main */
    336 void
    337 coproc_init()
    338 {
    339 	coproc.read = coproc.readw = coproc.write = -1;
    340 	coproc.njobs = 0;
    341 	coproc.id = 0;
    342 }
    343 
    344 /* Called by c_read() when eof is read - close fd if it is the co-process fd */
    345 void
    346 coproc_read_close(fd)
    347 	int fd;
    348 {
    349 	if (coproc.read >= 0 && fd == coproc.read) {
    350 		coproc_readw_close(fd);
    351 		close(coproc.read);
    352 		coproc.read = -1;
    353 	}
    354 }
    355 
    356 /* Called by c_read() and by iosetup() to close the other side of the
    357  * read pipe, so reads will actually terminate.
    358  */
    359 void
    360 coproc_readw_close(fd)
    361 	int fd;
    362 {
    363 	if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
    364 		close(coproc.readw);
    365 		coproc.readw = -1;
    366 	}
    367 }
    368 
    369 /* Called by c_print when a write to a fd fails with EPIPE and by iosetup
    370  * when co-process input is dup'd
    371  */
    372 void
    373 coproc_write_close(fd)
    374 	int fd;
    375 {
    376 	if (coproc.write >= 0 && fd == coproc.write) {
    377 		close(coproc.write);
    378 		coproc.write = -1;
    379 	}
    380 }
    381 
    382 /* Called to check for existance of/value of the co-process file descriptor.
    383  * (Used by check_fd() and by c_read/c_print to deal with -p option).
    384  */
    385 int
    386 coproc_getfd(mode, emsgp)
    387 	int mode;
    388 	const char **emsgp;
    389 {
    390 	int fd = (mode & R_OK) ? coproc.read : coproc.write;
    391 
    392 	if (fd >= 0)
    393 		return fd;
    394 	if (emsgp)
    395 		*emsgp = "no coprocess";
    396 	return -1;
    397 }
    398 
    399 /* called to close file descriptors related to the coprocess (if any)
    400  * Should be called with SIGCHLD blocked.
    401  */
    402 void
    403 coproc_cleanup(reuse)
    404 	int reuse;
    405 {
    406 	/* This to allow co-processes to share output pipe */
    407 	if (!reuse || coproc.readw < 0 || coproc.read < 0) {
    408 		if (coproc.read >= 0) {
    409 			close(coproc.read);
    410 			coproc.read = -1;
    411 		}
    412 		if (coproc.readw >= 0) {
    413 			close(coproc.readw);
    414 			coproc.readw = -1;
    415 		}
    416 	}
    417 	if (coproc.write >= 0) {
    418 		close(coproc.write);
    419 		coproc.write = -1;
    420 	}
    421 }
    422 #endif /* KSH */
    423 
    424 /*
    425  * temporary files
    426  */
    427 
    428 struct temp *
    429 maketemp(ap)
    430 	Area *ap;
    431 {
    432 	static unsigned int inc;
    433 	struct temp *tp;
    434 	int len;
    435 	int fd;
    436 	char *path;
    437 	const char *tmp;
    438 
    439 	tmp = tmpdir ? tmpdir : "/tmp";
    440 	/* The 20 + 20 is a paranoid worst case for pid/inc */
    441 	len = strlen(tmp) + 3 + 20 + 20 + 1;
    442 	tp = (struct temp *) alloc(sizeof(struct temp) + len, ap);
    443 	tp->name = path = (char *) &tp[1];
    444 	tp->shf = (struct shf *) 0;
    445 	while (1) {
    446 		/* Note that temp files need to fit 8.3 DOS limits */
    447 		shf_snprintf(path, len, "%s/sh%05u.%03x",
    448 			tmp, (unsigned) procpid, inc++);
    449 		/* Mode 0600 to be paranoid, O_TRUNC in case O_EXCL isn't
    450 		 * really there.
    451 		 */
    452 		fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_TRUNC, 0600);
    453 		if (fd >= 0) {
    454 			tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
    455 			break;
    456 		}
    457 		if (errno != EINTR
    458 #ifdef EEXIST
    459 		    && errno != EEXIST
    460 #endif /* EEXIST */
    461 #ifdef EISDIR
    462 		    && errno != EISDIR
    463 #endif /* EISDIR */
    464 			)
    465 			/* Error must be printed by called: don't know here if
    466 			 * errorf() or bi_errorf() should be used.
    467 			 */
    468 			break;
    469 	}
    470 	tp->next = NULL;
    471 	tp->pid = procpid;
    472 	return tp;
    473 }
    474