Home | History | Annotate | Download | only in util
      1 /*
      2  * Helper functions for handling target threads/cpus
      3  *
      4  * Copyright (C) 2012, LG Electronics, Namhyung Kim <namhyung.kim (at) lge.com>
      5  *
      6  * Released under the GPL v2.
      7  */
      8 
      9 #include "target.h"
     10 #include "debug.h"
     11 
     12 #include <pwd.h>
     13 #include <string.h>
     14 
     15 
     16 enum perf_target_errno perf_target__validate(struct perf_target *target)
     17 {
     18 	enum perf_target_errno ret = PERF_ERRNO_TARGET__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 == PERF_ERRNO_TARGET__SUCCESS)
     27 			ret = PERF_ERRNO_TARGET__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 == PERF_ERRNO_TARGET__SUCCESS)
     34 			ret = PERF_ERRNO_TARGET__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 == PERF_ERRNO_TARGET__SUCCESS)
     41 			ret = PERF_ERRNO_TARGET__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 == PERF_ERRNO_TARGET__SUCCESS)
     48 			ret = PERF_ERRNO_TARGET__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 == PERF_ERRNO_TARGET__SUCCESS)
     55 			ret = PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM;
     56 	}
     57 
     58 	return ret;
     59 }
     60 
     61 enum perf_target_errno perf_target__parse_uid(struct perf_target *target)
     62 {
     63 	struct passwd pwd, *result;
     64 	char buf[1024];
     65 	const char *str = target->uid_str;
     66 
     67 	target->uid = UINT_MAX;
     68 	if (str == NULL)
     69 		return PERF_ERRNO_TARGET__SUCCESS;
     70 
     71 	/* Try user name first */
     72 	getpwnam_r(str, &pwd, buf, sizeof(buf), &result);
     73 
     74 	if (result == NULL) {
     75 		/*
     76 		 * The user name not found. Maybe it's a UID number.
     77 		 */
     78 		char *endptr;
     79 		int uid = strtol(str, &endptr, 10);
     80 
     81 		if (*endptr != '\0')
     82 			return PERF_ERRNO_TARGET__INVALID_UID;
     83 
     84 		getpwuid_r(uid, &pwd, buf, sizeof(buf), &result);
     85 
     86 		if (result == NULL)
     87 			return PERF_ERRNO_TARGET__USER_NOT_FOUND;
     88 	}
     89 
     90 	target->uid = result->pw_uid;
     91 	return PERF_ERRNO_TARGET__SUCCESS;
     92 }
     93 
     94 /*
     95  * This must have a same ordering as the enum perf_target_errno.
     96  */
     97 static const char *perf_target__error_str[] = {
     98 	"PID/TID switch overriding CPU",
     99 	"PID/TID switch overriding UID",
    100 	"UID switch overriding CPU",
    101 	"PID/TID switch overriding SYSTEM",
    102 	"UID switch overriding SYSTEM",
    103 	"Invalid User: %s",
    104 	"Problems obtaining information for user %s",
    105 };
    106 
    107 int perf_target__strerror(struct perf_target *target, int errnum,
    108 			  char *buf, size_t buflen)
    109 {
    110 	int idx;
    111 	const char *msg;
    112 
    113 	BUG_ON(buflen == 0);
    114 
    115 	if (errnum >= 0) {
    116 		const char *err = strerror_r(errnum, buf, buflen);
    117 
    118 		if (err != buf) {
    119 			size_t len = strlen(err);
    120 			memcpy(buf, err, min(buflen - 1, len));
    121 			*(buf + min(buflen - 1, len)) = '\0';
    122 		}
    123 
    124 		return 0;
    125 	}
    126 
    127 	if (errnum <  __PERF_ERRNO_TARGET__START ||
    128 	    errnum >= __PERF_ERRNO_TARGET__END)
    129 		return -1;
    130 
    131 	idx = errnum - __PERF_ERRNO_TARGET__START;
    132 	msg = perf_target__error_str[idx];
    133 
    134 	switch (errnum) {
    135 	case PERF_ERRNO_TARGET__PID_OVERRIDE_CPU
    136 	 ... PERF_ERRNO_TARGET__UID_OVERRIDE_SYSTEM:
    137 		snprintf(buf, buflen, "%s", msg);
    138 		break;
    139 
    140 	case PERF_ERRNO_TARGET__INVALID_UID:
    141 	case PERF_ERRNO_TARGET__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