xref: /openbmc/linux/tools/perf/util/path.c (revision 864709302a80f26fa9da3be5b47304f0b8bae192)
1*86470930SIngo Molnar /*
2*86470930SIngo Molnar  * I'm tired of doing "vsnprintf()" etc just to open a
3*86470930SIngo Molnar  * file, so here's a "return static buffer with printf"
4*86470930SIngo Molnar  * interface for paths.
5*86470930SIngo Molnar  *
6*86470930SIngo Molnar  * It's obviously not thread-safe. Sue me. But it's quite
7*86470930SIngo Molnar  * useful for doing things like
8*86470930SIngo Molnar  *
9*86470930SIngo Molnar  *   f = open(mkpath("%s/%s.perf", base, name), O_RDONLY);
10*86470930SIngo Molnar  *
11*86470930SIngo Molnar  * which is what it's designed for.
12*86470930SIngo Molnar  */
13*86470930SIngo Molnar #include "cache.h"
14*86470930SIngo Molnar 
15*86470930SIngo Molnar static char bad_path[] = "/bad-path/";
16*86470930SIngo Molnar /*
17*86470930SIngo Molnar  * Two hacks:
18*86470930SIngo Molnar  */
19*86470930SIngo Molnar 
20*86470930SIngo Molnar static char *get_perf_dir(void)
21*86470930SIngo Molnar {
22*86470930SIngo Molnar 	return ".";
23*86470930SIngo Molnar }
24*86470930SIngo Molnar 
25*86470930SIngo Molnar size_t strlcpy(char *dest, const char *src, size_t size)
26*86470930SIngo Molnar {
27*86470930SIngo Molnar 	size_t ret = strlen(src);
28*86470930SIngo Molnar 
29*86470930SIngo Molnar 	if (size) {
30*86470930SIngo Molnar 		size_t len = (ret >= size) ? size - 1 : ret;
31*86470930SIngo Molnar 		memcpy(dest, src, len);
32*86470930SIngo Molnar 		dest[len] = '\0';
33*86470930SIngo Molnar 	}
34*86470930SIngo Molnar 	return ret;
35*86470930SIngo Molnar }
36*86470930SIngo Molnar 
37*86470930SIngo Molnar 
38*86470930SIngo Molnar static char *get_pathname(void)
39*86470930SIngo Molnar {
40*86470930SIngo Molnar 	static char pathname_array[4][PATH_MAX];
41*86470930SIngo Molnar 	static int index;
42*86470930SIngo Molnar 	return pathname_array[3 & ++index];
43*86470930SIngo Molnar }
44*86470930SIngo Molnar 
45*86470930SIngo Molnar static char *cleanup_path(char *path)
46*86470930SIngo Molnar {
47*86470930SIngo Molnar 	/* Clean it up */
48*86470930SIngo Molnar 	if (!memcmp(path, "./", 2)) {
49*86470930SIngo Molnar 		path += 2;
50*86470930SIngo Molnar 		while (*path == '/')
51*86470930SIngo Molnar 			path++;
52*86470930SIngo Molnar 	}
53*86470930SIngo Molnar 	return path;
54*86470930SIngo Molnar }
55*86470930SIngo Molnar 
56*86470930SIngo Molnar char *mksnpath(char *buf, size_t n, const char *fmt, ...)
57*86470930SIngo Molnar {
58*86470930SIngo Molnar 	va_list args;
59*86470930SIngo Molnar 	unsigned len;
60*86470930SIngo Molnar 
61*86470930SIngo Molnar 	va_start(args, fmt);
62*86470930SIngo Molnar 	len = vsnprintf(buf, n, fmt, args);
63*86470930SIngo Molnar 	va_end(args);
64*86470930SIngo Molnar 	if (len >= n) {
65*86470930SIngo Molnar 		strlcpy(buf, bad_path, n);
66*86470930SIngo Molnar 		return buf;
67*86470930SIngo Molnar 	}
68*86470930SIngo Molnar 	return cleanup_path(buf);
69*86470930SIngo Molnar }
70*86470930SIngo Molnar 
71*86470930SIngo Molnar static char *perf_vsnpath(char *buf, size_t n, const char *fmt, va_list args)
72*86470930SIngo Molnar {
73*86470930SIngo Molnar 	const char *perf_dir = get_perf_dir();
74*86470930SIngo Molnar 	size_t len;
75*86470930SIngo Molnar 
76*86470930SIngo Molnar 	len = strlen(perf_dir);
77*86470930SIngo Molnar 	if (n < len + 1)
78*86470930SIngo Molnar 		goto bad;
79*86470930SIngo Molnar 	memcpy(buf, perf_dir, len);
80*86470930SIngo Molnar 	if (len && !is_dir_sep(perf_dir[len-1]))
81*86470930SIngo Molnar 		buf[len++] = '/';
82*86470930SIngo Molnar 	len += vsnprintf(buf + len, n - len, fmt, args);
83*86470930SIngo Molnar 	if (len >= n)
84*86470930SIngo Molnar 		goto bad;
85*86470930SIngo Molnar 	return cleanup_path(buf);
86*86470930SIngo Molnar bad:
87*86470930SIngo Molnar 	strlcpy(buf, bad_path, n);
88*86470930SIngo Molnar 	return buf;
89*86470930SIngo Molnar }
90*86470930SIngo Molnar 
91*86470930SIngo Molnar char *perf_snpath(char *buf, size_t n, const char *fmt, ...)
92*86470930SIngo Molnar {
93*86470930SIngo Molnar 	va_list args;
94*86470930SIngo Molnar 	va_start(args, fmt);
95*86470930SIngo Molnar 	(void)perf_vsnpath(buf, n, fmt, args);
96*86470930SIngo Molnar 	va_end(args);
97*86470930SIngo Molnar 	return buf;
98*86470930SIngo Molnar }
99*86470930SIngo Molnar 
100*86470930SIngo Molnar char *perf_pathdup(const char *fmt, ...)
101*86470930SIngo Molnar {
102*86470930SIngo Molnar 	char path[PATH_MAX];
103*86470930SIngo Molnar 	va_list args;
104*86470930SIngo Molnar 	va_start(args, fmt);
105*86470930SIngo Molnar 	(void)perf_vsnpath(path, sizeof(path), fmt, args);
106*86470930SIngo Molnar 	va_end(args);
107*86470930SIngo Molnar 	return xstrdup(path);
108*86470930SIngo Molnar }
109*86470930SIngo Molnar 
110*86470930SIngo Molnar char *mkpath(const char *fmt, ...)
111*86470930SIngo Molnar {
112*86470930SIngo Molnar 	va_list args;
113*86470930SIngo Molnar 	unsigned len;
114*86470930SIngo Molnar 	char *pathname = get_pathname();
115*86470930SIngo Molnar 
116*86470930SIngo Molnar 	va_start(args, fmt);
117*86470930SIngo Molnar 	len = vsnprintf(pathname, PATH_MAX, fmt, args);
118*86470930SIngo Molnar 	va_end(args);
119*86470930SIngo Molnar 	if (len >= PATH_MAX)
120*86470930SIngo Molnar 		return bad_path;
121*86470930SIngo Molnar 	return cleanup_path(pathname);
122*86470930SIngo Molnar }
123*86470930SIngo Molnar 
124*86470930SIngo Molnar char *perf_path(const char *fmt, ...)
125*86470930SIngo Molnar {
126*86470930SIngo Molnar 	const char *perf_dir = get_perf_dir();
127*86470930SIngo Molnar 	char *pathname = get_pathname();
128*86470930SIngo Molnar 	va_list args;
129*86470930SIngo Molnar 	unsigned len;
130*86470930SIngo Molnar 
131*86470930SIngo Molnar 	len = strlen(perf_dir);
132*86470930SIngo Molnar 	if (len > PATH_MAX-100)
133*86470930SIngo Molnar 		return bad_path;
134*86470930SIngo Molnar 	memcpy(pathname, perf_dir, len);
135*86470930SIngo Molnar 	if (len && perf_dir[len-1] != '/')
136*86470930SIngo Molnar 		pathname[len++] = '/';
137*86470930SIngo Molnar 	va_start(args, fmt);
138*86470930SIngo Molnar 	len += vsnprintf(pathname + len, PATH_MAX - len, fmt, args);
139*86470930SIngo Molnar 	va_end(args);
140*86470930SIngo Molnar 	if (len >= PATH_MAX)
141*86470930SIngo Molnar 		return bad_path;
142*86470930SIngo Molnar 	return cleanup_path(pathname);
143*86470930SIngo Molnar }
144*86470930SIngo Molnar 
145*86470930SIngo Molnar 
146*86470930SIngo Molnar /* perf_mkstemp() - create tmp file honoring TMPDIR variable */
147*86470930SIngo Molnar int perf_mkstemp(char *path, size_t len, const char *template)
148*86470930SIngo Molnar {
149*86470930SIngo Molnar 	const char *tmp;
150*86470930SIngo Molnar 	size_t n;
151*86470930SIngo Molnar 
152*86470930SIngo Molnar 	tmp = getenv("TMPDIR");
153*86470930SIngo Molnar 	if (!tmp)
154*86470930SIngo Molnar 		tmp = "/tmp";
155*86470930SIngo Molnar 	n = snprintf(path, len, "%s/%s", tmp, template);
156*86470930SIngo Molnar 	if (len <= n) {
157*86470930SIngo Molnar 		errno = ENAMETOOLONG;
158*86470930SIngo Molnar 		return -1;
159*86470930SIngo Molnar 	}
160*86470930SIngo Molnar 	return mkstemp(path);
161*86470930SIngo Molnar }
162*86470930SIngo Molnar 
163*86470930SIngo Molnar 
164*86470930SIngo Molnar const char *make_relative_path(const char *abs, const char *base)
165*86470930SIngo Molnar {
166*86470930SIngo Molnar 	static char buf[PATH_MAX + 1];
167*86470930SIngo Molnar 	int baselen;
168*86470930SIngo Molnar 	if (!base)
169*86470930SIngo Molnar 		return abs;
170*86470930SIngo Molnar 	baselen = strlen(base);
171*86470930SIngo Molnar 	if (prefixcmp(abs, base))
172*86470930SIngo Molnar 		return abs;
173*86470930SIngo Molnar 	if (abs[baselen] == '/')
174*86470930SIngo Molnar 		baselen++;
175*86470930SIngo Molnar 	else if (base[baselen - 1] != '/')
176*86470930SIngo Molnar 		return abs;
177*86470930SIngo Molnar 	strcpy(buf, abs + baselen);
178*86470930SIngo Molnar 	return buf;
179*86470930SIngo Molnar }
180*86470930SIngo Molnar 
181*86470930SIngo Molnar /*
182*86470930SIngo Molnar  * It is okay if dst == src, but they should not overlap otherwise.
183*86470930SIngo Molnar  *
184*86470930SIngo Molnar  * Performs the following normalizations on src, storing the result in dst:
185*86470930SIngo Molnar  * - Ensures that components are separated by '/' (Windows only)
186*86470930SIngo Molnar  * - Squashes sequences of '/'.
187*86470930SIngo Molnar  * - Removes "." components.
188*86470930SIngo Molnar  * - Removes ".." components, and the components the precede them.
189*86470930SIngo Molnar  * Returns failure (non-zero) if a ".." component appears as first path
190*86470930SIngo Molnar  * component anytime during the normalization. Otherwise, returns success (0).
191*86470930SIngo Molnar  *
192*86470930SIngo Molnar  * Note that this function is purely textual.  It does not follow symlinks,
193*86470930SIngo Molnar  * verify the existence of the path, or make any system calls.
194*86470930SIngo Molnar  */
195*86470930SIngo Molnar int normalize_path_copy(char *dst, const char *src)
196*86470930SIngo Molnar {
197*86470930SIngo Molnar 	char *dst0;
198*86470930SIngo Molnar 
199*86470930SIngo Molnar 	if (has_dos_drive_prefix(src)) {
200*86470930SIngo Molnar 		*dst++ = *src++;
201*86470930SIngo Molnar 		*dst++ = *src++;
202*86470930SIngo Molnar 	}
203*86470930SIngo Molnar 	dst0 = dst;
204*86470930SIngo Molnar 
205*86470930SIngo Molnar 	if (is_dir_sep(*src)) {
206*86470930SIngo Molnar 		*dst++ = '/';
207*86470930SIngo Molnar 		while (is_dir_sep(*src))
208*86470930SIngo Molnar 			src++;
209*86470930SIngo Molnar 	}
210*86470930SIngo Molnar 
211*86470930SIngo Molnar 	for (;;) {
212*86470930SIngo Molnar 		char c = *src;
213*86470930SIngo Molnar 
214*86470930SIngo Molnar 		/*
215*86470930SIngo Molnar 		 * A path component that begins with . could be
216*86470930SIngo Molnar 		 * special:
217*86470930SIngo Molnar 		 * (1) "." and ends   -- ignore and terminate.
218*86470930SIngo Molnar 		 * (2) "./"           -- ignore them, eat slash and continue.
219*86470930SIngo Molnar 		 * (3) ".." and ends  -- strip one and terminate.
220*86470930SIngo Molnar 		 * (4) "../"          -- strip one, eat slash and continue.
221*86470930SIngo Molnar 		 */
222*86470930SIngo Molnar 		if (c == '.') {
223*86470930SIngo Molnar 			if (!src[1]) {
224*86470930SIngo Molnar 				/* (1) */
225*86470930SIngo Molnar 				src++;
226*86470930SIngo Molnar 			} else if (is_dir_sep(src[1])) {
227*86470930SIngo Molnar 				/* (2) */
228*86470930SIngo Molnar 				src += 2;
229*86470930SIngo Molnar 				while (is_dir_sep(*src))
230*86470930SIngo Molnar 					src++;
231*86470930SIngo Molnar 				continue;
232*86470930SIngo Molnar 			} else if (src[1] == '.') {
233*86470930SIngo Molnar 				if (!src[2]) {
234*86470930SIngo Molnar 					/* (3) */
235*86470930SIngo Molnar 					src += 2;
236*86470930SIngo Molnar 					goto up_one;
237*86470930SIngo Molnar 				} else if (is_dir_sep(src[2])) {
238*86470930SIngo Molnar 					/* (4) */
239*86470930SIngo Molnar 					src += 3;
240*86470930SIngo Molnar 					while (is_dir_sep(*src))
241*86470930SIngo Molnar 						src++;
242*86470930SIngo Molnar 					goto up_one;
243*86470930SIngo Molnar 				}
244*86470930SIngo Molnar 			}
245*86470930SIngo Molnar 		}
246*86470930SIngo Molnar 
247*86470930SIngo Molnar 		/* copy up to the next '/', and eat all '/' */
248*86470930SIngo Molnar 		while ((c = *src++) != '\0' && !is_dir_sep(c))
249*86470930SIngo Molnar 			*dst++ = c;
250*86470930SIngo Molnar 		if (is_dir_sep(c)) {
251*86470930SIngo Molnar 			*dst++ = '/';
252*86470930SIngo Molnar 			while (is_dir_sep(c))
253*86470930SIngo Molnar 				c = *src++;
254*86470930SIngo Molnar 			src--;
255*86470930SIngo Molnar 		} else if (!c)
256*86470930SIngo Molnar 			break;
257*86470930SIngo Molnar 		continue;
258*86470930SIngo Molnar 
259*86470930SIngo Molnar 	up_one:
260*86470930SIngo Molnar 		/*
261*86470930SIngo Molnar 		 * dst0..dst is prefix portion, and dst[-1] is '/';
262*86470930SIngo Molnar 		 * go up one level.
263*86470930SIngo Molnar 		 */
264*86470930SIngo Molnar 		dst--;	/* go to trailing '/' */
265*86470930SIngo Molnar 		if (dst <= dst0)
266*86470930SIngo Molnar 			return -1;
267*86470930SIngo Molnar 		/* Windows: dst[-1] cannot be backslash anymore */
268*86470930SIngo Molnar 		while (dst0 < dst && dst[-1] != '/')
269*86470930SIngo Molnar 			dst--;
270*86470930SIngo Molnar 	}
271*86470930SIngo Molnar 	*dst = '\0';
272*86470930SIngo Molnar 	return 0;
273*86470930SIngo Molnar }
274*86470930SIngo Molnar 
275*86470930SIngo Molnar /*
276*86470930SIngo Molnar  * path = Canonical absolute path
277*86470930SIngo Molnar  * prefix_list = Colon-separated list of absolute paths
278*86470930SIngo Molnar  *
279*86470930SIngo Molnar  * Determines, for each path in prefix_list, whether the "prefix" really
280*86470930SIngo Molnar  * is an ancestor directory of path.  Returns the length of the longest
281*86470930SIngo Molnar  * ancestor directory, excluding any trailing slashes, or -1 if no prefix
282*86470930SIngo Molnar  * is an ancestor.  (Note that this means 0 is returned if prefix_list is
283*86470930SIngo Molnar  * "/".) "/foo" is not considered an ancestor of "/foobar".  Directories
284*86470930SIngo Molnar  * are not considered to be their own ancestors.  path must be in a
285*86470930SIngo Molnar  * canonical form: empty components, or "." or ".." components are not
286*86470930SIngo Molnar  * allowed.  prefix_list may be null, which is like "".
287*86470930SIngo Molnar  */
288*86470930SIngo Molnar int longest_ancestor_length(const char *path, const char *prefix_list)
289*86470930SIngo Molnar {
290*86470930SIngo Molnar 	char buf[PATH_MAX+1];
291*86470930SIngo Molnar 	const char *ceil, *colon;
292*86470930SIngo Molnar 	int len, max_len = -1;
293*86470930SIngo Molnar 
294*86470930SIngo Molnar 	if (prefix_list == NULL || !strcmp(path, "/"))
295*86470930SIngo Molnar 		return -1;
296*86470930SIngo Molnar 
297*86470930SIngo Molnar 	for (colon = ceil = prefix_list; *colon; ceil = colon+1) {
298*86470930SIngo Molnar 		for (colon = ceil; *colon && *colon != PATH_SEP; colon++);
299*86470930SIngo Molnar 		len = colon - ceil;
300*86470930SIngo Molnar 		if (len == 0 || len > PATH_MAX || !is_absolute_path(ceil))
301*86470930SIngo Molnar 			continue;
302*86470930SIngo Molnar 		strlcpy(buf, ceil, len+1);
303*86470930SIngo Molnar 		if (normalize_path_copy(buf, buf) < 0)
304*86470930SIngo Molnar 			continue;
305*86470930SIngo Molnar 		len = strlen(buf);
306*86470930SIngo Molnar 		if (len > 0 && buf[len-1] == '/')
307*86470930SIngo Molnar 			buf[--len] = '\0';
308*86470930SIngo Molnar 
309*86470930SIngo Molnar 		if (!strncmp(path, buf, len) &&
310*86470930SIngo Molnar 		    path[len] == '/' &&
311*86470930SIngo Molnar 		    len > max_len) {
312*86470930SIngo Molnar 			max_len = len;
313*86470930SIngo Molnar 		}
314*86470930SIngo Molnar 	}
315*86470930SIngo Molnar 
316*86470930SIngo Molnar 	return max_len;
317*86470930SIngo Molnar }
318*86470930SIngo Molnar 
319*86470930SIngo Molnar /* strip arbitrary amount of directory separators at end of path */
320*86470930SIngo Molnar static inline int chomp_trailing_dir_sep(const char *path, int len)
321*86470930SIngo Molnar {
322*86470930SIngo Molnar 	while (len && is_dir_sep(path[len - 1]))
323*86470930SIngo Molnar 		len--;
324*86470930SIngo Molnar 	return len;
325*86470930SIngo Molnar }
326*86470930SIngo Molnar 
327*86470930SIngo Molnar /*
328*86470930SIngo Molnar  * If path ends with suffix (complete path components), returns the
329*86470930SIngo Molnar  * part before suffix (sans trailing directory separators).
330*86470930SIngo Molnar  * Otherwise returns NULL.
331*86470930SIngo Molnar  */
332*86470930SIngo Molnar char *strip_path_suffix(const char *path, const char *suffix)
333*86470930SIngo Molnar {
334*86470930SIngo Molnar 	int path_len = strlen(path), suffix_len = strlen(suffix);
335*86470930SIngo Molnar 
336*86470930SIngo Molnar 	while (suffix_len) {
337*86470930SIngo Molnar 		if (!path_len)
338*86470930SIngo Molnar 			return NULL;
339*86470930SIngo Molnar 
340*86470930SIngo Molnar 		if (is_dir_sep(path[path_len - 1])) {
341*86470930SIngo Molnar 			if (!is_dir_sep(suffix[suffix_len - 1]))
342*86470930SIngo Molnar 				return NULL;
343*86470930SIngo Molnar 			path_len = chomp_trailing_dir_sep(path, path_len);
344*86470930SIngo Molnar 			suffix_len = chomp_trailing_dir_sep(suffix, suffix_len);
345*86470930SIngo Molnar 		}
346*86470930SIngo Molnar 		else if (path[--path_len] != suffix[--suffix_len])
347*86470930SIngo Molnar 			return NULL;
348*86470930SIngo Molnar 	}
349*86470930SIngo Molnar 
350*86470930SIngo Molnar 	if (path_len && !is_dir_sep(path[path_len - 1]))
351*86470930SIngo Molnar 		return NULL;
352*86470930SIngo Molnar 	return xstrndup(path, chomp_trailing_dir_sep(path, path_len));
353*86470930SIngo Molnar }
354