Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1122 - (show annotations) (download)
Wed Aug 18 21:11:40 2010 UTC (13 years, 8 months ago) by niro
File MIME type: text/plain
File size: 10443 byte(s)
-updated to klibc-1.5.19
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 int nullredirs;
76 };
77
78
79 MKINIT struct redirtab *redirlist;
80 MKINIT int nullredirs;
81
82 STATIC int openredirect(union node *);
83 #ifdef notyet
84 STATIC void dupredirect(union node *, int, char[10]);
85 #else
86 STATIC void dupredirect(union node *, int);
87 #endif
88 STATIC int openhere(union node *);
89 STATIC int noclobberopen(const char *);
90
91
92 /*
93 * Process a list of redirection commands. If the REDIR_PUSH flag is set,
94 * old file descriptors are stashed away so that the redirection can be
95 * undone by calling popredir. If the REDIR_BACKQ flag is set, then the
96 * standard output, and the standard error if it becomes a duplicate of
97 * stdout, is saved in memory.
98 */
99
100 void
101 redirect(union node *redir, int flags)
102 {
103 union node *n;
104 struct redirtab *sv;
105 int i;
106 int fd;
107 int newfd;
108 int *p;
109 #if notyet
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 #endif
116 nullredirs++;
117 if (!redir) {
118 return;
119 }
120 sv = NULL;
121 INTOFF;
122 if (likely(flags & REDIR_PUSH)) {
123 struct redirtab *q;
124 q = ckmalloc(sizeof (struct redirtab));
125 q->next = redirlist;
126 redirlist = q;
127 q->nullredirs = nullredirs - 1;
128 for (i = 0 ; i < 10 ; i++)
129 q->renamed[i] = EMPTY;
130 nullredirs = 0;
131 sv = q;
132 }
133 n = redir;
134 do {
135 newfd = openredirect(n);
136 if (newfd < -1)
137 continue;
138
139 fd = n->nfile.fd;
140
141 if (sv) {
142 p = &sv->renamed[fd];
143 i = *p;
144
145 if (likely(i == EMPTY)) {
146 i = CLOSED;
147 if (fd != newfd) {
148 i = savefd(fd, fd);
149 fd = -1;
150 }
151 }
152
153 if (i == newfd)
154 /* Can only happen if i == newfd == CLOSED */
155 i = REALLY_CLOSED;
156
157 *p = i;
158 }
159
160 if (fd == newfd)
161 continue;
162
163 #ifdef notyet
164 dupredirect(n, newfd, memory);
165 #else
166 dupredirect(n, newfd);
167 #endif
168 } while ((n = n->nfile.next));
169 INTON;
170 #ifdef notyet
171 if (memory[1])
172 out1 = &memout;
173 if (memory[2])
174 out2 = &memout;
175 #endif
176 if (flags & REDIR_SAVEFD2 && sv->renamed[2] >= 0)
177 preverrout.fd = sv->renamed[2];
178 }
179
180
181 STATIC int
182 openredirect(union node *redir)
183 {
184 char *fname;
185 int f;
186
187 switch (redir->nfile.type) {
188 case NFROM:
189 fname = redir->nfile.expfname;
190 if ((f = open64(fname, O_RDONLY)) < 0)
191 goto eopen;
192 break;
193 case NFROMTO:
194 fname = redir->nfile.expfname;
195 if ((f = open64(fname, O_RDWR|O_CREAT, 0666)) < 0)
196 goto ecreate;
197 break;
198 case NTO:
199 /* Take care of noclobber mode. */
200 if (Cflag) {
201 fname = redir->nfile.expfname;
202 if ((f = noclobberopen(fname)) < 0)
203 goto ecreate;
204 break;
205 }
206 /* FALLTHROUGH */
207 case NCLOBBER:
208 fname = redir->nfile.expfname;
209 if ((f = open64(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 = open64(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
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
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
341 popredir(int drop)
342 {
343 struct redirtab *rp;
344 int i;
345
346 if (--nullredirs >= 0)
347 return;
348 INTOFF;
349 rp = redirlist;
350 for (i = 0 ; i < 10 ; i++) {
351 switch (rp->renamed[i]) {
352 case CLOSED:
353 if (!drop)
354 close(i);
355 break;
356 case EMPTY:
357 case REALLY_CLOSED:
358 break;
359 default:
360 if (!drop)
361 dup2(rp->renamed[i], i);
362 close(rp->renamed[i]);
363 break;
364 }
365 }
366 redirlist = rp->next;
367 nullredirs = rp->nullredirs;
368 ckfree(rp);
369 INTON;
370 }
371
372 /*
373 * Undo all redirections. Called on error or interrupt.
374 */
375
376 #ifdef mkinit
377
378 INCLUDE "redir.h"
379
380 RESET {
381 /*
382 * Discard all saved file descriptors.
383 */
384 for (;;) {
385 nullredirs = 0;
386 if (!redirlist)
387 break;
388 popredir(0);
389 }
390 }
391
392 #endif
393
394
395
396 /*
397 * Move a file descriptor to > 10. Invokes sh_error on error unless
398 * the original file dscriptor is not open.
399 */
400
401 int
402 savefd(int from, int ofd)
403 {
404 int newfd;
405 int err;
406
407 newfd = fcntl(from, F_DUPFD, 10);
408 err = newfd < 0 ? errno : 0;
409 if (err != EBADF) {
410 close(ofd);
411 if (err)
412 sh_error("%d: %s", from, strerror(err));
413 else
414 fcntl(newfd, F_SETFD, FD_CLOEXEC);
415 }
416
417 return newfd;
418 }
419
420
421 /*
422 * Open a file in noclobber mode.
423 * The code was copied from bash.
424 */
425 int
426 noclobberopen(fname)
427 const char *fname;
428 {
429 int r, fd;
430 struct stat64 finfo, finfo2;
431
432 /*
433 * If the file exists and is a regular file, return an error
434 * immediately.
435 */
436 r = stat64(fname, &finfo);
437 if (r == 0 && S_ISREG(finfo.st_mode)) {
438 errno = EEXIST;
439 return -1;
440 }
441
442 /*
443 * If the file was not present (r != 0), make sure we open it
444 * exclusively so that if it is created before we open it, our open
445 * will fail. Make sure that we do not truncate an existing file.
446 * Note that we don't turn on O_EXCL unless the stat failed -- if the
447 * file was not a regular file, we leave O_EXCL off.
448 */
449 if (r != 0)
450 return open64(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
451 fd = open64(fname, O_WRONLY|O_CREAT, 0666);
452
453 /* If the open failed, return the file descriptor right away. */
454 if (fd < 0)
455 return fd;
456
457 /*
458 * OK, the open succeeded, but the file may have been changed from a
459 * non-regular file to a regular file between the stat and the open.
460 * We are assuming that the O_EXCL open handles the case where FILENAME
461 * did not exist and is symlinked to an existing file between the stat
462 * and open.
463 */
464
465 /*
466 * If we can open it and fstat the file descriptor, and neither check
467 * revealed that it was a regular file, and the file has not been
468 * replaced, return the file descriptor.
469 */
470 if (fstat64(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
471 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
472 return fd;
473
474 /* The file has been replaced. badness. */
475 close(fd);
476 errno = EEXIST;
477 return -1;
478 }
479
480
481 int
482 redirectsafe(union node *redir, int flags)
483 {
484 int err;
485 volatile int saveint;
486 struct jmploc *volatile savehandler = handler;
487 struct jmploc jmploc;
488
489 SAVEINT(saveint);
490 if (!(err = setjmp(jmploc.loc) * 2)) {
491 handler = &jmploc;
492 redirect(redir, flags);
493 }
494 handler = savehandler;
495 if (err && exception != EXERROR)
496 longjmp(handler->loc, 1);
497 RESTOREINT(saveint);
498 return err;
499 }