/* * Generic implementation of background process infrastructure. */ #include "sub-process.h" #include "sigchain.h" #include "pkt-line.h" int cmd2process_cmp(const struct subprocess_entry *e1, const struct subprocess_entry *e2, const void *unused) { return strcmp(e1->cmd, e2->cmd); } struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const char *cmd) { struct subprocess_entry key; hashmap_entry_init(&key, strhash(cmd)); key.cmd = cmd; return hashmap_get(hashmap, &key, NULL); } int subprocess_read_status(int fd, struct strbuf *status) { struct strbuf **pair; char *line; int len; for (;;) { len = packet_read_line_gently(fd, NULL, &line); if ((len < 0) || !line) break; pair = strbuf_split_str(line, '=', 2); if (pair[0] && pair[0]->len && pair[1]) { /* the last "status=" line wins */ if (!strcmp(pair[0]->buf, "status=")) { strbuf_reset(status); strbuf_addbuf(status, pair[1]); } } strbuf_list_free(pair); } return (len < 0) ? len : 0; } void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry) { if (!entry) return; entry->process.clean_on_exit = 0; kill(entry->process.pid, SIGTERM); finish_command(&entry->process); hashmap_remove(hashmap, entry, NULL); } static void subprocess_exit_handler(struct child_process *process) { sigchain_push(SIGPIPE, SIG_IGN); /* Closing the pipe signals the subprocess to initiate a shutdown. */ close(process->in); close(process->out); sigchain_pop(SIGPIPE); /* Finish command will wait until the shutdown is complete. */ finish_command(process); } int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd, subprocess_start_fn startfn) { int err; struct child_process *process; const char *argv[] = { cmd, NULL }; entry->cmd = cmd; process = &entry->process; child_process_init(process); process->argv = argv; process->use_shell = 1; process->in = -1; process->out = -1; process->clean_on_exit = 1; process->clean_on_exit_handler = subprocess_exit_handler; err = start_command(process); if (err) { error("cannot fork to run subprocess '%s'", cmd); return err; } hashmap_entry_init(entry, strhash(cmd)); err = startfn(entry); if (err) { error("initialization for subprocess '%s' failed", cmd); subprocess_stop(hashmap, entry); return err; } hashmap_add(hashmap, entry); return 0; }