Generate local kernel and UST indexes
[lttng-tools.git] / src / common / utils.c
CommitLineData
81b86775
DG
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
35f90c40 19#include <assert.h>
81b86775
DG
20#include <ctype.h>
21#include <fcntl.h>
22#include <limits.h>
23#include <stdlib.h>
24#include <string.h>
2d851108 25#include <sys/stat.h>
0c7bcad5 26#include <sys/types.h>
2d851108 27#include <unistd.h>
fe4477ee 28#include <inttypes.h>
70d0b120 29#include <regex.h>
81b86775
DG
30
31#include <common/common.h>
fe4477ee 32#include <common/runas.h>
81b86775
DG
33
34#include "utils.h"
feb0f3e5 35#include "defaults.h"
81b86775
DG
36
37/*
38 * Return the realpath(3) of the path even if the last directory token does not
39 * exist. For example, with /tmp/test1/test2, if test2/ does not exist but the
40 * /tmp/test1 does, the real path is returned. In normal time, realpath(3)
41 * fails if the end point directory does not exist.
42 */
90e535ef 43LTTNG_HIDDEN
81b86775
DG
44char *utils_expand_path(const char *path)
45{
46 const char *end_path = path;
47 char *next, *cut_path = NULL, *expanded_path = NULL;
48
49 /* Safety net */
50 if (path == NULL) {
51 goto error;
52 }
53
54 /* Find last token delimited by '/' */
55 while ((next = strpbrk(end_path + 1, "/"))) {
56 end_path = next;
57 }
58
59 /* Cut last token from original path */
60 cut_path = strndup(path, end_path - path);
61
62 expanded_path = zmalloc(PATH_MAX);
63 if (expanded_path == NULL) {
64 PERROR("zmalloc expand path");
65 goto error;
66 }
67
68 expanded_path = realpath((char *)cut_path, expanded_path);
69 if (expanded_path == NULL) {
70 switch (errno) {
71 case ENOENT:
72 ERR("%s: No such file or directory", cut_path);
73 break;
74 default:
75 PERROR("realpath utils expand path");
76 break;
77 }
78 goto error;
79 }
80
81 /* Add end part to expanded path */
c30ce0b3 82 strncat(expanded_path, end_path, PATH_MAX - strlen(expanded_path) - 1);
81b86775
DG
83
84 free(cut_path);
85 return expanded_path;
86
87error:
88 free(expanded_path);
89 free(cut_path);
90 return NULL;
91}
92
93/*
94 * Create a pipe in dst.
95 */
90e535ef 96LTTNG_HIDDEN
81b86775
DG
97int utils_create_pipe(int *dst)
98{
99 int ret;
100
101 if (dst == NULL) {
102 return -1;
103 }
104
105 ret = pipe(dst);
106 if (ret < 0) {
107 PERROR("create pipe");
108 }
109
110 return ret;
111}
112
113/*
114 * Create pipe and set CLOEXEC flag to both fd.
115 *
116 * Make sure the pipe opened by this function are closed at some point. Use
117 * utils_close_pipe().
118 */
90e535ef 119LTTNG_HIDDEN
81b86775
DG
120int utils_create_pipe_cloexec(int *dst)
121{
122 int ret, i;
123
124 if (dst == NULL) {
125 return -1;
126 }
127
128 ret = utils_create_pipe(dst);
129 if (ret < 0) {
130 goto error;
131 }
132
133 for (i = 0; i < 2; i++) {
134 ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC);
135 if (ret < 0) {
136 PERROR("fcntl pipe cloexec");
137 goto error;
138 }
139 }
140
141error:
142 return ret;
143}
144
094f381c
MD
145/*
146 * Create pipe and set fd flags to FD_CLOEXEC and O_NONBLOCK.
147 *
148 * Make sure the pipe opened by this function are closed at some point. Use
149 * utils_close_pipe(). Using pipe() and fcntl rather than pipe2() to
150 * support OSes other than Linux 2.6.23+.
151 */
152LTTNG_HIDDEN
153int utils_create_pipe_cloexec_nonblock(int *dst)
154{
155 int ret, i;
156
157 if (dst == NULL) {
158 return -1;
159 }
160
161 ret = utils_create_pipe(dst);
162 if (ret < 0) {
163 goto error;
164 }
165
166 for (i = 0; i < 2; i++) {
167 ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC);
168 if (ret < 0) {
169 PERROR("fcntl pipe cloexec");
170 goto error;
171 }
172 /*
173 * Note: we override any flag that could have been
174 * previously set on the fd.
175 */
176 ret = fcntl(dst[i], F_SETFL, O_NONBLOCK);
177 if (ret < 0) {
178 PERROR("fcntl pipe nonblock");
179 goto error;
180 }
181 }
182
183error:
184 return ret;
185}
186
81b86775
DG
187/*
188 * Close both read and write side of the pipe.
189 */
90e535ef 190LTTNG_HIDDEN
81b86775
DG
191void utils_close_pipe(int *src)
192{
193 int i, ret;
194
195 if (src == NULL) {
196 return;
197 }
198
199 for (i = 0; i < 2; i++) {
200 /* Safety check */
201 if (src[i] < 0) {
202 continue;
203 }
204
205 ret = close(src[i]);
206 if (ret) {
207 PERROR("close pipe");
208 }
209 }
210}
a4b92340
DG
211
212/*
213 * Create a new string using two strings range.
214 */
90e535ef 215LTTNG_HIDDEN
a4b92340
DG
216char *utils_strdupdelim(const char *begin, const char *end)
217{
218 char *str;
219
220 str = zmalloc(end - begin + 1);
221 if (str == NULL) {
222 PERROR("zmalloc strdupdelim");
223 goto error;
224 }
225
226 memcpy(str, begin, end - begin);
227 str[end - begin] = '\0';
228
229error:
230 return str;
231}
b662582b
DG
232
233/*
234 * Set CLOEXEC flag to the give file descriptor.
235 */
90e535ef 236LTTNG_HIDDEN
b662582b
DG
237int utils_set_fd_cloexec(int fd)
238{
239 int ret;
240
241 if (fd < 0) {
242 ret = -EINVAL;
243 goto end;
244 }
245
246 ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
247 if (ret < 0) {
248 PERROR("fcntl cloexec");
249 ret = -errno;
250 }
251
252end:
253 return ret;
254}
35f90c40
DG
255
256/*
257 * Create pid file to the given path and filename.
258 */
90e535ef 259LTTNG_HIDDEN
35f90c40
DG
260int utils_create_pid_file(pid_t pid, const char *filepath)
261{
262 int ret;
263 FILE *fp;
264
265 assert(filepath);
266
267 fp = fopen(filepath, "w");
268 if (fp == NULL) {
269 PERROR("open pid file %s", filepath);
270 ret = -1;
271 goto error;
272 }
273
274 ret = fprintf(fp, "%d\n", pid);
275 if (ret < 0) {
276 PERROR("fprintf pid file");
277 }
278
279 fclose(fp);
280 DBG("Pid %d written in file %s", pid, filepath);
281error:
282 return ret;
283}
2d851108
DG
284
285/*
286 * Recursively create directory using the given path and mode.
287 *
288 * On success, return 0 else a negative error code.
289 */
90e535ef 290LTTNG_HIDDEN
2d851108
DG
291int utils_mkdir_recursive(const char *path, mode_t mode)
292{
293 char *p, tmp[PATH_MAX];
2d851108
DG
294 size_t len;
295 int ret;
296
297 assert(path);
298
299 ret = snprintf(tmp, sizeof(tmp), "%s", path);
300 if (ret < 0) {
301 PERROR("snprintf mkdir");
302 goto error;
303 }
304
305 len = ret;
306 if (tmp[len - 1] == '/') {
307 tmp[len - 1] = 0;
308 }
309
310 for (p = tmp + 1; *p; p++) {
311 if (*p == '/') {
312 *p = 0;
313 if (tmp[strlen(tmp) - 1] == '.' &&
314 tmp[strlen(tmp) - 2] == '.' &&
315 tmp[strlen(tmp) - 3] == '/') {
316 ERR("Using '/../' is not permitted in the trace path (%s)",
317 tmp);
318 ret = -1;
319 goto error;
320 }
0c7bcad5 321 ret = mkdir(tmp, mode);
2d851108 322 if (ret < 0) {
0c7bcad5
MD
323 if (errno != EEXIST) {
324 PERROR("mkdir recursive");
325 ret = -errno;
326 goto error;
2d851108
DG
327 }
328 }
329 *p = '/';
330 }
331 }
332
333 ret = mkdir(tmp, mode);
334 if (ret < 0) {
335 if (errno != EEXIST) {
336 PERROR("mkdir recursive last piece");
337 ret = -errno;
338 } else {
339 ret = 0;
340 }
341 }
342
343error:
344 return ret;
345}
fe4477ee
JD
346
347/*
348 * Create the stream tracefile on disk.
349 *
350 * Return 0 on success or else a negative value.
351 */
bc182241 352LTTNG_HIDDEN
07b86b52 353int utils_create_stream_file(const char *path_name, char *file_name, uint64_t size,
309167d2 354 uint64_t count, int uid, int gid, char *suffix)
fe4477ee 355{
be96a7d1 356 int ret, out_fd, flags, mode;
309167d2
JD
357 char full_path[PATH_MAX], *path_name_suffix = NULL, *path;
358 char *extra = NULL;
fe4477ee
JD
359
360 assert(path_name);
361 assert(file_name);
362
363 ret = snprintf(full_path, sizeof(full_path), "%s/%s",
364 path_name, file_name);
365 if (ret < 0) {
366 PERROR("snprintf create output file");
367 goto error;
368 }
369
309167d2
JD
370 /* Setup extra string if suffix or/and a count is needed. */
371 if (size > 0 && suffix) {
372 ret = asprintf(&extra, "_%" PRIu64 "%s", count, suffix);
373 } else if (size > 0) {
374 ret = asprintf(&extra, "_%" PRIu64, count);
375 } else if (suffix) {
376 ret = asprintf(&extra, "%s", suffix);
377 }
378 if (ret < 0) {
379 PERROR("Allocating extra string to name");
380 goto error;
381 }
382
fe4477ee
JD
383 /*
384 * If we split the trace in multiple files, we have to add the count at the
385 * end of the tracefile name
386 */
309167d2
JD
387 if (extra) {
388 ret = asprintf(&path_name_suffix, "%s%s", full_path, extra);
fe4477ee 389 if (ret < 0) {
309167d2
JD
390 PERROR("Allocating path name with extra string");
391 goto error_free_suffix;
fe4477ee 392 }
309167d2 393 path = path_name_suffix;
fe4477ee
JD
394 } else {
395 path = full_path;
396 }
397
be96a7d1 398 flags = O_WRONLY | O_CREAT | O_TRUNC;
0f907de1 399 /* Open with 660 mode */
be96a7d1
DG
400 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
401
402 if (uid < 0 || gid < 0) {
403 out_fd = open(path, flags, mode);
404 } else {
405 out_fd = run_as_open(path, flags, mode, uid, gid);
406 }
fe4477ee
JD
407 if (out_fd < 0) {
408 PERROR("open stream path %s", path);
409 goto error_open;
410 }
411 ret = out_fd;
412
413error_open:
309167d2
JD
414 free(path_name_suffix);
415error_free_suffix:
416 free(extra);
fe4477ee
JD
417error:
418 return ret;
419}
420
421/*
422 * Change the output tracefile according to the given size and count The
423 * new_count pointer is set during this operation.
424 *
425 * From the consumer, the stream lock MUST be held before calling this function
426 * because we are modifying the stream status.
427 *
428 * Return 0 on success or else a negative value.
429 */
bc182241 430LTTNG_HIDDEN
fe4477ee 431int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size,
309167d2
JD
432 uint64_t count, int uid, int gid, int out_fd, uint64_t *new_count,
433 int *stream_fd)
fe4477ee
JD
434{
435 int ret;
436
309167d2
JD
437 assert(new_count);
438 assert(stream_fd);
439
fe4477ee
JD
440 ret = close(out_fd);
441 if (ret < 0) {
442 PERROR("Closing tracefile");
443 goto error;
444 }
445
446 if (count > 0) {
447 *new_count = (*new_count + 1) % count;
448 } else {
449 (*new_count)++;
450 }
451
309167d2
JD
452 ret = utils_create_stream_file(path_name, file_name, size, *new_count,
453 uid, gid, 0);
454 if (ret < 0) {
455 goto error;
456 }
457 *stream_fd = ret;
458
459 /* Success. */
460 ret = 0;
461
fe4477ee
JD
462error:
463 return ret;
464}
70d0b120
SM
465
466/**
467 * Prints the error message corresponding to a regex error code.
468 *
469 * @param errcode The error code.
470 * @param regex The regex object that produced the error code.
471 */
472static void regex_print_error(int errcode, regex_t *regex)
473{
474 /* Get length of error message and allocate accordingly */
475 size_t length;
476 char *buffer;
477
478 assert(regex != NULL);
479
480 length = regerror(errcode, regex, NULL, 0);
481 if (length == 0) {
482 ERR("regerror returned a length of 0");
483 return;
484 }
485
486 buffer = zmalloc(length);
487 if (!buffer) {
488 ERR("regex_print_error: zmalloc failed");
489 return;
490 }
491
492 /* Get and print error message */
493 regerror(errcode, regex, buffer, length);
494 ERR("regex error: %s\n", buffer);
495 free(buffer);
496
497}
498
499/**
500 * Parse a string that represents a size in human readable format. It
501 * supports decimal integers suffixed by 'k', 'M' or 'G'.
502 *
503 * The suffix multiply the integer by:
504 * 'k': 1024
505 * 'M': 1024^2
506 * 'G': 1024^3
507 *
508 * @param str The string to parse.
509 * @param size Pointer to a size_t that will be filled with the
cfa9a5a2 510 * resulting size.
70d0b120
SM
511 *
512 * @return 0 on success, -1 on failure.
513 */
00a52467 514LTTNG_HIDDEN
70d0b120
SM
515int utils_parse_size_suffix(char *str, uint64_t *size)
516{
517 regex_t regex;
518 int ret;
519 const int nmatch = 3;
520 regmatch_t suffix_match, matches[nmatch];
521 unsigned long long base_size;
522 long shift = 0;
523
524 if (!str) {
525 return 0;
526 }
527
528 /* Compile regex */
529 ret = regcomp(&regex, "^\\(0x\\)\\{0,1\\}[0-9][0-9]*\\([kKMG]\\{0,1\\}\\)$", 0);
530 if (ret != 0) {
531 regex_print_error(ret, &regex);
532 ret = -1;
533 goto end;
534 }
535
536 /* Match regex */
537 ret = regexec(&regex, str, nmatch, matches, 0);
538 if (ret != 0) {
539 ret = -1;
540 goto free;
541 }
542
543 /* There is a match ! */
544 errno = 0;
545 base_size = strtoull(str, NULL, 0);
546 if (errno != 0) {
547 PERROR("strtoull");
548 ret = -1;
549 goto free;
550 }
551
552 /* Check if there is a suffix */
553 suffix_match = matches[2];
554 if (suffix_match.rm_eo - suffix_match.rm_so == 1) {
555 switch (*(str + suffix_match.rm_so)) {
556 case 'K':
557 case 'k':
558 shift = KIBI_LOG2;
559 break;
560 case 'M':
561 shift = MEBI_LOG2;
562 break;
563 case 'G':
564 shift = GIBI_LOG2;
565 break;
566 default:
567 ERR("parse_human_size: invalid suffix");
568 ret = -1;
569 goto free;
570 }
571 }
572
573 *size = base_size << shift;
574
575 /* Check for overflow */
576 if ((*size >> shift) != base_size) {
577 ERR("parse_size_suffix: oops, overflow detected.");
578 ret = -1;
579 goto free;
580 }
581
582 ret = 0;
583
584free:
585 regfree(&regex);
586end:
587 return ret;
588}
cfa9a5a2
DG
589
590/*
591 * fls: returns the position of the most significant bit.
592 * Returns 0 if no bit is set, else returns the position of the most
593 * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
594 */
595#if defined(__i386) || defined(__x86_64)
596static inline unsigned int fls_u32(uint32_t x)
597{
598 int r;
599
600 asm("bsrl %1,%0\n\t"
601 "jnz 1f\n\t"
602 "movl $-1,%0\n\t"
603 "1:\n\t"
604 : "=r" (r) : "rm" (x));
605 return r + 1;
606}
607#define HAS_FLS_U32
608#endif
609
610#ifndef HAS_FLS_U32
611static __attribute__((unused)) unsigned int fls_u32(uint32_t x)
612{
613 unsigned int r = 32;
614
615 if (!x) {
616 return 0;
617 }
618 if (!(x & 0xFFFF0000U)) {
619 x <<= 16;
620 r -= 16;
621 }
622 if (!(x & 0xFF000000U)) {
623 x <<= 8;
624 r -= 8;
625 }
626 if (!(x & 0xF0000000U)) {
627 x <<= 4;
628 r -= 4;
629 }
630 if (!(x & 0xC0000000U)) {
631 x <<= 2;
632 r -= 2;
633 }
634 if (!(x & 0x80000000U)) {
635 x <<= 1;
636 r -= 1;
637 }
638 return r;
639}
640#endif
641
642/*
643 * Return the minimum order for which x <= (1UL << order).
644 * Return -1 if x is 0.
645 */
646LTTNG_HIDDEN
647int utils_get_count_order_u32(uint32_t x)
648{
649 if (!x) {
650 return -1;
651 }
652
653 return fls_u32(x - 1);
654}
feb0f3e5
AM
655
656/**
657 * Obtain the value of LTTNG_HOME environment variable, if exists.
658 * Otherwise returns the value of HOME.
659 */
00a52467 660LTTNG_HIDDEN
feb0f3e5
AM
661char *utils_get_home_dir(void)
662{
663 char *val = NULL;
664 val = getenv(DEFAULT_LTTNG_HOME_ENV_VAR);
665 if (val != NULL) {
666 return val;
667 }
668 return getenv(DEFAULT_LTTNG_FALLBACK_HOME_ENV_VAR);
669}
26fe5938
DG
670
671/*
672 * With the given format, fill dst with the time of len maximum siz.
673 *
674 * Return amount of bytes set in the buffer or else 0 on error.
675 */
676LTTNG_HIDDEN
677size_t utils_get_current_time_str(const char *format, char *dst, size_t len)
678{
679 size_t ret;
680 time_t rawtime;
681 struct tm *timeinfo;
682
683 assert(format);
684 assert(dst);
685
686 /* Get date and time for session path */
687 time(&rawtime);
688 timeinfo = localtime(&rawtime);
689 ret = strftime(dst, len, format, timeinfo);
690 if (ret == 0) {
691 ERR("Unable to strftime with format %s at dst %p of len %lu", format,
692 dst, len);
693 }
694
695 return ret;
696}
This page took 0.055594 seconds and 4 git commands to generate.