int spawn(char *program, char *argv[], int sin, int sout, int serr, int search, char *envp[], char *pty_name, int wait) { pid_t pid; int fd; int channel[2]; sigset_t sset; channel[0] = -1; channel[1] = -1; if (!pipe(channel)) { if (-1==fcntl(channel[1], F_SETFD, FD_CLOEXEC)) { close(channel[1]); channel[1] = -1; } } pid = fork(); if (pid) { if ((-1 != pid) && (-1 != channel[1])) { int child_errno = 0; int bytes = sizeof(int); int n; char *p = (char*)&child_errno; close(channel[1]); /* Try to read child errno from channel. */ while ((bytes > 0) && (n = read(channel[0], p, bytes))) { if (-1 == n) { if (EINTR == errno) { continue; } else { break; } } else { bytes -= n; p += n; } } close(channel[0]); if (child_errno) { waitpid(pid, NULL, 0); /* Our convention to tell Lisp that it was the exec that * failed, not the fork. */ pid = -2; errno = child_errno; } } return pid; } close (channel[0]); /* Put us in our own process group, but only if we need not * share stdin with our parent. In the latter case we claim * control of the terminal. */ if (sin >= 0) { #if defined(LISP_FEATURE_HPUX) || defined(LISP_FEATURE_OPENBSD) setsid(); #elif defined(LISP_FEATURE_DARWIN) setpgid(0, getpid()); #elif defined(SVR4) || defined(__linux__) || defined(__osf__) setpgrp(); #else setpgrp(0, getpid()); #endif } else { tcsetpgrp(0, getpgrp()); } /* unblock signals */ sigemptyset(&sset); sigprocmask(SIG_SETMASK, &sset, NULL); /* If we are supposed to be part of some other pty, go for it. */ if (pty_name) set_pty(pty_name); else { /* Set up stdin, stdout, and stderr */ if (sin >= 0) dup2(sin, 0); if (sout >= 0) dup2(sout, 1); if (serr >= 0) dup2(serr, 2); } /* Close all other fds. */ #ifdef SVR4 for (fd = sysconf(_SC_OPEN_MAX)-1; fd >= 3; fd--) if (fd != channel[1]) close(fd); #else for (fd = getdtablesize()-1; fd >= 3; fd--) if (fd != channel[1]) close(fd); #endif if (envp) { environ = envp; } /* Exec the program. */ if (search) execvp(program, argv); else execv(program, argv); /* When exec fails and channel is available, send the errno value. */ if (-1 != channel[1]) { int our_errno = errno; int bytes = sizeof(int); int n; char *p = (char*)&our_errno; while ((bytes > 0) && (n = write(channel[1], p, bytes))) { if (-1 == n) { if (EINTR == errno) { continue; } else { break; } } else { bytes -= n; p += n; } } close(channel[1]); } _exit(1); }
int spawn(char *program, char *argv[], int sin, int sout, int serr, int search, char *envp[], char *pty_name, int wait) { int pid = fork(); int fd; sigset_t sset; if (pid != 0) return pid; /* Put us in our own process group, but only if we need not * share stdin with our parent. In the latter case we claim * control of the terminal. */ if (sin >= 0) { #if defined(LISP_FEATURE_HPUX) || defined(LISP_FEATURE_OPENBSD) setsid(); #elif defined(LISP_FEATURE_DARWIN) setpgid(0, getpid()); #elif defined(SVR4) || defined(__linux__) || defined(__osf__) setpgrp(); #else setpgrp(0, getpid()); #endif } else { tcsetpgrp(0, getpgrp()); } /* unblock signals */ sigemptyset(&sset); sigprocmask(SIG_SETMASK, &sset, NULL); /* If we are supposed to be part of some other pty, go for it. */ if (pty_name) set_pty(pty_name); else { /* Set up stdin, stdout, and stderr */ if (sin >= 0) dup2(sin, 0); if (sout >= 0) dup2(sout, 1); if (serr >= 0) dup2(serr, 2); } /* Close all other fds. */ #ifdef SVR4 for (fd = sysconf(_SC_OPEN_MAX)-1; fd >= 3; fd--) close(fd); #else for (fd = getdtablesize()-1; fd >= 3; fd--) close(fd); #endif environ = envp; /* Exec the program. */ if (search) execvp(program, argv); else execv(program, argv); exit (1); }