pid_t sys_start_dedup_filter_child(void) { pid_t cpid; if (dedup_filter_command_option == NULL) return -1; xpipe(dedup_filter_query_pipe); xpipe(dedup_filter_response_pipe); cpid = xfork(); if (cpid > 0) { // parent tar // we write to query pipe, read from response pipe // so close the other fds xclose(dedup_filter_query_pipe[PREAD]); xclose(dedup_filter_response_pipe[PWRITE]); return cpid; } // child (filter) reads from query and writes to response // so close the rest xclose(dedup_filter_query_pipe[PWRITE]); xclose(dedup_filter_response_pipe[PREAD]); xdup2(dedup_filter_query_pipe[PREAD], STDIN_FILENO); xdup2(dedup_filter_response_pipe[PWRITE], STDOUT_FILENO); program_name = _("tar (child)"); execlp(dedup_filter_command_option, NULL); }
void FAST_FUNC launch_helper(const char **argv) { // setup vanilla unidirectional pipes interchange int i; int pipes[4]; xpipe(pipes); xpipe(pipes + 2); // NB: handler must be installed before vfork bb_signals(0 + (1 << SIGCHLD) + (1 << SIGALRM) , signal_handler); G.helper_pid = xvfork(); i = (!G.helper_pid) * 2; // for parent:0, for child:2 close(pipes[i + 1]); // 1 or 3 - closing one write end close(pipes[2 - i]); // 2 or 0 - closing one read end xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - other write end if (!G.helper_pid) { // child: try to execute connection helper // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec BB_EXECVP_or_die((char**)argv); } // parent // check whether child is alive //redundant:signal_handler(SIGCHLD); // child seems OK -> parent goes on atexit(kill_helper); }
int execute_pipe_start(t_tree *tree, t_shell *st_shell) { int flag; int statut; int fd[2]; pid_t pid; if ((flag = prepare_all_commands(tree, st_shell)) != EXIT_SUCCESS) return (flag); if ((pid = xfork()) == 0) { if (xpipe(fd) == -1) exit(EXIT_FAILURE); reset_line(st_shell); set_fd_out(tree->right, fd[1]); set_fd_in(tree->left, fd[0]); if (tree->right->type == IS_CMD) init_first_pipe(tree, st_shell, fd); init_first_pipe_spe(tree, st_shell, fd); } else if (pid > 0) { if (waitpid(-1, &statut, 0) == -1) perror("Waitpid() :"); return (write_statut(statut)); } return (FATAL_ERROR); }
static void fatal_signal_init(void) { static bool inited = false; if (!inited) { size_t i; inited = true; xpipe(signal_fds); set_nonblocking(signal_fds[0]); set_nonblocking(signal_fds[1]); sigemptyset(&fatal_signal_set); for (i = 0; i < ARRAY_SIZE(fatal_signals); i++) { int sig_nr = fatal_signals[i]; struct sigaction old_sa; sigaddset(&fatal_signal_set, sig_nr); xsigaction(sig_nr, NULL, &old_sa); if (old_sa.sa_handler == SIG_DFL && signal(sig_nr, fatal_signal_handler) == SIG_ERR) { VLOG_FATAL("signal failed (%s)", strerror(errno)); } } atexit(atexit_handler); } }
int parse_command_for_pipe(char **command, int tab_len, int first) { int p[2]; int pid; int ret; if (xpipe(p) < 0) return (0); if ((pid = xfork()) > 0) { ret = exec_father(command[tab_len - 1], p, pid, first); if (ret > 0) return (ret); } else { xclose(p[0]); xdup2(p[1], 1); if (tab_len > 2) parse_command_for_pipe(command, tab_len - 1, 0); else parse_command_redir(command[0]); exit(0); } return (pid); }
int sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st) { int p[2]; char *argv[4]; xpipe (p); pipe_handler = signal (SIGPIPE, SIG_IGN); global_pid = xfork (); if (global_pid != 0) { xclose (p[PREAD]); return p[PWRITE]; } /* Child */ xdup2 (p[PREAD], STDIN_FILENO); xclose (p[PWRITE]); stat_to_env (file_name, typechar, st); argv[0] = "/bin/sh"; argv[1] = "-c"; argv[2] = to_command_option; argv[3] = NULL; execv ("/bin/sh", argv); exec_fatal (file_name); }
/* Callback called by glib main loop when a client connects to ABRT's socket. */ static gboolean server_socket_cb(GIOChannel *source, GIOCondition condition, gpointer ptr_unused) { kill_idle_timeout(); load_abrt_conf(); int socket = accept(g_io_channel_unix_get_fd(source), NULL, NULL); if (socket == -1) { perror_msg("accept"); goto server_socket_finitio; } log_notice("New client connected"); fflush(NULL); /* paranoia */ int pipefd[2]; xpipe(pipefd); pid_t pid = fork(); if (pid < 0) { perror_msg("fork"); close(socket); close(pipefd[0]); close(pipefd[1]); goto server_socket_finitio; } if (pid == 0) /* child */ { xdup2(socket, STDIN_FILENO); xdup2(socket, STDOUT_FILENO); close(socket); close(pipefd[0]); xmove_fd(pipefd[1], STDERR_FILENO); char *argv[3]; /* abrt-server [-s] NULL */ char **pp = argv; *pp++ = (char*)"abrt-server"; if (logmode & LOGMODE_JOURNAL) *pp++ = (char*)"-s"; *pp = NULL; execvp(argv[0], argv); perror_msg_and_die("Can't execute '%s'", argv[0]); } /* parent */ close(socket); close(pipefd[1]); add_abrt_server_proc(pid, pipefd[0]); server_socket_finitio: start_idle_timeout(); return TRUE; }
/* Call this before doing anything else. Sets up the socket pair * and installs the signal handler */ void udhcp_sp_setup(void) { /* was socketpair, but it needs AF_UNIX in kernel */ xpipe(signal_pipe); close_on_exec_on(signal_pipe[0]); close_on_exec_on(signal_pipe[1]); ndelay_on(signal_pipe[1]); signal(SIGUSR1, signal_handler); signal(SIGUSR2, signal_handler); signal(SIGTERM, signal_handler); }
/* unzip if needed */ FILE *xopen_unzip (const char *name, const char *mode) { char *p, *zprog = NULL; FILE *fi, *fo; const size_t buflen = 64 * 1024; char *buffer; pid_t pid; int status; int any_data = 0; p = strrchr(name, '.'); if (p != NULL) { if (!strcmp (p, ".bz2")) zprog = "bzcat"; else if (!strcmp(p, ".gz")) zprog = "zcat"; } if (zprog == NULL) return xopen_seekable (name, mode); buffer = xmalloc (buflen); fo = xtmpfile(); fi = xpipe(zprog, &pid, "r", zprog, name, NULL); while (!feof (fi)) { size_t count = fread (buffer, 1, buflen, fi); if (ferror (fi)) { perror(name); exit(1); } if (count < 1) break; fwrite (buffer, count, 1, fo); if (ferror (fo)) error (EXIT_FAILURE, errno, "writing temp file"); any_data = 1; } free (buffer); fclose (fi); waitpid (pid, &status, 0); if (any_data == 0 && WEXITSTATUS (status) != 0) { fclose (fo); exit (1); } fseek (fo, 0L, SEEK_SET); return fo; }
/* Call this before doing anything else. Sets up the socket pair * and installs the signal handler */ void udhcp_sp_setup(void) { /* was socketpair, but it needs AF_UNIX in kernel */ xpipe(signal_pipe); fcntl(signal_pipe[0], F_SETFD, FD_CLOEXEC); fcntl(signal_pipe[1], F_SETFD, FD_CLOEXEC); fcntl(signal_pipe[1], F_SETFL, O_NONBLOCK); signal(SIGUSR1, signal_handler); signal(SIGUSR2, signal_handler); signal(SIGTERM, signal_handler); }
/* Forks, then: * * - In the parent, waits for the child to signal that it has completed its * startup sequence. Then stores -1 in '*fdp' and returns the child's * pid in '*child_pid' argument. * * - In the child, stores a fd in '*fdp' and returns 0 through '*child_pid' * argument. The caller should pass the fd to fork_notify_startup() after * it finishes its startup sequence. * * Returns 0 on success. If something goes wrong and child process was not * able to signal its readiness by calling fork_notify_startup(), then this * function returns -1. However, even in case of failure it still sets child * process id in '*child_pid'. */ static int fork_and_wait_for_startup(int *fdp, pid_t *child_pid) { int fds[2]; pid_t pid; int ret = 0; xpipe(fds); pid = fork_and_clean_up(); if (pid > 0) { /* Running in parent process. */ size_t bytes_read; char c; close(fds[1]); if (read_fully(fds[0], &c, 1, &bytes_read) != 0) { int retval; int status; do { retval = waitpid(pid, &status, 0); } while (retval == -1 && errno == EINTR); if (retval == pid) { if (WIFEXITED(status) && WEXITSTATUS(status)) { /* Child exited with an error. Convey the same error * to our parent process as a courtesy. */ exit(WEXITSTATUS(status)); } else { char *status_msg = process_status_msg(status); //VLOG_ERR("fork child died before signaling startup (%s)", // status_msg); printf("fork child died before signaling startup (%s)", status_msg); ret = -1; } } else if (retval < 0) { //VLOG_FATAL("waitpid failed (%s)", ovs_strerror(errno)); printf("waitpid failed (%d)", errno); } else { abort(); } } close(fds[0]); *fdp = -1; } else if (!pid) { /* Running in child process. */ close(fds[0]); *fdp = fds[1]; } *child_pid = pid; return ret; }
void FAST_FUNC launch_helper(const char **argv) { // setup vanilla unidirectional pipes interchange int i; int pipes[4]; xpipe(pipes); xpipe(pipes + 2); // NB: handler must be installed before vfork bb_signals(0 + (1 << SIGCHLD) + (1 << SIGALRM) , signal_handler); G.helper_pid = xvfork(); i = (!G.helper_pid) * 2; // for parent:0, for child:2 close(pipes[i + 1]); // 1 or 3 - closing one write end close(pipes[2 - i]); // 2 or 0 - closing one read end xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - using other write end // End result: // parent stdout [3] -> child stdin [2] // child stdout [1] -> parent stdin [0] if (!G.helper_pid) { // child // if parent dies, get SIGTERM prctl(PR_SET_PDEATHSIG, SIGTERM, 0, 0, 0); // try to execute connection helper // NB: SIGCHLD & SIGALRM revert to SIG_DFL on exec BB_EXECVP_or_die((char**)argv); } // parent goes on }
static pid_t fork_and_wait_for_startup(int *fdp) { int fds[2]; pid_t pid; xpipe(fds); pid = fork(); if (pid > 0) { /* Running in parent process. */ size_t bytes_read; char c; close(fds[1]); fatal_signal_fork(); if (read_fully(fds[0], &c, 1, &bytes_read) != 0) { int retval; int status; do { retval = waitpid(pid, &status, 0); } while (retval == -1 && errno == EINTR); if (retval == pid && WIFEXITED(status) && WEXITSTATUS(status)) { /* Child exited with an error. Convey the same error to * our parent process as a courtesy. */ exit(WEXITSTATUS(status)); } VLOG_FATAL("fork child failed to signal startup (%s)", strerror(errno)); } close(fds[0]); *fdp = -1; } else if (!pid) { /* Running in child process. */ close(fds[0]); time_postfork(); lockfile_postfork(); *fdp = fds[1]; } else { VLOG_FATAL("fork failed (%s)", strerror(errno)); } return pid; }
int sys_exec_command (char *file_name, int typechar, struct tar_stat_info *st) { int p[2]; xpipe (p); pipe_handler = signal (SIGPIPE, SIG_IGN); global_pid = xfork (); if (global_pid != 0) { xclose (p[PREAD]); return p[PWRITE]; } /* Child */ xdup2 (p[PREAD], STDIN_FILENO); xclose (p[PWRITE]); stat_to_env (file_name, typechar, st); priv_set_restore_linkdir (); xexec (to_command_option); }
/* Set ARCHIVE for uncompressing, then reading an archive. */ pid_t sys_child_open_for_uncompress (void) { int parent_pipe[2]; int child_pipe[2]; pid_t grandchild_pid; pid_t child_pid; xpipe (parent_pipe); child_pid = xfork (); if (child_pid > 0) { /* The parent tar is still here! Just clean up. */ archive = parent_pipe[PREAD]; xclose (parent_pipe[PWRITE]); return child_pid; } /* The newborn child tar is here! */ set_program_name (_("tar (child)")); signal (SIGPIPE, SIG_DFL); xdup2 (parent_pipe[PWRITE], STDOUT_FILENO); xclose (parent_pipe[PREAD]); /* Check if we need a grandchild tar. This happens only if either: a) we're reading stdin: to force unblocking; b) the file is to be accessed by rmt: compressor doesn't know how; c) the file is not a plain file. */ if (strcmp (archive_name_array[0], "-") != 0 && !_remdev (archive_name_array[0]) && is_regular_file (archive_name_array[0])) { /* We don't need a grandchild tar. Open the archive and lauch the uncompressor. */ archive = open (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW); if (archive < 0) open_fatal (archive_name_array[0]); xdup2 (archive, STDIN_FILENO); execlp (use_compress_program_option, use_compress_program_option, "-d", (char *) 0); exec_fatal (use_compress_program_option); } /* We do need a grandchild tar. */ xpipe (child_pipe); grandchild_pid = xfork (); if (grandchild_pid == 0) { /* The newborn grandchild tar is here! Launch the uncompressor. */ set_program_name (_("tar (grandchild)")); xdup2 (child_pipe[PREAD], STDIN_FILENO); xclose (child_pipe[PWRITE]); execlp (use_compress_program_option, use_compress_program_option, "-d", (char *) 0); exec_fatal (use_compress_program_option); } /* The child tar is still here! */ /* Prepare for unblocking the data from the archive into the uncompressor. */ xdup2 (child_pipe[PWRITE], STDOUT_FILENO); xclose (child_pipe[PREAD]); if (strcmp (archive_name_array[0], "-") == 0) archive = STDIN_FILENO; else archive = rmtopen (archive_name_array[0], O_RDONLY | O_BINARY, MODE_RW, rsh_command_option); if (archive < 0) open_fatal (archive_name_array[0]); /* Let's read the archive and pipe it into stdout. */ while (1) { char *cursor; size_t maximum; size_t count; size_t status; clear_read_error_count (); error_loop: status = rmtread (archive, record_start->buffer, record_size); if (status == SAFE_READ_ERROR) { archive_read_error (); goto error_loop; } if (status == 0) break; cursor = record_start->buffer; maximum = status; while (maximum) { count = maximum < BLOCKSIZE ? maximum : BLOCKSIZE; if (full_write (STDOUT_FILENO, cursor, count) != count) write_error (use_compress_program_option); cursor += count; maximum -= count; } } xclose (STDOUT_FILENO); wait_for_grandchild (grandchild_pid); }
static int parse(const char *boundary, char **argv) { char *line, *s, *p; const char *type; int boundary_len = strlen(boundary); const char *delims = " ;\"\t\r\n"; const char *uniq; int ntokens; const char *tokens[32]; // 32 is enough // prepare unique string pattern uniq = xasprintf("%%llu.%u.%s", (unsigned)getpid(), safe_gethostname()); //bb_info_msg("PARSE[%s]", terminator); while ((line = xmalloc_fgets_str(stdin, "\r\n\r\n")) != NULL) { // seek to start of MIME section // N.B. to avoid false positives let us seek to the _last_ occurance p = NULL; s = line; while ((s=strcasestr(s, "Content-Type:")) != NULL) p = s++; if (!p) goto next; //bb_info_msg("L[%s]", p); // split to tokens // TODO: strip of comments which are of form: (comment-text) ntokens = 0; tokens[ntokens] = NULL; for (s = strtok(p, delims); s; s = strtok(NULL, delims)) { tokens[ntokens] = s; if (ntokens < ARRAY_SIZE(tokens) - 1) ntokens++; //bb_info_msg("L[%d][%s]", ntokens, s); } tokens[ntokens] = NULL; //bb_info_msg("N[%d]", ntokens); // analyse tokens type = find_token(tokens, "Content-Type:", "text/plain"); //bb_info_msg("T[%s]", type); if (0 == strncasecmp(type, "multipart/", 10)) { if (0 == strcasecmp(type+10, "mixed")) { parse(xfind_token(tokens, "boundary="), argv); } else bb_error_msg_and_die("no support of content type '%s'", type); } else { pid_t pid = pid; int rc; FILE *fp; // fetch charset const char *charset = find_token(tokens, "charset=", CONFIG_FEATURE_MIME_CHARSET); // fetch encoding const char *encoding = find_token(tokens, "Content-Transfer-Encoding:", "7bit"); // compose target filename char *filename = (char *)find_token(tokens, "filename=", NULL); if (!filename) filename = xasprintf(uniq, monotonic_us()); else filename = bb_get_last_path_component_strip(xstrdup(filename)); // start external helper, if any if (opts & OPT_X) { int fd[2]; xpipe(fd); pid = vfork(); if (0 == pid) { // child reads from fd[0] xdup2(fd[0], STDIN_FILENO); close(fd[0]); close(fd[1]); xsetenv("CONTENT_TYPE", type); xsetenv("CHARSET", charset); xsetenv("ENCODING", encoding); xsetenv("FILENAME", filename); BB_EXECVP(*argv, argv); _exit(EXIT_FAILURE); } // parent dumps to fd[1] close(fd[0]); fp = fdopen(fd[1], "w"); signal(SIGPIPE, SIG_IGN); // ignore EPIPE // or create a file for dump } else { char *fname = xasprintf("%s%s", *argv, filename); fp = xfopen_for_write(fname); free(fname); } // housekeeping free(filename); // dump to fp if (0 == strcasecmp(encoding, "base64")) { decode_base64(stdin, fp); } else if (0 != strcasecmp(encoding, "7bit") && 0 != strcasecmp(encoding, "8bit")) { // quoted-printable, binary, user-defined are unsupported so far bb_error_msg_and_die("no support of encoding '%s'", encoding); } else { // N.B. we have written redundant \n. so truncate the file // The following weird 2-tacts reading technique is due to // we have to not write extra \n at the end of the file // In case of -x option we could truncate the resulting file as // fseek(fp, -1, SEEK_END); // if (ftruncate(fileno(fp), ftell(fp))) // bb_perror_msg("ftruncate"); // But in case of -X we have to be much more careful. There is // no means to truncate what we already have sent to the helper. p = xmalloc_fgets_str(stdin, "\r\n"); while (p) { if ((s = xmalloc_fgets_str(stdin, "\r\n")) == NULL) break; if ('-' == s[0] && '-' == s[1] && 0 == strncmp(s+2, boundary, boundary_len)) break; fputs(p, fp); p = s; } /* while ((s = xmalloc_fgetline_str(stdin, "\r\n")) != NULL) { if ('-' == s[0] && '-' == s[1] && 0 == strncmp(s+2, boundary, boundary_len)) break; fprintf(fp, "%s\n", s); } // N.B. we have written redundant \n. so truncate the file fseek(fp, -1, SEEK_END); if (ftruncate(fileno(fp), ftell(fp))) bb_perror_msg("ftruncate"); */ } fclose(fp); // finalize helper if (opts & OPT_X) { signal(SIGPIPE, SIG_DFL); // exit if helper exited >0 rc = wait4pid(pid); if (rc) return rc+20; } // check multipart finalized if (s && '-' == s[2+boundary_len] && '-' == s[2+boundary_len+1]) { free(line); break; } } next: free(line); } //bb_info_msg("ENDPARSE[%s]", boundary); return EXIT_SUCCESS; }
void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) { file_header_t *file_header = archive_handle->file_header; #if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */ char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; if (!sctx) sctx = archive_handle->tar__sctx[PAX_GLOBAL]; if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ setfscreatecon(sctx); free(archive_handle->tar__sctx[PAX_NEXT_FILE]); archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; } #endif if ((file_header->mode & S_IFMT) == S_IFREG) { pid_t pid; int p[2], status; char *tar_env[TAR_MAX]; memset(tar_env, 0, sizeof(tar_env)); xpipe(p); pid = BB_MMU ? xfork() : xvfork(); if (pid == 0) { /* Child */ /* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */ oct2env(tar_env, TAR_MODE, file_header->mode); str2env(tar_env, TAR_FILENAME, file_header->name); str2env(tar_env, TAR_REALNAME, file_header->name); #if ENABLE_FEATURE_TAR_UNAME_GNAME str2env(tar_env, TAR_UNAME, file_header->tar__uname); str2env(tar_env, TAR_GNAME, file_header->tar__gname); #endif dec2env(tar_env, TAR_SIZE, file_header->size); dec2env(tar_env, TAR_UID, file_header->uid); dec2env(tar_env, TAR_GID, file_header->gid); close(p[1]); xdup2(p[0], STDIN_FILENO); signal(SIGPIPE, SIG_DFL); execl(archive_handle->tar__to_command_shell, archive_handle->tar__to_command_shell, "-c", archive_handle->tar__to_command, NULL); bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell); } close(p[0]); /* Our caller is expected to do signal(SIGPIPE, SIG_IGN) * so that we don't die if child don't read all the input: */ bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size); close(p[1]); if (safe_waitpid(pid, &status, 0) == -1) bb_perror_msg_and_die("waitpid"); if (WIFEXITED(status) && WEXITSTATUS(status)) bb_error_msg_and_die("'%s' returned status %d", archive_handle->tar__to_command, WEXITSTATUS(status)); if (WIFSIGNALED(status)) bb_error_msg_and_die("'%s' terminated on signal %d", archive_handle->tar__to_command, WTERMSIG(status)); if (!BB_MMU) { int i; for (i = 0; i < TAR_MAX; i++) { if (tar_env[i]) bb_unsetenv_and_free(tar_env[i]); } } } #if 0 /* ENABLE_FEATURE_TAR_SELINUX */ if (sctx) /* reset the context after creating an entry */ setfscreatecon(NULL); #endif }
static int create_and_upload_archive( const char *dump_dir_name, map_string_t *settings) { int result = 1; /* error */ pid_t child; TAR* tar = NULL; const char* errmsg = NULL; char* tempfile = NULL; struct dump_dir *dd = dd_opendir(dump_dir_name, /*flags:*/ 0); if (!dd) xfunc_die(); /* error msg is already logged by dd_opendir */ /* Gzipping e.g. 0.5gig coredump takes a while. Let client know what we are doing */ log(_("Compressing data")); //TODO: //Encrypt = yes //ArchiveType = .tar.bz2 //ExcludeFiles = foo,bar*,b*z const char* opt = getenv("Upload_URL"); if (!opt) opt = get_map_string_item_or_empty(settings, "URL"); char *url = opt[0] != '\0' ? xstrdup(opt) : ask_url(_("Please enter a URL (scp, ftp, etc.) where the problem data is to be exported:")); /* Create a child gzip which will compress the data */ /* SELinux guys are not happy with /tmp, using /var/run/abrt */ /* Reverted back to /tmp for ABRT2 */ /* Changed again to /var/tmp because of Fedora feature tmp-on-tmpfs */ tempfile = concat_path_basename(LARGE_DATA_TMP_DIR, dump_dir_name); tempfile = append_to_malloced_string(tempfile, ".tar.gz"); int pipe_from_parent_to_child[2]; xpipe(pipe_from_parent_to_child); child = vfork(); if (child == 0) { /* child */ close(pipe_from_parent_to_child[1]); xmove_fd(pipe_from_parent_to_child[0], 0); xmove_fd(xopen3(tempfile, O_WRONLY | O_CREAT | O_EXCL, 0600), 1); execlp("gzip", "gzip", NULL); perror_msg_and_die("Can't execute '%s'", "gzip"); } close(pipe_from_parent_to_child[0]); /* If child died (say, in xopen), then parent might get SIGPIPE. * We want to properly unlock dd, therefore we must not die on SIGPIPE: */ signal(SIGPIPE, SIG_IGN); /* Create tar writer object */ if (tar_fdopen(&tar, pipe_from_parent_to_child[1], tempfile, /*fileops:(standard)*/ NULL, O_WRONLY | O_CREAT, 0644, TAR_GNU) != 0) { errmsg = "Can't create temporary file in "LARGE_DATA_TMP_DIR; goto ret; } /* Write data to the tarball */ { string_vector_ptr_t exclude_from_report = get_global_always_excluded_elements(); dd_init_next_file(dd); char *short_name, *full_name; while (dd_get_next_file(dd, &short_name, &full_name)) { if (exclude_from_report && is_in_string_list(short_name, (const_string_vector_const_ptr_t)exclude_from_report)) goto next; // dd_get_next_file guarantees that it's a REG: //struct stat stbuf; //if (stat(full_name, &stbuf) != 0) // || !S_ISREG(stbuf.st_mode) //) { // goto next; //} if (tar_append_file(tar, full_name, short_name) != 0) { errmsg = "Can't create temporary file in "LARGE_DATA_TMP_DIR; free(short_name); free(full_name); goto ret; } next: free(short_name); free(full_name); } } dd_close(dd); dd = NULL; /* Close tar writer... */ if (tar_append_eof(tar) != 0 || tar_close(tar) != 0) { errmsg = "Can't create temporary file in "LARGE_DATA_TMP_DIR; goto ret; } tar = NULL; /* ...and check that gzip child finished successfully */ int status; safe_waitpid(child, &status, 0); child = -1; if (status != 0) { /* We assume the error was out-of-disk-space or out-of-quota */ errmsg = "Can't create temporary file in "LARGE_DATA_TMP_DIR; goto ret; } /* Upload the tarball */ /* Upload from /tmp to /tmp + deletion -> BAD, exclude this possibility */ if (url && url[0] && strcmp(url, "file://"LARGE_DATA_TMP_DIR"/") != 0) { post_state_t *state = new_post_state(POST_WANT_ERROR_MSG); state->username = getenv("Upload_Username"); char *password_inp = NULL; if (state->username != NULL && state->username[0] != '\0') { /* Load Password only if Username is configured, it doesn't make */ /* much sense to load Password without Username. */ state->password = getenv("Upload_Password"); if (state->password == NULL) { /* Be permissive and nice, ask only once and don't check */ /* the result. User can dismiss this prompt but the upload */ /* may work somehow??? */ char *msg = xasprintf(_("Please enter password for uploading:"), state->username); state->password = password_inp = ask_password(msg); free(msg); } } char *remote_name = upload_file_ext(state, url, tempfile, UPLOAD_FILE_HANDLE_ACCESS_DENIALS); result = (remote_name == NULL); /* error if NULL */ free(remote_name); free(password_inp); free_post_state(state); /* cleanup code will delete tempfile */ } else { result = 0; /* success */ log(_("Archive is created: '%s'"), tempfile); free(tempfile); tempfile = NULL; } ret: free(url); dd_close(dd); if (tar) tar_close(tar); /* close(pipe_from_parent_to_child[1]); - tar_close() does it itself */ if (child > 0) safe_waitpid(child, NULL, 0); if (tempfile) { unlink(tempfile); free(tempfile); } if (errmsg) error_msg_and_die("%s", errmsg); return result; }
int main(int argc, char** argv) { /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif abrt_init(argv); int parent_pid = getpid(); const char *program_usage_string = _( "& [options]" ); enum { OPT_v = 1 << 0, OPT_d = 1 << 1, OPT_s = 1 << 2, // TODO: get rid of -t NUM, it is no longer useful since dbus is moved to a separate tool OPT_t = 1 << 3, OPT_p = 1 << 4, }; /* Keep enum above and order of options below in sync! */ struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_BOOL( 'd', NULL, NULL , _("Do not daemonize")), OPT_BOOL( 's', NULL, NULL , _("Log to syslog even with -d")), OPT_INTEGER('t', NULL, &s_timeout, _("Exit after NUM seconds of inactivity")), OPT_BOOL( 'p', NULL, NULL , _("Add program names to log")), OPT_END() }; unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); export_abrt_envvars(opts & OPT_p); #if 0 /* We no longer use dbus */ /* When dbus daemon starts us, it doesn't set PATH * (I saw it set only DBUS_STARTER_ADDRESS and DBUS_STARTER_BUS_TYPE). * In this case, set something sane: */ const char *env_path = getenv("PATH"); if (!env_path || !env_path[0]) putenv((char*)"PATH=/usr/sbin:/usr/bin:/sbin:/bin"); #endif unsetenv("ABRT_SYSLOG"); msg_prefix = g_progname; /* for log_warning(), error_msg() and such */ if (getuid() != 0) error_msg_and_die("Must be run as root"); if (opts & OPT_s) start_logging(); xpipe(s_signal_pipe); close_on_exec_on(s_signal_pipe[0]); close_on_exec_on(s_signal_pipe[1]); ndelay_on(s_signal_pipe[0]); /* I/O should not block - */ ndelay_on(s_signal_pipe[1]); /* especially writes! they happen in signal handler! */ signal(SIGTERM, handle_signal); signal(SIGINT, handle_signal); signal(SIGCHLD, handle_signal); GIOChannel* channel_signal = NULL; guint channel_id_signal_event = 0; bool pidfile_created = false; struct abrt_inotify_watch *aiw = NULL; int ret = 1; /* Initialization */ log_notice("Loading settings"); if (load_abrt_conf() != 0) goto init_error; /* Moved before daemonization because parent waits for signal from daemon * only for short period and time consumed by * mark_unprocessed_dump_dirs_not_reportable() is slightly unpredictable. */ sanitize_dump_dir_rights(); mark_unprocessed_dump_dirs_not_reportable(g_settings_dump_location); /* Daemonize unless -d */ if (!(opts & OPT_d)) { /* forking to background */ fflush(NULL); /* paranoia */ pid_t pid = fork(); if (pid < 0) { perror_msg_and_die("fork"); } if (pid > 0) { /* Parent */ /* Wait for child to notify us via SIGTERM that it feels ok */ int i = 20; /* 2 sec */ while (s_sig_caught == 0 && --i) { usleep(100 * 1000); } if (s_sig_caught == SIGTERM) { exit(0); } if (s_sig_caught) { error_msg_and_die("Failed to start: got sig %d", s_sig_caught); } error_msg_and_die("Failed to start: timeout waiting for child"); } /* Child (daemon) continues */ if (setsid() < 0) perror_msg_and_die("setsid"); if (g_verbose == 0 && logmode != LOGMODE_JOURNAL) start_logging(); } log_notice("Creating glib main loop"); s_main_loop = g_main_loop_new(NULL, FALSE); /* Watching 'g_settings_dump_location' for delete self * because hooks expects that the dump location exists if abrtd is running */ aiw = abrt_inotify_watch_init(g_settings_dump_location, IN_DUMP_LOCATION_FLAGS, handle_inotify_cb, /*user data*/NULL); /* Add an event source which waits for INT/TERM signal */ log_notice("Adding signal pipe watch to glib main loop"); channel_signal = abrt_gio_channel_unix_new(s_signal_pipe[0]); channel_id_signal_event = add_watch_or_die(channel_signal, G_IO_IN | G_IO_PRI | G_IO_HUP, handle_signal_cb); guint name_id = 0; /* Mark the territory */ log_notice("Creating pid file"); if (create_pidfile() != 0) goto init_error; pidfile_created = true; /* Open socket to receive new problem data (from python etc). */ dumpsocket_init(); /* Inform parent that we initialized ok */ if (!(opts & OPT_d)) { log_notice("Signalling parent"); kill(parent_pid, SIGTERM); if (logmode != LOGMODE_JOURNAL) start_logging(); } /* Only now we want signal pipe to work */ s_signal_pipe_write = s_signal_pipe[1]; /* Own a name on D-Bus */ name_id = g_bus_own_name(G_BUS_TYPE_SYSTEM, ABRTD_DBUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE, on_bus_acquired, on_name_acquired, on_name_lost, NULL, NULL); start_idle_timeout(); /* Enter the event loop */ log_debug("Init complete, entering main loop"); g_main_loop_run(s_main_loop); ret = 0; /* Jump to exit */ goto cleanup; init_error: /* Initialization error */ error_msg("Error while initializing daemon"); /* Inform parent that initialization failed */ if (!(opts & OPT_d)) kill(parent_pid, SIGINT); cleanup: if (name_id > 0) g_bus_unown_name (name_id); /* Error or INT/TERM. Clean up, in reverse order. * Take care to not undo things we did not do. */ dumpsocket_shutdown(); if (pidfile_created) unlink(VAR_RUN_PIDFILE); if (channel_id_signal_event > 0) g_source_remove(channel_id_signal_event); if (channel_signal) g_io_channel_unref(channel_signal); abrt_inotify_watch_destroy(aiw); if (s_main_loop) g_main_loop_unref(s_main_loop); free_abrt_conf_data(); if (s_sig_caught && s_sig_caught != SIGCHLD) { /* We use TERM to stop abrtd, so not printing out error message. */ if (s_sig_caught != SIGTERM) { error_msg("Got signal %d, exiting", s_sig_caught); signal(s_sig_caught, SIG_DFL); raise(s_sig_caught); } } /* Exiting */ log_notice("Exiting"); return ret; }
int main(int argc, char **argv) { abrt_init(argv); /* I18n */ setlocale(LC_ALL, ""); #if ENABLE_NLS bindtextdomain(PACKAGE, LOCALEDIR); textdomain(PACKAGE); #endif /* without this the name is set to argv[0] which confuses * desktops which uses the name to find the corresponding .desktop file * trac#180 */ gtk_init(&argc, &argv); /* Can't keep these strings/structs static: _() doesn't support that */ const char *program_usage_string = _( "\b [-vp] [DIR]...\n" "\n" "Shows list of ABRT dump directories in specified DIR(s)\n" "(default DIRs: "DEBUG_DUMPS_DIR" $HOME/.abrt/spool)" ); enum { OPT_v = 1 << 0, OPT_p = 1 << 1, }; /* Keep enum above and order of options below in sync! */ struct options program_options[] = { OPT__VERBOSE(&g_verbose), OPT_BOOL( 'p', NULL, NULL , _("Add program names to log")), OPT_END() }; unsigned opts = parse_opts(argc, argv, program_options, program_usage_string); export_abrt_envvars(opts & OPT_p); GtkWidget *main_window = create_main_window(); const char *default_dirs[] = { "/var/spool/abrt", NULL, NULL, }; argv += optind; if (!argv[0]) { char *home = getenv("HOME"); if (home) default_dirs[1] = concat_path_file(home, ".abrt/spool"); argv = (char**)default_dirs; } s_dirs = argv; init_notify(); scan_dirs_and_add_to_dirlist(); gtk_widget_show_all(main_window); sanitize_cursor(NULL); /* Set up signal pipe */ xpipe(s_signal_pipe); close_on_exec_on(s_signal_pipe[0]); close_on_exec_on(s_signal_pipe[1]); ndelay_on(s_signal_pipe[0]); ndelay_on(s_signal_pipe[1]); signal(SIGCHLD, handle_signal); g_io_add_watch(g_io_channel_unix_new(s_signal_pipe[0]), G_IO_IN | G_IO_PRI | G_IO_ERR | G_IO_HUP | G_IO_NVAL, handle_signal_pipe, NULL); /* Enter main loop */ gtk_main(); return 0; }
int sys_exec_info_script (const char **archive_name, int volume_number) { pid_t pid; char *argv[4]; char uintbuf[UINTMAX_STRSIZE_BOUND]; int p[2]; static RETSIGTYPE (*saved_handler) (int sig); xpipe (p); saved_handler = signal (SIGPIPE, SIG_IGN); pid = xfork (); if (pid != 0) { /* Master */ int rc; int status; char *buf = NULL; size_t size = 0; FILE *fp; xclose (p[PWRITE]); fp = fdopen (p[PREAD], "r"); rc = getline (&buf, &size, fp); fclose (fp); if (rc > 0 && buf[rc-1] == '\n') buf[--rc] = 0; while (waitpid (pid, &status, 0) == -1) if (errno != EINTR) { signal (SIGPIPE, saved_handler); waitpid_error (info_script_option); return -1; } signal (SIGPIPE, saved_handler); if (WIFEXITED (status)) { if (WEXITSTATUS (status) == 0 && rc > 0) *archive_name = buf; else free (buf); return WEXITSTATUS (status); } free (buf); return -1; } /* Child */ setenv ("TAR_VERSION", PACKAGE_VERSION, 1); setenv ("TAR_ARCHIVE", *archive_name, 1); setenv ("TAR_VOLUME", STRINGIFY_BIGINT (volume_number, uintbuf), 1); setenv ("TAR_BLOCKING_FACTOR", STRINGIFY_BIGINT (blocking_factor, uintbuf), 1); setenv ("TAR_SUBCOMMAND", subcommand_string (subcommand_option), 1); setenv ("TAR_FORMAT", archive_format_string (current_format == DEFAULT_FORMAT ? archive_format : current_format), 1); setenv ("TAR_FD", STRINGIFY_BIGINT (p[PWRITE], uintbuf), 1); xclose (p[PREAD]); argv[0] = "/bin/sh"; argv[1] = "-c"; argv[2] = (char*) info_script_option; argv[3] = NULL; execv (argv[0], argv); exec_fatal (info_script_option); }
int open_input_file(void) { int fd, ret; struct stat stat_buf; if (!strncmp(opts.infile, "-", 1)) { return STDIN_FILENO; } /* We don't want to read from a regular file ** rather we want to execute a program and take ** this output as our data source. */ if (opts.execstring) { pid_t pid; int pipefd[2]; xpipe(pipefd); switch (pid = fork()) { case -1: err_sys_die(EXIT_FAILMISC, "Can't fork"); case 0: close(STDOUT_FILENO); close(STDERR_FILENO); close(pipefd[0]); dup(pipefd[1]); dup(pipefd[1]); system(opts.execstring); exit(0); break; default: close(pipefd[1]); return pipefd[0]; break; } } /* Thats the normal case: we open a regular file and take ** the content as our source. */ ret = stat(opts.infile, &stat_buf); if (ret == -1) err_sys_die(EXIT_FAILMISC, "Can't stat file %s", opts.infile); #if 0 if (!(stat_buf.st_mode & S_IFREG)) { err_sys("Not an regular file %s", opts.infile); exit(EXIT_FAILOPT); } #endif #ifdef O_NOATIME fd = open(opts.infile, O_RDONLY|O_NOATIME); #else fd = open(opts.infile, O_RDONLY); #endif if (fd == -1) err_msg_die(EXIT_FAILMISC, "Can't open input file: %s", opts.infile); return fd; }
static void fork_dvips(char **argv, struct save_or_print_info *info, childProcT proc) { int print_io[2]; int i; struct file_info *finfo = info->finfo; /* printlog_append(argv[0], strlen(argv[0])); */ FILE *fout = NULL; if (info->act == FILE_SAVE || info->print_target == TO_FILE) { /* printing to PS file, open file for writing */ const char *out_file; if (info->print_target == TO_FILE || info->fmt == FMT_PS) out_file = finfo->out_file; else out_file = finfo->tmp_ps_file; if ((fout = XFOPEN(out_file, "w")) == NULL) { popup_message(globals.widgets.top_level, MSG_ERR, NULL, "Could not open %s for writing: %s.", out_file, strerror(errno)); return; } } printlog_popup(info); printlog_append_str(info, "Calling: `"); printlog_append_str(info, argv[0]); for (i = 1; argv[i] != NULL; i++) { printlog_append_str(info, " "); printlog_append_str(info, argv[i]); } printlog_append_str(info, "'\n"); if (xpipe(print_io) != 0) { perror("[xdvi] pipe"); return; } /* Fork process */ /* flush output buffers to avoid double buffering (i.e. data waiting in the output buffer being written twice, by the parent and the child) */ fflush(stderr); fflush(stdout); print_child.name = xstrdup(argv[0]); print_child.proc = proc; print_child.data = info; print_child.pid = fork(); if (print_child.pid == 0) { /* if child */ /* change into dir of DVI file so that included image files etc. are found */ (void)chdir(globals.dvi_file.dirname); /* make the input file pointer the STDIN of the dvips process */ if (info->page_selection == PAGE_MARKED) { /* printing selected pages from temporary file */ ASSERT(finfo->tmp_dvi_fp != NULL, "tmp fp mustn't be NULL!"); (void)dup2(fileno(finfo->tmp_dvi_fp), STDIN_FILENO); } else { /* printing from main or backup file */ (void)dup2(fileno(finfo->in_fp), STDIN_FILENO); } (void)lseek(0, 0, SEEK_SET); if (fout != NULL) { /* printing to file, make stdout of child go to fout */ (void)dup2(fileno(fout), STDOUT_FILENO); (void)close(fileno(fout)); } else { /* printing to printer, make stdout of child go to print_io[1] */ (void)dup2(print_io[1], STDOUT_FILENO); } /* make stderr of child go to print_io[1] */ (void)dup2(print_io[1], STDERR_FILENO); (void)close(print_io[1]); (void)close(print_io[0]); if (setsid() == -1) { /* so we can kill the process group */ perror("setsid"); fflush(stderr); _exit(1); } (void)execvp(*argv, argv); popup_message(globals.widgets.top_level, MSG_ERR, NULL, "Execution of \"%s\" failed: %s.\n", *argv, strerror(errno)); fflush(stderr); _exit(1); } if (fout != NULL) fclose(fout); if (print_child.pid == -1) { /* error */ perror("[xdvi] vfork"); return; } set_chld(&print_child); dvips_sig = SIGINT; (void)close(print_io[1]); /* Set up file descriptor for non-blocking I/O */ prep_fd(print_io[0], True); print_xio.fd = print_io[0]; print_xio.data = info; set_io(&print_xio); dvips_status = DVIPS_STAT_RUN; /* running */ }
int main(int argc, char *argv[]) { const char*filename = "jtest.caf"; const char*myname=argv[0]; observe_signals (); struct recorder d; ambix_matrix_t*matrix=NULL; int32_t order = -1; d.buffer_frames = 4096; d.minimal_frames = 32; d.channels = 2; d.timer_seconds = -1.0; d.timer_counter = 0; d.sample_format = AMBIX_SAMPLEFORMAT_FLOAT32; d.file_format = AMBIX_BASIC; int c; while((c = getopt(argc, argv, "hVx:X:O:b:fhm:n:t:")) != -1) { switch(c) { case 'x': d.e_channels = (int) strtol(optarg, NULL, 0); d.file_format = AMBIX_EXTENDED; break; case 'X': matrix=matrix_read(optarg, matrix); if(!matrix) { eprintf("%s: couldn't read matrix-file '%s'\n", myname, optarg); FAILURE; } d.file_format = AMBIX_EXTENDED; break; case 'O': order = (uint32_t) strtol(optarg, NULL, 0); break; case 'b': d.buffer_frames = (int) strtol(optarg, NULL, 0); break; #if 0 case 'f': d.file_format = (int) strtol(optarg, NULL, 0); break; #endif case 'V': version (myname); break; case 'h': usage (myname); break; case 'm': d.minimal_frames = (int) strtol(optarg, NULL, 0); break; case 't': d.timer_seconds = (float) strtod(optarg, NULL); break; default: eprintf("%s: illegal option, %c\n", myname, c); usage (myname); break; } } if(optind == argc - 1) { filename=argv[optind]; } else { eprintf("opening default file '%s'\n", filename); //usage (myname); } /* Allocate channel based data. */ if(matrix) { if(order<0) { d.a_channels = matrix->cols; } else { if(ambix_order2channels(order) != matrix->rows) { eprintf("%s: ambisonics order:%d cannot use [%dx%d] adaptor matrix.\n", myname, order, matrix->rows, matrix->cols); FAILURE; } d.a_channels = matrix->cols; } } else { if(order<0) order=1; d.a_channels=ambix_order2channels(order); } switch(d.file_format) { case AMBIX_BASIC: //d.a_channels; d.e_channels=0; break; case AMBIX_EXTENDED: //d.a_channels; //d.e_channels; break; case AMBIX_NONE: default: d.a_channels=0; //d.e_channels; } d.channels = d.a_channels+d.e_channels; if(d.channels < 1) { eprintf("%s: illegal number of channels: %d\n", myname, d.channels); FAILURE; } d.in = (float**)xmalloc(d.channels * sizeof(float *)); d.input_port = (jack_port_t**)xmalloc(d.channels * sizeof(jack_port_t *)); /* Connect to JACK. */ jack_client_t *client = jack_client_unique_("ambix-jrecord"); jack_set_error_function(jack_client_minimal_error_handler); jack_on_shutdown(client, jack_client_minimal_shutdown_handler, 0); jack_set_process_callback(client, process, &d); d.sample_rate = jack_get_sample_rate(client); /* Setup timer. */ if(d.timer_seconds < 0.0) { d.timer_frames = -1; } else { d.timer_frames = d.timer_seconds * d.sample_rate; } /* Create sound file. */ ambix_info_t sfinfo; memset(&sfinfo, 0, sizeof(sfinfo)); sfinfo.samplerate = (int) d.sample_rate; sfinfo.frames = 0; sfinfo.fileformat = d.file_format; sfinfo.ambichannels = d.a_channels; sfinfo.extrachannels = d.e_channels; d.sound_file = ambix_open(filename, AMBIX_WRITE, &sfinfo); if(matrix) { ambix_err_t aerr = ambix_set_adaptormatrix(d.sound_file, matrix); if(AMBIX_ERR_SUCCESS != aerr) { eprintf("setting [%dx%d] matrix returned %d.\n", matrix->rows, matrix->cols, aerr); FAILURE; } } /* Allocate buffers. */ d.buffer_samples = d.buffer_frames * d.channels; d.buffer_bytes = d.buffer_samples * sizeof(float); d.a_buffer = (float32_t*)xmalloc(d.buffer_frames * d.a_channels * sizeof(float32_t)); d.e_buffer = (float32_t*)xmalloc(d.buffer_frames * d.e_channels * sizeof(float32_t)); d.d_buffer = (float*)xmalloc(d.buffer_bytes); d.j_buffer = (float*)xmalloc(d.buffer_bytes); d.u_buffer = (float*)xmalloc(d.buffer_bytes); d.ring_buffer = jack_ringbuffer_create(d.buffer_bytes); /* Create communication pipe. */ xpipe(d.pipe); /* Start disk thread. */ pthread_create (&(d.disk_thread), NULL, disk_thread_procedure, &d); /* Create input ports and activate client. */ #if 0 jack_port_make_standard(client, d.input_port, d.channels, false); jack_client_activate(client); #else do { int i=0, a, e; const char*format=(sfinfo.fileformat == AMBIX_BASIC)?"ACN_%d":"ambisonics_%d"; const int a_offset=(sfinfo.fileformat == AMBIX_BASIC)?0:1; for(a=0; a<d.a_channels; a++) { d.input_port[i] = _jack_port_register(client, JackPortIsInput, format, a+a_offset); i++; } for(e=0; e<d.e_channels; e++) { d.input_port[i] = _jack_port_register(client, JackPortIsInput, "in_%d", e+1); i++; } } while(0); if(jack_activate(client)) { eprintf("jack_activate() failed\n"); FAILURE; } #endif /* Wait for disk thread to end, which it does when it reaches the end of the file or is interrupted. */ pthread_join(d.disk_thread, NULL); /* Close sound file, free ring buffer, close JACK connection, close pipe, free data buffers, indicate success. */ jack_client_close(client); ambix_close(d.sound_file); jack_ringbuffer_free(d.ring_buffer); close(d.pipe[0]); close(d.pipe[1]); free(d.a_buffer); free(d.e_buffer); free(d.d_buffer); free(d.j_buffer); free(d.u_buffer); free(d.in); free(d.input_port); if(matrix)ambix_matrix_destroy(matrix); return EXIT_SUCCESS; }
/* Returns pid */ pid_t fork_execv_on_steroids(int flags, char **argv, int *pipefds, char **env_vec, const char *dir, uid_t uid) { pid_t child; /* Reminder: [0] is read end, [1] is write end */ int pipe_to_child[2]; int pipe_fm_child[2]; /* Sanitize flags */ if (!pipefds) flags &= ~(EXECFLG_INPUT | EXECFLG_OUTPUT); if (flags & EXECFLG_INPUT) xpipe(pipe_to_child); if (flags & EXECFLG_OUTPUT) xpipe(pipe_fm_child); fflush(NULL); child = fork(); if (child == -1) { perror_msg_and_die("fork"); } if (child == 0) { /* Child */ if (dir) xchdir(dir); if (flags & EXECFLG_SETGUID) { struct passwd* pw = getpwuid(uid); gid_t gid = pw ? pw->pw_gid : uid; setgroups(1, &gid); xsetregid(gid, gid); xsetreuid(uid, uid); } if (env_vec) { /* Note: we use the glibc extension that putenv("var") * *unsets* $var if "var" string has no '=' */ while (*env_vec) putenv(*env_vec++); } /* Play with stdio descriptors */ if (flags & EXECFLG_INPUT) { xmove_fd(pipe_to_child[0], STDIN_FILENO); close(pipe_to_child[1]); } else if (flags & EXECFLG_INPUT_NUL) { xmove_fd(xopen("/dev/null", O_RDWR), STDIN_FILENO); } if (flags & EXECFLG_OUTPUT) { xmove_fd(pipe_fm_child[1], STDOUT_FILENO); close(pipe_fm_child[0]); } else if (flags & EXECFLG_OUTPUT_NUL) { xmove_fd(xopen("/dev/null", O_RDWR), STDOUT_FILENO); } /* This should be done BEFORE stderr redirect */ VERB1 { char *r = concat_str_vector(argv); log("Executing: %s", r); free(r); } if (flags & EXECFLG_ERR2OUT) { /* Want parent to see errors in the same stream */ xdup2(STDOUT_FILENO, STDERR_FILENO); } else if (flags & EXECFLG_ERR_NUL) { xmove_fd(xopen("/dev/null", O_RDWR), STDERR_FILENO); } if (flags & EXECFLG_SETSID) setsid(); execvp(argv[0], argv); if (!(flags & EXECFLG_QUIET)) perror_msg("Can't execute '%s'", argv[0]); exit(127); /* shell uses this exit code in this case */ } if (flags & EXECFLG_INPUT) { close(pipe_to_child[0]); pipefds[1] = pipe_to_child[1]; } if (flags & EXECFLG_OUTPUT) { close(pipe_fm_child[1]); pipefds[0] = pipe_fm_child[0]; } return child; }
/* Set ARCHIVE for writing, then compressing an archive. */ pid_t sys_child_open_for_compress (void) { int parent_pipe[2]; int child_pipe[2]; pid_t grandchild_pid; pid_t child_pid; xpipe (parent_pipe); child_pid = xfork (); if (child_pid > 0) { /* The parent tar is still here! Just clean up. */ archive = parent_pipe[PWRITE]; xclose (parent_pipe[PREAD]); return child_pid; } /* The new born child tar is here! */ set_program_name (_("tar (child)")); signal (SIGPIPE, SIG_DFL); xdup2 (parent_pipe[PREAD], STDIN_FILENO); xclose (parent_pipe[PWRITE]); /* Check if we need a grandchild tar. This happens only if either: a) the file is to be accessed by rmt: compressor doesn't know how; b) the file is not a plain file. */ if (!_remdev (archive_name_array[0]) && is_regular_file (archive_name_array[0])) { if (backup_option) maybe_backup_file (archive_name_array[0], 1); /* We don't need a grandchild tar. Open the archive and launch the compressor. */ if (strcmp (archive_name_array[0], "-")) { archive = creat (archive_name_array[0], MODE_RW); if (archive < 0) { int saved_errno = errno; if (backup_option) undo_last_backup (); errno = saved_errno; open_fatal (archive_name_array[0]); } xdup2 (archive, STDOUT_FILENO); } execlp (use_compress_program_option, use_compress_program_option, NULL); exec_fatal (use_compress_program_option); } /* We do need a grandchild tar. */ xpipe (child_pipe); grandchild_pid = xfork (); if (grandchild_pid == 0) { /* The newborn grandchild tar is here! Launch the compressor. */ set_program_name (_("tar (grandchild)")); xdup2 (child_pipe[PWRITE], STDOUT_FILENO); xclose (child_pipe[PREAD]); execlp (use_compress_program_option, use_compress_program_option, (char *) 0); exec_fatal (use_compress_program_option); } /* The child tar is still here! */ /* Prepare for reblocking the data from the compressor into the archive. */ xdup2 (child_pipe[PREAD], STDIN_FILENO); xclose (child_pipe[PWRITE]); if (strcmp (archive_name_array[0], "-") == 0) archive = STDOUT_FILENO; else { archive = rmtcreat (archive_name_array[0], MODE_RW, rsh_command_option); if (archive < 0) open_fatal (archive_name_array[0]); } /* Let's read out of the stdin pipe and write an archive. */ while (1) { size_t status = 0; char *cursor; size_t length; /* Assemble a record. */ for (length = 0, cursor = record_start->buffer; length < record_size; length += status, cursor += status) { size_t size = record_size - length; status = safe_read (STDIN_FILENO, cursor, size); if (status == SAFE_READ_ERROR) read_fatal (use_compress_program_option); if (status == 0) break; } /* Copy the record. */ if (status == 0) { /* We hit the end of the file. Write last record at full length, as the only role of the grandchild is doing proper reblocking. */ if (length > 0) { memset (record_start->buffer + length, 0, record_size - length); status = sys_write_archive_buffer (); if (status != record_size) archive_write_error (status); } /* There is nothing else to read, break out. */ break; } status = sys_write_archive_buffer (); if (status != record_size) archive_write_error (status); } wait_for_grandchild (grandchild_pid); }