From 5fd83771641d15c418f747bd343ba6738d3875f7 Mon Sep 17 00:00:00 2001 From: Cameron Katri Date: Sun, 9 May 2021 14:20:58 -0400 Subject: Import macOS userland adv_cmds-176 basic_cmds-55 bootstrap_cmds-116.100.1 developer_cmds-66 diskdev_cmds-667.40.1 doc_cmds-53.60.1 file_cmds-321.40.3 mail_cmds-35 misc_cmds-34 network_cmds-606.40.1 patch_cmds-17 remote_cmds-63 shell_cmds-216.60.1 system_cmds-880.60.2 text_cmds-106 --- .../taskpolicy.tproj/taskpolicy-entitlements.plist | 8 + system_cmds/taskpolicy.tproj/taskpolicy.8 | 75 +++++ system_cmds/taskpolicy.tproj/taskpolicy.c | 324 +++++++++++++++++++++ 3 files changed, 407 insertions(+) create mode 100644 system_cmds/taskpolicy.tproj/taskpolicy-entitlements.plist create mode 100644 system_cmds/taskpolicy.tproj/taskpolicy.8 create mode 100644 system_cmds/taskpolicy.tproj/taskpolicy.c (limited to 'system_cmds/taskpolicy.tproj') diff --git a/system_cmds/taskpolicy.tproj/taskpolicy-entitlements.plist b/system_cmds/taskpolicy.tproj/taskpolicy-entitlements.plist new file mode 100644 index 0000000..39c14ef --- /dev/null +++ b/system_cmds/taskpolicy.tproj/taskpolicy-entitlements.plist @@ -0,0 +1,8 @@ + + + + + com.apple.security.cs.debugger.root + + + diff --git a/system_cmds/taskpolicy.tproj/taskpolicy.8 b/system_cmds/taskpolicy.tproj/taskpolicy.8 new file mode 100644 index 0000000..b13af54 --- /dev/null +++ b/system_cmds/taskpolicy.tproj/taskpolicy.8 @@ -0,0 +1,75 @@ +.Dd 2/21/13 +.Dt taskpolicy 8 +.Os Darwin +.Sh NAME +.Nm taskpolicy +.Nd execute a program with an altered I/O or scheduling policy or change settings of already running process +.Sh SYNOPSIS +.Nm +.Op Fl d Ar policy +.Op Fl g Ar policy +.Op Fl c Ar clamp +.Op Fl b +.Op Fl t Ar thruput_tier +.Op Fl l Ar latency_tier +.Op Fl a +.Ar program +.Oo +.Ar arg1 +.Op Ar ... +.Oc +.Nm +.Op Fl b|-B +.Op Fl t Ar thruput_tier +.Op Fl l Ar latency_tier +.Op Fl p Ar pid +.Sh DESCRIPTION +The +.Nm +program uses the +.Xr setiopolicy_np 3 +and +.Xr setpriority 2 +APIs to execute a program with altered I/O or scheduling policies. All +children of the specified program also inherit these policies. +.Pp +.Nm +accepts the following flags and arguments: +.Bl -tag -width "d policy " -offset indent +.It Fl d Ar policy +Run the program after calling +.Xr setiopolicy_np 3 +with an iotype of IOPOL_TYPE_DISK, a scope of IOPOL_SCOPE_PROCESS, and the +specified policy. The argument can either be an integer, or a symbolic string +like "default" or "throttle", which is interpreted case-insensitively. +.It Fl g Ar policy +Run the program after calling +.Xr setiopolicy_np 3 +with an iotype of IOPOL_TYPE_DISK, a scope of IOPOL_SCOPE_DARWIN_BG, and the +specified policy. The argument is interpreted in the same manner as +.Fl d . +.It Fl c Ar clamp +Run the program using the specified QoS clamp. The argument can be either +"utility", "background", or "maintenance", which is interpreted case-insensitively. +.It Fl p Ar pid +Change settings for the process specified by +.Ar pid . +.It Fl b +Run the program after calling +.Xr setpriority 2 +with a priority of PRIO_DARWIN_BG. +.It Fl B +Move target process out of PRIO_DARWIN_BG. +.It Fl t +Set throughput tier of the process to +.Ar thruput_tier . +.It Fl l +Set latency tier of the process to +.Ar latency_tier . +.It Fl a +Run the program with the resource management policies given to applications. +.El +.Pp +.Sh SEE ALSO +.Xr setpriority 2 , +.Xr setiopolicy_np 3 diff --git a/system_cmds/taskpolicy.tproj/taskpolicy.c b/system_cmds/taskpolicy.tproj/taskpolicy.c new file mode 100644 index 0000000..3260bb6 --- /dev/null +++ b/system_cmds/taskpolicy.tproj/taskpolicy.c @@ -0,0 +1,324 @@ +/* + * Copyright (c) 2013-2016 Apple Inc. All rights reserved. + * + * @APPLE_LICENSE_HEADER_START@ + * + * "Portions Copyright (c) 1999 Apple Computer, Inc. All Rights + * Reserved. This file contains Original Code and/or Modifications of + * Original Code as defined in and that are subject to the Apple Public + * Source License Version 1.0 (the 'License'). You may not use this file + * except in compliance with the License. Please obtain a copy of the + * License at http://www.apple.com/publicsource and read it before using + * this file. + * + * The Original Code and all software distributed under the License are + * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER + * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, + * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the + * License for the specific language governing rights and limitations + * under the License." + * + * @APPLE_LICENSE_HEADER_END@ + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define QOS_PARAMETER_LATENCY 0 +#define QOS_PARAMETER_THROUGHPUT 1 + +extern char **environ; + +static void usage(void); +static int parse_disk_policy(const char *strpolicy); +static int parse_qos_tier(const char *strpolicy, int parameter); +static uint64_t parse_qos_clamp(const char *qos_string); + +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, flaga = 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:a")) != -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 'a': + flaga = true; + 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"); + } + + if (flaga) { + ret = posix_spawnattr_setprocesstype_np(&attr, POSIX_SPAWN_PROC_TYPE_APP_DEFAULT); + if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawnattr_setprocesstype_np"); + + ret = posix_spawnattr_set_darwin_role_np(&attr, PRIO_DARWIN_ROLE_UI); + if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawnattr_set_darwin_role_np"); + } + + ret = posix_spawnp(&pid, argv[0], NULL, &attr, argv, environ); + if (ret != 0) errc(EX_NOINPUT, ret, "posix_spawn"); + + return EX_OSERR; +} + +static void usage(void) +{ + fprintf(stderr, "Usage: %s [-x|-X] [-d ] [-g policy] [-c clamp] [-b] [-t ]\n" + " [-l ] [-a] [ [...]]\n", getprogname()); + fprintf(stderr, " %s [-b|-B] [-t ] [-l ] -p pid\n", getprogname()); + exit(EX_USAGE); +} + +static int parse_disk_policy(const char *strpolicy) +{ + long policy; + char *endptr = NULL; + + /* first try as an integer */ + policy = strtol(strpolicy, &endptr, 0); + if (endptr && (endptr[0] == '\0') && (strpolicy[0] != '\0')) { + /* parsed complete string as a number */ + return (int)policy; + } + + if (0 == strcasecmp(strpolicy, "DEFAULT") ) { + return IOPOL_DEFAULT; + } else if (0 == strcasecmp(strpolicy, "IMPORTANT")) { + return IOPOL_IMPORTANT; + } else if (0 == strcasecmp(strpolicy, "PASSIVE")) { + return IOPOL_PASSIVE; + } else if (0 == strcasecmp(strpolicy, "THROTTLE")) { + return IOPOL_THROTTLE; + } else if (0 == strcasecmp(strpolicy, "UTILITY")) { + return IOPOL_UTILITY; + } else if (0 == strcasecmp(strpolicy, "STANDARD")) { + return IOPOL_STANDARD; + } else { + return -1; + } +} + +static int parse_qos_tier(const char *strtier, int parameter){ + long policy; + char *endptr = NULL; + + /* first try as an integer */ + policy = strtol(strtier, &endptr, 0); + if (endptr && (endptr[0] == '\0') && (strtier[0] != '\0')) { + switch (policy) { + case 0: + return parameter ? THROUGHPUT_QOS_TIER_0 : LATENCY_QOS_TIER_0; + break; + case 1: + return parameter ? THROUGHPUT_QOS_TIER_1 : LATENCY_QOS_TIER_1; + break; + case 2: + return parameter ? THROUGHPUT_QOS_TIER_2 : LATENCY_QOS_TIER_2; + break; + case 3: + return parameter ? THROUGHPUT_QOS_TIER_3 : LATENCY_QOS_TIER_3; + break; + case 4: + return parameter ? THROUGHPUT_QOS_TIER_4 : LATENCY_QOS_TIER_4; + break; + case 5: + return parameter ? THROUGHPUT_QOS_TIER_5 : LATENCY_QOS_TIER_5; + break; + default: + return -1; + break; + } + } + + return -1; +} + +static uint64_t parse_qos_clamp(const char *qos_string) { + + if (0 == strcasecmp(qos_string, "utility") ) { + return POSIX_SPAWN_PROC_CLAMP_UTILITY; + } else if (0 == strcasecmp(qos_string, "background")) { + return POSIX_SPAWN_PROC_CLAMP_BACKGROUND; + } else if (0 == strcasecmp(qos_string, "maintenance")) { + return POSIX_SPAWN_PROC_CLAMP_MAINTENANCE; + } else { + return POSIX_SPAWN_PROC_CLAMP_NONE; + } +} -- cgit v1.2.3-56-ge451