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