Changeset 97cdbaf5 for filterproc.c


Ignore:
Timestamp:
Mar 11, 2012, 10:57:35 PM (12 years ago)
Author:
David Benjamin <davidben@mit.edu>
Branches:
master, release-1.10, release-1.9
Children:
a03a409
Parents:
1f39ded
git-author:
David Benjamin <davidben@mit.edu> (01/23/12 00:38:29)
git-committer:
David Benjamin <davidben@mit.edu> (03/11/12 22:57:35)
Message:
Rewrite call_filter to use g_spawn_async_with_pipes

This simplifies the error-handling code. Also fixes a bug where file
descriptors get double-closed in call_filter. Also adds a unit test. The
separate prog argument is removed to avoid having to deal with
G_SPAWN_FILE_AND_ARGV_ZERO, and since we don't really use it anyway.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • filterproc.c

    r1f39ded r97cdbaf5  
    33#include <poll.h>
    44
    5 int send_receive(int rfd, int wfd, const char *out, char **in)
     5/* Even in case of error, send_receive is responsible for closing wfd
     6 * (to EOF the child) and rfd (for consistency). */
     7static int send_receive(int rfd, int wfd, const char *out, char **in)
    68{
    79  GString *str = g_string_new("");
     
    2123  if(!out || !*out) {
    2224    /* Nothing to write. Close our end so the child doesn't hang waiting. */
    23     close(wfd);
     25    close(wfd); wfd = -1;
    2426    out = NULL;
    2527  }
     
    4648      }
    4749      if(!out || !*out || fds[1].revents & (POLLERR | POLLHUP)) {
    48         close(wfd);
     50        close(wfd); wfd = -1;
    4951        out = NULL;
    5052      }
     
    6264  }
    6365
     66  if (wfd >= 0) close(wfd);
     67  close(rfd);
    6468  *in = g_string_free(str, err < 0);
    6569  return err;
    6670}
    6771
    68 int call_filter(const char *prog, const char *const *argv, const char *in, char **out, int *status)
     72int call_filter(const char *const *argv, const char *in, char **out, int *status)
    6973{
    70   int err = 0;
    71   pid_t pid;
    72   int rfd[2];
    73   int wfd[2];
     74  int err;
     75  GPid child_pid;
     76  int child_stdin, child_stdout;
    7477
    75   if((err = pipe(rfd))) goto out;
    76   if((err = pipe(wfd))) goto out_close_rfd;
    77 
    78   pid = fork();
    79   if(pid < 0) {
    80     err = pid;
    81     goto out_close_all;
    82   }
    83   if(pid) {
    84     /* parent */
    85     close(rfd[1]);
    86     close(wfd[0]);
    87     err = send_receive(rfd[0], wfd[1], in, out);
    88     if(err == 0) {
    89       waitpid(pid, status, 0);
    90     }
    91   } else {
    92     /* child */
    93     close(rfd[0]);
    94     close(wfd[1]);
    95     dup2(rfd[1], 1);
    96     dup2(wfd[0], 0);
    97     close(rfd[1]);
    98     close(wfd[0]);
    99 
    100     if(execvp(prog, (char *const *)argv)) {
    101       _exit(-1);
    102     }
     78  if (!g_spawn_async_with_pipes(NULL, (char**)argv, NULL,
     79                                G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
     80                                NULL, NULL,
     81                                &child_pid, &child_stdin, &child_stdout, NULL,
     82                                NULL)) {
     83    return 1;
    10384  }
    10485
    105  out_close_all:
    106   close(wfd[0]);
    107   close(wfd[1]);
    108  out_close_rfd:
    109   close(rfd[0]);
    110   close(rfd[1]);
    111  out:
     86  err = send_receive(child_stdout, child_stdin, in, out);
     87  if (err == 0) {
     88    waitpid(child_pid, status, 0);
     89  }
    11290  return err;
    11391}
Note: See TracChangeset for help on using the changeset viewer.