Magellan Linux

Annotation of /trunk/mkinitrd-magellan/klibc/usr/dash/redir.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 532 - (hide annotations) (download)
Sat Sep 1 22:45:15 2007 UTC (16 years, 9 months ago) by niro
File MIME type: text/plain
File size: 10319 byte(s)
-import if magellan mkinitrd; it is a fork of redhats mkinitrd-5.0.8 with all magellan patches and features; deprecates magellan-src/mkinitrd

1 niro 532 /*-
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 EMPTY -2 /* marks an unused slot in redirtab */
61     #ifndef PIPE_BUF
62     # define PIPESIZE 4096 /* amount of buffering in a pipe */
63     #else
64     # define PIPESIZE PIPE_BUF
65     #endif
66    
67    
68     MKINIT
69     struct redirtab {
70     struct redirtab *next;
71     int renamed[10];
72     int nullredirs;
73     };
74    
75    
76     MKINIT struct redirtab *redirlist;
77     MKINIT int nullredirs;
78    
79     STATIC int openredirect(union node *);
80     #ifdef notyet
81     STATIC void dupredirect(union node *, int, char[10]);
82     #else
83     STATIC void dupredirect(union node *, int);
84     #endif
85     STATIC int openhere(union node *);
86     STATIC int noclobberopen(const char *);
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
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     nullredirs++;
114     if (!redir) {
115     return;
116     }
117     sv = NULL;
118     INTOFF;
119     if (flags & REDIR_PUSH) {
120     struct redirtab *q;
121     q = ckmalloc(sizeof (struct redirtab));
122     q->next = redirlist;
123     redirlist = q;
124     q->nullredirs = nullredirs - 1;
125     for (i = 0 ; i < 10 ; i++)
126     q->renamed[i] = EMPTY;
127     nullredirs = 0;
128     sv = q;
129     }
130     n = redir;
131     do {
132     fd = n->nfile.fd;
133     if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
134     n->ndup.dupfd == fd)
135     continue; /* redirect from/to same file descriptor */
136    
137     newfd = openredirect(n);
138     if (fd == newfd)
139     continue;
140     if (sv && *(p = &sv->renamed[fd]) == EMPTY) {
141     int i = fcntl(fd, F_DUPFD, 10);
142     if (i == -1) {
143     i = errno;
144     if (i != EBADF) {
145     const char *m = strerror(i);
146     close(newfd);
147     sh_error("%d: %s", fd, m);
148     /* NOTREACHED */
149     }
150     } else {
151     *p = i;
152     close(fd);
153     }
154     } else {
155     close(fd);
156     }
157     #ifdef notyet
158     dupredirect(n, newfd, memory);
159     #else
160     dupredirect(n, newfd);
161     #endif
162     } while ((n = n->nfile.next));
163     INTON;
164     #ifdef notyet
165     if (memory[1])
166     out1 = &memout;
167     if (memory[2])
168     out2 = &memout;
169     #endif
170     if (flags & REDIR_SAVEFD2 && sv && sv->renamed[2] >= 0)
171     preverrout.fd = sv->renamed[2];
172     }
173    
174    
175     STATIC int
176     openredirect(union node *redir)
177     {
178     char *fname;
179     int f;
180    
181     switch (redir->nfile.type) {
182     case NFROM:
183     fname = redir->nfile.expfname;
184     if ((f = open64(fname, O_RDONLY)) < 0)
185     goto eopen;
186     break;
187     case NFROMTO:
188     fname = redir->nfile.expfname;
189     if ((f = open64(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
190     goto ecreate;
191     break;
192     case NTO:
193     /* Take care of noclobber mode. */
194     if (Cflag) {
195     fname = redir->nfile.expfname;
196     if ((f = noclobberopen(fname)) < 0)
197     goto ecreate;
198     break;
199     }
200     /* FALLTHROUGH */
201     case NCLOBBER:
202     fname = redir->nfile.expfname;
203     if ((f = open64(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
204     goto ecreate;
205     break;
206     case NAPPEND:
207     fname = redir->nfile.expfname;
208     if ((f = open64(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
209     goto ecreate;
210     break;
211     default:
212     #ifdef DEBUG
213     abort();
214     #endif
215     /* Fall through to eliminate warning. */
216     case NTOFD:
217     case NFROMFD:
218     f = -1;
219     break;
220     case NHERE:
221     case NXHERE:
222     f = openhere(redir);
223     break;
224     }
225    
226     return f;
227     ecreate:
228     sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
229     eopen:
230     sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
231     }
232    
233    
234     STATIC void
235     #ifdef notyet
236     dupredirect(redir, f, memory)
237     #else
238     dupredirect(redir, f)
239     #endif
240     union node *redir;
241     int f;
242     #ifdef notyet
243     char memory[10];
244     #endif
245     {
246     int fd = redir->nfile.fd;
247    
248     #ifdef notyet
249     memory[fd] = 0;
250     #endif
251     if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
252     if (redir->ndup.dupfd >= 0) { /* if not ">&-" */
253     #ifdef notyet
254     if (memory[redir->ndup.dupfd])
255     memory[fd] = 1;
256     else
257     #endif
258     copyfd(redir->ndup.dupfd, fd);
259     }
260     return;
261     }
262    
263     if (f != fd) {
264     copyfd(f, fd);
265     close(f);
266     }
267     return;
268     }
269    
270    
271     /*
272     * Handle here documents. Normally we fork off a process to write the
273     * data to a pipe. If the document is short, we can stuff the data in
274     * the pipe without forking.
275     */
276    
277     STATIC int
278     openhere(union node *redir)
279     {
280     int pip[2];
281     size_t len = 0;
282    
283     if (pipe(pip) < 0)
284     sh_error("Pipe call failed");
285     if (redir->type == NHERE) {
286     len = strlen(redir->nhere.doc->narg.text);
287     if (len <= PIPESIZE) {
288     xwrite(pip[1], redir->nhere.doc->narg.text, len);
289     goto out;
290     }
291     }
292     if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
293     close(pip[0]);
294     signal(SIGINT, SIG_IGN);
295     signal(SIGQUIT, SIG_IGN);
296     signal(SIGHUP, SIG_IGN);
297     #ifdef SIGTSTP
298     signal(SIGTSTP, SIG_IGN);
299     #endif
300     signal(SIGPIPE, SIG_DFL);
301     if (redir->type == NHERE)
302     xwrite(pip[1], redir->nhere.doc->narg.text, len);
303     else
304     expandhere(redir->nhere.doc, pip[1]);
305     _exit(0);
306     }
307     out:
308     close(pip[1]);
309     return pip[0];
310     }
311    
312    
313    
314     /*
315     * Undo the effects of the last redirection.
316     */
317    
318     void
319     popredir(int drop)
320     {
321     struct redirtab *rp;
322     int i;
323    
324     if (--nullredirs >= 0)
325     return;
326     INTOFF;
327     rp = redirlist;
328     for (i = 0 ; i < 10 ; i++) {
329     if (rp->renamed[i] != EMPTY) {
330     if (!drop) {
331     close(i);
332     copyfd(rp->renamed[i], i);
333     }
334     close(rp->renamed[i]);
335     }
336     }
337     redirlist = rp->next;
338     nullredirs = rp->nullredirs;
339     ckfree(rp);
340     INTON;
341     }
342    
343     /*
344     * Undo all redirections. Called on error or interrupt.
345     */
346    
347     #ifdef mkinit
348    
349     INCLUDE "redir.h"
350    
351     RESET {
352     clearredir(0);
353     }
354    
355     #endif
356    
357     /*
358     * Discard all saved file descriptors.
359     */
360    
361     void
362     clearredir(int drop)
363     {
364     for (;;) {
365     nullredirs = 0;
366     if (!redirlist)
367     break;
368     popredir(drop);
369     }
370     }
371    
372    
373    
374     /*
375     * Copy a file descriptor to be >= to. Returns -1
376     * if the source file descriptor is closed, EMPTY if there are no unused
377     * file descriptors left.
378     */
379    
380     int
381     copyfd(int from, int to)
382     {
383     int newfd;
384    
385     newfd = fcntl(from, F_DUPFD, to);
386     if (newfd < 0) {
387     int errno2 = errno;
388     if (errno2 == EMFILE)
389     return EMPTY;
390     else
391     sh_error("%d: %s", from, strerror(errno2));
392     }
393     return newfd;
394     }
395    
396    
397     /*
398     * Open a file in noclobber mode.
399     * The code was copied from bash.
400     */
401     int
402     noclobberopen(fname)
403     const char *fname;
404     {
405     int r, fd;
406     struct stat64 finfo, finfo2;
407    
408     /*
409     * If the file exists and is a regular file, return an error
410     * immediately.
411     */
412     r = stat64(fname, &finfo);
413     if (r == 0 && S_ISREG(finfo.st_mode)) {
414     errno = EEXIST;
415     return -1;
416     }
417    
418     /*
419     * If the file was not present (r != 0), make sure we open it
420     * exclusively so that if it is created before we open it, our open
421     * will fail. Make sure that we do not truncate an existing file.
422     * Note that we don't turn on O_EXCL unless the stat failed -- if the
423     * file was not a regular file, we leave O_EXCL off.
424     */
425     if (r != 0)
426     return open64(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
427     fd = open64(fname, O_WRONLY|O_CREAT, 0666);
428    
429     /* If the open failed, return the file descriptor right away. */
430     if (fd < 0)
431     return fd;
432    
433     /*
434     * OK, the open succeeded, but the file may have been changed from a
435     * non-regular file to a regular file between the stat and the open.
436     * We are assuming that the O_EXCL open handles the case where FILENAME
437     * did not exist and is symlinked to an existing file between the stat
438     * and open.
439     */
440    
441     /*
442     * If we can open it and fstat the file descriptor, and neither check
443     * revealed that it was a regular file, and the file has not been
444     * replaced, return the file descriptor.
445     */
446     if (fstat64(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
447     finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
448     return fd;
449    
450     /* The file has been replaced. badness. */
451     close(fd);
452     errno = EEXIST;
453     return -1;
454     }
455    
456    
457     int
458     redirectsafe(union node *redir, int flags)
459     {
460     int err;
461     volatile int saveint;
462     struct jmploc *volatile savehandler = handler;
463     struct jmploc jmploc;
464    
465     SAVEINT(saveint);
466     if (!(err = setjmp(jmploc.loc) * 2)) {
467     handler = &jmploc;
468     redirect(redir, flags);
469     }
470     handler = savehandler;
471     if (err && exception != EXERROR)
472     longjmp(handler->loc, 1);
473     RESTOREINT(saveint);
474     return err;
475     }