1/* 2 * fork_program.c 3 * kext_tools 4 * 5 * Created by nik on 5/11/08. 6 * Copyright 2008 __MyCompanyName__. All rights reserved. 7 * 8 */ 9 10#include "fork_program.h" 11#include "kext_tools_util.h" 12#include <spawn.h> 13#include <sys/wait.h> 14#include <libc.h> 15#include <crt_externs.h> 16 17/******************************************************************************* 18* Fork a process after a specified delay, and either wait on it to exit or 19* leave it to run in the background. 20* 21* Returns -2 on spawn() failure, -1 on other failure, and depending on wait: 22* wait: true - exit status of forked program 23* wait: false - pid of background process 24*******************************************************************************/ 25int fork_program(const char * argv0, char * const argv[], Boolean wait) 26{ 27 int result; 28 int spawn_result; 29 pid_t child_pid; 30 int child_status; 31 int normal_iopolicy = getiopolicy_np(IOPOL_TYPE_DISK, 32 IOPOL_SCOPE_PROCESS); 33 char ** environ = *(_NSGetEnviron()); 34 35 if (!wait) { 36 setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE); 37 } 38 39 spawn_result = posix_spawn(&child_pid, argv0, /* file_actions */ NULL, 40 /* spawnattrs */ NULL, argv, environ); 41 42 // If we couldn't spawn the process, return -2 with errno for detail 43 if (spawn_result != 0) { 44 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel, 45 "posix_spawn failed for %s.", argv0); 46 errno = spawn_result; 47 result = -2; 48 goto finish; 49 } 50 51 OSKextLog(/* kext */ NULL, kOSKextLogDetailLevel, 52 "started child process %s[%d] (%ssynchronous).", 53 argv0, child_pid, wait ? "" : "a"); 54 55 if (wait) { 56 OSKextLogSpec logSpec = kOSKextLogDetailLevel; 57 if (waitpid(child_pid, &child_status, 0) == -1) { 58 result = -1; 59 goto finish; 60 } 61 if (WIFEXITED(child_status)) { 62 result = WEXITSTATUS(child_status); 63 if (result) { 64 logSpec = kOSKextLogErrorLevel; 65 } 66 OSKextLog(/* kext */ NULL, logSpec, 67 "Child process %s[%d] exited with status %d.", 68 argv0, child_pid, result); 69 } else if (WIFSIGNALED(child_status)) { 70 result = WTERMSIG(child_status); 71 logSpec = kOSKextLogErrorLevel; 72 OSKextLog(/* kext */ NULL, logSpec, 73 "Child process %s[%d] exited due to signal %d.", 74 argv0, child_pid, result); 75 } else { 76 // shouldn't be any other types of exit 77 result = -1; 78 } 79 } else { 80 result = child_pid; 81 } 82 83finish: 84 setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, normal_iopolicy); 85 86 return result; 87} 88