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