/* * returns pid, or -1 for failure */ int _openchild (const char *command, FILE ** fto, FILE ** ffrom) { int i; int pid; int pdto[2]; int pdfrom[2]; if (__pipe (pdto) < 0) goto error1; if (__pipe (pdfrom) < 0) goto error2; switch (pid = __fork ()) { case -1: goto error3; case 0: /* * child: read from pdto[0], write into pdfrom[1] */ __close (0); __dup (pdto[0]); __close (1); __dup (pdfrom[1]); fflush (stderr); for (i = _rpc_dtablesize () - 1; i >= 3; i--) __close (i); fflush (stderr); execlp (command, command, NULL); perror ("exec"); _exit (~0); default: /* * parent: write into pdto[1], read from pdfrom[0] */ *fto = __fdopen (pdto[1], "w"); __close (pdto[0]); *ffrom = __fdopen (pdfrom[0], "r"); __close (pdfrom[1]); break; } return pid; /* * error cleanup and return */ error3: __close (pdfrom[0]); __close (pdfrom[1]); error2: __close (pdto[0]); __close (pdto[1]); error1: return -1; }
/* Print a line on stderr consisting of the text in S, a colon, a space, a message describing the meaning of the contents of `errno' and a newline. If S is NULL or "", the colon and space are omitted. */ void perror (const char *s) { int errnum = errno; FILE *fp; int fd = -1; /* The standard says that 'perror' must not change the orientation of the stream. What is supposed to happen when the stream isn't oriented yet? In this case we'll create a new stream which is using the same underlying file descriptor. */ if (__builtin_expect (_IO_fwide (stderr, 0) != 0, 1) || (fd = fileno (stderr)) == -1 || (fd = __dup (fd)) == -1 || (fp = fdopen (fd, "w+")) == NULL) { if (__builtin_expect (fd != -1, 0)) __close (fd); /* Use standard error as is. */ perror_internal (stderr, s, errnum); } else { /* We don't have to do any special hacks regarding the file position. Since the stderr stream wasn't used so far we just write to the descriptor. */ perror_internal (fp, s, errnum); /* Close the stream. */ fclose (fp); } }
int dup(int oldfd) { int newfd = 0; newfd = __dup(oldfd); if (fdleak_record_backtrace) { fdleak_record_backtrace(newfd); } return newfd; }
int dup(int oldfd) { return __dup(oldfd); }
/* Function used in the clone call to setup the signals mask, posix_spawn attributes, and file actions. It run on its own stack (provided by the posix_spawn call). */ static int __spawni_child (void *arguments) { struct posix_spawn_args *args = arguments; const posix_spawnattr_t *restrict attr = args->attr; const posix_spawn_file_actions_t *file_actions = args->fa; int p = args->pipe[1]; int ret; close_not_cancel (args->pipe[0]); /* The child must ensure that no signal handler are enabled because it shared memory with parent, so the signal disposition must be either SIG_DFL or SIG_IGN. It does by iterating over all signals and although it could possibly be more optimized (by tracking which signal potentially have a signal handler), it might requires system specific solutions (since the sigset_t data type can be very different on different architectures). */ struct sigaction sa; memset (&sa, '\0', sizeof (sa)); sigset_t hset; __sigprocmask (SIG_BLOCK, 0, &hset); for (int sig = 1; sig < _NSIG; ++sig) { if ((attr->__flags & POSIX_SPAWN_SETSIGDEF) && sigismember (&attr->__sd, sig)) { sa.sa_handler = SIG_DFL; } else if (sigismember (&hset, sig)) { if (__nptl_is_internal_signal (sig)) sa.sa_handler = SIG_IGN; else { __libc_sigaction (sig, 0, &sa); if (sa.sa_handler == SIG_IGN) continue; sa.sa_handler = SIG_DFL; } } else continue; __libc_sigaction (sig, &sa, 0); } #ifdef _POSIX_PRIORITY_SCHEDULING /* Set the scheduling algorithm and parameters. */ if ((attr->__flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER)) == POSIX_SPAWN_SETSCHEDPARAM) { if ((ret = __sched_setparam (0, &attr->__sp)) == -1) goto fail; } else if ((attr->__flags & POSIX_SPAWN_SETSCHEDULER) != 0) { if ((ret = __sched_setscheduler (0, attr->__policy, &attr->__sp)) == -1) goto fail; } #endif /* Set the process group ID. */ if ((attr->__flags & POSIX_SPAWN_SETPGROUP) != 0 && (ret = __setpgid (0, attr->__pgrp)) != 0) goto fail; /* Set the effective user and group IDs. */ if ((attr->__flags & POSIX_SPAWN_RESETIDS) != 0 && ((ret = local_seteuid (__getuid ())) != 0 || (ret = local_setegid (__getgid ())) != 0)) goto fail; /* Execute the file actions. */ if (file_actions != 0) { int cnt; struct rlimit64 fdlimit; bool have_fdlimit = false; for (cnt = 0; cnt < file_actions->__used; ++cnt) { struct __spawn_action *action = &file_actions->__actions[cnt]; /* Dup the pipe fd onto an unoccupied one to avoid any file operation to clobber it. */ if ((action->action.close_action.fd == p) || (action->action.open_action.fd == p) || (action->action.dup2_action.fd == p)) { if ((ret = __dup (p)) < 0) goto fail; p = ret; } switch (action->tag) { case spawn_do_close: if ((ret = close_not_cancel (action->action.close_action.fd)) != 0) { if (!have_fdlimit) { __getrlimit64 (RLIMIT_NOFILE, &fdlimit); have_fdlimit = true; } /* Signal errors only for file descriptors out of range. */ if (action->action.close_action.fd < 0 || action->action.close_action.fd >= fdlimit.rlim_cur) goto fail; } break; case spawn_do_open: { ret = open_not_cancel (action->action.open_action.path, action->action. open_action.oflag | O_LARGEFILE, action->action.open_action.mode); if (ret == -1) goto fail; int new_fd = ret; /* Make sure the desired file descriptor is used. */ if (ret != action->action.open_action.fd) { if ((ret = __dup2 (new_fd, action->action.open_action.fd)) != action->action.open_action.fd) goto fail; if ((ret = close_not_cancel (new_fd)) != 0) goto fail; } } break; case spawn_do_dup2: if ((ret = __dup2 (action->action.dup2_action.fd, action->action.dup2_action.newfd)) != action->action.dup2_action.newfd) goto fail; break; } } } /* Set the initial signal mask of the child if POSIX_SPAWN_SETSIGMASK is set, otherwise restore the previous one. */ __sigprocmask (SIG_SETMASK, (attr->__flags & POSIX_SPAWN_SETSIGMASK) ? &attr->__ss : &args->oldmask, 0); args->exec (args->file, args->argv, args->envp); /* This is compatibility function required to enable posix_spawn run script without shebang definition for older posix_spawn versions (2.15). */ maybe_script_execute (args); ret = -errno; fail: /* Since sizeof errno < PIPE_BUF, the write is atomic. */ ret = -ret; if (ret) while (write_not_cancel (p, &ret, sizeof ret) < 0) continue; exit (SPAWN_ERROR); }
int dup(int oldfd) { _gfs_hook_debug_v(fputs("Hooking dup\n", stderr)); return (__dup(oldfd)); }