1 1.76 kre /* $NetBSD: redir.c,v 1.76 2024/11/11 22:57:42 kre Exp $ */ 2 1.11 cgd 3 1.1 cgd /*- 4 1.7 jtc * Copyright (c) 1991, 1993 5 1.7 jtc * The Regents of the University of California. All rights reserved. 6 1.1 cgd * 7 1.1 cgd * This code is derived from software contributed to Berkeley by 8 1.1 cgd * Kenneth Almquist. 9 1.1 cgd * 10 1.1 cgd * Redistribution and use in source and binary forms, with or without 11 1.1 cgd * modification, are permitted provided that the following conditions 12 1.1 cgd * are met: 13 1.1 cgd * 1. Redistributions of source code must retain the above copyright 14 1.1 cgd * notice, this list of conditions and the following disclaimer. 15 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright 16 1.1 cgd * notice, this list of conditions and the following disclaimer in the 17 1.1 cgd * documentation and/or other materials provided with the distribution. 18 1.28 agc * 3. Neither the name of the University nor the names of its contributors 19 1.1 cgd * may be used to endorse or promote products derived from this software 20 1.1 cgd * without specific prior written permission. 21 1.1 cgd * 22 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 1.1 cgd * SUCH DAMAGE. 33 1.1 cgd */ 34 1.1 cgd 35 1.16 christos #include <sys/cdefs.h> 36 1.1 cgd #ifndef lint 37 1.11 cgd #if 0 38 1.12 christos static char sccsid[] = "@(#)redir.c 8.2 (Berkeley) 5/4/95"; 39 1.11 cgd #else 40 1.76 kre __RCSID("$NetBSD: redir.c,v 1.76 2024/11/11 22:57:42 kre Exp $"); 41 1.11 cgd #endif 42 1.1 cgd #endif /* not lint */ 43 1.1 cgd 44 1.12 christos #include <sys/types.h> 45 1.17 christos #include <sys/param.h> /* PIPE_BUF */ 46 1.48 christos #include <sys/stat.h> 47 1.12 christos #include <signal.h> 48 1.12 christos #include <string.h> 49 1.12 christos #include <fcntl.h> 50 1.12 christos #include <errno.h> 51 1.12 christos #include <unistd.h> 52 1.12 christos #include <stdlib.h> 53 1.12 christos 54 1.1 cgd /* 55 1.1 cgd * Code for dealing with input/output redirection. 56 1.1 cgd */ 57 1.1 cgd 58 1.25 christos #include "main.h" 59 1.50 christos #include "builtins.h" 60 1.1 cgd #include "shell.h" 61 1.1 cgd #include "nodes.h" 62 1.1 cgd #include "jobs.h" 63 1.23 christos #include "options.h" 64 1.1 cgd #include "expand.h" 65 1.1 cgd #include "redir.h" 66 1.1 cgd #include "output.h" 67 1.1 cgd #include "memalloc.h" 68 1.51 kre #include "mystring.h" 69 1.1 cgd #include "error.h" 70 1.59 kre #include "show.h" 71 1.1 cgd 72 1.1 cgd 73 1.44 kre #define CLOSED -1 /* fd was not open before redir */ 74 1.76 kre 75 1.17 christos #ifndef PIPE_BUF 76 1.17 christos # define PIPESIZE 4096 /* amount of buffering in a pipe */ 77 1.17 christos #else 78 1.17 christos # define PIPESIZE PIPE_BUF 79 1.17 christos #endif 80 1.1 cgd 81 1.65 kre #ifndef FD_CLOEXEC 82 1.65 kre # define FD_CLOEXEC 1 /* well known from before there was a name */ 83 1.65 kre #endif 84 1.65 kre 85 1.65 kre #ifndef F_DUPFD_CLOEXEC 86 1.65 kre #define F_DUPFD_CLOEXEC F_DUPFD 87 1.76 kre #define CLOEXEC(fd) (fcntl((fd), F_SETFD, \ 88 1.76 kre (fcntl_int)(fcntl((fd), F_GETFD) | FD_CLOEXEC))) 89 1.65 kre #else 90 1.76 kre #define CLOEXEC(fd) __nothing 91 1.65 kre #endif 92 1.65 kre 93 1.76 kre /* yes, this is correct, bizarre parens and all -- used only as a cast */ 94 1.76 kre #define fcntl_int void *)(intptr_t 95 1.76 kre #undef fcntl_int 96 1.76 kre #define fcntl_int int 97 1.76 kre 98 1.1 cgd 99 1.1 cgd MKINIT 100 1.43 christos struct renamelist { 101 1.43 christos struct renamelist *next; 102 1.43 christos int orig; 103 1.43 christos int into; 104 1.76 kre int cloexec; /* orig had FD_CLOEXEC set (into always does) */ 105 1.43 christos }; 106 1.43 christos 107 1.43 christos MKINIT 108 1.1 cgd struct redirtab { 109 1.1 cgd struct redirtab *next; 110 1.43 christos struct renamelist *renamed; 111 1.1 cgd }; 112 1.1 cgd 113 1.1 cgd 114 1.1 cgd MKINIT struct redirtab *redirlist; 115 1.1 cgd 116 1.13 christos /* 117 1.7 jtc * We keep track of whether or not fd0 has been redirected. This is for 118 1.7 jtc * background commands, where we want to redirect fd0 to /dev/null only 119 1.13 christos * if it hasn't already been redirected. 120 1.43 christos */ 121 1.43 christos STATIC int fd0_redirected = 0; 122 1.1 cgd 123 1.43 christos /* 124 1.43 christos * And also where to put internal use fds that should be out of the 125 1.43 christos * way of user defined fds (normally) 126 1.43 christos */ 127 1.43 christos STATIC int big_sh_fd = 0; 128 1.76 kre STATIC int biggest_sh_fd = 2; 129 1.43 christos 130 1.43 christos STATIC const struct renamelist *is_renamed(const struct renamelist *, int); 131 1.76 kre STATIC void fd_rename(struct redirtab *, int, int, int); 132 1.68 kre STATIC int * saved_redirected_fd(int); 133 1.43 christos STATIC void free_rl(struct redirtab *, int); 134 1.29 christos STATIC void openredirect(union node *, char[10], int); 135 1.34 yamt STATIC int openhere(const union node *); 136 1.76 kre STATIC int copyfd(int, int, int, int); 137 1.43 christos STATIC void find_big_fd(void); 138 1.43 christos 139 1.54 kre 140 1.54 kre struct shell_fds { /* keep track of internal shell fds */ 141 1.54 kre struct shell_fds *nxt; 142 1.54 kre void (*cb)(int, int); 143 1.54 kre int fd; 144 1.54 kre }; 145 1.54 kre 146 1.54 kre STATIC struct shell_fds *sh_fd_list; 147 1.54 kre 148 1.68 kre STATIC int pick_new_fd(int); 149 1.54 kre STATIC void renumber_sh_fd(struct shell_fds *); 150 1.54 kre STATIC struct shell_fds *sh_fd(int); 151 1.54 kre 152 1.43 christos STATIC const struct renamelist * 153 1.43 christos is_renamed(const struct renamelist *rl, int fd) 154 1.43 christos { 155 1.43 christos while (rl != NULL) { 156 1.43 christos if (rl->orig == fd) 157 1.43 christos return rl; 158 1.43 christos rl = rl->next; 159 1.43 christos } 160 1.43 christos return NULL; 161 1.43 christos } 162 1.43 christos 163 1.68 kre STATIC int * 164 1.68 kre saved_redirected_fd(int fd) 165 1.68 kre { 166 1.68 kre struct redirtab *rt; 167 1.68 kre struct renamelist *rl; 168 1.68 kre 169 1.68 kre for (rt = redirlist; rt != NULL; rt = rt->next) { 170 1.68 kre for (rl = rt->renamed; rl != NULL; rl = rl->next) { 171 1.68 kre if (rl->into == fd) 172 1.68 kre return &rl->into; 173 1.68 kre } 174 1.68 kre } 175 1.68 kre return NULL; 176 1.68 kre } 177 1.68 kre 178 1.43 christos STATIC void 179 1.43 christos free_rl(struct redirtab *rt, int reset) 180 1.43 christos { 181 1.43 christos struct renamelist *rl, *rn = rt->renamed; 182 1.43 christos 183 1.43 christos while ((rl = rn) != NULL) { 184 1.43 christos rn = rl->next; 185 1.76 kre 186 1.43 christos if (rl->orig == 0) 187 1.43 christos fd0_redirected--; 188 1.76 kre 189 1.60 kre VTRACE(DBG_REDIR, ("popredir %d%s: %s", 190 1.60 kre rl->orig, rl->orig==0 ? " (STDIN)" : "", 191 1.76 kre reset == POPREDIR_UNDO ? "" : 192 1.76 kre reset == POPREDIR_PERMANENT ? "make permanent" : 193 1.76 kre "no reset\n")); 194 1.76 kre 195 1.76 kre switch (reset) { 196 1.76 kre case POPREDIR_UNDO: 197 1.60 kre if (rl->into < 0) { 198 1.76 kre VTRACE(DBG_REDIR, (" closed\n")); 199 1.43 christos close(rl->orig); 200 1.60 kre } else { 201 1.76 kre VTRACE(DBG_REDIR, 202 1.76 kre (" from %d%s\n", rl->into, 203 1.76 kre rl->cloexec ? " (colexec)" : "")); 204 1.76 kre copyfd(rl->into, rl->orig, rl->cloexec, 1); 205 1.76 kre } 206 1.76 kre break; 207 1.76 kre 208 1.76 kre case POPREDIR_PERMANENT: 209 1.76 kre if (rl->into < 0) { 210 1.76 kre VTRACE(DBG_REDIR, (" was closed\n")); 211 1.76 kre /* nothing to do */ 212 1.76 kre } else { 213 1.76 kre VTRACE(DBG_REDIR, 214 1.76 kre (" close savefd %d\n", rl->into)); 215 1.76 kre close(rl->into); 216 1.60 kre } 217 1.76 kre break; 218 1.76 kre 219 1.76 kre default: 220 1.76 kre /* nothing to do */ 221 1.76 kre break; 222 1.43 christos } 223 1.43 christos ckfree(rl); 224 1.43 christos } 225 1.43 christos rt->renamed = NULL; 226 1.43 christos } 227 1.1 cgd 228 1.43 christos STATIC void 229 1.76 kre fd_rename(struct redirtab *rt, int from, int to, int cloexec) 230 1.43 christos { 231 1.60 kre /* XXX someday keep a short list (8..10) of freed renamelists XXX */ 232 1.43 christos struct renamelist *rl = ckmalloc(sizeof(struct renamelist)); 233 1.43 christos 234 1.76 kre /* 235 1.76 kre * Note this list is operated as LIFO so saved fd's are 236 1.76 kre * undone in the opposite order to that they were saved 237 1.76 kre * (needed to ensure correct results) 238 1.76 kre */ 239 1.43 christos rl->next = rt->renamed; 240 1.43 christos rt->renamed = rl; 241 1.43 christos 242 1.43 christos rl->orig = from; 243 1.43 christos rl->into = to; 244 1.76 kre rl->cloexec = cloexec; 245 1.43 christos } 246 1.1 cgd 247 1.1 cgd /* 248 1.1 cgd * Process a list of redirection commands. If the REDIR_PUSH flag is set, 249 1.1 cgd * old file descriptors are stashed away so that the redirection can be 250 1.1 cgd * undone by calling popredir. If the REDIR_BACKQ flag is set, then the 251 1.1 cgd * standard output, and the standard error if it becomes a duplicate of 252 1.1 cgd * stdout, is saved in memory. 253 1.1 cgd */ 254 1.1 cgd 255 1.1 cgd void 256 1.27 christos redirect(union node *redir, int flags) 257 1.27 christos { 258 1.1 cgd union node *n; 259 1.16 christos struct redirtab *sv = NULL; 260 1.1 cgd int i; 261 1.1 cgd int fd; 262 1.13 christos char memory[10]; /* file descriptors to write to memory */ 263 1.1 cgd 264 1.60 kre CTRACE(DBG_REDIR, ("redirect(F=0x%x):%s\n", flags, redir?"":" NONE")); 265 1.76 kre 266 1.1 cgd for (i = 10 ; --i >= 0 ; ) 267 1.1 cgd memory[i] = 0; 268 1.1 cgd memory[1] = flags & REDIR_BACKQ; 269 1.1 cgd if (flags & REDIR_PUSH) { 270 1.60 kre /* 271 1.60 kre * We don't have to worry about REDIR_VFORK here, as 272 1.24 christos * flags & REDIR_PUSH is never true if REDIR_VFORK is set. 273 1.24 christos */ 274 1.1 cgd sv = ckmalloc(sizeof (struct redirtab)); 275 1.43 christos sv->renamed = NULL; 276 1.1 cgd sv->next = redirlist; 277 1.1 cgd redirlist = sv; 278 1.1 cgd } 279 1.1 cgd for (n = redir ; n ; n = n->nfile.next) { 280 1.68 kre int *renamed; 281 1.68 kre 282 1.1 cgd fd = n->nfile.fd; 283 1.68 kre VTRACE(DBG_REDIR, ("redir %d (max=%d limit=%ld) ", 284 1.68 kre fd, max_user_fd, user_fd_limit)); 285 1.68 kre if (fd < user_fd_limit && fd > max_user_fd) 286 1.53 kre max_user_fd = fd; 287 1.69 kre if ((n->nfile.type == NTOFD || n->nfile.type == NFROMFD) && 288 1.69 kre n->ndup.dupfd == fd) { 289 1.69 kre VTRACE(DBG_REDIR, ("!cloexec\n")); 290 1.69 kre if (sh_fd(fd) != NULL || 291 1.69 kre saved_redirected_fd(fd) != NULL) 292 1.69 kre error("fd %d: %s", fd, strerror(EBADF)); 293 1.69 kre /* redirect from/to same file descriptor */ 294 1.69 kre /* make sure it stays open */ 295 1.76 kre if (fcntl(fd, F_SETFD, (fcntl_int)0) < 0) 296 1.69 kre error("fd %d: %s", fd, strerror(errno)); 297 1.69 kre continue; 298 1.69 kre } 299 1.68 kre if ((renamed = saved_redirected_fd(fd)) != NULL) { 300 1.68 kre int to = pick_new_fd(fd); 301 1.68 kre 302 1.68 kre VTRACE(DBG_REDIR, 303 1.68 kre ("redirect: moved holding fd %d to %d\n", fd, to)); 304 1.68 kre *renamed = to; 305 1.68 kre if (to != fd) /* always... */ 306 1.68 kre (void)close(fd); 307 1.68 kre } 308 1.54 kre renumber_sh_fd(sh_fd(fd)); 309 1.15 christos 310 1.43 christos if ((flags & REDIR_PUSH) && !is_renamed(sv->renamed, fd)) { 311 1.67 kre int bigfd; 312 1.76 kre int cloexec; 313 1.76 kre 314 1.76 kre cloexec = fcntl(fd, F_GETFD); 315 1.76 kre if (cloexec >= 0) 316 1.76 kre cloexec &= FD_CLOEXEC; 317 1.76 kre else 318 1.76 kre cloexec = 0; 319 1.67 kre 320 1.1 cgd INTOFF; 321 1.43 christos if (big_sh_fd < 10) 322 1.43 christos find_big_fd(); 323 1.67 kre if ((bigfd = big_sh_fd) < max_user_fd) 324 1.67 kre bigfd = max_user_fd; 325 1.76 kre if ((i = fcntl(fd, F_DUPFD, 326 1.76 kre (fcntl_int)(bigfd + 1))) == -1) { 327 1.15 christos switch (errno) { 328 1.15 christos case EBADF: 329 1.35 yamt i = CLOSED; 330 1.35 yamt break; 331 1.43 christos case EMFILE: 332 1.43 christos case EINVAL: 333 1.43 christos find_big_fd(); 334 1.76 kre i = fcntl(fd, F_DUPFD, 335 1.76 kre (fcntl_int) big_sh_fd); 336 1.43 christos if (i >= 0) 337 1.43 christos break; 338 1.68 kre if (errno == EMFILE || errno == EINVAL) 339 1.76 kre i = fcntl(fd, F_DUPFD, 340 1.76 kre (fcntl_int) 3); 341 1.68 kre if (i >= 0) 342 1.68 kre break; 343 1.43 christos /* FALLTHRU */ 344 1.15 christos default: 345 1.67 kre error("%d: %s", fd, strerror(errno)); 346 1.19 mycroft /* NOTREACHED */ 347 1.15 christos } 348 1.43 christos } 349 1.76 kre if (i > biggest_sh_fd) 350 1.76 kre biggest_sh_fd = i; 351 1.43 christos if (i >= 0) 352 1.76 kre (void)fcntl(i, F_SETFD, (fcntl_int) FD_CLOEXEC); 353 1.76 kre fd_rename(sv, fd, i, cloexec); 354 1.76 kre VTRACE(DBG_REDIR, ("fd %d saved as %d%s ", fd, i, 355 1.76 kre cloexec ? "+" : "")); 356 1.1 cgd INTON; 357 1.1 cgd } 358 1.60 kre VTRACE(DBG_REDIR, ("%s\n", fd == 0 ? "STDIN" : "")); 359 1.44 kre if (fd == 0) 360 1.44 kre fd0_redirected++; 361 1.35 yamt openredirect(n, memory, flags); 362 1.1 cgd } 363 1.1 cgd if (memory[1]) 364 1.1 cgd out1 = &memout; 365 1.1 cgd if (memory[2]) 366 1.1 cgd out2 = &memout; 367 1.1 cgd } 368 1.1 cgd 369 1.1 cgd 370 1.1 cgd STATIC void 371 1.29 christos openredirect(union node *redir, char memory[10], int flags) 372 1.27 christos { 373 1.36 christos struct stat sb; 374 1.1 cgd int fd = redir->nfile.fd; 375 1.1 cgd char *fname; 376 1.1 cgd int f; 377 1.42 christos int eflags, cloexec; 378 1.1 cgd 379 1.1 cgd /* 380 1.1 cgd * We suppress interrupts so that we won't leave open file 381 1.1 cgd * descriptors around. This may not be such a good idea because 382 1.1 cgd * an open of a device or a fifo can block indefinitely. 383 1.1 cgd */ 384 1.1 cgd INTOFF; 385 1.43 christos if (fd < 10) 386 1.43 christos memory[fd] = 0; 387 1.1 cgd switch (redir->nfile.type) { 388 1.1 cgd case NFROM: 389 1.1 cgd fname = redir->nfile.expfname; 390 1.29 christos if (flags & REDIR_VFORK) 391 1.29 christos eflags = O_NONBLOCK; 392 1.29 christos else 393 1.29 christos eflags = 0; 394 1.29 christos if ((f = open(fname, O_RDONLY|eflags)) < 0) 395 1.20 christos goto eopen; 396 1.59 kre VTRACE(DBG_REDIR, ("openredirect(< '%s') -> %d [%#x]", 397 1.59 kre fname, f, eflags)); 398 1.29 christos if (eflags) 399 1.76 kre (void)fcntl(f, F_SETFL, 400 1.76 kre (fcntl_int)(fcntl(f, F_GETFL) & ~eflags)); 401 1.20 christos break; 402 1.20 christos case NFROMTO: 403 1.20 christos fname = redir->nfile.expfname; 404 1.61 kre if ((f = open(fname, O_RDWR|O_CREAT, 0666)) < 0) 405 1.20 christos goto ecreate; 406 1.59 kre VTRACE(DBG_REDIR, ("openredirect(<> '%s') -> %d", fname, f)); 407 1.1 cgd break; 408 1.1 cgd case NTO: 409 1.36 christos if (Cflag) { 410 1.36 christos fname = redir->nfile.expfname; 411 1.37 christos if ((f = open(fname, O_WRONLY)) == -1) { 412 1.36 christos if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 413 1.36 christos 0666)) < 0) 414 1.36 christos goto ecreate; 415 1.37 christos } else if (fstat(f, &sb) == -1) { 416 1.37 christos int serrno = errno; 417 1.37 christos close(f); 418 1.37 christos errno = serrno; 419 1.37 christos goto ecreate; 420 1.37 christos } else if (S_ISREG(sb.st_mode)) { 421 1.37 christos close(f); 422 1.36 christos errno = EEXIST; 423 1.36 christos goto ecreate; 424 1.36 christos } 425 1.60 kre VTRACE(DBG_REDIR, ("openredirect(>| '%s') -> %d", 426 1.60 kre fname, f)); 427 1.36 christos break; 428 1.36 christos } 429 1.23 christos /* FALLTHROUGH */ 430 1.23 christos case NCLOBBER: 431 1.1 cgd fname = redir->nfile.expfname; 432 1.36 christos if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) 433 1.20 christos goto ecreate; 434 1.59 kre VTRACE(DBG_REDIR, ("openredirect(> '%s') -> %d", fname, f)); 435 1.20 christos break; 436 1.1 cgd case NAPPEND: 437 1.1 cgd fname = redir->nfile.expfname; 438 1.1 cgd if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) 439 1.20 christos goto ecreate; 440 1.59 kre VTRACE(DBG_REDIR, ("openredirect(>> '%s') -> %d", fname, f)); 441 1.20 christos break; 442 1.1 cgd case NTOFD: 443 1.1 cgd case NFROMFD: 444 1.1 cgd if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ 445 1.68 kre if (sh_fd(redir->ndup.dupfd) != NULL || 446 1.68 kre saved_redirected_fd(redir->ndup.dupfd) != NULL) 447 1.67 kre error("Redirect (from %d to %d) failed: %s", 448 1.67 kre redir->ndup.dupfd, fd, strerror(EBADF)); 449 1.43 christos if (fd < 10 && redir->ndup.dupfd < 10 && 450 1.43 christos memory[redir->ndup.dupfd]) 451 1.1 cgd memory[fd] = 1; 452 1.47 kre else if (copyfd(redir->ndup.dupfd, fd, 453 1.76 kre (flags & REDIR_KEEP) == 0, 0) < 0) 454 1.47 kre error("Redirect (from %d to %d) failed: %s", 455 1.47 kre redir->ndup.dupfd, fd, strerror(errno)); 456 1.59 kre VTRACE(DBG_REDIR, ("openredirect: %d%c&%d\n", fd, 457 1.59 kre "<>"[redir->nfile.type==NTOFD], redir->ndup.dupfd)); 458 1.59 kre } else { 459 1.47 kre (void) close(fd); 460 1.59 kre VTRACE(DBG_REDIR, ("openredirect: %d%c&-\n", fd, 461 1.59 kre "<>"[redir->nfile.type==NTOFD])); 462 1.59 kre } 463 1.20 christos INTON; 464 1.20 christos return; 465 1.1 cgd case NHERE: 466 1.1 cgd case NXHERE: 467 1.60 kre VTRACE(DBG_REDIR, ("openredirect: %d<<...", fd)); 468 1.1 cgd f = openhere(redir); 469 1.20 christos break; 470 1.1 cgd default: 471 1.1 cgd abort(); 472 1.1 cgd } 473 1.20 christos 474 1.76 kre if (f > biggest_sh_fd) 475 1.76 kre biggest_sh_fd = f; 476 1.76 kre 477 1.55 kre cloexec = fd > 2 && (flags & REDIR_KEEP) == 0 && !posix; 478 1.20 christos if (f != fd) { 479 1.59 kre VTRACE(DBG_REDIR, (" -> %d", fd)); 480 1.76 kre if (copyfd(f, fd, cloexec, 1) < 0) { 481 1.47 kre int e = errno; 482 1.47 kre 483 1.69 kre VTRACE(DBG_REDIR, (" failed: %s\n", strerror(e))); 484 1.47 kre error("redirect reassignment (fd %d) failed: %s", fd, 485 1.47 kre strerror(e)); 486 1.47 kre } 487 1.42 christos } else if (cloexec) 488 1.76 kre (void)fcntl(f, F_SETFD, (fcntl_int) FD_CLOEXEC); 489 1.59 kre VTRACE(DBG_REDIR, ("%s\n", cloexec ? " cloexec" : "")); 490 1.38 christos 491 1.1 cgd INTON; 492 1.20 christos return; 493 1.60 kre ecreate: 494 1.30 msaitoh exerrno = 1; 495 1.20 christos error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); 496 1.60 kre eopen: 497 1.30 msaitoh exerrno = 1; 498 1.20 christos error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); 499 1.1 cgd } 500 1.1 cgd 501 1.1 cgd 502 1.1 cgd /* 503 1.1 cgd * Handle here documents. Normally we fork off a process to write the 504 1.1 cgd * data to a pipe. If the document is short, we can stuff the data in 505 1.1 cgd * the pipe without forking. 506 1.1 cgd */ 507 1.1 cgd 508 1.1 cgd STATIC int 509 1.34 yamt openhere(const union node *redir) 510 1.27 christos { 511 1.1 cgd int pip[2]; 512 1.12 christos int len = 0; 513 1.1 cgd 514 1.1 cgd if (pipe(pip) < 0) 515 1.1 cgd error("Pipe call failed"); 516 1.76 kre if (pip[1] > biggest_sh_fd) 517 1.76 kre biggest_sh_fd = pip[1]; 518 1.72 kre len = strlen(redir->nhere.text); 519 1.72 kre VTRACE(DBG_REDIR, ("openhere(%p) [%d] \"%.*s\"%s\n", redir, len, 520 1.72 kre (len < 40 ? len : 40), redir->nhere.text, (len < 40 ? "" : "..."))); 521 1.72 kre if (len <= PIPESIZE) { /* XXX eventually copy FreeBSD method */ 522 1.72 kre xwrite(pip[1], redir->nhere.text, len); 523 1.72 kre goto out; 524 1.1 cgd } 525 1.60 kre VTRACE(DBG_REDIR, (" forking [%d,%d]\n", pip[0], pip[1])); 526 1.32 plunky if (forkshell(NULL, NULL, FORK_NOJOB) == 0) { 527 1.1 cgd close(pip[0]); 528 1.1 cgd signal(SIGINT, SIG_IGN); 529 1.1 cgd signal(SIGQUIT, SIG_IGN); 530 1.1 cgd signal(SIGHUP, SIG_IGN); 531 1.1 cgd #ifdef SIGTSTP 532 1.1 cgd signal(SIGTSTP, SIG_IGN); 533 1.1 cgd #endif 534 1.1 cgd signal(SIGPIPE, SIG_DFL); 535 1.72 kre xwrite(pip[1], redir->nhere.text, len); 536 1.70 kre VTRACE(DBG_PROCS|DBG_REDIR, ("wrote here doc. exiting(0)\n")); 537 1.1 cgd _exit(0); 538 1.1 cgd } 539 1.60 kre VTRACE(DBG_REDIR, ("openhere (closing %d)", pip[1])); 540 1.76 kre out:; 541 1.1 cgd close(pip[1]); 542 1.60 kre VTRACE(DBG_REDIR, (" (pipe fd=%d)", pip[0])); 543 1.1 cgd return pip[0]; 544 1.1 cgd } 545 1.1 cgd 546 1.1 cgd 547 1.1 cgd 548 1.1 cgd /* 549 1.76 kre * if (reset == POPREDIR_UNDO) 550 1.76 kre * Undo the effects of the last redirection. 551 1.76 kre * else if (reset == POPREDIR_PERMANENT) 552 1.76 kre * Make the last redirection permanent 553 1.76 kre * else / * reset == POPREDIR_DISCARD * / 554 1.76 kre * Just throw away the redirection 555 1.1 cgd */ 556 1.1 cgd 557 1.1 cgd void 558 1.76 kre popredir(int reset) 559 1.27 christos { 560 1.14 tls struct redirtab *rp = redirlist; 561 1.1 cgd 562 1.1 cgd INTOFF; 563 1.76 kre free_rl(rp, reset); 564 1.1 cgd redirlist = rp->next; 565 1.1 cgd ckfree(rp); 566 1.1 cgd INTON; 567 1.1 cgd } 568 1.1 cgd 569 1.1 cgd /* 570 1.1 cgd * Undo all redirections. Called on error or interrupt. 571 1.1 cgd */ 572 1.1 cgd 573 1.1 cgd #ifdef mkinit 574 1.1 cgd 575 1.1 cgd INCLUDE "redir.h" 576 1.1 cgd 577 1.1 cgd RESET { 578 1.1 cgd while (redirlist) 579 1.76 kre popredir(POPREDIR_UNDO); 580 1.1 cgd } 581 1.1 cgd 582 1.1 cgd SHELLPROC { 583 1.24 christos clearredir(0); 584 1.1 cgd } 585 1.1 cgd 586 1.1 cgd #endif 587 1.1 cgd 588 1.7 jtc /* Return true if fd 0 has already been redirected at least once. */ 589 1.7 jtc int 590 1.43 christos fd0_redirected_p(void) 591 1.43 christos { 592 1.44 kre return fd0_redirected != 0; 593 1.7 jtc } 594 1.1 cgd 595 1.1 cgd /* 596 1.1 cgd * Discard all saved file descriptors. 597 1.1 cgd */ 598 1.1 cgd 599 1.1 cgd void 600 1.33 matt clearredir(int vforked) 601 1.24 christos { 602 1.14 tls struct redirtab *rp; 603 1.43 christos struct renamelist *rl; 604 1.1 cgd 605 1.76 kre /* 606 1.76 kre * This happens only in a child process attempting to 607 1.76 kre * exec a script which failed ENOEXEC. Any redirections 608 1.76 kre * that have been made are for that script, after it 609 1.76 kre * is done, we exit, there is nothing to restore, so 610 1.76 kre * just make the refirectoins permanent. 611 1.76 kre * 612 1.76 kre * free_rl() does that does that for us, unless we're 613 1.76 kre * a child of a vfork() in which case that is unsafe to 614 1.76 kre * call - that should never happen, but just in case, fale 615 1.76 kre * it here 616 1.76 kre */ 617 1.76 kre 618 1.1 cgd for (rp = redirlist ; rp ; rp = rp->next) { 619 1.43 christos if (!vforked) 620 1.76 kre free_rl(rp, POPREDIR_PERMANENT); 621 1.43 christos else for (rl = rp->renamed; rl; rl = rl->next) 622 1.43 christos if (rl->into >= 0) 623 1.43 christos close(rl->into); 624 1.1 cgd } 625 1.1 cgd } 626 1.1 cgd 627 1.1 cgd 628 1.1 cgd 629 1.1 cgd /* 630 1.76 kre * Copy a file descriptor (from) to (also) be 'to'.. 631 1.47 kre * cloexec indicates if we want close-on-exec or not. 632 1.76 kre * move indicates if "from" should be closed on success (yes if set). 633 1.47 kre * Returns -1 if any error occurs. 634 1.1 cgd */ 635 1.1 cgd 636 1.47 kre STATIC int 637 1.76 kre copyfd(int from, int to, int cloexec, int move) 638 1.9 cgd { 639 1.1 cgd int newfd; 640 1.1 cgd 641 1.65 kre if (cloexec && to > 2) { 642 1.65 kre #ifdef O_CLOEXEC 643 1.47 kre newfd = dup3(from, to, O_CLOEXEC); 644 1.65 kre #else 645 1.65 kre newfd = dup2(from, to); 646 1.76 kre if (newfd >= 0) 647 1.76 kre fcntl(newfd, F_SETFD, 648 1.76 kre (fcntl_int)(fcntl(newfd, F_GETFD) | FD_CLOEXEC)); 649 1.65 kre #endif 650 1.65 kre } else 651 1.47 kre newfd = dup2(from, to); 652 1.47 kre 653 1.76 kre if (move && newfd == to && from != to) 654 1.76 kre close(from); 655 1.76 kre 656 1.76 kre if (newfd != to) { 657 1.76 kre if (newfd < 0) 658 1.76 kre error("Unable to dup(%d->%d): %s", from, to, 659 1.76 kre strerror(errno)); 660 1.76 kre else { 661 1.76 kre close(newfd); 662 1.76 kre error("Moving fd %d to %d made %d!", from, to, newfd); 663 1.76 kre } 664 1.76 kre } 665 1.76 kre 666 1.76 kre if (newfd > biggest_sh_fd) 667 1.76 kre biggest_sh_fd = newfd; 668 1.76 kre 669 1.1 cgd return newfd; 670 1.1 cgd } 671 1.43 christos 672 1.47 kre /* 673 1.47 kre * rename fd from to be fd to (closing from). 674 1.47 kre * close-on-exec is never set on 'to' (unless 675 1.47 kre * from==to and it was set on from) - ie: a no-op 676 1.60 kre * returns to (or errors() if an error occurs). 677 1.47 kre * 678 1.47 kre * This is mostly used for rearranging the 679 1.47 kre * results from pipe(). 680 1.47 kre */ 681 1.43 christos int 682 1.43 christos movefd(int from, int to) 683 1.43 christos { 684 1.76 kre if (from > biggest_sh_fd) 685 1.76 kre biggest_sh_fd = from; 686 1.76 kre if (to > biggest_sh_fd) 687 1.76 kre biggest_sh_fd = to; 688 1.76 kre 689 1.43 christos if (from == to) 690 1.43 christos return to; 691 1.43 christos 692 1.76 kre (void)close(to); 693 1.76 kre if (copyfd(from, to, 0, 1) != to) { 694 1.47 kre int e = errno; 695 1.47 kre 696 1.47 kre (void) close(from); 697 1.47 kre error("Unable to make fd %d: %s", to, strerror(e)); 698 1.47 kre } 699 1.43 christos 700 1.43 christos return to; 701 1.43 christos } 702 1.43 christos 703 1.43 christos STATIC void 704 1.43 christos find_big_fd(void) 705 1.43 christos { 706 1.43 christos int i, fd; 707 1.57 kre static int last_start = 3; /* aim to keep sh fd's under 20 */ 708 1.43 christos 709 1.54 kre if (last_start < 10) 710 1.54 kre last_start++; 711 1.54 kre 712 1.54 kre for (i = (1 << last_start); i >= 10; i >>= 1) { 713 1.76 kre if ((fd = fcntl(0, F_DUPFD, (fcntl_int)(i - 1))) >= 0) { 714 1.76 kre if (fd > biggest_sh_fd) 715 1.76 kre biggest_sh_fd = fd; 716 1.43 christos close(fd); 717 1.43 christos break; 718 1.43 christos } 719 1.43 christos } 720 1.43 christos 721 1.43 christos fd = (i / 5) * 4; 722 1.54 kre if (fd < 10) 723 1.43 christos fd = 10; 724 1.43 christos 725 1.43 christos big_sh_fd = fd; 726 1.43 christos } 727 1.43 christos 728 1.47 kre /* 729 1.47 kre * If possible, move file descriptor fd out of the way 730 1.47 kre * of expected user fd values. Returns the new fd 731 1.47 kre * (which may be the input fd if things do not go well.) 732 1.47 kre * Always set close-on-exec on the result, and close 733 1.47 kre * the input fd unless it is to be our result. 734 1.47 kre */ 735 1.43 christos int 736 1.43 christos to_upper_fd(int fd) 737 1.43 christos { 738 1.43 christos int i; 739 1.43 christos 740 1.59 kre VTRACE(DBG_REDIR|DBG_OUTPUT, ("to_upper_fd(%d)", fd)); 741 1.68 kre if (big_sh_fd < 10 || big_sh_fd >= user_fd_limit) 742 1.43 christos find_big_fd(); 743 1.43 christos do { 744 1.76 kre i = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) big_sh_fd); 745 1.43 christos if (i >= 0) { 746 1.76 kre if (i > biggest_sh_fd) 747 1.76 kre biggest_sh_fd = i; 748 1.43 christos if (fd != i) 749 1.43 christos close(fd); 750 1.59 kre VTRACE(DBG_REDIR|DBG_OUTPUT, ("-> %d\n", i)); 751 1.43 christos return i; 752 1.43 christos } 753 1.54 kre if (errno != EMFILE && errno != EINVAL) 754 1.43 christos break; 755 1.43 christos find_big_fd(); 756 1.43 christos } while (big_sh_fd > 10); 757 1.43 christos 758 1.46 kre /* 759 1.47 kre * If we wanted to move this fd to some random high number 760 1.46 kre * we certainly do not intend to pass it through exec, even 761 1.46 kre * if the reassignment failed. 762 1.46 kre */ 763 1.76 kre (void)fcntl(fd, F_SETFD, (fcntl_int) FD_CLOEXEC); 764 1.59 kre VTRACE(DBG_REDIR|DBG_OUTPUT, (" fails ->%d\n", fd)); 765 1.43 christos return fd; 766 1.43 christos } 767 1.50 christos 768 1.54 kre void 769 1.54 kre register_sh_fd(int fd, void (*cb)(int, int)) 770 1.54 kre { 771 1.54 kre struct shell_fds *fp; 772 1.54 kre 773 1.54 kre fp = ckmalloc(sizeof (struct shell_fds)); 774 1.54 kre if (fp != NULL) { 775 1.54 kre fp->nxt = sh_fd_list; 776 1.54 kre sh_fd_list = fp; 777 1.54 kre 778 1.54 kre fp->fd = fd; 779 1.54 kre fp->cb = cb; 780 1.54 kre } 781 1.54 kre } 782 1.54 kre 783 1.54 kre void 784 1.54 kre sh_close(int fd) 785 1.54 kre { 786 1.54 kre struct shell_fds **fpp, *fp; 787 1.54 kre 788 1.54 kre fpp = &sh_fd_list; 789 1.54 kre while ((fp = *fpp) != NULL) { 790 1.54 kre if (fp->fd == fd) { 791 1.54 kre *fpp = fp->nxt; 792 1.54 kre ckfree(fp); 793 1.54 kre break; 794 1.54 kre } 795 1.54 kre fpp = &fp->nxt; 796 1.54 kre } 797 1.54 kre (void)close(fd); 798 1.54 kre } 799 1.54 kre 800 1.54 kre STATIC struct shell_fds * 801 1.54 kre sh_fd(int fd) 802 1.54 kre { 803 1.54 kre struct shell_fds *fp; 804 1.54 kre 805 1.54 kre for (fp = sh_fd_list; fp != NULL; fp = fp->nxt) 806 1.54 kre if (fp->fd == fd) 807 1.54 kre return fp; 808 1.54 kre return NULL; 809 1.54 kre } 810 1.54 kre 811 1.68 kre STATIC int 812 1.68 kre pick_new_fd(int fd) 813 1.68 kre { 814 1.68 kre int to; 815 1.68 kre 816 1.76 kre to = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) big_sh_fd); 817 1.68 kre if (to == -1 && big_sh_fd >= 22) 818 1.76 kre to = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) (big_sh_fd / 2)); 819 1.68 kre if (to == -1) 820 1.76 kre to = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) (fd + 1)); 821 1.68 kre if (to == -1) 822 1.76 kre to = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) 10); 823 1.68 kre if (to == -1) 824 1.76 kre to = fcntl(fd, F_DUPFD_CLOEXEC, (fcntl_int) 3); 825 1.68 kre if (to == -1) 826 1.68 kre error("insufficient file descriptors available"); 827 1.68 kre CLOEXEC(to); 828 1.76 kre if (to > biggest_sh_fd) 829 1.76 kre biggest_sh_fd = to; 830 1.68 kre return to; 831 1.68 kre } 832 1.68 kre 833 1.54 kre STATIC void 834 1.54 kre renumber_sh_fd(struct shell_fds *fp) 835 1.54 kre { 836 1.54 kre int to; 837 1.54 kre 838 1.54 kre if (fp == NULL) 839 1.54 kre return; 840 1.54 kre 841 1.57 kre /* 842 1.57 kre * if we have had a collision, and the sh fd was a "big" one 843 1.57 kre * try moving the sh fd base to a higher number (if possible) 844 1.57 kre * so future sh fds are less likely to be in the user's sights 845 1.57 kre * (incl this one when moved) 846 1.57 kre */ 847 1.57 kre if (fp->fd >= big_sh_fd) 848 1.57 kre find_big_fd(); 849 1.57 kre 850 1.68 kre to = pick_new_fd(fp->fd); 851 1.54 kre 852 1.54 kre if (fp->fd == to) /* impossible? */ 853 1.54 kre return; 854 1.54 kre 855 1.68 kre VTRACE(DBG_REDIR, ("renumber_sh_fd: moved shell fd %d to %d\n", 856 1.68 kre fp->fd, to)); 857 1.68 kre 858 1.54 kre (*fp->cb)(fp->fd, to); 859 1.54 kre (void)close(fp->fd); 860 1.54 kre fp->fd = to; 861 1.54 kre } 862 1.54 kre 863 1.51 kre static const struct flgnames { 864 1.50 christos const char *name; 865 1.56 kre uint16_t minch; 866 1.50 christos uint32_t value; 867 1.50 christos } nv[] = { 868 1.50 christos #ifdef O_APPEND 869 1.56 kre { "append", 2, O_APPEND }, 870 1.65 kre #else 871 1.65 kre # define O_APPEND 0 872 1.50 christos #endif 873 1.50 christos #ifdef O_ASYNC 874 1.56 kre { "async", 2, O_ASYNC }, 875 1.65 kre #else 876 1.65 kre # define O_ASYNC 0 877 1.50 christos #endif 878 1.50 christos #ifdef O_SYNC 879 1.56 kre { "sync", 2, O_SYNC }, 880 1.65 kre #else 881 1.65 kre # define O_SYNC 0 882 1.50 christos #endif 883 1.50 christos #ifdef O_NONBLOCK 884 1.56 kre { "nonblock", 3, O_NONBLOCK }, 885 1.65 kre #else 886 1.65 kre # define O_NONBLOCK 0 887 1.50 christos #endif 888 1.50 christos #ifdef O_FSYNC 889 1.56 kre { "fsync", 2, O_FSYNC }, 890 1.65 kre #else 891 1.65 kre # define O_FSYNC 0 892 1.50 christos #endif 893 1.50 christos #ifdef O_DSYNC 894 1.56 kre { "dsync", 2, O_DSYNC }, 895 1.65 kre #else 896 1.65 kre # define O_DSYNC 0 897 1.50 christos #endif 898 1.50 christos #ifdef O_RSYNC 899 1.56 kre { "rsync", 2, O_RSYNC }, 900 1.65 kre #else 901 1.65 kre # define O_RSYNC 0 902 1.50 christos #endif 903 1.62 kamil #ifdef O_ALT_IO 904 1.56 kre { "altio", 2, O_ALT_IO }, 905 1.65 kre #else 906 1.65 kre # define O_ALT_IO 0 907 1.50 christos #endif 908 1.50 christos #ifdef O_DIRECT 909 1.56 kre { "direct", 2, O_DIRECT }, 910 1.65 kre #else 911 1.65 kre # define O_DIRECT 0 912 1.50 christos #endif 913 1.50 christos #ifdef O_NOSIGPIPE 914 1.56 kre { "nosigpipe", 3, O_NOSIGPIPE }, 915 1.65 kre #else 916 1.65 kre # define O_NOSIGPIPE 0 917 1.50 christos #endif 918 1.65 kre 919 1.65 kre #define ALLFLAGS (O_APPEND|O_ASYNC|O_SYNC|O_NONBLOCK|O_DSYNC|O_RSYNC|\ 920 1.65 kre O_ALT_IO|O_DIRECT|O_NOSIGPIPE) 921 1.65 kre 922 1.65 kre #ifndef O_CLOEXEC 923 1.66 kre # define O_CLOEXEC ((~ALLFLAGS) ^ ((~ALLFLAGS) & ((~ALLFLAGS) - 1))) 924 1.65 kre #endif 925 1.65 kre 926 1.65 kre /* for any system we support, close on exec is always defined */ 927 1.56 kre { "cloexec", 2, O_CLOEXEC }, 928 1.56 kre { 0, 0, 0 } 929 1.50 christos }; 930 1.65 kre 931 1.65 kre #ifndef O_ACCMODE 932 1.65 kre # define O_ACCMODE 0 933 1.65 kre #endif 934 1.65 kre #ifndef O_RDONLY 935 1.65 kre # define O_RDONLY 0 936 1.65 kre #endif 937 1.65 kre #ifndef O_WRONLY 938 1.65 kre # define O_WRONLY 0 939 1.65 kre #endif 940 1.65 kre #ifndef O_RWDR 941 1.65 kre # define O_RWDR 0 942 1.65 kre #endif 943 1.65 kre #ifndef O_SHLOCK 944 1.65 kre # define O_SHLOCK 0 945 1.65 kre #endif 946 1.65 kre #ifndef O_EXLOCK 947 1.65 kre # define O_EXLOCK 0 948 1.65 kre #endif 949 1.65 kre #ifndef O_NOFOLLOW 950 1.65 kre # define O_NOFOLLOW 0 951 1.65 kre #endif 952 1.65 kre #ifndef O_CREAT 953 1.65 kre # define O_CREAT 0 954 1.65 kre #endif 955 1.65 kre #ifndef O_TRUNC 956 1.65 kre # define O_TRUNC 0 957 1.65 kre #endif 958 1.65 kre #ifndef O_EXCL 959 1.65 kre # define O_EXCL 0 960 1.65 kre #endif 961 1.65 kre #ifndef O_NOCTTY 962 1.65 kre # define O_NOCTTY 0 963 1.65 kre #endif 964 1.65 kre #ifndef O_DIRECTORY 965 1.65 kre # define O_DIRECTORY 0 966 1.65 kre #endif 967 1.65 kre #ifndef O_REGULAR 968 1.65 kre # define O_REGULAR 0 969 1.65 kre #endif 970 1.65 kre /* 971 1.65 kre * flags that F_GETFL might return that we want to ignore 972 1.65 kre * 973 1.65 kre * F_GETFL should not actually return these, they're all just open() 974 1.65 kre * modifiers, rather than state, but just in case... 975 1.65 kre */ 976 1.65 kre #define IGNFLAGS (O_ACCMODE|O_RDONLY|O_WRONLY|O_RDWR|O_SHLOCK|O_EXLOCK| \ 977 1.65 kre O_NOFOLLOW|O_CREAT|O_TRUNC|O_EXCL|O_NOCTTY|O_DIRECTORY|O_REGULAR) 978 1.50 christos 979 1.50 christos static int 980 1.76 kre getflags(int fd, int p, int all) 981 1.50 christos { 982 1.50 christos int c, f; 983 1.50 christos 984 1.76 kre if (!all && (sh_fd(fd) != NULL || saved_redirected_fd(fd) != NULL)) { 985 1.54 kre if (!p) 986 1.54 kre return -1; 987 1.67 kre error("Can't get status for fd=%d (%s)", fd, strerror(EBADF)); 988 1.54 kre } 989 1.54 kre 990 1.50 christos if ((c = fcntl(fd, F_GETFD)) == -1) { 991 1.50 christos if (!p) 992 1.50 christos return -1; 993 1.50 christos error("Can't get status for fd=%d (%s)", fd, strerror(errno)); 994 1.50 christos } 995 1.50 christos if ((f = fcntl(fd, F_GETFL)) == -1) { 996 1.50 christos if (!p) 997 1.50 christos return -1; 998 1.50 christos error("Can't get flags for fd=%d (%s)", fd, strerror(errno)); 999 1.50 christos } 1000 1.65 kre f &= ~IGNFLAGS; /* clear anything we know about, but ignore */ 1001 1.51 kre if (c & FD_CLOEXEC) 1002 1.50 christos f |= O_CLOEXEC; 1003 1.65 kre return f; 1004 1.50 christos } 1005 1.50 christos 1006 1.50 christos static void 1007 1.51 kre printone(int fd, int p, int verbose, int pfd) 1008 1.50 christos { 1009 1.76 kre int f = getflags(fd, p, verbose > 1); 1010 1.51 kre const struct flgnames *fn; 1011 1.50 christos 1012 1.50 christos if (f == -1) 1013 1.50 christos return; 1014 1.50 christos 1015 1.51 kre if (pfd) 1016 1.51 kre outfmt(out1, "%d: ", fd); 1017 1.51 kre for (fn = nv; fn->name; fn++) { 1018 1.51 kre if (f & fn->value) { 1019 1.51 kre outfmt(out1, "%s%s", verbose ? "+" : "", fn->name); 1020 1.51 kre f &= ~fn->value; 1021 1.50 christos } else if (verbose) 1022 1.51 kre outfmt(out1, "-%s", fn->name); 1023 1.50 christos else 1024 1.50 christos continue; 1025 1.51 kre if (f || (verbose && fn[1].name)) 1026 1.50 christos outfmt(out1, ","); 1027 1.50 christos } 1028 1.51 kre if (verbose && f) /* f should be normally be 0 */ 1029 1.51 kre outfmt(out1, " +%#x", f); 1030 1.50 christos outfmt(out1, "\n"); 1031 1.50 christos } 1032 1.50 christos 1033 1.51 kre static void 1034 1.50 christos parseflags(char *s, int *p, int *n) 1035 1.50 christos { 1036 1.51 kre int *v, *w; 1037 1.51 kre const struct flgnames *fn; 1038 1.56 kre size_t len; 1039 1.50 christos 1040 1.50 christos *p = 0; 1041 1.50 christos *n = 0; 1042 1.50 christos for (s = strtok(s, ","); s; s = strtok(NULL, ",")) { 1043 1.51 kre switch (*s++) { 1044 1.50 christos case '+': 1045 1.50 christos v = p; 1046 1.51 kre w = n; 1047 1.50 christos break; 1048 1.50 christos case '-': 1049 1.50 christos v = n; 1050 1.51 kre w = p; 1051 1.50 christos break; 1052 1.50 christos default: 1053 1.51 kre error("Missing +/- indicator before flag %s", s-1); 1054 1.50 christos } 1055 1.60 kre 1056 1.56 kre len = strlen(s); 1057 1.51 kre for (fn = nv; fn->name; fn++) 1058 1.56 kre if (len >= fn->minch && strncmp(s,fn->name,len) == 0) { 1059 1.51 kre *v |= fn->value; 1060 1.51 kre *w &=~ fn->value; 1061 1.50 christos break; 1062 1.50 christos } 1063 1.51 kre if (fn->name == 0) 1064 1.50 christos error("Bad flag `%s'", s); 1065 1.50 christos } 1066 1.50 christos } 1067 1.50 christos 1068 1.50 christos static void 1069 1.50 christos setone(int fd, int pos, int neg, int verbose) 1070 1.50 christos { 1071 1.76 kre int f = getflags(fd, 1, 0); 1072 1.51 kre int n, cloexec; 1073 1.51 kre 1074 1.50 christos if (f == -1) 1075 1.50 christos return; 1076 1.50 christos 1077 1.51 kre cloexec = -1; 1078 1.50 christos if ((pos & O_CLOEXEC) && !(f & O_CLOEXEC)) 1079 1.50 christos cloexec = FD_CLOEXEC; 1080 1.50 christos if ((neg & O_CLOEXEC) && (f & O_CLOEXEC)) 1081 1.50 christos cloexec = 0; 1082 1.50 christos 1083 1.76 kre /* Don't allow O_CLOEXEC on stdin, stdout, or stderr */ 1084 1.76 kre if ((cloexec > 0 && fd <= 2 && (errno = EINVAL)) || 1085 1.76 kre (cloexec != -1 && fcntl(fd, F_SETFD, (fcntl_int) cloexec) == -1)) 1086 1.50 christos error("Can't set status for fd=%d (%s)", fd, strerror(errno)); 1087 1.50 christos 1088 1.50 christos pos &= ~O_CLOEXEC; 1089 1.50 christos neg &= ~O_CLOEXEC; 1090 1.50 christos f &= ~O_CLOEXEC; 1091 1.51 kre n = f; 1092 1.50 christos n |= pos; 1093 1.50 christos n &= ~neg; 1094 1.76 kre if (n != f && fcntl(fd, F_SETFL, (fcntl_int)n) == -1) 1095 1.50 christos error("Can't set flags for fd=%d (%s)", fd, strerror(errno)); 1096 1.50 christos if (verbose) 1097 1.51 kre printone(fd, 1, verbose, 1); 1098 1.50 christos } 1099 1.50 christos 1100 1.50 christos int 1101 1.50 christos fdflagscmd(int argc, char *argv[]) 1102 1.50 christos { 1103 1.50 christos char *num; 1104 1.50 christos int verbose = 0, ch, pos = 0, neg = 0; 1105 1.50 christos char *setflags = NULL; 1106 1.50 christos 1107 1.50 christos optreset = 1; optind = 1; /* initialize getopt */ 1108 1.76 kre while ((ch = getopt(argc, argv, ":vs:" 1109 1.76 kre #ifdef DEBUG 1110 1.76 kre "V" 1111 1.76 kre #endif 1112 1.76 kre )) != -1) 1113 1.50 christos switch ((char)ch) { 1114 1.76 kre #ifdef DEBUG 1115 1.76 kre case 'V': 1116 1.76 kre verbose = 2; 1117 1.76 kre break; 1118 1.76 kre #endif 1119 1.50 christos case 'v': 1120 1.50 christos verbose = 1; 1121 1.50 christos break; 1122 1.50 christos case 's': 1123 1.51 kre if (setflags) 1124 1.51 kre goto msg; 1125 1.50 christos setflags = optarg; 1126 1.50 christos break; 1127 1.50 christos case '?': 1128 1.50 christos default: 1129 1.50 christos msg: 1130 1.51 kre error("Usage: fdflags [-v] [-s <flags> fd] [fd...]"); 1131 1.50 christos /* NOTREACHED */ 1132 1.50 christos } 1133 1.50 christos 1134 1.50 christos argc -= optind, argv += optind; 1135 1.50 christos 1136 1.51 kre if (setflags) 1137 1.51 kre parseflags(setflags, &pos, &neg); 1138 1.50 christos 1139 1.50 christos if (argc == 0) { 1140 1.53 kre int i; 1141 1.51 kre 1142 1.50 christos if (setflags) 1143 1.50 christos goto msg; 1144 1.51 kre 1145 1.53 kre for (i = 0; i <= max_user_fd; i++) 1146 1.51 kre printone(i, 0, verbose, 1); 1147 1.76 kre if (verbose > 1) 1148 1.76 kre while (i <= biggest_sh_fd) 1149 1.76 kre printone(i++, 0, verbose, 1); 1150 1.50 christos 1151 1.71 kre } else while ((num = *argv++) != NULL) { 1152 1.51 kre int fd = number(num); 1153 1.51 kre 1154 1.52 kre while (num[0] == '0' && num[1] != '\0') /* skip 0's */ 1155 1.52 kre num++; 1156 1.68 kre if (strlen(num) > 5 || 1157 1.68 kre (fd >= user_fd_limit && fd > max_user_fd)) 1158 1.68 kre error("%s: too big to be a file descriptor", num); 1159 1.51 kre 1160 1.50 christos if (setflags) 1161 1.50 christos setone(fd, pos, neg, verbose); 1162 1.50 christos else 1163 1.51 kre printone(fd, 1, verbose, argc > 1); 1164 1.50 christos } 1165 1.71 kre flushout(out1); 1166 1.71 kre if (io_err(out1)) { 1167 1.71 kre out2str("fdflags: I/O error\n"); 1168 1.71 kre return 1; 1169 1.71 kre } 1170 1.50 christos return 0; 1171 1.50 christos } 1172 1.58 kre 1173 1.58 kre #undef MAX /* in case we inherited them from somewhere */ 1174 1.58 kre #undef MIN 1175 1.58 kre 1176 1.58 kre #define MIN(a,b) (/*CONSTCOND*/((a)<=(b)) ? (a) : (b)) 1177 1.58 kre #define MAX(a,b) (/*CONSTCOND*/((a)>=(b)) ? (a) : (b)) 1178 1.58 kre 1179 1.58 kre /* now make the compiler work for us... */ 1180 1.58 kre #define MIN_REDIR MIN(MIN(MIN(MIN(NTO,NFROM), MIN(NTOFD,NFROMFD)), \ 1181 1.58 kre MIN(MIN(NCLOBBER,NAPPEND), MIN(NHERE,NXHERE))), NFROMTO) 1182 1.58 kre #define MAX_REDIR MAX(MAX(MAX(MAX(NTO,NFROM), MAX(NTOFD,NFROMFD)), \ 1183 1.58 kre MAX(MAX(NCLOBBER,NAPPEND), MAX(NHERE,NXHERE))), NFROMTO) 1184 1.58 kre 1185 1.58 kre static const char *redir_sym[MAX_REDIR - MIN_REDIR + 1] = { 1186 1.58 kre [NTO - MIN_REDIR]= ">", 1187 1.58 kre [NFROM - MIN_REDIR]= "<", 1188 1.58 kre [NTOFD - MIN_REDIR]= ">&", 1189 1.58 kre [NFROMFD - MIN_REDIR]= "<&", 1190 1.58 kre [NCLOBBER - MIN_REDIR]= ">|", 1191 1.58 kre [NAPPEND - MIN_REDIR]= ">>", 1192 1.58 kre [NHERE - MIN_REDIR]= "<<", 1193 1.58 kre [NXHERE - MIN_REDIR]= "<<", 1194 1.58 kre [NFROMTO - MIN_REDIR]= "<>", 1195 1.58 kre }; 1196 1.58 kre 1197 1.58 kre int 1198 1.58 kre outredir(struct output *out, union node *n, int sep) 1199 1.58 kre { 1200 1.58 kre if (n == NULL) 1201 1.58 kre return 0; 1202 1.58 kre if (n->type < MIN_REDIR || n->type > MAX_REDIR || 1203 1.58 kre redir_sym[n->type - MIN_REDIR] == NULL) 1204 1.58 kre return 0; 1205 1.58 kre 1206 1.58 kre if (sep) 1207 1.58 kre outc(sep, out); 1208 1.58 kre 1209 1.58 kre /* 1210 1.58 kre * ugly, but all redir node types have "fd" in same slot... 1211 1.58 kre * (and code other places assumes it as well) 1212 1.58 kre */ 1213 1.58 kre if ((redir_sym[n->type - MIN_REDIR][0] == '<' && n->nfile.fd != 0) || 1214 1.58 kre (redir_sym[n->type - MIN_REDIR][0] == '>' && n->nfile.fd != 1)) 1215 1.58 kre outfmt(out, "%d", n->nfile.fd); 1216 1.58 kre 1217 1.58 kre outstr(redir_sym[n->type - MIN_REDIR], out); 1218 1.58 kre 1219 1.58 kre switch (n->type) { 1220 1.58 kre case NHERE: 1221 1.58 kre outstr("'...'", out); 1222 1.58 kre break; 1223 1.58 kre case NXHERE: 1224 1.58 kre outstr("...", out); 1225 1.58 kre break; 1226 1.58 kre case NTOFD: 1227 1.58 kre case NFROMFD: 1228 1.58 kre if (n->ndup.dupfd < 0) 1229 1.58 kre outc('-', out); 1230 1.58 kre else 1231 1.58 kre outfmt(out, "%d", n->ndup.dupfd); 1232 1.58 kre break; 1233 1.58 kre default: 1234 1.58 kre outstr(n->nfile.expfname, out); 1235 1.58 kre break; 1236 1.58 kre } 1237 1.58 kre return 1; 1238 1.58 kre } 1239