Admin/bash_process/bash_process.c
author wenzelm
Tue, 25 Oct 2016 17:22:05 +0200
changeset 64398 5076725247fa
parent 62575 590df5f4e531
child 73599 981df2e1f646
permissions -rw-r--r--
more robust printing of names in the context of outer syntax;

/*  Author:     Makarius

Bash process with separate process group id.
*/

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

static void fail(const char *msg)
{
  fprintf(stderr, "%s\n", msg);
  fflush(stderr);
  exit(2);
}

static time_t now()
{
  struct timeval tv;
  if (gettimeofday(&tv, NULL) == 0) {
    return tv.tv_sec * 1000 + tv.tv_usec / 1000;
  }
  else {
    return time(NULL) * 1000;
  }
}


int main(int argc, char *argv[])
{
  /* args */

  if (argc < 3) {
    fprintf(stderr, "Bad arguments: PID_FILE and TIMING_FILE required\n");
    fflush(stderr);
    exit(1);
  }
  char *pid_name = argv[1];
  char *timing_name = argv[2];


  /* potential fork */

  time_t time_start = now();

  if (strlen(timing_name) > 0 || setsid() == -1) {
    pid_t pid = fork();

    if (pid == -1) fail("Cannot set session id (failed to fork)");
    else if (pid != 0) {
      int status;

      // ingore SIGINT
      struct sigaction sa;
      memset(&sa, 0, sizeof(sa));
      sa.sa_handler = SIG_IGN;
      sigaction(SIGINT, &sa, 0);

      if (waitpid(pid, &status, 0) == -1) {
        fail("Cannot join forked process");
      }

      /* report timing */

      if (strlen(timing_name) > 0) {
        long long timing_elapsed = now() - time_start;

        struct rusage ru;
        getrusage(RUSAGE_CHILDREN, &ru);

        long long timing_cpu =
          ru.ru_utime.tv_sec * 1000 + ru.ru_utime.tv_usec / 1000 +
          ru.ru_stime.tv_sec * 1000 + ru.ru_stime.tv_usec / 1000;

        FILE *timing_file = fopen(timing_name, "w");
        if (timing_file == NULL) fail("Cannot open timing file");
        fprintf(timing_file, "%lld %lld", timing_elapsed, timing_cpu);
        fclose(timing_file);
      }

      if (WIFEXITED(status)) {
        exit(WEXITSTATUS(status));
      }
      else if (WIFSIGNALED(status)) {
        exit(128 + WTERMSIG(status));
      }
      else {
        fail("Unknown status of forked process");
      }
    }
    else if (setsid() == -1) fail("Cannot set session id (after fork)");
  }


  /* report pid */

  if (strcmp(pid_name, "-") == 0) {
    fprintf(stdout, "%d\n", getpid());
    fflush(stdout);
  }
  else if (strlen(pid_name) > 0) {
    FILE *pid_file;
    pid_file = fopen(pid_name, "w");
    if (pid_file == NULL) fail("Cannot open pid file");
    fprintf(pid_file, "%d", getpid());
    fclose(pid_file);
  }


  /* shift command line */

  int i;
  for (i = 3; i < argc; i++) {
    argv[i - 3] = argv[i];
  }
  argv[argc - 3] = NULL;
  argv[argc - 2] = NULL;
  argv[argc - 1] = NULL;


  /* exec */

  execvp("bash", argv);
  fail("Cannot exec process");
}