static int run(int argc, char *argv[]) { _cleanup_close_ int fd = -1, saved_stderr = -1; int r; log_parse_environment(); log_open(); r = parse_argv(argc, argv); if (r <= 0) return r; fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix); if (fd < 0) return log_error_errno(fd, "Failed to create stream fd: %m"); saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3); r = rearrange_stdio(STDIN_FILENO, fd, fd); /* Invalidates fd on succcess + error! */ TAKE_FD(fd); if (r < 0) return log_error_errno(r, "Failed to rearrange stdout/stderr: %m"); if (argc <= optind) (void) execl("/bin/cat", "/bin/cat", NULL); else (void) execvp(argv[optind], argv + optind); r = -errno; /* Let's try to restore a working stderr, so we can print the error message */ if (saved_stderr >= 0) (void) dup3(saved_stderr, STDERR_FILENO, 0); return log_error_errno(r, "Failed to execute process: %m"); }
static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid) { pid_t _pid; int r; if (null_or_empty_path(path)) { log_debug("%s is empty (a mask).", path); return 0; } r = safe_fork("(direxec)", FORK_DEATHSIG|FORK_LOG, &_pid); if (r < 0) return r; if (r == 0) { char *_argv[2]; if (stdout_fd >= 0) { r = rearrange_stdio(STDIN_FILENO, stdout_fd, STDERR_FILENO); if (r < 0) _exit(EXIT_FAILURE); } (void) rlimit_nofile_safe(); if (!argv) { _argv[0] = (char*) path; _argv[1] = NULL; argv = _argv; } else argv[0] = (char*) path; execv(path, argv); log_error_errno(errno, "Failed to execute %s: %m", path); _exit(EXIT_FAILURE); } *pid = _pid; return 1; }
static void test_rearrange_stdio(void) { pid_t pid; int r; r = safe_fork("rearrange", FORK_WAIT|FORK_LOG, &pid); assert_se(r >= 0); if (r == 0) { _cleanup_free_ char *path = NULL; char buffer[10]; /* Child */ safe_close(STDERR_FILENO); /* Let's close an fd < 2, to make it more interesting */ assert_se(rearrange_stdio(-1, -1, -1) >= 0); assert_se(fd_get_path(STDIN_FILENO, &path) >= 0); assert_se(path_equal(path, "/dev/null")); path = mfree(path); assert_se(fd_get_path(STDOUT_FILENO, &path) >= 0); assert_se(path_equal(path, "/dev/null")); path = mfree(path); assert_se(fd_get_path(STDOUT_FILENO, &path) >= 0); assert_se(path_equal(path, "/dev/null")); path = mfree(path); safe_close(STDIN_FILENO); safe_close(STDOUT_FILENO); safe_close(STDERR_FILENO); { int pair[2]; assert_se(pipe(pair) >= 0); assert_se(pair[0] == 0); assert_se(pair[1] == 1); assert_se(fd_move_above_stdio(0) == 3); } assert_se(open("/dev/full", O_WRONLY|O_CLOEXEC) == 0); assert_se(acquire_data_fd("foobar", 6, 0) == 2); assert_se(rearrange_stdio(2, 0, 1) >= 0); assert_se(write(1, "x", 1) < 0 && errno == ENOSPC); assert_se(write(2, "z", 1) == 1); assert_se(read(3, buffer, sizeof(buffer)) == 1); assert_se(buffer[0] == 'z'); assert_se(read(0, buffer, sizeof(buffer)) == 6); assert_se(memcmp(buffer, "foobar", 6) == 0); assert_se(rearrange_stdio(-1, 1, 2) >= 0); assert_se(write(1, "a", 1) < 0 && errno == ENOSPC); assert_se(write(2, "y", 1) == 1); assert_se(read(3, buffer, sizeof(buffer)) == 1); assert_se(buffer[0] == 'y'); assert_se(fd_get_path(0, &path) >= 0); assert_se(path_equal(path, "/dev/null")); path = mfree(path); _exit(EXIT_SUCCESS); } }