Magellan Linux

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 815 - (show annotations) (download)
Fri Apr 24 18:32:46 2009 UTC (15 years ago) by niro
File MIME type: text/plain
File size: 10482 byte(s)
-updated to klibc-1.5.15
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);
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|O_TRUNC, 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 int pip[2];
299 size_t len = 0;
300
301 if (pipe(pip) < 0)
302 sh_error("Pipe call failed");
303 if (redir->type == NHERE) {
304 len = strlen(redir->nhere.doc->narg.text);
305 if (len <= PIPESIZE) {
306 xwrite(pip[1], redir->nhere.doc->narg.text, len);
307 goto out;
308 }
309 }
310 if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
311 close(pip[0]);
312 signal(SIGINT, SIG_IGN);
313 signal(SIGQUIT, SIG_IGN);
314 signal(SIGHUP, SIG_IGN);
315 #ifdef SIGTSTP
316 signal(SIGTSTP, SIG_IGN);
317 #endif
318 signal(SIGPIPE, SIG_DFL);
319 if (redir->type == NHERE)
320 xwrite(pip[1], redir->nhere.doc->narg.text, len);
321 else
322 expandhere(redir->nhere.doc, pip[1]);
323 _exit(0);
324 }
325 out:
326 close(pip[1]);
327 return pip[0];
328 }
329
330
331
332 /*
333 * Undo the effects of the last redirection.
334 */
335
336 void
337 popredir(int drop)
338 {
339 struct redirtab *rp;
340 int i;
341
342 if (--nullredirs >= 0)
343 return;
344 INTOFF;
345 rp = redirlist;
346 for (i = 0 ; i < 10 ; i++) {
347 switch (rp->renamed[i]) {
348 case CLOSED:
349 if (!drop)
350 close(i);
351 break;
352 case EMPTY:
353 case REALLY_CLOSED:
354 break;
355 default:
356 if (!drop)
357 dup2(rp->renamed[i], i);
358 close(rp->renamed[i]);
359 break;
360 }
361 }
362 redirlist = rp->next;
363 nullredirs = rp->nullredirs;
364 ckfree(rp);
365 INTON;
366 }
367
368 /*
369 * Undo all redirections. Called on error or interrupt.
370 */
371
372 #ifdef mkinit
373
374 INCLUDE "redir.h"
375
376 RESET {
377 /*
378 * Discard all saved file descriptors.
379 */
380 for (;;) {
381 nullredirs = 0;
382 if (!redirlist)
383 break;
384 popredir(0);
385 }
386 }
387
388 #endif
389
390
391
392 /*
393 * Move a file descriptor to > 10. Invokes sh_error on error unless
394 * the original file dscriptor is not open.
395 */
396
397 int
398 savefd(int from)
399 {
400 int newfd;
401 int err;
402
403 newfd = fcntl(from, F_DUPFD, 10);
404 err = newfd < 0 ? errno : 0;
405 if (err != EBADF) {
406 close(from);
407 if (err)
408 sh_error("%d: %s", from, strerror(err));
409 else
410 fcntl(newfd, F_SETFD, FD_CLOEXEC);
411 }
412
413 return newfd;
414 }
415
416
417 /*
418 * Open a file in noclobber mode.
419 * The code was copied from bash.
420 */
421 int
422 noclobberopen(fname)
423 const char *fname;
424 {
425 int r, fd;
426 struct stat64 finfo, finfo2;
427
428 /*
429 * If the file exists and is a regular file, return an error
430 * immediately.
431 */
432 r = stat64(fname, &finfo);
433 if (r == 0 && S_ISREG(finfo.st_mode)) {
434 errno = EEXIST;
435 return -1;
436 }
437
438 /*
439 * If the file was not present (r != 0), make sure we open it
440 * exclusively so that if it is created before we open it, our open
441 * will fail. Make sure that we do not truncate an existing file.
442 * Note that we don't turn on O_EXCL unless the stat failed -- if the
443 * file was not a regular file, we leave O_EXCL off.
444 */
445 if (r != 0)
446 return open64(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
447 fd = open64(fname, O_WRONLY|O_CREAT, 0666);
448
449 /* If the open failed, return the file descriptor right away. */
450 if (fd < 0)
451 return fd;
452
453 /*
454 * OK, the open succeeded, but the file may have been changed from a
455 * non-regular file to a regular file between the stat and the open.
456 * We are assuming that the O_EXCL open handles the case where FILENAME
457 * did not exist and is symlinked to an existing file between the stat
458 * and open.
459 */
460
461 /*
462 * If we can open it and fstat the file descriptor, and neither check
463 * revealed that it was a regular file, and the file has not been
464 * replaced, return the file descriptor.
465 */
466 if (fstat64(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
467 finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
468 return fd;
469
470 /* The file has been replaced. badness. */
471 close(fd);
472 errno = EEXIST;
473 return -1;
474 }
475
476
477 int
478 redirectsafe(union node *redir, int flags)
479 {
480 int err;
481 volatile int saveint;
482 struct jmploc *volatile savehandler = handler;
483 struct jmploc jmploc;
484
485 SAVEINT(saveint);
486 if (!(err = setjmp(jmploc.loc) * 2)) {
487 handler = &jmploc;
488 redirect(redir, flags);
489 }
490 handler = savehandler;
491 if (err && exception != EXERROR)
492 longjmp(handler->loc, 1);
493 RESTOREINT(saveint);
494 return err;
495 }