1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Helper functions for handling target threads/cpus 4 * 5 * Copyright (C) 2012, LG Electronics, Namhyung Kim <namhyung.kim@lge.com> 6 */ 7 8 #include "target.h" 9 #include "util.h" 10 #include "debug.h" 11 12 #include <pwd.h> 13 #include <stdio.h> 14 #include <stdlib.h> 15 #include <string.h> 16 #include <linux/kernel.h> 17 #include <linux/string.h> 18 19 enum target_errno target__validate(struct target *target) 20 { 21 enum target_errno ret = TARGET_ERRNO__SUCCESS; 22 23 if (target->pid) 24 target->tid = target->pid; 25 26 /* CPU and PID are mutually exclusive */ 27 if (target->tid && target->cpu_list) { 28 target->cpu_list = NULL; 29 if (ret == TARGET_ERRNO__SUCCESS) 30 ret = TARGET_ERRNO__PID_OVERRIDE_CPU; 31 } 32 33 /* UID and PID are mutually exclusive */ 34 if (target->tid && target->uid_str) { 35 target->uid_str = NULL; 36 if (ret == TARGET_ERRNO__SUCCESS) 37 ret = TARGET_ERRNO__PID_OVERRIDE_UID; 38 } 39 40 /* UID and CPU are mutually exclusive */ 41 if (target->uid_str && target->cpu_list) { 42 target->cpu_list = NULL; 43 if (ret == TARGET_ERRNO__SUCCESS) 44 ret = TARGET_ERRNO__UID_OVERRIDE_CPU; 45 } 46 47 /* PID and SYSTEM are mutually exclusive */ 48 if (target->tid && target->system_wide) { 49 target->system_wide = false; 50 if (ret == TARGET_ERRNO__SUCCESS) 51 ret = TARGET_ERRNO__PID_OVERRIDE_SYSTEM; 52 } 53 54 /* UID and SYSTEM are mutually exclusive */ 55 if (target->uid_str && target->system_wide) { 56 target->system_wide = false; 57 if (ret == TARGET_ERRNO__SUCCESS) 58 ret = TARGET_ERRNO__UID_OVERRIDE_SYSTEM; 59 } 60 61 /* THREAD and SYSTEM/CPU are mutually exclusive */ 62 if (target->per_thread && (target->system_wide || target->cpu_list)) { 63 target->per_thread = false; 64 if (ret == TARGET_ERRNO__SUCCESS) 65 ret = TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD; 66 } 67 68 return ret; 69 } 70 71 enum target_errno target__parse_uid(struct target *target) 72 { 73 struct passwd pwd, *result; 74 char buf[1024]; 75 const char *str = target->uid_str; 76 77 target->uid = UINT_MAX; 78 if (str == NULL) 79 return TARGET_ERRNO__SUCCESS; 80 81 /* Try user name first */ 82 getpwnam_r(str, &pwd, buf, sizeof(buf), &result); 83 84 if (result == NULL) { 85 /* 86 * The user name not found. Maybe it's a UID number. 87 */ 88 char *endptr; 89 int uid = strtol(str, &endptr, 10); 90 91 if (*endptr != '\0') 92 return TARGET_ERRNO__INVALID_UID; 93 94 getpwuid_r(uid, &pwd, buf, sizeof(buf), &result); 95 96 if (result == NULL) 97 return TARGET_ERRNO__USER_NOT_FOUND; 98 } 99 100 target->uid = result->pw_uid; 101 return TARGET_ERRNO__SUCCESS; 102 } 103 104 /* 105 * This must have a same ordering as the enum target_errno. 106 */ 107 static const char *target__error_str[] = { 108 "PID/TID switch overriding CPU", 109 "PID/TID switch overriding UID", 110 "UID switch overriding CPU", 111 "PID/TID switch overriding SYSTEM", 112 "UID switch overriding SYSTEM", 113 "SYSTEM/CPU switch overriding PER-THREAD", 114 "Invalid User: %s", 115 "Problems obtaining information for user %s", 116 }; 117 118 int target__strerror(struct target *target, int errnum, 119 char *buf, size_t buflen) 120 { 121 int idx; 122 const char *msg; 123 124 BUG_ON(buflen == 0); 125 126 if (errnum >= 0) { 127 str_error_r(errnum, buf, buflen); 128 return 0; 129 } 130 131 if (errnum < __TARGET_ERRNO__START || errnum >= __TARGET_ERRNO__END) 132 return -1; 133 134 idx = errnum - __TARGET_ERRNO__START; 135 msg = target__error_str[idx]; 136 137 switch (errnum) { 138 case TARGET_ERRNO__PID_OVERRIDE_CPU ... 139 TARGET_ERRNO__SYSTEM_OVERRIDE_THREAD: 140 snprintf(buf, buflen, "%s", msg); 141 break; 142 143 case TARGET_ERRNO__INVALID_UID: 144 case TARGET_ERRNO__USER_NOT_FOUND: 145 snprintf(buf, buflen, msg, target->uid_str); 146 break; 147 148 default: 149 /* cannot reach here */ 150 break; 151 } 152 153 return 0; 154 } 155