1/*
2 * Helper functions for handling target threads/cpus
3 *
4 * Copyright (C) 2012, LG Electronics, Namhyung Kim <namhyung.kim@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
16enum 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
61enum 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 */
97static 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
107int 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