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; }