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