Changeset 34132f7 for filterproc.c


Ignore:
Timestamp:
Mar 11, 2012, 10:34:18 PM (11 years ago)
Author:
David Benjamin <davidben@mit.edu>
Branches:
release-1.8
Children:
6a08f16
Parents:
4a80a16
git-author:
David Benjamin <davidben@mit.edu> (01/23/12 00:38:29)
git-committer:
David Benjamin <davidben@mit.edu> (03/11/12 22:34:18)
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

    r4a80a16 r34132f7  
    1010#include <glib.h>
    1111
    12 int send_receive(int rfd, int wfd, const char *out, char **in)
     12/* Even in case of error, send_receive is responsible for closing wfd
     13 * (to EOF the child) and rfd (for consistency). */
     14static int send_receive(int rfd, int wfd, const char *out, char **in)
    1315{
    1416  GString *str = g_string_new("");
     
    2830  if(!out || !*out) {
    2931    /* Nothing to write. Close our end so the child doesn't hang waiting. */
    30     close(wfd);
     32    close(wfd); wfd = -1;
    3133    out = NULL;
    3234  }
     
    5355      }
    5456      if(!out || !*out || fds[1].revents & (POLLERR | POLLHUP)) {
    55         close(wfd);
     57        close(wfd); wfd = -1;
    5658        out = NULL;
    5759      }
     
    6971  }
    7072
     73  if (wfd >= 0) close(wfd);
     74  close(rfd);
    7175  *in = g_string_free(str, err < 0);
    7276  return err;
    7377}
    7478
    75 int call_filter(const char *prog, const char *const *argv, const char *in, char **out, int *status)
     79int call_filter(const char *const *argv, const char *in, char **out, int *status)
    7680{
    77   int err = 0;
    78   pid_t pid;
    79   int rfd[2];
    80   int wfd[2];
     81  int err;
     82  GPid child_pid;
     83  int child_stdin, child_stdout;
    8184
    82   if((err = pipe(rfd))) goto out;
    83   if((err = pipe(wfd))) goto out_close_rfd;
    84 
    85   pid = fork();
    86   if(pid < 0) {
    87     err = pid;
    88     goto out_close_all;
    89   }
    90   if(pid) {
    91     /* parent */
    92     close(rfd[1]);
    93     close(wfd[0]);
    94     err = send_receive(rfd[0], wfd[1], in, out);
    95     if(err == 0) {
    96       waitpid(pid, status, 0);
    97     }
    98   } else {
    99     /* child */
    100     close(rfd[0]);
    101     close(wfd[1]);
    102     dup2(rfd[1], 1);
    103     dup2(wfd[0], 0);
    104     close(rfd[1]);
    105     close(wfd[0]);
    106 
    107     if(execvp(prog, (char *const *)argv)) {
    108       _exit(-1);
    109     }
     85  if (!g_spawn_async_with_pipes(NULL, (char**)argv, NULL,
     86                                G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
     87                                NULL, NULL,
     88                                &child_pid, &child_stdin, &child_stdout, NULL,
     89                                NULL)) {
     90    return 1;
    11091  }
    11192
    112  out_close_all:
    113   close(wfd[0]);
    114   close(wfd[1]);
    115  out_close_rfd:
    116   close(rfd[0]);
    117   close(rfd[1]);
    118  out:
     93  err = send_receive(child_stdout, child_stdin, in, out);
     94  if (err == 0) {
     95    waitpid(child_pid, status, 0);
     96  }
    11997  return err;
    12098}
Note: See TracChangeset for help on using the changeset viewer.