io.c revision 1.6 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