changelog for 0.9.1
[posh.git] / io.c
blobc0720644a6f995bf265c82939dc8226278354b61
1 /*
2 * shell buffered IO and formatted output
3 */
5 #include <ctype.h>
6 #include "sh.h"
7 #include "ksh_stat.h"
9 static int initio_done;
12 * formatted output functions
16 /* A shell error occured (eg, syntax error, etc.) */
17 void
18 errorf(const char *fmt, ...)
20 va_list va;
22 shl_stdout_ok = 0; /* debugging: note that stdout not valid */
23 exstat = 1;
24 if (*fmt) {
25 error_prefix(TRUE);
26 SH_VA_START(va, fmt);
27 shf_vfprintf(shl_out, fmt, va);
28 va_end(va);
29 shf_putchar('\n', shl_out);
31 shf_flush(shl_out);
32 unwind(LERROR);
35 /* like errorf(), but no unwind is done */
36 void
37 warningf(int fileline, const char *fmt, ...)
39 va_list va;
41 error_prefix(fileline);
42 SH_VA_START(va, fmt);
43 shf_vfprintf(shl_out, fmt, va);
44 va_end(va);
45 shf_putchar('\n', shl_out);
46 shf_flush(shl_out);
49 /* Used by built-in utilities to prefix shell and utility name to message
50 * (also unwinds environments for special builtins).
52 void
53 bi_errorf(const char *fmt, ...)
55 va_list va;
57 shl_stdout_ok = 0; /* debugging: note that stdout not valid */
58 exstat = 1;
59 if (*fmt) {
60 error_prefix(TRUE);
61 /* not set when main() calls parse_args() */
62 if (builtin_argv0)
63 shf_fprintf(shl_out, "%s: ", builtin_argv0);
64 SH_VA_START(va, fmt);
65 shf_vfprintf(shl_out, fmt, va);
66 va_end(va);
67 shf_putchar('\n', shl_out);
69 shf_flush(shl_out);
70 /* POSIX special builtins and ksh special builtins cause
71 * non-interactive shells to exit.
72 * XXX odd use of KEEPASN; also may not want LERROR here
74 if ((builtin_flag & SPEC_BI) || (builtin_flag & KEEPASN))
76 builtin_argv0 = (char *) 0;
77 unwind(LERROR);
81 /* Called when something that shouldn't happen does */
82 void
83 internal_errorf(int jump, const char *fmt, ...)
85 va_list va;
87 error_prefix(TRUE);
88 shf_fprintf(shl_out, "internal error: ");
89 SH_VA_START(va, fmt);
90 shf_vfprintf(shl_out, fmt, va);
91 va_end(va);
92 shf_putchar('\n', shl_out);
93 shf_flush(shl_out);
94 if (jump)
95 unwind(LERROR);
98 void error_prefix(int fileline)
100 if (!fileline || !source || !source->file
101 || strcmp(source->file, poshname) != 0)
102 shf_fprintf(shl_out, "%s: ", poshname + (*poshname == '-'));
103 if (fileline && source && source->file != NULL) {
104 shf_fprintf(shl_out, "%s:%d: ", source->file,
105 source->errline > 0 ? source->errline : source->line);
106 source->errline = 0;
110 /* printf to shl_out (stderr) with flush */
111 void
112 shellf(const char *fmt, ...)
114 va_list va;
116 if (!initio_done) /* shl_out may not be set up yet... */
117 return;
118 SH_VA_START(va, fmt);
119 shf_vfprintf(shl_out, fmt, va);
120 va_end(va);
121 shf_flush(shl_out);
124 /* printf to shl_stdout (stdout) */
125 void
126 shprintf(const char *fmt, ...)
128 va_list va;
130 if (!shl_stdout_ok)
131 internal_errorf(1, "shl_stdout not valid");
132 SH_VA_START(va, fmt);
133 shf_vfprintf(shl_stdout, fmt, va);
134 va_end(va);
137 #ifdef KSH_DEBUG
138 static struct shf *kshdebug_shf;
140 void
141 kshdebug_init_()
143 if (kshdebug_shf)
144 shf_close(kshdebug_shf);
145 kshdebug_shf = shf_open("/tmp/ksh-debug.log",
146 O_WRONLY|O_APPEND|O_CREAT, 0600,
147 SHF_WR|SHF_MAPHI);
148 if (kshdebug_shf) {
149 shf_fprintf(kshdebug_shf, "\nNew shell[pid %d]\n", getpid());
150 shf_flush(kshdebug_shf);
154 /* print to debugging log */
155 void
156 kshdebug_printf_(const char *fmt, ...)
158 va_list va;
160 if (!kshdebug_shf)
161 return;
162 SH_VA_START(va, fmt);
163 shf_fprintf(kshdebug_shf, "[%d] ", getpid());
164 shf_vfprintf(kshdebug_shf, fmt, va);
165 va_end(va);
166 shf_flush(kshdebug_shf);
169 void
170 kshdebug_dump_(str, mem, nbytes)
171 const char *str;
172 const void *mem;
173 int nbytes;
175 int i, j;
176 int nprow = 16;
178 if (!kshdebug_shf)
179 return;
180 shf_fprintf(kshdebug_shf, "[%d] %s:\n", getpid(), str);
181 for (i = 0; i < nbytes; i += nprow) {
182 char c = '\t';
183 for (j = 0; j < nprow && i + j < nbytes; j++) {
184 shf_fprintf(kshdebug_shf, "%c%02x",
185 c, ((const unsigned char *) mem)[i + j]);
186 c = ' ';
188 shf_fprintf(kshdebug_shf, "\n");
190 shf_flush(kshdebug_shf);
192 #endif /* KSH_DEBUG */
194 /* test if we can seek backwards fd (returns 0 or SHF_UNBUF) */
196 can_seek(fd)
197 int fd;
199 struct stat statb;
201 return fstat(fd, &statb) == 0 && !S_ISREG(statb.st_mode) ?
202 SHF_UNBUF : 0;
205 struct shf shf_iob[3];
207 void
208 initio()
210 shf_fdopen(1, SHF_WR, shl_stdout); /* force buffer allocation */
211 shf_fdopen(2, SHF_WR, shl_out);
212 shf_fdopen(2, SHF_WR, shl_spare); /* force buffer allocation */
213 initio_done = 1;
216 /* A dup2() with error checking */
218 ksh_dup2(int ofd, int nfd, int errok)
220 int ret = dup2(ofd, nfd);
222 if (ret < 0 && errno != EBADF && !errok)
223 errorf("too many files open in shell");
225 #ifdef DUP2_BROKEN
226 /* Ultrix systems like to preserve the close-on-exec flag */
227 if (ret >= 0)
228 (void) fcntl(nfd, F_SETFD, 0);
229 #endif /* DUP2_BROKEN */
231 return ret;
235 * move fd from user space (0<=fd<10) to shell space (fd>=10),
236 * set close-on-exec flag.
239 savefd(fd, noclose)
240 int fd;
241 int noclose;
243 int nfd;
245 if (fd < FDBASE) {
246 nfd = ksh_dupbase(fd, FDBASE);
247 if (nfd < 0) {
248 if (errno == EBADF)
249 return -1;
250 else
251 errorf("too many files open in shell");
253 if (!noclose)
254 close(fd);
255 } else
256 nfd = fd;
257 fd_clexec(nfd);
258 return nfd;
261 void
262 restfd(fd, ofd)
263 int fd, ofd;
265 if (fd == 2)
266 shf_flush(&shf_iob[fd]);
267 if (ofd < 0) /* original fd closed */
268 close(fd);
269 else {
270 ksh_dup2(ofd, fd, TRUE); /* XXX: what to do if this fails? */
271 close(ofd);
275 void
276 openpipe(pv)
277 int *pv;
279 if (pipe(pv) < 0)
280 errorf("can't create pipe - try again");
281 pv[0] = savefd(pv[0], 0);
282 pv[1] = savefd(pv[1], 0);
285 void
286 closepipe(pv)
287 int *pv;
289 close(pv[0]);
290 close(pv[1]);
293 /* Called by iosetup() (deals with 2>&4, etc.), c_read, c_print to turn
294 * a string (the X in 2>&X, read -uX, print -uX) into a file descriptor.
297 check_fd(name, mode, emsgp)
298 char *name;
299 int mode;
300 const char **emsgp;
302 int fd, fl;
304 if (isdigit(name[0]) && !name[1]) {
305 fd = name[0] - '0';
306 if ((fl = fcntl(fd = name[0] - '0', F_GETFL, 0)) < 0) {
307 if (emsgp)
308 *emsgp = "bad file descriptor";
309 return -1;
311 fl &= O_ACCMODE;
312 #ifdef OS2
313 if (mode == W_OK ) {
314 if (setmode(fd, O_TEXT) == -1) {
315 if (emsgp)
316 *emsgp = "couldn't set write mode";
317 return -1;
319 } else if (mode == R_OK)
320 if (setmode(fd, O_BINARY) == -1) {
321 if (emsgp)
322 *emsgp = "couldn't set read mode";
323 return -1;
325 #else /* OS2 */
326 /* X_OK is a kludge to disable this check for dups (x<&1):
327 * historical shells never did this check (XXX don't know what
328 * posix has to say).
330 if (!(mode & X_OK) && fl != O_RDWR
331 && (((mode & R_OK) && fl != O_RDONLY)
332 || ((mode & W_OK) && fl != O_WRONLY)))
334 if (emsgp)
335 *emsgp = (fl == O_WRONLY) ?
336 "fd not open for reading"
337 : "fd not open for writing";
338 return -1;
340 #endif /* OS2 */
341 return fd;
343 #ifdef KSH
344 else if (name[0] == 'p' && !name[1])
345 return coproc_getfd(mode, emsgp);
346 #endif /* KSH */
347 if (emsgp)
348 *emsgp = "illegal file descriptor name";
349 return -1;
352 #ifdef KSH
353 /* Called once from main */
354 void
355 coproc_init()
357 coproc.read = coproc.readw = coproc.write = -1;
358 coproc.njobs = 0;
359 coproc.id = 0;
362 /* Called by c_read() when eof is read - close fd if it is the co-process fd */
363 void
364 coproc_read_close(fd)
365 int fd;
367 if (coproc.read >= 0 && fd == coproc.read) {
368 coproc_readw_close(fd);
369 close(coproc.read);
370 coproc.read = -1;
374 /* Called by c_read() and by iosetup() to close the other side of the
375 * read pipe, so reads will actually terminate.
377 void
378 coproc_readw_close(fd)
379 int fd;
381 if (coproc.readw >= 0 && coproc.read >= 0 && fd == coproc.read) {
382 close(coproc.readw);
383 coproc.readw = -1;
387 /* Called by c_print when a write to a fd fails with EPIPE and by iosetup
388 * when co-process input is dup'd
390 void
391 coproc_write_close(fd)
392 int fd;
394 if (coproc.write >= 0 && fd == coproc.write) {
395 close(coproc.write);
396 coproc.write = -1;
400 /* Called to check for existance of/value of the co-process file descriptor.
401 * (Used by check_fd() and by c_read/c_print to deal with -p option).
404 coproc_getfd(mode, emsgp)
405 int mode;
406 const char **emsgp;
408 int fd = (mode & R_OK) ? coproc.read : coproc.write;
410 if (fd >= 0)
411 return fd;
412 if (emsgp)
413 *emsgp = "no coprocess";
414 return -1;
417 /* called to close file descriptors related to the coprocess (if any)
418 * Should be called with SIGCHLD blocked.
420 void
421 coproc_cleanup(reuse)
422 int reuse;
424 /* This to allow co-processes to share output pipe */
425 if (!reuse || coproc.readw < 0 || coproc.read < 0) {
426 if (coproc.read >= 0) {
427 close(coproc.read);
428 coproc.read = -1;
430 if (coproc.readw >= 0) {
431 close(coproc.readw);
432 coproc.readw = -1;
435 if (coproc.write >= 0) {
436 close(coproc.write);
437 coproc.write = -1;
440 #endif /* KSH */
444 * temporary files
447 struct temp *
448 maketemp(ap, type, tlist)
449 Area *ap;
450 Temp_type type;
451 struct temp **tlist;
453 /* static unsigned int inc; */
454 struct temp *tp;
455 int len;
456 int fd;
457 char *path;
458 const char *dir;
460 dir = tmpdir ? tmpdir : "/tmp";
461 /* The 20 + 20 is a paranoid worst case for pid/inc */
462 len = strlen(dir) + 3 + 20 + 20 + 1;
463 tp = (struct temp *) alloc(sizeof(struct temp) + len, ap);
464 tp->name = path = (char *) &tp[1];
465 tp->shf = (struct shf *) 0;
466 tp->type = type;
467 snprintf(path, len, "%s/poshXXXXXX", dir);
468 fd = mkstemp(path);
469 if (fd >= 0)
470 tp->shf = shf_fdopen(fd, SHF_WR, (struct shf *) 0);
471 if (fd >= 0)
472 fchmod(fd, 0600);
473 tp->pid = procpid;
475 tp->next = *tlist;
476 *tlist = tp;
478 return tp;