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