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