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