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 71MKINIT 72struct redirtab { 73 struct redirtab *next; 74 int renamed[10]; 75}; 76 77 78MKINIT struct redirtab *redirlist; 79 80STATIC int openredirect(union node *); 81#ifdef notyet 82STATIC void dupredirect(union node *, int, char[10]); 83#else 84STATIC void dupredirect(union node *, int); 85#endif 86STATIC 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 97void 98redirect(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 167STATIC int 168openredirect(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; 235ecreate: 236 sh_error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 237eopen: 238 sh_error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); 239} 240 241 242STATIC void 243#ifdef notyet 244dupredirect(redir, f, memory) 245#else 246dupredirect(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 284err: 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 295STATIC int 296openhere(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 } 329out: 330 close(pip[1]); 331 return pip[0]; 332} 333 334 335 336/* 337 * Undo the effects of the last redirection. 338 */ 339 340void 341popredir(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 375INCLUDE "redir.h" 376 377RESET { 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 393int 394savefd(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 413int 414redirectsafe(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 434void unwindredir(struct redirtab *stop) 435{ 436 while (redirlist != stop) 437 popredir(0); 438} 439 440 441struct 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 457out: 458 return q; 459} 460