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
errorf(const char * fmt,...)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
warningf(int fileline,const char * fmt,...)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
bi_errorf(const char * fmt,...)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
internal_errorf(int jump,const char * fmt,...)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
error_prefix(fileline)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
shellf(const char * fmt,...)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
shprintf(const char * fmt,...)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
kshdebug_init_()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
kshdebug_printf_(const char * fmt,...)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
kshdebug_dump_(str,mem,nbytes)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
can_seek(fd)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
initio()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
ksh_dup2(ofd,nfd,errok)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
savefd(fd,noclose)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
restfd(fd,ofd)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
openpipe(pv)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
closepipe(pv)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
check_fd(name,mode,emsgp)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
coproc_init()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
coproc_read_close(fd)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
coproc_readw_close(fd)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
coproc_write_close(fd)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
coproc_getfd(mode,emsgp)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
coproc_cleanup(reuse)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 *
maketemp(ap,type,tlist)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