int run_process(const char *path, char *argv[], int flags) { pid_t pid; int rc, devnull_fd; char **argp; pid = vfork(); if (pid == 0) { devnull_fd = open("/dev/null", O_WRONLY); if (devnull_fd < 0) _exit(-1); if (!(flags & STDOUT_VERBOSE)) (void) dup2(devnull_fd, STDOUT_FILENO); if (!(flags & STDERR_VERBOSE)) (void) dup2(devnull_fd, STDERR_FILENO); close(devnull_fd); #if 0 { int i; fprintf(stderr, "Running process: "); for (i = 0; argv[i]; i++) fprintf(stderr, "'%s' ", argv[i]); fprintf(stderr, "\r\n"); } #endif setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE); (void) execvp(path, argv); perror(path); _exit(-1); } else if (pid > 0) { int status; while ((rc = waitpid(pid, &status, 0)) == -1 && errno == EINTR); if (rc < 0 || !WIFEXITED(status)) return (-1); return (WEXITSTATUS(status)); } return (-1); }
void Initializer::initDaemon() const { if (FLAGS_config_check) { // No need to daemonize, emit log lines, or create process mutexes. return; } #ifndef __APPLE__ // OS X uses launchd to daemonize. if (osquery::FLAGS_daemonize) { if (daemon(0, 0) == -1) { shutdown(EXIT_FAILURE); } } #endif // Print the version to SYSLOG. syslog( LOG_NOTICE, "%s started [version=%s]", binary_.c_str(), kVersion.c_str()); // Check if /var/osquery exists if ((Flag::isDefault("pidfile") || Flag::isDefault("database_path")) && !isDirectory(OSQUERY_HOME)) { std::cerr << CONFIG_ERROR; } // Create a process mutex around the daemon. auto pid_status = createPidFile(); if (!pid_status.ok()) { LOG(ERROR) << binary_ << " initialize failed: " << pid_status.toString(); shutdown(EXIT_FAILURE); } // Nice ourselves if using a watchdog and the level is not too permissive. if (!FLAGS_disable_watchdog && FLAGS_watchdog_level >= WATCHDOG_LEVEL_DEFAULT && FLAGS_watchdog_level != WATCHDOG_LEVEL_DEBUG) { // Set CPU scheduling I/O limits. setpriority(PRIO_PGRP, 0, 10); #ifdef __linux__ // Using: ioprio_set(IOPRIO_WHO_PGRP, 0, IOPRIO_CLASS_IDLE); syscall(SYS_ioprio_set, IOPRIO_WHO_PGRP, 0, IOPRIO_CLASS_IDLE); #elif defined(__APPLE__) setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE); #endif } }
void Initializer::initDaemon() const { if (FLAGS_config_check) { // No need to daemonize, emit log lines, or create process mutexes. return; } #if !defined(__APPLE__) && !defined(WIN32) // OS X uses launchd to daemonize. if (osquery::FLAGS_daemonize) { if (daemon(0, 0) == -1) { shutdown(EXIT_FAILURE); } } #endif // Print the version to the OS system log. systemLog(binary_ + " started [version=" + kVersion + "]"); if (!FLAGS_ephemeral) { if ((Flag::isDefault("pidfile") || Flag::isDefault("database_path")) && !isDirectory(OSQUERY_HOME)) { std::cerr << CONFIG_ERROR; } // Create a process mutex around the daemon. auto pid_status = createPidFile(); if (!pid_status.ok()) { LOG(ERROR) << binary_ << " initialize failed: " << pid_status.toString(); shutdown(EXIT_FAILURE); } } // Nice ourselves if using a watchdog and the level is not too permissive. if (!FLAGS_disable_watchdog && FLAGS_watchdog_level >= 0) { // Set CPU scheduling I/O limits. setToBackgroundPriority(); #ifdef __linux__ // Using: ioprio_set(IOPRIO_WHO_PGRP, 0, IOPRIO_CLASS_IDLE); syscall(SYS_ioprio_set, IOPRIO_WHO_PGRP, 0, IOPRIO_CLASS_IDLE); #elif defined(__APPLE__) setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE); #endif } }
int main(int argc, char *argv[]) { int c; if (argc < 2) { fprintf(stderr, "Usage: %s <command>\n", argv[0]); exit(EXIT_FAILURE); } while ((c = getopt(argc, argv, "c:")) != -1); argc -= optind; argv += optind; setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE); int err = run_process(argv[0], &argv[0], 0x03); exit (err); }
int main(int argc, char * argv[]) { int ch, ret; bool flagx = false, flagX = false, flagb = false; int flagd = -1, flagg = -1; struct task_qos_policy qosinfo = { LATENCY_QOS_TIER_UNSPECIFIED, THROUGHPUT_QOS_TIER_UNSPECIFIED }; while ((ch = getopt(argc, argv, "xXbd:g:t:l:")) != -1) { switch (ch) { case 'x': flagx = true; break; case 'X': flagX = true; break; case 'b': flagb = true; break; case 'd': flagd = parse_disk_policy(optarg); if (flagd == -1) { warnx("Could not parse '%s' as a disk policy", optarg); usage(); } break; case 'g': flagg = parse_disk_policy(optarg); if (flagg == -1) { warnx("Could not parse '%s' as a disk policy", optarg); usage(); } break; case 't': qosinfo.task_throughput_qos_tier = parse_qos_tier(optarg, QOS_PARAMETER_THROUGHPUT); if (qosinfo.task_throughput_qos_tier == -1) { warnx("Could not parse '%s' as a qos tier", optarg); usage(); } break; case 'l': qosinfo.task_latency_qos_tier = parse_qos_tier(optarg, QOS_PARAMETER_LATENCY); if (qosinfo.task_latency_qos_tier == -1) { warnx("Could not parse '%s' as a qos tier", optarg); usage(); } break; case '?': default: usage(); } } argc -= optind; argv += optind; if (argc == 0) { usage(); } if (flagx && flagX){ warnx("Incompatible options -x, -X"); usage(); } if (flagx) { ret = setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY, IOPOL_SCOPE_PROCESS, IOPOL_VFS_HFS_CASE_SENSITIVITY_FORCE_CASE_SENSITIVE); if (ret == -1) { err(EX_SOFTWARE, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)"); } } if (flagX) { ret = setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY, IOPOL_SCOPE_PROCESS, IOPOL_VFS_HFS_CASE_SENSITIVITY_DEFAULT); if (ret == -1) { err(EX_SOFTWARE, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)"); } } if (flagb) { ret = setpriority(PRIO_DARWIN_PROCESS, 0, PRIO_DARWIN_BG); if (ret == -1) { err(EX_SOFTWARE, "setpriority()"); } } if (flagd >= 0) { ret = setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, flagd); if (ret == -1) { err(EX_SOFTWARE, "setiopolicy_np(...IOPOL_SCOPE_PROCESS...)"); } } if (flagg >= 0){ ret = setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_DARWIN_BG, flagg); if (ret == -1) { err(EX_SOFTWARE, "setiopolicy_np(...IOPOL_SCOPE_DARWIN_BG...)"); } } if (qosinfo.task_latency_qos_tier != LATENCY_QOS_TIER_UNSPECIFIED || qosinfo.task_throughput_qos_tier != THROUGHPUT_QOS_TIER_UNSPECIFIED){ ret = task_policy_set(mach_task_self(), TASK_OVERRIDE_QOS_POLICY, (task_policy_t)&qosinfo, TASK_QOS_POLICY_COUNT); if (ret != KERN_SUCCESS){ err(EX_SOFTWARE, "task_policy_set(...TASK_OVERRIDE_QOS_POLICY...)"); } } ret = execvp(argv[0], argv); if (ret == -1) { err(EX_NOINPUT, "Could not execute %s", argv[0]); } return EX_OSERR; }
int main(int argc, char * argv[]) { int ch, ret; pid_t pid = 0; posix_spawnattr_t attr; extern char **environ; bool flagx = false, flagX = false, flagb = false, flagB = false; int flagd = -1, flagg = -1; struct task_qos_policy qosinfo = { LATENCY_QOS_TIER_UNSPECIFIED, THROUGHPUT_QOS_TIER_UNSPECIFIED }; uint64_t qos_clamp = POSIX_SPAWN_PROC_CLAMP_NONE; while ((ch = getopt(argc, argv, "xXbBd:g:c:t:l:p:")) != -1) { switch (ch) { case 'x': flagx = true; break; case 'X': flagX = true; break; case 'b': flagb = true; break; case 'B': flagB = true; break; case 'd': flagd = parse_disk_policy(optarg); if (flagd == -1) { warnx("Could not parse '%s' as a disk policy", optarg); usage(); } break; case 'g': flagg = parse_disk_policy(optarg); if (flagg == -1) { warnx("Could not parse '%s' as a disk policy", optarg); usage(); } break; case 'c': qos_clamp = parse_qos_clamp(optarg); if (qos_clamp == POSIX_SPAWN_PROC_CLAMP_NONE) { warnx("Could not parse '%s' as a QoS clamp", optarg); usage(); } break; case 't': qosinfo.task_throughput_qos_tier = parse_qos_tier(optarg, QOS_PARAMETER_THROUGHPUT); if (qosinfo.task_throughput_qos_tier == -1) { warnx("Could not parse '%s' as a qos tier", optarg); usage(); } break; case 'l': qosinfo.task_latency_qos_tier = parse_qos_tier(optarg, QOS_PARAMETER_LATENCY); if (qosinfo.task_latency_qos_tier == -1) { warnx("Could not parse '%s' as a qos tier", optarg); usage(); } break; case 'p': pid = atoi(optarg); if (pid == 0) { warnx("Invalid pid '%s' specified", optarg); usage(); } break; case '?': default: usage(); } } argc -= optind; argv += optind; if (pid == 0 && argc == 0) { usage(); } if (pid != 0 && (flagx || flagX || flagg != -1 || flagd != -1)) { warnx("Incompatible option(s) used with -p"); usage(); } if (flagx && flagX) { warnx("Incompatible options -x, -X"); usage(); } if (flagb && flagB) { warnx("Incompatible options -b, -B"); usage(); } if (flagB && pid == 0) { warnx("The -B option can only be used with the -p option"); usage(); } if (flagx) { ret = setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY, IOPOL_SCOPE_PROCESS, IOPOL_VFS_HFS_CASE_SENSITIVITY_FORCE_CASE_SENSITIVE); if (ret == -1) { err(EX_SOFTWARE, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)"); } } if (flagX) { ret = setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY, IOPOL_SCOPE_PROCESS, IOPOL_VFS_HFS_CASE_SENSITIVITY_DEFAULT); if (ret == -1) { err(EX_SOFTWARE, "setiopolicy_np(IOPOL_TYPE_VFS_HFS_CASE_SENSITIVITY...)"); } } if (flagb) { ret = setpriority(PRIO_DARWIN_PROCESS, pid, PRIO_DARWIN_BG); if (ret == -1) { err(EX_SOFTWARE, "setpriority()"); } } if (flagB) { ret = setpriority(PRIO_DARWIN_PROCESS, pid, 0); if (ret == -1) { err(EX_SOFTWARE, "setpriority()"); } } if (flagd >= 0) { ret = setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, flagd); if (ret == -1) { err(EX_SOFTWARE, "setiopolicy_np(...IOPOL_SCOPE_PROCESS...)"); } } if (flagg >= 0) { ret = setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_DARWIN_BG, flagg); if (ret == -1) { err(EX_SOFTWARE, "setiopolicy_np(...IOPOL_SCOPE_DARWIN_BG...)"); } } if (qosinfo.task_latency_qos_tier != LATENCY_QOS_TIER_UNSPECIFIED || qosinfo.task_throughput_qos_tier != THROUGHPUT_QOS_TIER_UNSPECIFIED) { mach_port_t task; if (pid) { ret = task_for_pid(mach_task_self(), pid, &task); if (ret != KERN_SUCCESS) { err(EX_SOFTWARE, "task_for_pid(%d) failed", pid); return EX_OSERR; } } else { task = mach_task_self(); } ret = task_policy_set((task_t)task, TASK_OVERRIDE_QOS_POLICY, (task_policy_t)&qosinfo, TASK_QOS_POLICY_COUNT); if (ret != KERN_SUCCESS) { err(EX_SOFTWARE, "task_policy_set(...TASK_OVERRIDE_QOS_POLICY...)"); } } if (pid != 0) return 0; ret = posix_spawnattr_init(&attr); if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawnattr_init"); ret = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETEXEC); if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawnattr_setflags"); if (qos_clamp != POSIX_SPAWN_PROC_CLAMP_NONE) { ret = posix_spawnattr_set_qos_clamp_np(&attr, qos_clamp); if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawnattr_set_qos_clamp_np"); } ret = posix_spawnp(&pid, argv[0], NULL, &attr, argv, environ); if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawn"); return EX_OSERR; }
/******************************************************************************* * Fork a process after a specified delay, and either wait on it to exit or * leave it to run in the background. * * Returns -2 on spawn() failure, -1 on other failure, and depending on wait: * wait: true - exit status of forked program * wait: false - pid of background process *******************************************************************************/ int fork_program(const char * argv0, char * const argv[], Boolean wait) { int result; int spawn_result; pid_t child_pid; int child_status; int normal_iopolicy = getiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS); char ** environ = *(_NSGetEnviron()); if (!wait) { setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, IOPOL_THROTTLE); } spawn_result = posix_spawn(&child_pid, argv0, /* file_actions */ NULL, /* spawnattrs */ NULL, argv, environ); // If we couldn't spawn the process, return -2 with errno for detail if (spawn_result != 0) { OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel, "posix_spawn failed for %s.", argv0); errno = spawn_result; result = -2; goto finish; } OSKextLog(/* kext */ NULL, kOSKextLogDetailLevel, "started child process %s[%d] (%ssynchronous).", argv0, child_pid, wait ? "" : "a"); if (wait) { OSKextLogSpec logSpec = kOSKextLogDetailLevel; if (waitpid(child_pid, &child_status, 0) == -1) { result = -1; goto finish; } if (WIFEXITED(child_status)) { result = WEXITSTATUS(child_status); if (result) { logSpec = kOSKextLogErrorLevel; } OSKextLog(/* kext */ NULL, logSpec, "Child process %s[%d] exited with status %d.", argv0, child_pid, result); } else if (WIFSIGNALED(child_status)) { result = WTERMSIG(child_status); logSpec = kOSKextLogErrorLevel; OSKextLog(/* kext */ NULL, logSpec, "Child process %s[%d] exited due to signal %d.", argv0, child_pid, result); } else { // shouldn't be any other types of exit result = -1; } } else { result = child_pid; } finish: setiopolicy_np(IOPOL_TYPE_DISK, IOPOL_SCOPE_PROCESS, normal_iopolicy); return result; }