Subversion Repositories HelenOS

Rev

Rev 2714 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2714 cejka 1
/*  $NetBSD: redir.c,v 1.22 2000/05/22 10:18:47 elric 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. All advertising materials mentioning features or use of this software
19
 *    must display the following acknowledgement:
20
 *  This product includes software developed by the University of
21
 *  California, Berkeley and its contributors.
22
 * 4. Neither the name of the University nor the names of its contributors
23
 *    may be used to endorse or promote products derived from this software
24
 *    without specific prior written permission.
25
 *
26
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36
 * SUCH DAMAGE.
37
 */
38
 
39
#include <sys/cdefs.h>
40
#ifndef lint
41
#if 0
42
static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95";
43
#else
44
__RCSID("$NetBSD: redir.c,v 1.22 2000/05/22 10:18:47 elric Exp $");
45
#endif
46
#endif /* not lint */
47
 
48
#include <sys/stat.h>
49
#include <sys/types.h>
50
#include <sys/param.h>  /* PIPE_BUF */
51
#include <signal.h>
52
#include <string.h>
53
#include <fcntl.h>
54
#include <errno.h>
55
#include <unistd.h>
56
#include <stdlib.h>
57
 
58
/*
59
 * Code for dealing with input/output redirection.
60
 */
61
 
62
#include "shell.h"
63
#include "nodes.h"
64
#include "jobs.h"
65
#include "expand.h"
66
#include "redir.h"
67
#include "output.h"
68
#include "memalloc.h"
69
#include "error.h"
70
#include "options.h"
71
 
72
 
73
#define EMPTY -2        /* marks an unused slot in redirtab */
74
#ifndef PIPE_BUF
75
# define PIPESIZE 4096      /* amount of buffering in a pipe */
76
#else
77
# define PIPESIZE PIPE_BUF
78
#endif
79
 
80
 
81
MKINIT
82
struct redirtab {
83
    struct redirtab *next;
84
    short renamed[10];
85
};
86
 
87
 
88
MKINIT struct redirtab *redirlist;
89
 
90
/*
91
 * We keep track of whether or not fd0 has been redirected.  This is for
92
 * background commands, where we want to redirect fd0 to /dev/null only
93
 * if it hasn't already been redirected.
94
*/
95
int fd0_redirected = 0;
96
 
97
/*
98
 * We also keep track of where fd2 goes.
99
 */
100
int fd2 = 2;
101
 
102
STATIC int openredirect (union node *);
103
STATIC void dupredirect (union node *, int, char[10 ]);
104
STATIC int openhere (union node *);
105
STATIC int noclobberopen (const char *);
106
 
107
 
108
/*
109
 * Process a list of redirection commands.  If the REDIR_PUSH flag is set,
110
 * old file descriptors are stashed away so that the redirection can be
111
 * undone by calling popredir.  If the REDIR_BACKQ flag is set, then the
112
 * standard output, and the standard error if it becomes a duplicate of
113
 * stdout, is saved in memory.
114
 */
115
 
116
void
117
redirect(redir, flags)
118
    union node *redir;
119
    int flags;
120
    {
121
    union node *n;
122
    struct redirtab *sv = NULL;
123
    int i;
124
    int fd;
125
    int newfd;
126
    int try;
127
    char memory[10];    /* file descriptors to write to memory */
128
 
129
    for (i = 10 ; --i >= 0 ; )
130
        memory[i] = 0;
131
    memory[1] = flags & REDIR_BACKQ;
132
    if (flags & REDIR_PUSH) {
133
        sv = ckmalloc(sizeof (struct redirtab));
134
        for (i = 0 ; i < 10 ; i++)
135
            sv->renamed[i] = EMPTY;
136
        sv->next = redirlist;
137
        redirlist = sv;
138
    }
139
    for (n = redir ; n ; n = n->nfile.next) {
140
        fd = n->nfile.fd;
141
        try = 0;
142
        if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) &&
143
            n->ndup.dupfd == fd)
144
            continue; /* redirect from/to same file descriptor */
145
 
146
        INTOFF;
147
        newfd = openredirect(n);
148
        if (((flags & REDIR_PUSH) && sv->renamed[fd] == EMPTY) ||
149
            (fd == fd2)) {
150
            if (newfd == fd) {
151
                try++;
152
            } else if ((i = fcntl(fd, F_DUPFD, 10)) == -1) {
153
                switch (errno) {
154
                case EBADF:
155
                    if (!try) {
156
                        dupredirect(n, newfd, memory);
157
                        try++;
158
                        break;
159
                    }
160
                    /* FALLTHROUGH*/
161
                default:
162
                    if (newfd >= 0) {
163
                        close(newfd);
164
                    }
165
                    INTON;
166
                    error("%d: %s", fd, strerror(errno));
167
                    /* NOTREACHED */
168
                }
169
            }
170
            if (!try) {
171
                close(fd);
172
                if (flags & REDIR_PUSH) {
173
                    sv->renamed[fd] = i;
174
                }
175
                if (fd == fd2) {
176
                    fd2 = i;
177
                }
178
            }
179
        } else if (fd != newfd) {
180
            close(fd);
181
        }
182
                if (fd == 0)
183
                        fd0_redirected++;
184
        if (!try)
185
            dupredirect(n, newfd, memory);
186
        INTON;
187
    }
188
    if (memory[1])
189
        out1 = &memout;
190
    if (memory[2])
191
        out2 = &memout;
192
}
193
 
194
 
195
STATIC int
196
openredirect(redir)
197
    union node *redir;
198
    {
199
    char *fname;
200
    int f;
201
 
202
    switch (redir->nfile.type) {
203
    case NFROM:
204
        fname = redir->nfile.expfname;
205
        if ((f = open(fname, O_RDONLY)) < 0)
206
            goto eopen;
207
        break;
208
    case NFROMTO:
209
        fname = redir->nfile.expfname;
210
        if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0)
211
            goto ecreate;
212
        break;
213
    case NTO:
214
        /* Take care of noclobber mode. */
215
        if (Cflag) {
216
            fname = redir->nfile.expfname;
217
            if ((f = noclobberopen(fname)) < 0)
218
                goto ecreate;
219
            break;
220
        }
221
    case NTOOV:
222
        fname = redir->nfile.expfname;
223
#ifdef O_CREAT
224
        if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0)
225
            goto ecreate;
226
#else
227
        if ((f = creat(fname, 0666)) < 0)
228
            goto ecreate;
229
#endif
230
        break;
231
    case NAPPEND:
232
        fname = redir->nfile.expfname;
233
#ifdef O_APPEND
234
        if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0)
235
            goto ecreate;
236
#else
237
        if ((f = open(fname, O_WRONLY)) < 0
238
         && (f = creat(fname, 0666)) < 0)
239
            goto ecreate;
240
        lseek(f, (off_t)0, 2);
241
#endif
242
        break;
243
    case NTOFD:
244
    case NFROMFD:
245
        f = -1;
246
        break;
247
    case NHERE:
248
    case NXHERE:
249
        f = openhere(redir);
250
        break;
251
    default:
252
        abort();
253
    }
254
 
255
    return f;
256
ecreate:
257
    error("cannot create %s: %s", fname, errmsg(errno, E_CREAT));
258
eopen:
259
    error("cannot open %s: %s", fname, errmsg(errno, E_OPEN));
260
}
261
 
262
 
263
STATIC void
264
dupredirect(redir, f, memory)
265
    union node *redir;
266
    int f;
267
    char memory[10];
268
    {
269
    int fd = redir->nfile.fd;
270
 
271
    memory[fd] = 0;
272
    if (redir->nfile.type == NTOFD || redir->nfile.type == NFROMFD) {
273
        if (redir->ndup.dupfd >= 0) {   /* if not ">&-" */
274
            if (memory[redir->ndup.dupfd])
275
                memory[fd] = 1;
276
            else
277
                copyfd(redir->ndup.dupfd, fd);
278
        }
279
        return;
280
    }
281
 
282
    if (f != fd) {
283
        copyfd(f, fd);
284
        close(f);
285
    }
286
    return;
287
}
288
 
289
 
290
/*
291
 * Handle here documents.  Normally we fork off a process to write the
292
 * data to a pipe.  If the document is short, we can stuff the data in
293
 * the pipe without forking.
294
 */
295
 
296
STATIC int
297
openhere(redir)
298
    union node *redir;
299
    {
300
    int pip[2];
301
    int len = 0;
302
 
303
    if (pipe(pip) < 0)
304
        error("Pipe call failed");
305
    if (redir->type == NHERE) {
306
        len = strlen(redir->nhere.doc->narg.text);
307
        if (len <= PIPESIZE) {
308
            xwrite(pip[1], redir->nhere.doc->narg.text, len);
309
            goto out;
310
        }
311
    }
312
    if (forkshell((struct job *)NULL, (union node *)NULL, FORK_NOJOB) == 0) {
313
        close(pip[0]);
314
        signal(SIGINT, SIG_IGN);
315
        signal(SIGQUIT, SIG_IGN);
316
        signal(SIGHUP, SIG_IGN);
317
#ifdef SIGTSTP
318
        signal(SIGTSTP, SIG_IGN);
319
#endif
320
        signal(SIGPIPE, SIG_DFL);
321
        if (redir->type == NHERE)
322
            xwrite(pip[1], redir->nhere.doc->narg.text, len);
323
        else
324
            expandhere(redir->nhere.doc, pip[1]);
325
        _exit(0);
326
    }
327
out:
328
    close(pip[1]);
329
    return pip[0];
330
}
331
 
332
 
333
 
334
/*
335
 * Undo the effects of the last redirection.
336
 */
337
 
338
void
339
popredir() {
340
    struct redirtab *rp = redirlist;
341
    int i;
342
 
343
    INTOFF;
344
    for (i = 0 ; i < 10 ; i++) {
345
        if (rp->renamed[i] != EMPTY) {
346
                        if (i == 0)
347
                                fd0_redirected--;
348
            close(i);
349
            if (rp->renamed[i] >= 0) {
350
                copyfd(rp->renamed[i], i);
351
                close(rp->renamed[i]);
352
            }
353
            if (rp->renamed[i] == fd2) {
354
                fd2 = i;
355
            }
356
        }
357
    }
358
    redirlist = rp->next;
359
    ckfree(rp);
360
    INTON;
361
}
362
 
363
/*
364
 * Undo all redirections.  Called on error or interrupt.
365
 */
366
 
367
#ifdef mkinit
368
 
369
INCLUDE "redir.h"
370
 
371
RESET {
372
    while (redirlist)
373
        popredir();
374
}
375
 
376
SHELLPROC {
377
    clearredir();
378
}
379
 
380
#endif
381
 
382
/* Return true if fd 0 has already been redirected at least once.  */
383
int
384
fd0_redirected_p () {
385
        return fd0_redirected != 0;
386
}
387
 
388
/*
389
 * Discard all saved file descriptors.
390
 */
391
 
392
void
393
clearredir() {
394
    struct redirtab *rp;
395
    int i;
396
 
397
    for (rp = redirlist ; rp ; rp = rp->next) {
398
        for (i = 0 ; i < 10 ; i++) {
399
            if (rp->renamed[i] >= 0) {
400
                close(rp->renamed[i]);
401
                if (rp->renamed[i] == fd2) {
402
                    fd2 = -1;
403
                }
404
            }
405
            rp->renamed[i] = EMPTY;
406
        }
407
    }
408
}
409
 
410
 
411
 
412
/*
413
 * Copy 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
 
418
int
419
copyfd(from, to)
420
    int from;
421
    int to;
422
{
423
    int newfd;
424
 
425
    newfd = fcntl(from, F_DUPFD, to);
426
    if (newfd < 0) {
427
        if (errno == EMFILE)
428
            return EMPTY;
429
        else
430
            error("%d: %s", from, strerror(errno));
431
    }
432
    return newfd;
433
}
434
 
435
/*
436
 * Open a file in noclobber mode.
437
 * The code was copied from bash.
438
 */
439
int
440
noclobberopen(fname)
441
    const char *fname;
442
{
443
    int r, fd;
444
    struct stat finfo, finfo2;
445
 
446
    /*
447
     * If the file exists and is a regular file, return an error
448
     * immediately.
449
     */
450
    r = stat(fname, &finfo);
451
    if (r == 0 && S_ISREG(finfo.st_mode)) {
452
        errno = EEXIST;
453
        return -1;
454
    }
455
 
456
    /*
457
     * If the file was not present (r != 0), make sure we open it
458
     * exclusively so that if it is created before we open it, our open
459
     * will fail.  Make sure that we do not truncate an existing file.
460
     * Note that we don't turn on O_EXCL unless the stat failed -- if the
461
     * file was not a regular file, we leave O_EXCL off.
462
     */
463
    if (r != 0)
464
        return open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666);
465
    fd = open(fname, O_WRONLY|O_CREAT, 0666);
466
 
467
    /* If the open failed, return the file descriptor right away. */
468
    if (fd < 0)
469
        return fd;
470
 
471
    /*
472
     * OK, the open succeeded, but the file may have been changed from a
473
     * non-regular file to a regular file between the stat and the open.
474
     * We are assuming that the O_EXCL open handles the case where FILENAME
475
     * did not exist and is symlinked to an existing file between the stat
476
     * and open.
477
     */
478
 
479
    /*
480
     * If we can open it and fstat the file descriptor, and neither check
481
     * revealed that it was a regular file, and the file has not been
482
     * replaced, return the file descriptor.
483
     */
484
     if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) &&
485
         finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino)
486
        return fd;
487
 
488
    /* The file has been replaced.  badness. */
489
    close(fd);
490
    errno = EEXIST;
491
    return -1;
492
}