source: trunk/src/kash/redir.c@ 3463

Last change on this file since 3463 was 3463, checked in by bird, 5 years ago

kash: indent

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 11.8 KB
Line 
1/* $NetBSD: redir.c,v 1.29 2004/07/08 03:57:33 christos Exp $ */
2
3/*-
4 * Copyright (c) 1991, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * This code is derived from software contributed to Berkeley by
8 * Kenneth Almquist.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 */
34
35#if 0
36#ifndef lint
37static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95";
38#else
39__RCSID("$NetBSD: redir.c,v 1.29 2004/07/08 03:57:33 christos Exp $");
40#endif /* not lint */
41#endif
42
43#include <sys/types.h>
44#include <limits.h> /* PIPE_BUF */
45#include <assert.h>
46#include <string.h>
47#include <errno.h>
48#include <stddef.h>
49#include <stdlib.h>
50
51/*
52 * Code for dealing with input/output redirection.
53 */
54
55#include "main.h"
56#include "shell.h"
57#include "nodes.h"
58#include "jobs.h"
59#include "options.h"
60#include "expand.h"
61#include "redir.h"
62#include "output.h"
63#include "memalloc.h"
64#include "error.h"
65#include "shinstance.h"
66
67
68#define EMPTY -2 /* marks an unused slot in redirtab */
69#ifndef PIPE_BUF
70# define PIPESIZE 4096 /* amount of buffering in a pipe */
71#else
72# define PIPESIZE PIPE_BUF
73#endif
74
75
76MKINIT
77
78//MKINIT struct redirtab *redirlist;
79
80/*
81 * We keep track of whether or not fd0 has been redirected. This is for
82 * background commands, where we want to redirect fd0 to /dev/null only
83 * if it hasn't already been redirected.
84*/
85//int fd0_redirected = 0;
86
87STATIC void openredirect(shinstance *, union node *, char[10], int, const char *);
88STATIC int openhere(shinstance *, union node *);
89
90
91#ifndef SH_FORKED_MODE
92void
93subshellinitredir(shinstance *psh, shinstance *inherit)
94{
95 /* We can have a redirlist here if we're handling backtick while expanding
96 arguments, just copy it even if the subshell probably doesn't need it. */
97 struct redirtab *src = inherit->redirlist;
98 if (src)
99 {
100 struct redirtab **dstp = &psh->redirlist;
101 do
102 {
103 struct redirtab *dst = ckmalloc(psh, sizeof(*dst));
104 memcpy(dst->renamed, src->renamed, sizeof(dst->renamed));
105 *dstp = dst;
106 dstp = &dst->next;
107 src = src->next;
108 } while (src);
109 *dstp = NULL;
110
111 psh->fd0_redirected = inherit->fd0_redirected;
112 }
113
114 /* Copy the expanded redirection filenames (stack), but only the last entry
115 as the subshell does not have the ability to unwind stack in the parent
116 and therefore cannot get to the earlier redirection stuff: */
117 if (inherit->expfnames)
118 {
119 redirexpfnames * const expfnamesrc = inherit->expfnames;
120 unsigned i = expfnamesrc->count;
121 redirexpfnames *dst = stalloc(psh, offsetof(redirexpfnames, names) + sizeof(dst->names[0]) * i);
122 dst->count = i;
123 dst->depth = 1;
124 dst->prev = NULL;
125 while (i-- > 0)
126 dst->names[i] = stsavestr(psh, expfnamesrc->names[i]);
127 psh->expfnames = dst;
128 }
129}
130#endif /* !SH_FORKED_MODE */
131
132
133/*
134 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
135 * old file descriptors are stashed away so that the redirection can be
136 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
137 * standard output, and the standard error if it becomes a duplicate of
138 * stdout, is saved in memory.
139 */
140
141void
142redirect(shinstance *psh, union node *redir, int flags)
143{
144 union node *n;
145 struct redirtab *sv = NULL;
146 int i;
147 int fd;
148 int try;
149 char memory[10]; /* file descriptors to write to memory */
150 unsigned idxexpfname;
151
152 for (i = 10 ; --i >= 0 ; )
153 memory[i] = 0;
154 memory[1] = flags & REDIR_BACKQ;
155 if (flags & REDIR_PUSH) {
156 sv = ckmalloc(psh, sizeof (struct redirtab));
157 for (i = 0 ; i < 10 ; i++)
158 sv->renamed[i] = EMPTY;
159 sv->next = psh->redirlist;
160 psh->redirlist = sv;
161 }
162 idxexpfname = 0;
163 for (n = redir, idxexpfname = 0 ; n ; n = n->nfile.next, idxexpfname++) {
164 assert(idxexpfname < psh->expfnames->count);
165 fd = n->nfile.fd;
166 try = 0;
167 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
168 n->ndup.dupfd == fd)
169 continue; /* redirect from/to same file descriptor */
170
171 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
172 INTOFF;
173again:
174 if ((i = shfile_fcntl(&psh->fdtab, fd, F_DUPFD, 10)) == -1) {
175 switch (errno) {
176 case EBADF:
177 if (!try) {
178 openredirect(psh, n, memory, flags, psh->expfnames->names[idxexpfname]);
179 try++;
180 goto again;
181 }
182 /* FALLTHROUGH*/
183 default:
184 INTON;
185 error(psh, "%d: %s", fd, sh_strerror(psh, errno));
186 /* NOTREACHED */
187 }
188 }
189 if (!try) {
190 sv->renamed[fd] = i;
191 shfile_close(&psh->fdtab, fd);
192 }
193 INTON;
194 } else {
195 shfile_close(&psh->fdtab, fd);
196 }
197 if (fd == 0)
198 psh->fd0_redirected++;
199 if (!try)
200 openredirect(psh, n, memory, flags, psh->expfnames->names[idxexpfname]);
201 }
202 assert(!redir || idxexpfname == psh->expfnames->count);
203 if (memory[1])
204 psh->out1 = &psh->memout;
205 if (memory[2])
206 psh->out2 = &psh->memout;
207}
208
209
210STATIC void
211openredirect(shinstance *psh, union node *redir, char memory[10], int flags, const char *fname)
212{
213 int fd = redir->nfile.fd;
214 int f;
215 int oflags = O_WRONLY|O_CREAT|O_TRUNC;
216
217 /*
218 * We suppress interrupts so that we won't leave open file
219 * descriptors around. This may not be such a good idea because
220 * an open of a device or a fifo can block indefinitely.
221 */
222 INTOFF;
223 memory[fd] = 0;
224 switch (redir->nfile.type) {
225 case NFROM:
226 if ((f = shfile_open(&psh->fdtab, fname, O_RDONLY, 0)) < 0)
227 goto eopen;
228 break;
229 case NFROMTO:
230 if ((f = shfile_open(&psh->fdtab, fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
231 goto ecreate;
232 break;
233 case NTO:
234 if (Cflag(psh))
235 oflags |= O_EXCL;
236 /* FALLTHROUGH */
237 case NCLOBBER:
238 if ((f = shfile_open(&psh->fdtab, fname, oflags, 0666)) < 0)
239 goto ecreate;
240 break;
241 case NAPPEND:
242 if ((f = shfile_open(&psh->fdtab, fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
243 goto ecreate;
244 break;
245 case NTOFD:
246 case NFROMFD:
247 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
248 if (memory[redir->ndup.dupfd])
249 memory[fd] = 1;
250 else
251 copyfd(psh, redir->ndup.dupfd, fd);
252 }
253 INTON;
254 return;
255 case NHERE:
256 case NXHERE:
257 f = openhere(psh, redir);
258 break;
259 default:
260 sh_abort(psh);
261 }
262
263 if (f != fd) {
264 movefd(psh, f, fd);
265 }
266 INTON;
267 return;
268ecreate:
269 error(psh, "cannot create %s: %s", fname, errmsg(psh, errno, E_CREAT));
270eopen:
271 error(psh, "cannot open %s: %s", fname, errmsg(psh, errno, E_OPEN));
272}
273
274#ifdef KASH_USE_FORKSHELL2
275struct openherechild
276{
277 int pip[2];
278 size_t len;
279};
280static int openhere_child(shinstance *psh, union node *n, void *argp)
281{
282 struct openherechild args = *(struct openherechild *)argp;
283
284 shfile_close(&psh->fdtab, args.pip[0]);
285 sh_signal(psh, SIGINT, SH_SIG_IGN);
286 sh_signal(psh, SIGQUIT, SH_SIG_IGN);
287 sh_signal(psh, SIGHUP, SH_SIG_IGN);
288# ifdef SIGTSTP
289 sh_signal(psh, SIGTSTP, SH_SIG_IGN);
290# endif
291 sh_signal(psh, SIGPIPE, SH_SIG_DFL);
292 if (n->type == NHERE)
293 xwrite(psh, args.pip[1], n->nhere.doc->narg.text, args.len);
294 else
295 expandhere(psh, n->nhere.doc, args.pip[1]);
296 return 0;
297}
298
299#endif /* KASH_USE_FORKSHELL2*/
300
301/*
302 * Handle here documents. Normally we fork off a process to write the
303 * data to a pipe. If the document is short, we can stuff the data in
304 * the pipe without forking.
305 */
306
307STATIC int
308openhere(shinstance *psh, union node *redir)
309{
310 int pip[2];
311 size_t len = 0;
312
313 if (shfile_pipe(&psh->fdtab, pip) < 0)
314 error(psh, "Pipe call failed");
315 if (redir->type == NHERE) {
316 len = strlen(redir->nhere.doc->narg.text);
317 if (len <= PIPESIZE) {
318 xwrite(psh, pip[1], redir->nhere.doc->narg.text, len);
319 goto out;
320 }
321 }
322#ifdef KASH_USE_FORKSHELL2
323 {
324 struct openherechild args;
325 args.pip[0] = pip[0];
326 args.pip[1] = pip[1];
327 args.len = len;
328 forkshell2(psh, (struct job *)NULL, redir,
329 FORK_NOJOB | FORK_JUST_IO,
330 openhere_child, redir, &args, sizeof(args), NULL);
331 }
332#else
333 if (forkshell(psh, (struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
334 shfile_close(&psh->fdtab, pip[0]);
335 sh_signal(psh, SIGINT, SH_SIG_IGN);
336 sh_signal(psh, SIGQUIT, SH_SIG_IGN);
337 sh_signal(psh, SIGHUP, SH_SIG_IGN);
338#ifdef SIGTSTP
339 sh_signal(psh, SIGTSTP, SH_SIG_IGN);
340#endif
341 sh_signal(psh, SIGPIPE, SH_SIG_DFL);
342 if (redir->type == NHERE)
343 xwrite(psh, pip[1], redir->nhere.doc->narg.text, len);
344 else
345 expandhere(psh, redir->nhere.doc, pip[1]);
346 sh__exit(psh, 0);
347 }
348#endif
349out:
350 shfile_close(&psh->fdtab, pip[1]);
351 return pip[0];
352}
353
354
355
356/*
357 * Undo the effects of the last redirection.
358 */
359
360void
361popredir(shinstance *psh)
362{
363 struct redirtab *rp = psh->redirlist;
364 int i;
365
366 for (i = 0 ; i < 10 ; i++) {
367 if (rp->renamed[i] != EMPTY) {
368 if (i == 0)
369 psh->fd0_redirected--;
370 if (rp->renamed[i] >= 0) {
371 movefd(psh, rp->renamed[i], i);
372 } else {
373 shfile_close(&psh->fdtab, i);
374 }
375 }
376 }
377 INTOFF;
378 psh->redirlist = rp->next;
379 ckfree(psh, rp);
380 INTON;
381}
382
383/*
384 * Undo all redirections. Called on error or interrupt.
385 */
386
387#ifdef mkinit
388
389INCLUDE "redir.h"
390
391RESET {
392 while (psh->redirlist)
393 popredir(psh);
394}
395
396SHELLPROC {
397 clearredir(psh);
398}
399
400#endif
401
402/* Return true if fd 0 has already been redirected at least once. */
403int
404fd0_redirected_p(shinstance *psh) {
405 return psh->fd0_redirected != 0;
406}
407
408/*
409 * Discard all saved file descriptors.
410 */
411
412void
413clearredir(shinstance *psh)
414{
415 struct redirtab *rp;
416 int i;
417
418 for (rp = psh->redirlist ; rp ; rp = rp->next) {
419 for (i = 0 ; i < 10 ; i++) {
420 if (rp->renamed[i] >= 0) {
421 shfile_close(&psh->fdtab, rp->renamed[i]);
422 }
423 rp->renamed[i] = EMPTY;
424 }
425 }
426}
427
428
429
430/*
431 * Copy a file descriptor to be >= to. Returns -1
432 * if the source file descriptor is closed, EMPTY if there are no unused
433 * file descriptors left.
434 */
435
436int
437copyfd(shinstance *psh, int from, int to)
438{
439 int newfd;
440
441 newfd = shfile_fcntl(&psh->fdtab, from, F_DUPFD, to);
442 if (newfd < 0) {
443 if (errno == EMFILE)
444 return EMPTY;
445 error(psh, "%d: %s", from, sh_strerror(psh, errno));
446 }
447 return newfd;
448}
449
450
451/*
452 * Move a file descriptor to be == to. Returns -1
453 * if the source file descriptor is closed, EMPTY if there are no unused
454 * file descriptors left.
455 */
456
457int
458movefd(shinstance *psh, int from, int to)
459{
460 int newfd;
461
462 newfd = shfile_movefd(&psh->fdtab, from, to);
463 if (newfd < 0) {
464 if (errno == EMFILE)
465 return EMPTY;
466 error(psh, "%d: %s", from, sh_strerror(psh, errno));
467 }
468 return newfd;
469}
470
471
472/*
473 * Move a file descriptor to be >= to. Returns -1
474 * if the source file descriptor is closed, EMPTY if there are no unused
475 * file descriptors left.
476 */
477
478int
479movefd_above(shinstance *psh, int from, int to)
480{
481 int newfd;
482
483 newfd = shfile_movefd_above(&psh->fdtab, from, to);
484 if (newfd < 0) {
485 if (errno == EMFILE)
486 return EMPTY;
487 error(psh, "%d: %s", from, sh_strerror(psh, errno));
488 }
489 return newfd;
490}
491
Note: See TracBrowser for help on using the repository browser.