#include #include #include "cloexec.h" #include "xalloc.h" #define PROGRAM_NAME_TEMPLATE "m4XXXXXX" #define prepare_spawn(argv) \ (__gnuc_extension__ \ ({ \ size_t _argc; \ char **_new_argv; \ \ for (_argc = 0; (argv)[_argc]; _argc++) \ ; \ \ _new_argv = xmalloc((1 + _argc + 1) * sizeof(_new_argv[0])); \ /* \ * Do not use neither an absolute path to the bash program \ * nor the environment variable /dev/env/DJDIR. It can never \ * be assumed that they are setup correctly. Let the system \ * search along the PATH and hope for the best. \ */ \ *_new_argv++ = "bash.exe"; \ \ for (_argc = 0; (_new_argv[_argc] = argv[_argc]); _argc++) \ ; \ \ _new_argv; \ }) \ ) #define PIPE_STDIN 0 #define PIPE_STDOUT 1 char tmp_file_name[2][L_tmpnam]; /* 0: pipe stdin, 1: pipe stdout. */ static int tmp_file_desc[2] = {-1, -1}; /* 0: pipe stdin, 1: pipe stdout. */ #define remove_tmp_file(name) \ (__gnuc_extension__ \ ({ \ if ((name)) \ unlink((name)); \ else \ { \ if (tmp_file_name[PIPE_STDIN][0]) \ { \ if (tmp_file_desc[PIPE_STDIN] > -1) \ close(tmp_file_desc[PIPE_STDIN]); \ unlink(tmp_file_name[PIPE_STDIN]); \ tmp_file_name[PIPE_STDIN][0] = '\0'; \ tmp_file_desc[PIPE_STDIN] = -1; \ } \ if (tmp_file_name[PIPE_STDOUT][0]) \ { \ if (tmp_file_desc[PIPE_STDOUT] > -1) \ { \ fsync(tmp_file_desc[PIPE_STDOUT]); \ close(tmp_file_desc[PIPE_STDOUT]); \ } \ unlink(tmp_file_name[PIPE_STDOUT]); \ tmp_file_name[PIPE_STDOUT][0] = '\0'; \ tmp_file_desc[PIPE_STDOUT] = -1; \ } \ } \ }) \ ) /* Duplicates a file handle, making the copy uninheritable. Returns -1 for a file handle that is equivalent to closed. */ static int dup_noinherit(int fd) { fd = dup_cloexec(fd); if (fd < 0 && errno == EMFILE) error(EXIT_FAILURE, errno, _("fcntl failed")); return fd; } /* Returns a file descriptor equivalent to FD, except that the resulting file descriptor is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. FD must be open and non-inheritable. The result will be non-inheritable as well. If FD < 0, FD itself is returned. */ static int fd_safer_noinherit(int fd) { if (STDIN_FILENO <= fd && fd <= STDERR_FILENO) { /* The recursion depth is at most 3. */ int nfd = fd_safer_noinherit(dup_noinherit(fd)); int saved_errno = errno; close(fd); errno = saved_errno; return nfd; } return fd; } /* Duplicates a file handle, making the copy uninheritable and ensuring the result is none of STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO. Returns -1 for a file handle that is equivalent to closed. */ static int dup_safer_noinherit(int fd) { return fd_safer_noinherit(dup_noinherit(fd)); } /* Undoes the effect of TEMPFD = dup_safer_noinherit (ORIGFD); */ static void undup_safer_noinherit(int tempfd, int origfd) { if (tempfd >= 0) { if (dup2(tempfd, origfd) < 0) error(EXIT_FAILURE, errno, _("cannot restore fd %d: dup2 failed"), origfd); close(tempfd); } else { /* origfd was closed or open to no handle at all. Set it to a closed state. This is (nearly) equivalent to the original state. */ close(origfd); } } #ifdef _SPAWN_PIPE_H static int djgpp_pipe(int pipe_fd[2], int pipe_end) { int fd; strcpy(tmp_file_name[pipe_end], "/dev/env/TMPDIR/"PROGRAM_NAME_TEMPLATE); if ((fd = mkstemp(tmp_file_name[pipe_end])) < 0) { strcpy(tmp_file_name[pipe_end], "/dev/env/TMP/"PROGRAM_NAME_TEMPLATE); if ((fd = mkstemp(tmp_file_name[pipe_end])) < 0) { strcpy(tmp_file_name[pipe_end], "/dev/env/TEMP/"PROGRAM_NAME_TEMPLATE); if ((fd = mkstemp(tmp_file_name[pipe_end])) < 0) return -1; } } if (pipe_end == PIPE_STDIN) { pipe_fd[PIPE_STDIN] = tmp_file_desc[PIPE_STDIN] = fd; pipe_fd[PIPE_STDOUT] = -1; tmp_file_name[PIPE_STDOUT][0] = '\0'; } else if (pipe_end == PIPE_STDOUT) { pipe_fd[PIPE_STDOUT] = tmp_file_desc[PIPE_STDOUT] = fd; pipe_fd[PIPE_STDIN] = -1; tmp_file_name[PIPE_STDIN][0] = '\0'; } return 0; } #endif