static int pipelineExecProc(struct pipeline* pl, struct plProc *proc, int prevStdoutFd, int stdinFd, int stdoutFd, int stderrFd, void *otherEndBuf, size_t otherEndBufSize) /* start a process in the pipeline, return the stdout fd of the process */ { /* determine stdin/stdout to use */ int procStdinFd, procStdoutFd; if (proc == pl->procs) procStdinFd = stdinFd; /* first process in pipeline */ else procStdinFd = prevStdoutFd; if (proc->next == NULL) procStdoutFd = stdoutFd; /* last process in pipeline */ else prevStdoutFd = pipeCreate(&procStdoutFd); /* start process */ if ((proc->pid = fork()) < 0) errnoAbort("can't fork"); if (proc->pid == 0) { if (otherEndBuf != NULL) plProcMemWrite(proc, procStdoutFd, stderrFd, otherEndBuf, otherEndBufSize); else plProcExecChild(proc, procStdinFd, procStdoutFd, stderrFd); } /* don't leave intermediate pipes open in parent */ if (proc != pl->procs) safeClose(&procStdinFd); if (proc->next != NULL) safeClose(&procStdoutFd); return prevStdoutFd; }
/* Closes all open FDs except for stdin, stdout and stderr */ static void closeFDs(int errnofd) { DIR *dp; int dfd; struct dirent *ep; int fdNum = -1; dfd = open("/proc/self/fd/", O_RDONLY); dp = fdopendir(dfd); while ((ep = readdir(dp))) { if(sscanf(ep->d_name, "%d", &fdNum) < 1) { continue; } if (fdNum < 3) { continue; } if (fdNum == dfd) { continue; } if (fdNum == errnofd) { continue; } safeClose(fdNum); } closedir(dp); safeClose(dfd); }
int main(int argc, char *argv[]) { int fd, newfd; int numWritten; Bool useDup2; if (argc < 2 || argc > 3) { helpAndLeave(argv[0], EXIT_FAILURE); } fd = (int) atol(argv[1]); newfd = -1; /* if not using dup2, this variable will not be used */ if (argc == 3) { useDup2 = TRUE; newfd = (int) atol(argv[2]); } else { useDup2 = FALSE; } newfd = duplicate(fd, newfd, useDup2); numWritten = write(newfd, writeStr, sizeof(writeStr)); if (numWritten == -1) { pexit("write"); } safeClose(fd); safeClose(newfd); printf("Done. Written %d bytes to the new file descriptor #%d\n", numWritten, newfd); return EXIT_SUCCESS; }
static void pipelineStartWrite(struct pipeline *pl, int stdoutFd, int stderrFd) /* start a write pipeline */ { int pipeRdFd = pipeCreate(&pl->pipeFd); pipelineExec(pl, pipeRdFd, stdoutFd, stderrFd, NULL, 0); safeClose(&pipeRdFd); }
int _dup2(int oldfd, int newfd) { int nextfd; /* First, check if oldfd is a valid file descriptor */ int flags = fcntl(oldfd, F_GETFL); if (flags == -1) { errno = EBADF; return -1; } /* if both descriptors are the same, do nothing */ if (oldfd == newfd) { return newfd; } /* close newfd if necessary */ flags = fcntl(newfd, F_GETFL); if (flags != -1) { safeClose(newfd); } /* perform the copy */ nextfd = fcntl(oldfd, F_DUPFD, newfd); if (nextfd != newfd) { fprintf(stderr, "_dup2 is not atomic, so sometimes it fails. It just did. Expected fd %d, got %d\n", newfd, nextfd); exit(EXIT_FAILURE); } return newfd; }
void closeAll(poll_list::iterator begin, poll_list::iterator end) { while (begin != end) { safeClose(begin->fd); ++begin; } }
static void pipelineStartRead(struct pipeline *pl, int stdinFd, int stderrFd, void *otherEndBuf, size_t otherEndBufSize) /* start a read pipeline */ { int pipeWrFd; pl->pipeFd = pipeCreate(&pipeWrFd); pipelineExec(pl, stdinFd, pipeWrFd, stderrFd, otherEndBuf, otherEndBufSize); safeClose(&pipeWrFd); }
struct pipeline *pipelineOpen(char ***cmds, unsigned opts, char *otherEndFile, char *stderrFile) /* Create a pipeline from an array of commands. See pipeline.h for * full documentation */ { int otherEndFd; int stderrFd = (stderrFile == NULL) ? STDERR_FILENO : openWrite(stderrFile); checkOpts(opts); if (opts & pipelineRead) otherEndFd = (otherEndFile == NULL) ? STDIN_FILENO : openRead(otherEndFile); else otherEndFd = (otherEndFile == NULL) ? STDOUT_FILENO : openWrite(otherEndFile); struct pipeline *pl = pipelineOpenFd(cmds, opts, otherEndFd, stderrFd); safeClose(&otherEndFd); if (stderrFile != NULL) safeClose(&stderrFd); return pl; }
/** * Safely connect socket file descriptor to server address. * @see man(2) connect for params ******************************************************************************/ void safeConnect( int sockfd, const struct sockaddr *addr, socklen_t addrlen) { errno = 0; if (connect( sockfd, addr, addrlen ) < 0 ) { perror("connect error"); safeClose(sockfd); exit(1); } }
/** * Safely bind an address to a socked file descriptor. * @param socket created by socket() * @param address pointer to sockaddr struct describing the server * @see man(2) bind for wrapped function description. ******************************************************************************/ void safeBind(int socket, const struct sockaddr *address, socklen_t address_len) { errno = 0; if ( bind(socket, address, address_len) < -1) { perror("bind error"); safeClose(socket); exit(1); } }
Hardware::~Hardware() { safeClose(); //delete buzz; delete adc_i2c; delete adc; delete imu; delete pwmR; delete pwmG; delete pwmB; }
void ProgramRunner::operator()() { // Send the never_close_handle flag so that we can handle closing the fd below with safeClose. boost::iostreams::stream_buffer<boost::iostreams::file_descriptor_source> fdBuf( _pipe, boost::iostreams::file_descriptor_flags::never_close_handle); std::istream fdStream(&fdBuf); std::string line; while (std::getline(fdStream, line)) { if (line.find('\0') != std::string::npos) { programOutputLogger.appendLine( _port, _pid, _name, "WARNING: mongod wrote null bytes to output"); } programOutputLogger.appendLine(_port, _pid, _name, line); } // Close the read end of the pipe. safeClose(_pipe); }
void gracefullyExit(int fd,struct sigaction signal){ restoreHandler(signal); safeUnlink(); safeClose(fd); }
extern "C" JNIEXPORT void JNICALL Java_java_lang_Runtime_exec(JNIEnv* e, jclass, jobjectArray command, jlongArray process) { char** argv = static_cast<char**> (malloc((e->GetArrayLength(command) + 1) * sizeof(char*))); int i; for(i = 0; i < e->GetArrayLength(command); i++){ jstring element = (jstring) e->GetObjectArrayElement(command, i); char* s = const_cast<char*>(e->GetStringUTFChars(element, 0)); argv[i] = s; } argv[i] = 0; int in[] = { -1, -1 }; int out[] = { -1, -1 }; int err[] = { -1, -1 }; int msg[] = { -1, -1 }; makePipe(e, in); if(e->ExceptionCheck()) return; jlong inDescriptor = static_cast<jlong>(in[0]); e->SetLongArrayRegion(process, 2, 1, &inDescriptor); makePipe(e, out); if(e->ExceptionCheck()) return; jlong outDescriptor = static_cast<jlong>(out[1]); e->SetLongArrayRegion(process, 3, 1, &outDescriptor); makePipe(e, err); if(e->ExceptionCheck()) return; jlong errDescriptor = static_cast<jlong>(err[0]); e->SetLongArrayRegion(process, 4, 1, &errDescriptor); makePipe(e, msg); if(e->ExceptionCheck()) return; if(fcntl(msg[1], F_SETFD, FD_CLOEXEC) != 0) { throwNewErrno(e, "java/io/IOException"); return; } #ifdef __QNX__ // fork(2) doesn't work in multithreaded QNX programs. See // http://www.qnx.com/developers/docs/6.4.1/neutrino/getting_started/s1_procs.html pid_t pid = vfork(); #else // We might be able to just use vfork on all UNIX-style systems, but // the manual makes it sound dangerous due to the shared // parent/child address space, so we use fork if we can. pid_t pid = fork(); #endif switch(pid){ case -1: // error throwNewErrno(e, "java/io/IOException"); return; case 0: { // child // Setup stdin, stdout and stderr dup2(in[1], 1); close(in); dup2(out[0], 0); close(out); dup2(err[1], 2); close(err); close(msg[0]); execvp(argv[0], argv); // Error if here int val = errno; ssize_t rv UNUSED = write(msg[1], &val, sizeof(val)); exit(127); } break; default: { //parent jlong JNIPid = static_cast<jlong>(pid); e->SetLongArrayRegion(process, 0, 1, &JNIPid); safeClose(in[1]); safeClose(out[0]); safeClose(err[1]); safeClose(msg[1]); int val; int r = read(msg[0], &val, sizeof(val)); if(r == -1) { throwNewErrno(e, "java/io/IOException"); return; } else if(r) { errno = val; throwNewErrno(e, "java/io/IOException"); return; } } break; } safeClose(msg[0]); clean(e, command, argv); fcntl(in[0], F_SETFD, FD_CLOEXEC); fcntl(out[1], F_SETFD, FD_CLOEXEC); fcntl(err[0], F_SETFD, FD_CLOEXEC); }
/* Python's implementation of Popen forks back to python before execing. * Forking a python proc is a very complex and volatile process. * * This is a simpler method of execing that doesn't go back to python after * forking. This allows for faster safer exec. * * return NULL on error and sets the python error accordingly. */ static PyObject * createProcess(PyObject *self, PyObject *args) { int cpid; int deathSignal = 0; int rv; int outfd[2] = {-1, -1}; int in1fd[2] = {-1, -1}; int in2fd[2] = {-1, -1}; int errnofd[2] = {-1, -1}; int childErrno = 0; PyObject* pyArgList; PyObject* pyEnvList; const char* cwd; int close_fds = 0; char** argv = NULL; char** envp = NULL; if (!PyArg_ParseTuple(args, "O!iiiiiiizOi:createProcess;", &PyList_Type, &pyArgList, &close_fds, &outfd[0], &outfd[1], &in1fd[0], &in1fd[1], &in2fd[0], &in2fd[1], &cwd, &pyEnvList, &deathSignal)) { return NULL; } argv = pyListToArray(pyArgList, 1); if (!argv) { goto fail; } if (PyList_Check(pyEnvList)) { envp = pyListToArray(pyEnvList, 0); if (!envp) { goto fail; } } if(pipe(errnofd) < 0) { PyErr_SetFromErrno(PyExc_OSError); goto fail; } try_fork: cpid = fork(); if (cpid < 0) { if (errno == EAGAIN || errno == EINTR ) { goto try_fork; } PyErr_SetFromErrno(PyExc_OSError); goto fail; } if (!cpid) { safeClose(0); safeClose(1); safeClose(2); dup2(outfd[0], 0); dup2(in1fd[1], 1); dup2(in2fd[1], 2); safeClose(outfd[0]); safeClose(outfd[1]); safeClose(in1fd[0]); safeClose(in1fd[1]); safeClose(in2fd[0]); safeClose(in2fd[1]); safeClose(errnofd[0]); if (deathSignal) { childErrno = prctl(PR_SET_PDEATHSIG, deathSignal); if (childErrno < 0) { childErrno = errno; } /* Check that parent did not already die between fork and us * setting the death signal */ if (write(errnofd[1], &childErrno, sizeof(int)) < sizeof(int)) { exit(-1); } if (childErrno != 0) { exit(-1); } } if (setCloseOnExec(errnofd[1]) < 0) { goto sendErrno; } if (close_fds) { closeFDs(errnofd[1]); } if (cwd) { if (chdir(cwd) < 0) { goto sendErrno; } setenv("PWD", cwd, 1); } exec: if (envp) { execvpe(argv[0], argv, envp); } else { execvp(argv[0], argv); } if (errno == EINTR || errno == EAGAIN ) { goto exec; } sendErrno: if (write(errnofd[1], &errno, sizeof(int)) < 0) { exit(errno); } exit(-1); } safeClose(errnofd[1]); errnofd[1] = -1; if (deathSignal) { /* death signal sync point */ rv = safeRead(errnofd[0], &childErrno, sizeof(int)); if (rv != sizeof(int)) { PyErr_SetFromErrno(PyExc_OSError); goto fail; } else if (childErrno != 0) { PyErr_SetString(PyExc_OSError, strerror(childErrno)); goto fail; } } /* error sync point */ rv = safeRead(errnofd[0], &childErrno, sizeof(int)); if (rv == sizeof(int)) { PyErr_SetString(PyExc_OSError, strerror(childErrno)); goto fail; } else if (rv < 0) { PyErr_SetFromErrno(PyExc_OSError); goto fail; } safeClose(errnofd[0]); errnofd[0] = -1; /* From this point errors shouldn't occur, if they do something is very * very very wrong */ freeStringArray(argv); if (envp) { freeStringArray(envp); } return Py_BuildValue("(iiii)", cpid, outfd[1], in1fd[0], in2fd[0]); fail: if (argv) { freeStringArray(argv); } if (envp) { freeStringArray(envp); } if (errnofd[0] >= 0) { safeClose(errnofd[0]); } if (errnofd[1] >= 0) { safeClose(errnofd[1]); } return NULL; }
void ProgramRunner::start() { int pipeEnds[2]; { // NOTE(JCAREY): // // We take this lock from before our call to pipe until after we close the write side (in // the parent) to avoid leaking fds from threads racing around fork(). I.e. // // Thread A: calls pipe() // Thread B: calls fork() // A: sets cloexec on read and write sides // B: has a forked child with open fds // A: spawns a child thread to read it's child process's stdout // A: A's child process exits // A: wait's on A's reader thread in de-register // A: deadlocks forever (because the child reader thread stays in read() because of the open // fd in B) // // Holding the lock for the duration of those events prevents the leaks and thus the // associated deadlocks. stdx::lock_guard<stdx::mutex> lk(_createProcessMtx); int status = pipe(pipeEnds); if (status != 0) { const auto ewd = errnoWithDescription(); error() << "failed to create pipe: " << ewd; fassertFailed(16701); } #ifndef _WIN32 // The calls to fcntl to set CLOEXEC ensure that processes started by the process we are // about to fork do *not* inherit the file descriptors for the pipe. If grandchild processes // could inherit the FD for the pipe, than the pipe wouldn't close on child process exit. On // windows, instead the handle inherit flag is turned off after the call to CreateProcess. status = fcntl(pipeEnds[0], F_SETFD, FD_CLOEXEC); if (status != 0) { const auto ewd = errnoWithDescription(); error() << "failed to set FD_CLOEXEC on pipe end 0: " << ewd; fassertFailed(40308); } status = fcntl(pipeEnds[1], F_SETFD, FD_CLOEXEC); if (status != 0) { const auto ewd = errnoWithDescription(); error() << "failed to set FD_CLOEXEC on pipe end 1: " << ewd; fassertFailed(40317); } #endif fflush(0); launchProcess(pipeEnds[1]); // sets _pid // Close the write end of the pipe. safeClose(pipeEnds[1]); } if (_port >= 0) { registry.registerProgram(_pid, _port); } else { registry.registerProgram(_pid); } _pipe = pipeEnds[0]; { stringstream ss; ss << "shell: started program (sh" << _pid << "): "; for (unsigned i = 0; i < _argv.size(); i++) { ss << " " << _argv[i]; } log() << ss.str(); } }