38f78a7e8e7d40cd6fcebefd297e5bb240c52aaf
[lttng-tools.git] / src / common / utils.c
1 /*
2 * Copyright (C) 2012 - David Goulet <dgoulet@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #define _GNU_SOURCE
19 #include <assert.h>
20 #include <ctype.h>
21 #include <fcntl.h>
22 #include <limits.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <unistd.h>
28 #include <inttypes.h>
29 #include <regex.h>
30
31 #include <common/common.h>
32 #include <common/runas.h>
33
34 #include "utils.h"
35
36 /*
37 * Return the realpath(3) of the path even if the last directory token does not
38 * exist. For example, with /tmp/test1/test2, if test2/ does not exist but the
39 * /tmp/test1 does, the real path is returned. In normal time, realpath(3)
40 * fails if the end point directory does not exist.
41 */
42 LTTNG_HIDDEN
43 char *utils_expand_path(const char *path)
44 {
45 const char *end_path = path;
46 char *next, *cut_path = NULL, *expanded_path = NULL;
47
48 /* Safety net */
49 if (path == NULL) {
50 goto error;
51 }
52
53 /* Find last token delimited by '/' */
54 while ((next = strpbrk(end_path + 1, "/"))) {
55 end_path = next;
56 }
57
58 /* Cut last token from original path */
59 cut_path = strndup(path, end_path - path);
60
61 expanded_path = zmalloc(PATH_MAX);
62 if (expanded_path == NULL) {
63 PERROR("zmalloc expand path");
64 goto error;
65 }
66
67 expanded_path = realpath((char *)cut_path, expanded_path);
68 if (expanded_path == NULL) {
69 switch (errno) {
70 case ENOENT:
71 ERR("%s: No such file or directory", cut_path);
72 break;
73 default:
74 PERROR("realpath utils expand path");
75 break;
76 }
77 goto error;
78 }
79
80 /* Add end part to expanded path */
81 strncat(expanded_path, end_path, PATH_MAX - strlen(expanded_path) - 1);
82
83 free(cut_path);
84 return expanded_path;
85
86 error:
87 free(expanded_path);
88 free(cut_path);
89 return NULL;
90 }
91
92 /*
93 * Create a pipe in dst.
94 */
95 LTTNG_HIDDEN
96 int utils_create_pipe(int *dst)
97 {
98 int ret;
99
100 if (dst == NULL) {
101 return -1;
102 }
103
104 ret = pipe(dst);
105 if (ret < 0) {
106 PERROR("create pipe");
107 }
108
109 return ret;
110 }
111
112 /*
113 * Create pipe and set CLOEXEC flag to both fd.
114 *
115 * Make sure the pipe opened by this function are closed at some point. Use
116 * utils_close_pipe().
117 */
118 LTTNG_HIDDEN
119 int utils_create_pipe_cloexec(int *dst)
120 {
121 int ret, i;
122
123 if (dst == NULL) {
124 return -1;
125 }
126
127 ret = utils_create_pipe(dst);
128 if (ret < 0) {
129 goto error;
130 }
131
132 for (i = 0; i < 2; i++) {
133 ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC);
134 if (ret < 0) {
135 PERROR("fcntl pipe cloexec");
136 goto error;
137 }
138 }
139
140 error:
141 return ret;
142 }
143
144 /*
145 * Close both read and write side of the pipe.
146 */
147 LTTNG_HIDDEN
148 void utils_close_pipe(int *src)
149 {
150 int i, ret;
151
152 if (src == NULL) {
153 return;
154 }
155
156 for (i = 0; i < 2; i++) {
157 /* Safety check */
158 if (src[i] < 0) {
159 continue;
160 }
161
162 ret = close(src[i]);
163 if (ret) {
164 PERROR("close pipe");
165 }
166 }
167 }
168
169 /*
170 * Create a new string using two strings range.
171 */
172 LTTNG_HIDDEN
173 char *utils_strdupdelim(const char *begin, const char *end)
174 {
175 char *str;
176
177 str = zmalloc(end - begin + 1);
178 if (str == NULL) {
179 PERROR("zmalloc strdupdelim");
180 goto error;
181 }
182
183 memcpy(str, begin, end - begin);
184 str[end - begin] = '\0';
185
186 error:
187 return str;
188 }
189
190 /*
191 * Set CLOEXEC flag to the give file descriptor.
192 */
193 LTTNG_HIDDEN
194 int utils_set_fd_cloexec(int fd)
195 {
196 int ret;
197
198 if (fd < 0) {
199 ret = -EINVAL;
200 goto end;
201 }
202
203 ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
204 if (ret < 0) {
205 PERROR("fcntl cloexec");
206 ret = -errno;
207 }
208
209 end:
210 return ret;
211 }
212
213 /*
214 * Create pid file to the given path and filename.
215 */
216 LTTNG_HIDDEN
217 int utils_create_pid_file(pid_t pid, const char *filepath)
218 {
219 int ret;
220 FILE *fp;
221
222 assert(filepath);
223
224 fp = fopen(filepath, "w");
225 if (fp == NULL) {
226 PERROR("open pid file %s", filepath);
227 ret = -1;
228 goto error;
229 }
230
231 ret = fprintf(fp, "%d\n", pid);
232 if (ret < 0) {
233 PERROR("fprintf pid file");
234 }
235
236 fclose(fp);
237 DBG("Pid %d written in file %s", pid, filepath);
238 error:
239 return ret;
240 }
241
242 /*
243 * Recursively create directory using the given path and mode.
244 *
245 * On success, return 0 else a negative error code.
246 */
247 LTTNG_HIDDEN
248 int utils_mkdir_recursive(const char *path, mode_t mode)
249 {
250 char *p, tmp[PATH_MAX];
251 struct stat statbuf;
252 size_t len;
253 int ret;
254
255 assert(path);
256
257 ret = snprintf(tmp, sizeof(tmp), "%s", path);
258 if (ret < 0) {
259 PERROR("snprintf mkdir");
260 goto error;
261 }
262
263 len = ret;
264 if (tmp[len - 1] == '/') {
265 tmp[len - 1] = 0;
266 }
267
268 for (p = tmp + 1; *p; p++) {
269 if (*p == '/') {
270 *p = 0;
271 if (tmp[strlen(tmp) - 1] == '.' &&
272 tmp[strlen(tmp) - 2] == '.' &&
273 tmp[strlen(tmp) - 3] == '/') {
274 ERR("Using '/../' is not permitted in the trace path (%s)",
275 tmp);
276 ret = -1;
277 goto error;
278 }
279 ret = stat(tmp, &statbuf);
280 if (ret < 0) {
281 ret = mkdir(tmp, mode);
282 if (ret < 0) {
283 if (errno != EEXIST) {
284 PERROR("mkdir recursive");
285 ret = -errno;
286 goto error;
287 }
288 }
289 }
290 *p = '/';
291 }
292 }
293
294 ret = mkdir(tmp, mode);
295 if (ret < 0) {
296 if (errno != EEXIST) {
297 PERROR("mkdir recursive last piece");
298 ret = -errno;
299 } else {
300 ret = 0;
301 }
302 }
303
304 error:
305 return ret;
306 }
307
308 /*
309 * Create the stream tracefile on disk.
310 *
311 * Return 0 on success or else a negative value.
312 */
313 LTTNG_HIDDEN
314 int utils_create_stream_file(char *path_name, char *file_name, uint64_t size,
315 uint64_t count, int uid, int gid)
316 {
317 int ret, out_fd, flags, mode;
318 char full_path[PATH_MAX], *path_name_id = NULL, *path;
319
320 assert(path_name);
321 assert(file_name);
322
323 ret = snprintf(full_path, sizeof(full_path), "%s/%s",
324 path_name, file_name);
325 if (ret < 0) {
326 PERROR("snprintf create output file");
327 goto error;
328 }
329
330 /*
331 * If we split the trace in multiple files, we have to add the count at the
332 * end of the tracefile name
333 */
334 if (size > 0) {
335 ret = asprintf(&path_name_id, "%s_%" PRIu64, full_path, count);
336 if (ret < 0) {
337 PERROR("Allocating path name ID");
338 goto error;
339 }
340 path = path_name_id;
341 } else {
342 path = full_path;
343 }
344
345 flags = O_WRONLY | O_CREAT | O_TRUNC;
346 /* Open with 660 mode */
347 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
348
349 if (uid < 0 || gid < 0) {
350 out_fd = open(path, flags, mode);
351 } else {
352 out_fd = run_as_open(path, flags, mode, uid, gid);
353 }
354 if (out_fd < 0) {
355 PERROR("open stream path %s", path);
356 goto error_open;
357 }
358 ret = out_fd;
359
360 error_open:
361 free(path_name_id);
362 error:
363 return ret;
364 }
365
366 /*
367 * Change the output tracefile according to the given size and count The
368 * new_count pointer is set during this operation.
369 *
370 * From the consumer, the stream lock MUST be held before calling this function
371 * because we are modifying the stream status.
372 *
373 * Return 0 on success or else a negative value.
374 */
375 LTTNG_HIDDEN
376 int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size,
377 uint64_t count, int uid, int gid, int out_fd, uint64_t *new_count)
378 {
379 int ret;
380
381 ret = close(out_fd);
382 if (ret < 0) {
383 PERROR("Closing tracefile");
384 goto error;
385 }
386
387 if (count > 0) {
388 *new_count = (*new_count + 1) % count;
389 } else {
390 (*new_count)++;
391 }
392
393 return utils_create_stream_file(path_name, file_name, size, *new_count,
394 uid, gid);
395 error:
396 return ret;
397 }
398
399 /**
400 * Prints the error message corresponding to a regex error code.
401 *
402 * @param errcode The error code.
403 * @param regex The regex object that produced the error code.
404 */
405 static void regex_print_error(int errcode, regex_t *regex)
406 {
407 /* Get length of error message and allocate accordingly */
408 size_t length;
409 char *buffer;
410
411 assert(regex != NULL);
412
413 length = regerror(errcode, regex, NULL, 0);
414 if (length == 0) {
415 ERR("regerror returned a length of 0");
416 return;
417 }
418
419 buffer = zmalloc(length);
420 if (!buffer) {
421 ERR("regex_print_error: zmalloc failed");
422 return;
423 }
424
425 /* Get and print error message */
426 regerror(errcode, regex, buffer, length);
427 ERR("regex error: %s\n", buffer);
428 free(buffer);
429
430 }
431
432 /**
433 * Parse a string that represents a size in human readable format. It
434 * supports decimal integers suffixed by 'k', 'M' or 'G'.
435 *
436 * The suffix multiply the integer by:
437 * 'k': 1024
438 * 'M': 1024^2
439 * 'G': 1024^3
440 *
441 * @param str The string to parse.
442 * @param size Pointer to a size_t that will be filled with the
443 * resulting size.
444 *
445 * @return 0 on success, -1 on failure.
446 */
447 int utils_parse_size_suffix(char *str, uint64_t *size)
448 {
449 regex_t regex;
450 int ret;
451 const int nmatch = 3;
452 regmatch_t suffix_match, matches[nmatch];
453 unsigned long long base_size;
454 long shift = 0;
455
456 if (!str) {
457 return 0;
458 }
459
460 /* Compile regex */
461 ret = regcomp(&regex, "^\\(0x\\)\\{0,1\\}[0-9][0-9]*\\([kKMG]\\{0,1\\}\\)$", 0);
462 if (ret != 0) {
463 regex_print_error(ret, &regex);
464 ret = -1;
465 goto end;
466 }
467
468 /* Match regex */
469 ret = regexec(&regex, str, nmatch, matches, 0);
470 if (ret != 0) {
471 ret = -1;
472 goto free;
473 }
474
475 /* There is a match ! */
476 errno = 0;
477 base_size = strtoull(str, NULL, 0);
478 if (errno != 0) {
479 PERROR("strtoull");
480 ret = -1;
481 goto free;
482 }
483
484 /* Check if there is a suffix */
485 suffix_match = matches[2];
486 if (suffix_match.rm_eo - suffix_match.rm_so == 1) {
487 switch (*(str + suffix_match.rm_so)) {
488 case 'K':
489 case 'k':
490 shift = KIBI_LOG2;
491 break;
492 case 'M':
493 shift = MEBI_LOG2;
494 break;
495 case 'G':
496 shift = GIBI_LOG2;
497 break;
498 default:
499 ERR("parse_human_size: invalid suffix");
500 ret = -1;
501 goto free;
502 }
503 }
504
505 *size = base_size << shift;
506
507 /* Check for overflow */
508 if ((*size >> shift) != base_size) {
509 ERR("parse_size_suffix: oops, overflow detected.");
510 ret = -1;
511 goto free;
512 }
513
514 ret = 0;
515
516 free:
517 regfree(&regex);
518 end:
519 return ret;
520 }
521
522 /*
523 * fls: returns the position of the most significant bit.
524 * Returns 0 if no bit is set, else returns the position of the most
525 * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
526 */
527 #if defined(__i386) || defined(__x86_64)
528 static inline unsigned int fls_u32(uint32_t x)
529 {
530 int r;
531
532 asm("bsrl %1,%0\n\t"
533 "jnz 1f\n\t"
534 "movl $-1,%0\n\t"
535 "1:\n\t"
536 : "=r" (r) : "rm" (x));
537 return r + 1;
538 }
539 #define HAS_FLS_U32
540 #endif
541
542 #ifndef HAS_FLS_U32
543 static __attribute__((unused)) unsigned int fls_u32(uint32_t x)
544 {
545 unsigned int r = 32;
546
547 if (!x) {
548 return 0;
549 }
550 if (!(x & 0xFFFF0000U)) {
551 x <<= 16;
552 r -= 16;
553 }
554 if (!(x & 0xFF000000U)) {
555 x <<= 8;
556 r -= 8;
557 }
558 if (!(x & 0xF0000000U)) {
559 x <<= 4;
560 r -= 4;
561 }
562 if (!(x & 0xC0000000U)) {
563 x <<= 2;
564 r -= 2;
565 }
566 if (!(x & 0x80000000U)) {
567 x <<= 1;
568 r -= 1;
569 }
570 return r;
571 }
572 #endif
573
574 /*
575 * Return the minimum order for which x <= (1UL << order).
576 * Return -1 if x is 0.
577 */
578 LTTNG_HIDDEN
579 int utils_get_count_order_u32(uint32_t x)
580 {
581 if (!x) {
582 return -1;
583 }
584
585 return fls_u32(x - 1);
586 }
This page took 0.043608 seconds and 5 git commands to generate.