Exemple #1
0
int decode_command_call_into_process(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[], process_t **ptr)
{
    // Instantiate a new process
    if (pm_new_process(ptr))
        return -1;

    process_t *process = *ptr;
    const ERL_NIF_TERM* big_tuple;
    int arity = 2;
    // Get the outer tuple
    if(!enif_get_tuple(env, argv[0], &arity, &big_tuple)) return -1;

    // The first command is a string
    char command[MAX_BUFFER_SZ], key[MAX_BUFFER_SZ], value[MAX_BUFFER_SZ];
    memset(&command, '\0', sizeof(command));

    // Get the command
    if (enif_get_string(env, big_tuple[0], command, sizeof(command), ERL_NIF_LATIN1) < 0) return -1;
    pm_malloc_and_set_attribute(&process->command, command);

    // The second element of the tuple is a list of options
    const ERL_NIF_TERM* tuple;
    ERL_NIF_TERM head, tail, list = big_tuple[1];

    // int enif_get_tuple(ErlNifEnv* env, ERL_NIF_TERM term, int* arity, const ERL_NIF_TERM** array)
    while(enif_get_list_cell(env, list, &head, &tail)) {
        // Get the tuple
        if(!enif_get_tuple(env, head, &arity, &tuple)) return -1;
        // First element is an atom
        if (!enif_get_atom(env, tuple[0], key, sizeof(key))) return -2;
        if (enif_get_string(env, tuple[1], value, sizeof(value), ERL_NIF_LATIN1) < 0) return -3;
        if (!strcmp(key, "do_before")) {
            // Do before
            pm_malloc_and_set_attribute(&process->before, value);
        } else if (!strcmp(key, "do_after")) {
            pm_malloc_and_set_attribute(&process->after, value);
        } else if (!strcmp(key, "cd")) {
            pm_malloc_and_set_attribute(&process->cd, value);
        } else if (!strcmp(key, "env")) {
            pm_add_env(&process, value);
        } else if (!strcmp(key, "nice")) {
            process->nice = atoi(value);
        }
        list = tail;
    }
    return 0;
}
process_return_t* pm_run_and_spawn_process(process_t *process)
{
  process_return_t* ret = pm_new_process_return();
  // Setup the stdin
  int child_stdin; 
  if (ret == NULL) return NULL;
  // make a pidfile
  char pidfile[] = "/tmp/babysitter.XXXXXXXXX";
  int pid_file_fd;
  if ((pid_file_fd = mkstemp(pidfile)) < 0) {perror("pidfile");}
  
  // char *pidfile = tmpname(strdup("/tmp/babysitter.pidfile.XXXXXXXXX"));
  char *pidfile_env = (char*) calloc(1, sizeof(char)*(strlen(pidfile) + 10));
  strncpy(pidfile_env, "PID_FILE=", 10);
  strncat(pidfile_env, pidfile, 33);
  
    // Add the pidfile to the run
  pm_add_env(&process, pidfile_env);
  // new_process_return
  if (process->env) process->env[process->env_c] = NULL;
  
  // Run afterhook
  if (process->before) {
    if (run_hook(BEFORE_HOOK, process, ret)) {
      unlink(pidfile);
      return ret;
    }
  }
  
  ret->stage = PRS_COMMAND;
  ret->pid = pm_execute(0,  (const char*)process->command, 
                            (const char*)process->cd, 
                            (int)process->nice, 
                            (const char**)process->env, 
                            &child_stdin,
                            (const char*)process->stdout, (const char*)process->stderr);
                          
  pid_t pid_from_pidfile;
  // If the program wrote to the pidfile, we'll want to use that instead, so check
  if (( pid_from_pidfile = (pid_t)get_pid_from_file_or_retry(pidfile, 5)) > 0) {
    ret->pid = pid_from_pidfile;
  };
  
  close(pid_file_fd);
  unlink(pidfile); // Clean up after ourselves
  
  if (errno) {
    if (process->stdout) ret->stdout = read_from_file((const char*)process->stdout);
    
    if (process->stderr) {
      ret->stderr = read_from_file((const char*)process->stderr);
    } else {
      ret->stderr = (char*)calloc(1, sizeof(char)*strlen(strerror(errno)));
      strncpy(ret->stderr, strerror(errno), strlen(strerror(errno)));
    }
  }
  
  if (ret->pid < 0) {
    return ret;
  }
  
  ret->exit_status = wait_for_pid(ret->pid, WNOHANG);
  if (ret->exit_status) {
    // printf("command: %s pid: %d exit_status: %d - %s / %s\n", process->command, ret->pid, ret->exit_status, ret->stdout, ret->stderr);
    return ret;
  }
  
  // Run afterhook
  if (process->after) {
    if (run_hook(AFTER_HOOK, process, ret)) return ret;
  }

  // Yay, we finished properly
  ret->stage = PRS_OKAY;
  process_struct *ps = (process_struct *) calloc(1, sizeof(process_struct));
  ps->pid = ret->pid;
#if USE_PIPES
  ps->stdin = child_stdin;
#endif
  ps->transId = process->transId;
  HASH_ADD_INT(running_children, pid, ps);
  
  return ret;
}