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

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

kash: refactoring evalcommand - complicated, part II.

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