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