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 33 34IOPOL_SCOPE_PROCESS); 35 char ** environ = *(_NSGetEnviron()); 36 37#if 0 // spew program and arguments we are forking... 38 if (argv0) { 39 int i; 40 int commandLen = 0; 41 42 OSKextLog(NULL, 43 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 44 "Forking: %s", 45 argv0); 46 for (i = 0; argv[i] != NULL; i++) { 47 commandLen += strlen(argv[i]); 48 commandLen++; 49 } 50 if (commandLen > 0) { 51 char * myCmd = NULL; 52 myCmd = (char *) malloc(commandLen); 53 if (myCmd) { 54 for (i = 0; argv[i] != NULL; i++) { 55 strcat(myCmd, argv[i]); 56 strcat(myCmd, " "); 57 } 58 OSKextLog(NULL, 59 kOSKextLogErrorLevel | kOSKextLogGeneralFlag, 60 "%s ", 61 myCmd); 62 free(myCmd); 63 } 64 } 65 } 66#endif 67 68 if (!wait) { 69 setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE); 70 } 71 72 spawn_result = posix_spawn(&child_pid, argv0, /* file_actions */ NULL, 73 /* spawnattrs */ NULL, argv, environ); 74 75 // If we couldn't spawn the process, return -2 with errno for detail 76 if (spawn_result != 0) { 77 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel, 78 "posix_spawn failed for %s.", argv0); 79 errno = spawn_result; 80 result = -2; 81 goto finish; 82 } 83 84 OSKextLog(/* kext */ NULL, kOSKextLogDetailLevel, 85 "started child process %s[%d] (%ssynchronous).", 86 argv0, child_pid, wait ? "" : "a"); 87 88 if (wait) { 89 OSKextLogSpec logSpec = kOSKextLogDetailLevel; 90 if (waitpid(child_pid, &child_status, 0) == -1) { 91 result = -1; 92 goto finish; 93 } 94 if (WIFEXITED(child_status)) { 95 result = WEXITSTATUS(child_status); 96 if (result) { 97 logSpec = kOSKextLogErrorLevel; 98 } 99 OSKextLog(/* kext */ NULL, logSpec, 100 "Child process %s[%d] exited with status %d.", 101 argv0, child_pid, result); 102 } else if (WIFSIGNALED(child_status)) { 103 result = WTERMSIG(child_status); 104 logSpec = kOSKextLogErrorLevel; 105 OSKextLog(/* kext */ NULL, logSpec, 106 "Child process %s[%d] exited due to signal %d.", 107 argv0, child_pid, result); 108 } else { 109 // shouldn't be any other types of exit 110 result = -1; 111 } 112 } else { 113 result = child_pid; 114 } 115 116finish: 117 setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, normal_iopolicy); 118 119 return result; 120} 121