Logo Search packages:      
Sourcecode: mswatch version File versions  Download package

inputkill.c

#include <assert.h>
#include <errno.h>
#include <glib.h>
#include <libgen.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#include "compat.h"
#include "lib/util.h"

static void signal_child(int ignore)
{
      pid_t child;
      int status;
      int v;
      (void) ignore;

      child = wait(&status);
      assert(child > 0);

      if (WIFEXITED(status))
            v = WEXITSTATUS(status);
      else
            v = 1;

      exit(v);
}

static void configure_inputkill(int argc, char** argv, char*** child_command)
{
      gboolean version = 0;
      GOptionContext* ctx;
      GError* gerror = NULL;
      gboolean r;

      GOptionEntry options[] =
      {
            { "version", 'V', 0, G_OPTION_ARG_NONE, &version,
              "Display version", NULL },
            { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_STRING_ARRAY, child_command,
              "Command to run", NULL },
            { NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
      };

      ctx = g_option_context_new("<PROGRAM> [ARGUMENT...]\n\t- run PROGRAM until stdin is closed");
      g_option_context_add_main_entries(ctx, options, NULL);
      r = g_option_context_parse(ctx, &argc, &argv, &gerror);
      if (r == FALSE)
      {
            GQuark error = G_OPTION_ERROR;
            assert(error == G_OPTION_ERROR_BAD_VALUE);
            fprintf(stderr, "%s\n", gerror->message);
            g_error_free(gerror);
            exit(1);
      }
      assert(!gerror);
      g_option_context_free(ctx);
      ctx = NULL;

      if (version)
      {
            printf("inputkill\n");
            printf(PACKAGE " " VERSION "\n");
            exit(1);
      }

      if (!child_command || !*child_command)
      {
            fprintf(stderr, "No child command arguments. Use -? or --help for help.\n");
            exit(1);
      }
}

int main(int argc, char** argv)
{
      char** child_command = NULL;
      pid_t child;
      // 'buf' need hold only a single char, but make it larger so that reading
      // into it is not inefficient if we must read lots of data
      char buf[1024];
      int r;

      configure_inputkill(argc, argv, &child_command);

      if (set_signal_handler(SIGCHLD, signal_child) < 0)
            exit(1);

      if (!(child = fork()))
      {
            if (close(STDIN_FILENO) < 0)
            {
                  error("%s: close(STDIN_FILENO)", argv[0]);
                  exit(1);
            }
                  
            execvp(child_command[0], &child_command[0]);
            error("%s: Unable to execute \"%s\"", argv[0], child_command[0]);
            exit(1);
      }
      die_if(child < 0, "%s: fork()", argv[0]);

      // we won't use stdout, so close it
      (void) close(STDOUT_FILENO);

      // stdin EOF means it is time to exit and tell child to exit
      do
            r = TEMP_FAILURE_RETRY(read(STDIN_FILENO, &buf, sizeof(buf)));
      while (r > 0 || (r == -1 && errno == -EAGAIN));

      r = kill(child, SIGTERM);
      die_if(r < 0, "%s: Unable to kill %d (%s)", argv[0], child, argv[1]);

      // Wait for exit? Or wait for a bit, then SIGKILL? But for how long?
      // And then wait for exit? ...
      // For now at least, take the simple road and just assume child
      // gets the idea that it is time to exit.
      
      return 0;
}

Generated by  Doxygen 1.6.0   Back to index