1 /*-
2 * Copyright (c) 1991, 1993
3 * The Regents of the University of California. All rights reserved.
4 * Copyright (c) 1997-2005
5 * Herbert Xu <herbert@gondor.apana.org.au>. 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 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <sys/param.h> /* PIPE_BUF */
38 #include <signal.h>
39 #include <string.h>
40 #include <fcntl.h>
41 #include <unistd.h>
42 #include <stdlib.h>
43
44 /*
45 * Code for dealing with input/output redirection.
46 */
47
48 #include "main.h"
49 #include "shell.h"
50 #include "nodes.h"
51 #include "jobs.h"
52 #include "options.h"
53 #include "expand.h"
54 #include "redir.h"
55 #include "output.h"
56 #include "memalloc.h"
57 #include "error.h"
58
59
60 #define REALLY_CLOSED -3 /* fd that was closed and still is */
61 #define EMPTY -2 /* marks an unused slot in redirtab */
62 #define CLOSED -1 /* fd opened for redir needs to be closed */
63
64 #ifndef PIPE_BUF
65 # define PIPESIZE 4096 /* amount of buffering in a pipe */
66 #else
67 # define PIPESIZE PIPE_BUF
68 #endif
69
70
71 MKINIT
72 struct redirtab {
73 struct redirtab *next;
74 int renamed[10];
75 };
76
77
78 MKINIT struct redirtab *redirlist;
79
80 STATIC int openredirect(union node *);
81 #ifdef notyet
82 STATIC void dupredirect(union node *, int, char[10]);
83 #else
84 STATIC void dupredirect(union node *, int);
85 #endif
86 STATIC int openhere(union node *);
87
88
89 /*
90 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
91 * old file descriptors are stashed away so that the redirection can be
92 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
93 * standard output, and the standard error if it becomes a duplicate of
94 * stdout, is saved in memory.
95 */
96
97 void
redirect(union node * redir,int flags)98 redirect(union node *redir, int flags)
99 {
100 union node *n;
101 struct redirtab *sv;
102 int i;
103 int fd;
104 int newfd;
105 int *p;
106 #if notyet
107 char memory[10]; /* file descriptors to write to memory */
108
109 for (i = 10 ; --i >= 0 ; )
110 memory[i] = 0;
111 memory[1] = flags & REDIR_BACKQ;
112 #endif
113 if (!redir)
114 return;
115 sv = NULL;
116 INTOFF;
117 if (likely(flags & REDIR_PUSH))
118 sv = redirlist;
119 n = redir;
120 do {
121 newfd = openredirect(n);
122 if (newfd < -1)
123 continue;
124
125 fd = n->nfile.fd;
126
127 if (sv) {
128 p = &sv->renamed[fd];
129 i = *p;
130
131 if (likely(i == EMPTY)) {
132 i = CLOSED;
133 if (fd != newfd) {
134 i = savefd(fd, fd);
135 fd = -1;
136 }
137 }
138
139 if (i == newfd)
140 /* Can only happen if i == newfd == CLOSED */
141 i = REALLY_CLOSED;
142
143 *p = i;
144 }
145
146 if (fd == newfd)
147 continue;
148
149 #ifdef notyet
150 dupredirect(n, newfd, memory);
151 #else
152 dupredirect(n, newfd);
153 #endif
154 } while ((n = n->nfile.next));
155 INTON;
156 #ifdef notyet
157 if (memory[1])
158 out1 = &memout;
159 if (memory[2])
160 out2 = &memout;
161 #endif
162 if (flags & REDIR_SAVEFD2 && sv->renamed[2] >= 0)
163 preverrout.fd = sv->renamed[2];
164 }
165
166
167 STATIC int
openredirect(union node * redir)168 openredirect(union node *redir)
169 {
170 struct stat sb;
171 char *fname;
172 int f;
173
174 switch (redir->nfile.type) {
175 case NFROM:
176 fname = redir->nfile.expfname;
177 if ((f = open(fname, O_RDONLY)) < 0)
178 goto eopen;
179 break;
180 case NFROMTO:
181 fname = redir->nfile.expfname;
182 if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0)
183 goto ecreate;
184 break;
185 case NTO:
186 /* Take care of noclobber mode. */
187 if (Cflag) {
188 fname = redir->nfile.expfname;
189 if (stat(fname, &sb) < 0) {
190 if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0)
191 goto ecreate;
192 } else if (!S_ISREG(sb.st_mode)) {
193 if ((f = open(fname, O_WRONLY, 0666)) < 0)
194 goto ecreate;
195 if (fstat(f, &sb) < 0 && S_ISREG(sb.st_mode)) {
196 close(f);
197 errno = EEXIST;
198 goto ecreate;
199 }
200 } else {
201 errno = EEXIST;
202 goto ecreate;
203 }
204 break;
205 }
206 /* FALLTHROUGH */
207 case NCLOBBER:
208 fname = redir->nfile.expfname;
209 if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
210 goto ecreate;
211 break;
212 case NAPPEND:
213 fname = redir->nfile.expfname;
214 if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
215 goto ecreate;
216 break;
217 case NTOFD:
218 case NFROMFD:
219 f = redir->ndup.dupfd;
220 if (f == redir->nfile.fd)
221 f = -2;
222 break;
223 default:
224 #ifdef DEBUG
225 abort();
226 #endif
227 /* Fall through to eliminate warning. */
228 case NHERE:
229 case NXHERE:
230 f = openhere(redir);
231 break;
232 }
233
234 return f;
235 ecreate:
236 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
237 eopen:
238 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
239 }
240
241
242 STATIC void
243 #ifdef notyet
dupredirect(redir,f,memory)244 dupredirect(redir, f, memory)
245 #else
246 dupredirect(redir, f)
247 #endif
248 union node *redir;
249 int f;
250 #ifdef notyet
251 char memory[10];
252 #endif
253 {
254 int fd = redir->nfile.fd;
255 int err = 0;
256
257 #ifdef notyet
258 memory[fd] = 0;
259 #endif
260 if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
261 /* if not ">&-" */
262 if (f >= 0) {
263 #ifdef notyet
264 if (memory[f])
265 memory[fd] = 1;
266 else
267 #endif
268 if (dup2(f, fd) < 0) {
269 err = errno;
270 goto err;
271 }
272 return;
273 }
274 f = fd;
275 } else if (dup2(f, fd) < 0)
276 err = errno;
277
278 close(f);
279 if (err < 0)
280 goto err;
281
282 return;
283
284 err:
285 sh_error("%d: %s", f, strerror(err));
286 }
287
288
289 /*
290 * Handle here documents. Normally we fork off a process to write the
291 * data to a pipe. If the document is short, we can stuff the data in
292 * the pipe without forking.
293 */
294
295 STATIC int
openhere(union node * redir)296 openhere(union node *redir)
297 {
298 char *p;
299 int pip[2];
300 size_t len = 0;
301
302 if (pipe(pip) < 0)
303 sh_error("Pipe call failed");
304
305 p = redir->nhere.doc->narg.text;
306 if (redir->type == NXHERE) {
307 expandarg(redir->nhere.doc, NULL, EXP_QUOTED);
308 p = stackblock();
309 }
310
311 len = strlen(p);
312 if (len <= PIPESIZE) {
313 xwrite(pip[1], p, len);
314 goto out;
315 }
316
317 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
318 close(pip[0]);
319 signal(SIGINT, SIG_IGN);
320 signal(SIGQUIT, SIG_IGN);
321 signal(SIGHUP, SIG_IGN);
322 #ifdef SIGTSTP
323 signal(SIGTSTP, SIG_IGN);
324 #endif
325 signal(SIGPIPE, SIG_DFL);
326 xwrite(pip[1], p, len);
327 _exit(0);
328 }
329 out:
330 close(pip[1]);
331 return pip[0];
332 }
333
334
335
336 /*
337 * Undo the effects of the last redirection.
338 */
339
340 void
popredir(int drop)341 popredir(int drop)
342 {
343 struct redirtab *rp;
344 int i;
345
346 INTOFF;
347 rp = redirlist;
348 for (i = 0 ; i < 10 ; i++) {
349 switch (rp->renamed[i]) {
350 case CLOSED:
351 if (!drop)
352 close(i);
353 break;
354 case EMPTY:
355 case REALLY_CLOSED:
356 break;
357 default:
358 if (!drop)
359 dup2(rp->renamed[i], i);
360 close(rp->renamed[i]);
361 break;
362 }
363 }
364 redirlist = rp->next;
365 ckfree(rp);
366 INTON;
367 }
368
369 /*
370 * Undo all redirections. Called on error or interrupt.
371 */
372
373 #ifdef mkinit
374
375 INCLUDE "redir.h"
376
377 RESET {
378 /*
379 * Discard all saved file descriptors.
380 */
381 unwindredir(0);
382 }
383
384 #endif
385
386
387
388 /*
389 * Move a file descriptor to > 10. Invokes sh_error on error unless
390 * the original file dscriptor is not open.
391 */
392
393 int
savefd(int from,int ofd)394 savefd(int from, int ofd)
395 {
396 int newfd;
397 int err;
398
399 newfd = fcntl(from, F_DUPFD, 10);
400 err = newfd < 0 ? errno : 0;
401 if (err != EBADF) {
402 close(ofd);
403 if (err)
404 sh_error("%d: %s", from, strerror(err));
405 else
406 fcntl(newfd, F_SETFD, FD_CLOEXEC);
407 }
408
409 return newfd;
410 }
411
412
413 int
redirectsafe(union node * redir,int flags)414 redirectsafe(union node *redir, int flags)
415 {
416 int err;
417 volatile int saveint;
418 struct jmploc *volatile savehandler = handler;
419 struct jmploc jmploc;
420
421 SAVEINT(saveint);
422 if (!(err = setjmp(jmploc.loc) * 2)) {
423 handler = &jmploc;
424 redirect(redir, flags);
425 }
426 handler = savehandler;
427 if (err && exception != EXERROR)
428 longjmp(handler->loc, 1);
429 RESTOREINT(saveint);
430 return err;
431 }
432
433
unwindredir(struct redirtab * stop)434 void unwindredir(struct redirtab *stop)
435 {
436 while (redirlist != stop)
437 popredir(0);
438 }
439
440
pushredir(union node * redir)441 struct redirtab *pushredir(union node *redir)
442 {
443 struct redirtab *sv;
444 struct redirtab *q;
445 int i;
446
447 q = redirlist;
448 if (!redir)
449 goto out;
450
451 sv = ckmalloc(sizeof (struct redirtab));
452 sv->next = q;
453 redirlist = sv;
454 for (i = 0; i < 10; i++)
455 sv->renamed[i] = EMPTY;
456
457 out:
458 return q;
459 }
460