VirtualBox

source: kBuild/trunk/src/kash/redir.c

Last change on this file was 3480, checked in by bird, 4 years ago

kash: build fixes (darwin).

  • Property svn:eol-style set to LF
  • Property svn:keywords set to Id
File size: 11.7 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 <string.h>
46#include <errno.h>
47#include <stddef.h>
48#include <stdlib.h>
49
50/*
51 * Code for dealing with input/output redirection.
52 */
53
54#include "main.h"
55#include "shell.h"
56#include "nodes.h"
57#include "jobs.h"
58#include "options.h"
59#include "expand.h"
60#include "redir.h"
61#include "output.h"
62#include "memalloc.h"
63#include "error.h"
64#include "shinstance.h"
65
66
67#define EMPTY -2 /* marks an unused slot in redirtab */
68#define PIPESIZE SHFILE_PIPE_SIZE
69
70
71//MKINIT struct redirtab *redirlist;
72
73/*
74 * We keep track of whether or not fd0 has been redirected. This is for
75 * background commands, where we want to redirect fd0 to /dev/null only
76 * if it hasn't already been redirected.
77*/
78//int fd0_redirected = 0;
79
80STATIC void openredirect(shinstance *, union node *, char[10], int, const char *);
81STATIC int openhere(shinstance *, union node *);
82
83
84#ifndef SH_FORKED_MODE
85void
86subshellinitredir(shinstance *psh, shinstance *inherit)
87{
88 /* We can have a redirlist here if we're handling backtick while expanding
89 arguments, just copy it even if the subshell probably doesn't need it. */
90 struct redirtab *src = inherit->redirlist;
91 if (src)
92 {
93 struct redirtab **dstp = &psh->redirlist;
94 do
95 {
96 struct redirtab *dst = ckmalloc(psh, sizeof(*dst));
97 memcpy(dst->renamed, src->renamed, sizeof(dst->renamed));
98 *dstp = dst;
99 dstp = &dst->next;
100 src = src->next;
101 } while (src);
102 *dstp = NULL;
103
104 psh->fd0_redirected = inherit->fd0_redirected;
105 }
106
107 /* Copy the expanded redirection filenames (stack), but only the last entry
108 as the subshell does not have the ability to unwind stack in the parent
109 and therefore cannot get to the earlier redirection stuff: */
110 if (inherit->expfnames)
111 {
112 redirexpfnames * const expfnamesrc = inherit->expfnames;
113 unsigned i = expfnamesrc->count;
114 redirexpfnames *dst = stalloc(psh, offsetof(redirexpfnames, names) + sizeof(dst->names[0]) * i);
115 dst->count = i;
116 dst->depth = 1;
117 dst->prev = NULL;
118 while (i-- > 0)
119 dst->names[i] = stsavestr(psh, expfnamesrc->names[i]);
120 psh->expfnames = dst;
121 }
122}
123#endif /* !SH_FORKED_MODE */
124
125
126/*
127 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
128 * old file descriptors are stashed away so that the redirection can be
129 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
130 * standard output, and the standard error if it becomes a duplicate of
131 * stdout, is saved in memory.
132 */
133
134void
135redirect(shinstance *psh, union node *redir, int flags)
136{
137 union node *n;
138 struct redirtab *sv = NULL;
139 int i;
140 int fd;
141 int try;
142 char memory[10]; /* file descriptors to write to memory */
143 unsigned idxexpfname;
144
145 for (i = 10 ; --i >= 0 ; )
146 memory[i] = 0;
147 memory[1] = flags & REDIR_BACKQ;
148 if (flags & REDIR_PUSH) {
149 sv = ckmalloc(psh, sizeof (struct redirtab));
150 for (i = 0 ; i < 10 ; i++)
151 sv->renamed[i] = EMPTY;
152 sv->next = psh->redirlist;
153 psh->redirlist = sv;
154 }
155 idxexpfname = 0;
156 for (n = redir, idxexpfname = 0 ; n ; n = n->nfile.next, idxexpfname++) {
157 kHlpAssert(idxexpfname < psh->expfnames->count);
158 fd = n->nfile.fd;
159 try = 0;
160 if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
161 n->ndup.dupfd == fd)
162 continue; /* redirect from/to same file descriptor */
163
164 if ((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) {
165 INTOFF;
166again:
167 if ((i = shfile_fcntl(&psh->fdtab, fd, F_DUPFD, 10)) == -1) {
168 switch (errno) {
169 case EBADF:
170 if (!try) {
171 openredirect(psh, n, memory, flags, psh->expfnames->names[idxexpfname]);
172 try++;
173 goto again;
174 }
175 /* FALLTHROUGH*/
176 default:
177 INTON;
178 error(psh, "%d: %s", fd, sh_strerror(psh, errno));
179 /* NOTREACHED */
180 }
181 }
182 if (!try) {
183 sv->renamed[fd] = i;
184 shfile_close(&psh->fdtab, fd);
185 }
186 INTON;
187 } else {
188 shfile_close(&psh->fdtab, fd);
189 }
190 if (fd == 0)
191 psh->fd0_redirected++;
192 if (!try)
193 openredirect(psh, n, memory, flags, psh->expfnames->names[idxexpfname]);
194 }
195 kHlpAssert(!redir || idxexpfname == psh->expfnames->count);
196 if (memory[1])
197 psh->out1 = &psh->memout;
198 if (memory[2])
199 psh->out2 = &psh->memout;
200}
201
202
203STATIC void
204openredirect(shinstance *psh, union node *redir, char memory[10], int flags, const char *fname)
205{
206 int fd = redir->nfile.fd;
207 int f;
208 int oflags = O_WRONLY|O_CREAT|O_TRUNC;
209
210 /*
211 * We suppress interrupts so that we won't leave open file
212 * descriptors around. This may not be such a good idea because
213 * an open of a device or a fifo can block indefinitely.
214 */
215 INTOFF;
216 memory[fd] = 0;
217 switch (redir->nfile.type) {
218 case NFROM:
219 if ((f = shfile_open(&psh->fdtab, fname, O_RDONLY, 0)) < 0)
220 goto eopen;
221 break;
222 case NFROMTO:
223 if ((f = shfile_open(&psh->fdtab, fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
224 goto ecreate;
225 break;
226 case NTO:
227 if (Cflag(psh))
228 oflags |= O_EXCL;
229 /* FALLTHROUGH */
230 case NCLOBBER:
231 if ((f = shfile_open(&psh->fdtab, fname, oflags, 0666)) < 0)
232 goto ecreate;
233 break;
234 case NAPPEND:
235 if ((f = shfile_open(&psh->fdtab, fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
236 goto ecreate;
237 break;
238 case NTOFD:
239 case NFROMFD:
240 if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
241 if (memory[redir->ndup.dupfd])
242 memory[fd] = 1;
243 else
244 copyfd(psh, redir->ndup.dupfd, fd);
245 }
246 INTON;
247 return;
248 case NHERE:
249 case NXHERE:
250 f = openhere(psh, redir);
251 break;
252 default:
253 sh_abort(psh);
254 }
255
256 if (f != fd) {
257 movefd(psh, f, fd);
258 }
259 INTON;
260 return;
261ecreate:
262 error(psh, "cannot create %s: %s", fname, errmsg(psh, errno, E_CREAT));
263eopen:
264 error(psh, "cannot open %s: %s", fname, errmsg(psh, errno, E_OPEN));
265}
266
267#ifdef KASH_USE_FORKSHELL2
268struct openherechild
269{
270 int pip[2];
271 size_t len;
272};
273static int openhere_child(shinstance *psh, union node *n, void *argp)
274{
275 struct openherechild args = *(struct openherechild *)argp;
276
277 shfile_close(&psh->fdtab, args.pip[0]);
278 sh_signal(psh, SIGINT, SH_SIG_IGN);
279 sh_signal(psh, SIGQUIT, SH_SIG_IGN);
280 sh_signal(psh, SIGHUP, SH_SIG_IGN);
281# ifdef SIGTSTP
282 sh_signal(psh, SIGTSTP, SH_SIG_IGN);
283# endif
284 sh_signal(psh, SIGPIPE, SH_SIG_DFL);
285 if (n->type == NHERE)
286 xwrite(psh, args.pip[1], n->nhere.doc->narg.text, args.len);
287 else
288 expandhere(psh, n->nhere.doc, args.pip[1]);
289 return 0;
290}
291
292#endif /* KASH_USE_FORKSHELL2*/
293
294/*
295 * Handle here documents. Normally we fork off a process to write the
296 * data to a pipe. If the document is short, we can stuff the data in
297 * the pipe without forking.
298 */
299
300STATIC int
301openhere(shinstance *psh, union node *redir)
302{
303 int pip[2];
304 size_t len = 0;
305
306 if (shfile_pipe(&psh->fdtab, pip) < 0)
307 error(psh, "Pipe call failed");
308 if (redir->type == NHERE) {
309 len = strlen(redir->nhere.doc->narg.text);
310 if (len <= PIPESIZE) {
311 xwrite(psh, pip[1], redir->nhere.doc->narg.text, len);
312 goto out;
313 }
314 }
315#ifdef KASH_USE_FORKSHELL2
316 {
317 struct openherechild args;
318 args.pip[0] = pip[0];
319 args.pip[1] = pip[1];
320 args.len = len;
321 forkshell2(psh, (struct job *)NULL, redir,
322 FORK_NOJOB | FORK_JUST_IO,
323 openhere_child, redir, &args, sizeof(args), NULL);
324 }
325#else
326 if (forkshell(psh, (struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
327 shfile_close(&psh->fdtab, pip[0]);
328 sh_signal(psh, SIGINT, SH_SIG_IGN);
329 sh_signal(psh, SIGQUIT, SH_SIG_IGN);
330 sh_signal(psh, SIGHUP, SH_SIG_IGN);
331#ifdef SIGTSTP
332 sh_signal(psh, SIGTSTP, SH_SIG_IGN);
333#endif
334 sh_signal(psh, SIGPIPE, SH_SIG_DFL);
335 if (redir->type == NHERE)
336 xwrite(psh, pip[1], redir->nhere.doc->narg.text, len);
337 else
338 expandhere(psh, redir->nhere.doc, pip[1]);
339 sh__exit(psh, 0);
340 }
341#endif
342out:
343 shfile_close(&psh->fdtab, pip[1]);
344 return pip[0];
345}
346
347
348
349/*
350 * Undo the effects of the last redirection.
351 */
352
353void
354popredir(shinstance *psh)
355{
356 struct redirtab *rp = psh->redirlist;
357 int i;
358
359 for (i = 0 ; i < 10 ; i++) {
360 if (rp->renamed[i] != EMPTY) {
361 if (i == 0)
362 psh->fd0_redirected--;
363 if (rp->renamed[i] >= 0) {
364 movefd(psh, rp->renamed[i], i);
365 } else {
366 shfile_close(&psh->fdtab, i);
367 }
368 }
369 }
370 INTOFF;
371 psh->redirlist = rp->next;
372 ckfree(psh, rp);
373 INTON;
374}
375
376/*
377 * Undo all redirections. Called on error or interrupt.
378 */
379
380#ifdef mkinit
381
382INCLUDE "redir.h"
383
384RESET {
385 while (psh->redirlist)
386 popredir(psh);
387}
388
389SHELLPROC {
390 clearredir(psh);
391}
392
393#endif
394
395/* Return true if fd 0 has already been redirected at least once. */
396int
397fd0_redirected_p(shinstance *psh) {
398 return psh->fd0_redirected != 0;
399}
400
401/*
402 * Discard all saved file descriptors.
403 */
404
405void
406clearredir(shinstance *psh)
407{
408 struct redirtab *rp;
409 int i;
410
411 for (rp = psh->redirlist ; rp ; rp = rp->next) {
412 for (i = 0 ; i < 10 ; i++) {
413 if (rp->renamed[i] >= 0) {
414 shfile_close(&psh->fdtab, rp->renamed[i]);
415 }
416 rp->renamed[i] = EMPTY;
417 }
418 }
419}
420
421
422
423/*
424 * Copy a file descriptor to be >= to. Returns -1
425 * if the source file descriptor is closed, EMPTY if there are no unused
426 * file descriptors left.
427 */
428
429int
430copyfd(shinstance *psh, int from, int to)
431{
432 int newfd;
433
434 newfd = shfile_fcntl(&psh->fdtab, from, F_DUPFD, to);
435 if (newfd < 0) {
436 if (errno == EMFILE)
437 return EMPTY;
438 error(psh, "%d: %s", from, sh_strerror(psh, errno));
439 }
440 return newfd;
441}
442
443
444/*
445 * Move a file descriptor to be == to. Returns -1
446 * if the source file descriptor is closed, EMPTY if there are no unused
447 * file descriptors left.
448 */
449
450int
451movefd(shinstance *psh, int from, int to)
452{
453 int newfd;
454
455 newfd = shfile_movefd(&psh->fdtab, from, to);
456 if (newfd < 0) {
457 if (errno == EMFILE)
458 return EMPTY;
459 error(psh, "%d: %s", from, sh_strerror(psh, errno));
460 }
461 return newfd;
462}
463
464
465/*
466 * Move a file descriptor to be >= to. Returns -1
467 * if the source file descriptor is closed, EMPTY if there are no unused
468 * file descriptors left.
469 */
470
471int
472movefd_above(shinstance *psh, int from, int to)
473{
474 int newfd;
475
476 newfd = shfile_movefd_above(&psh->fdtab, from, to);
477 if (newfd < 0) {
478 if (errno == EMFILE)
479 return EMPTY;
480 error(psh, "%d: %s", from, sh_strerror(psh, errno));
481 }
482 return newfd;
483}
484
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette