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