sub-process.con commit RelNotes: mention "log: add -P as a synonym for --perl-regexp" (9902d36)
   1/*
   2 * Generic implementation of background process infrastructure.
   3 */
   4#include "sub-process.h"
   5#include "sigchain.h"
   6#include "pkt-line.h"
   7
   8int cmd2process_cmp(const void *unused_cmp_data,
   9                    const struct subprocess_entry *e1,
  10                    const struct subprocess_entry *e2,
  11                    const void *unused_keydata)
  12{
  13        return strcmp(e1->cmd, e2->cmd);
  14}
  15
  16struct subprocess_entry *subprocess_find_entry(struct hashmap *hashmap, const char *cmd)
  17{
  18        struct subprocess_entry key;
  19
  20        hashmap_entry_init(&key, strhash(cmd));
  21        key.cmd = cmd;
  22        return hashmap_get(hashmap, &key, NULL);
  23}
  24
  25int subprocess_read_status(int fd, struct strbuf *status)
  26{
  27        struct strbuf **pair;
  28        char *line;
  29        int len;
  30
  31        for (;;) {
  32                len = packet_read_line_gently(fd, NULL, &line);
  33                if ((len < 0) || !line)
  34                        break;
  35                pair = strbuf_split_str(line, '=', 2);
  36                if (pair[0] && pair[0]->len && pair[1]) {
  37                        /* the last "status=<foo>" line wins */
  38                        if (!strcmp(pair[0]->buf, "status=")) {
  39                                strbuf_reset(status);
  40                                strbuf_addbuf(status, pair[1]);
  41                        }
  42                }
  43                strbuf_list_free(pair);
  44        }
  45
  46        return (len < 0) ? len : 0;
  47}
  48
  49void subprocess_stop(struct hashmap *hashmap, struct subprocess_entry *entry)
  50{
  51        if (!entry)
  52                return;
  53
  54        entry->process.clean_on_exit = 0;
  55        kill(entry->process.pid, SIGTERM);
  56        finish_command(&entry->process);
  57
  58        hashmap_remove(hashmap, entry, NULL);
  59}
  60
  61static void subprocess_exit_handler(struct child_process *process)
  62{
  63        sigchain_push(SIGPIPE, SIG_IGN);
  64        /* Closing the pipe signals the subprocess to initiate a shutdown. */
  65        close(process->in);
  66        close(process->out);
  67        sigchain_pop(SIGPIPE);
  68        /* Finish command will wait until the shutdown is complete. */
  69        finish_command(process);
  70}
  71
  72int subprocess_start(struct hashmap *hashmap, struct subprocess_entry *entry, const char *cmd,
  73        subprocess_start_fn startfn)
  74{
  75        int err;
  76        struct child_process *process;
  77        const char *argv[] = { cmd, NULL };
  78
  79        entry->cmd = cmd;
  80        process = &entry->process;
  81
  82        child_process_init(process);
  83        process->argv = argv;
  84        process->use_shell = 1;
  85        process->in = -1;
  86        process->out = -1;
  87        process->clean_on_exit = 1;
  88        process->clean_on_exit_handler = subprocess_exit_handler;
  89
  90        err = start_command(process);
  91        if (err) {
  92                error("cannot fork to run subprocess '%s'", cmd);
  93                return err;
  94        }
  95
  96        hashmap_entry_init(entry, strhash(cmd));
  97
  98        err = startfn(entry);
  99        if (err) {
 100                error("initialization for subprocess '%s' failed", cmd);
 101                subprocess_stop(hashmap, entry);
 102                return err;
 103        }
 104
 105        hashmap_add(hashmap, entry);
 106        return 0;
 107}