configure: add '-Wundef' to warning flags
[lttng-tools.git] / src / common / utils.cpp
CommitLineData
81b86775 1/*
ab5be9fa 2 * Copyright (C) 2012 David Goulet <dgoulet@efficios.com>
ab5be9fa 3 * Copyright (C) 2013 Jérémie Galarneau <jeremie.galarneau@efficios.com>
81b86775 4 *
c922647d 5 * SPDX-License-Identifier: LGPL-2.1-only
81b86775 6 *
81b86775
DG
7 */
8
159b042f 9#include "common/macros.h"
13dd7782 10#include <stdint.h>
6c1c0768 11#define _LGPL_SOURCE
81b86775
DG
12#include <ctype.h>
13#include <fcntl.h>
14#include <limits.h>
15#include <stdlib.h>
2d851108 16#include <sys/stat.h>
0c7bcad5 17#include <sys/types.h>
2d851108 18#include <unistd.h>
fe4477ee 19#include <inttypes.h>
6c71277b 20#include <grp.h>
fb198a11 21#include <pwd.h>
c9cb3e7d 22#include <sys/file.h>
a98e236e 23#include <unistd.h>
81b86775
DG
24
25#include <common/common.h>
09b72f7a 26#include <common/readwrite.h>
fe4477ee 27#include <common/runas.h>
e8fa9fb0 28#include <common/compat/getenv.h>
f5436bfc 29#include <common/compat/string.h>
5a2451c9 30#include <common/compat/dirent.h>
18710679 31#include <common/compat/directory-handle.h>
28ab59d0 32#include <common/dynamic-buffer.h>
40804255 33#include <common/string-utils/format.h>
d7c23421 34#include <lttng/constant.h>
81b86775
DG
35
36#include "utils.h"
feb0f3e5 37#include "defaults.h"
2daf6502 38#include "time.h"
81b86775 39
09b72f7a
FD
40#define PROC_MEMINFO_PATH "/proc/meminfo"
41#define PROC_MEMINFO_MEMAVAILABLE_LINE "MemAvailable:"
42#define PROC_MEMINFO_MEMTOTAL_LINE "MemTotal:"
43
44/* The length of the longest field of `/proc/meminfo`. */
45#define PROC_MEMINFO_FIELD_MAX_NAME_LEN 20
46
47#if (PROC_MEMINFO_FIELD_MAX_NAME_LEN == 20)
48#define MAX_NAME_LEN_SCANF_IS_A_BROKEN_API "19"
49#else
50#error MAX_NAME_LEN_SCANF_IS_A_BROKEN_API must be updated to match (PROC_MEMINFO_FIELD_MAX_NAME_LEN - 1)
51#endif
52
159b042f
JG
53#define FALLBACK_USER_BUFLEN 16384
54#define FALLBACK_GROUP_BUFLEN 16384
55
81b86775
DG
56/*
57 * Create a pipe in dst.
58 */
59int utils_create_pipe(int *dst)
60{
61 int ret;
62
63 if (dst == NULL) {
64 return -1;
65 }
66
67 ret = pipe(dst);
68 if (ret < 0) {
69 PERROR("create pipe");
70 }
71
72 return ret;
73}
74
75/*
76 * Create pipe and set CLOEXEC flag to both fd.
77 *
78 * Make sure the pipe opened by this function are closed at some point. Use
79 * utils_close_pipe().
80 */
81int utils_create_pipe_cloexec(int *dst)
82{
83 int ret, i;
84
85 if (dst == NULL) {
86 return -1;
87 }
88
89 ret = utils_create_pipe(dst);
90 if (ret < 0) {
91 goto error;
92 }
93
94 for (i = 0; i < 2; i++) {
95 ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC);
96 if (ret < 0) {
97 PERROR("fcntl pipe cloexec");
98 goto error;
99 }
100 }
101
102error:
103 return ret;
104}
105
094f381c
MD
106/*
107 * Create pipe and set fd flags to FD_CLOEXEC and O_NONBLOCK.
108 *
109 * Make sure the pipe opened by this function are closed at some point. Use
110 * utils_close_pipe(). Using pipe() and fcntl rather than pipe2() to
111 * support OSes other than Linux 2.6.23+.
112 */
094f381c
MD
113int utils_create_pipe_cloexec_nonblock(int *dst)
114{
115 int ret, i;
116
117 if (dst == NULL) {
118 return -1;
119 }
120
121 ret = utils_create_pipe(dst);
122 if (ret < 0) {
123 goto error;
124 }
125
126 for (i = 0; i < 2; i++) {
127 ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC);
128 if (ret < 0) {
129 PERROR("fcntl pipe cloexec");
130 goto error;
131 }
132 /*
133 * Note: we override any flag that could have been
134 * previously set on the fd.
135 */
136 ret = fcntl(dst[i], F_SETFL, O_NONBLOCK);
137 if (ret < 0) {
138 PERROR("fcntl pipe nonblock");
139 goto error;
140 }
141 }
142
143error:
144 return ret;
145}
146
81b86775
DG
147/*
148 * Close both read and write side of the pipe.
149 */
150void utils_close_pipe(int *src)
151{
152 int i, ret;
153
154 if (src == NULL) {
155 return;
156 }
157
158 for (i = 0; i < 2; i++) {
159 /* Safety check */
160 if (src[i] < 0) {
161 continue;
162 }
163
164 ret = close(src[i]);
165 if (ret) {
166 PERROR("close pipe");
167 }
11f8d2f7 168 src[i] = -1;
81b86775
DG
169 }
170}
a4b92340
DG
171
172/*
173 * Create a new string using two strings range.
174 */
175char *utils_strdupdelim(const char *begin, const char *end)
176{
177 char *str;
178
a6bc4ca9 179 str = (char *) zmalloc(end - begin + 1);
a4b92340
DG
180 if (str == NULL) {
181 PERROR("zmalloc strdupdelim");
182 goto error;
183 }
184
185 memcpy(str, begin, end - begin);
186 str[end - begin] = '\0';
187
188error:
189 return str;
190}
b662582b
DG
191
192/*
193 * Set CLOEXEC flag to the give file descriptor.
194 */
b662582b
DG
195int utils_set_fd_cloexec(int fd)
196{
197 int ret;
198
199 if (fd < 0) {
200 ret = -EINVAL;
201 goto end;
202 }
203
204 ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
205 if (ret < 0) {
206 PERROR("fcntl cloexec");
207 ret = -errno;
208 }
209
210end:
211 return ret;
212}
35f90c40
DG
213
214/*
215 * Create pid file to the given path and filename.
216 */
35f90c40
DG
217int utils_create_pid_file(pid_t pid, const char *filepath)
218{
219 int ret;
220 FILE *fp;
221
a0377dfe 222 LTTNG_ASSERT(filepath);
35f90c40
DG
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
d1f721c5 231 ret = fprintf(fp, "%d\n", (int) pid);
35f90c40
DG
232 if (ret < 0) {
233 PERROR("fprintf pid file");
e205d79b 234 goto error;
35f90c40
DG
235 }
236
e205d79b
MD
237 if (fclose(fp)) {
238 PERROR("fclose");
239 }
d1f721c5 240 DBG("Pid %d written in file %s", (int) pid, filepath);
e205d79b 241 ret = 0;
35f90c40
DG
242error:
243 return ret;
244}
2d851108 245
c9cb3e7d
JG
246/*
247 * Create lock file to the given path and filename.
248 * Returns the associated file descriptor, -1 on error.
249 */
c9cb3e7d
JG
250int utils_create_lock_file(const char *filepath)
251{
252 int ret;
253 int fd;
77e7fddf 254 struct flock lock;
c9cb3e7d 255
a0377dfe 256 LTTNG_ASSERT(filepath);
c9cb3e7d 257
77e7fddf
MJ
258 memset(&lock, 0, sizeof(lock));
259 fd = open(filepath, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR |
260 S_IRGRP | S_IWGRP);
c9cb3e7d
JG
261 if (fd < 0) {
262 PERROR("open lock file %s", filepath);
e6576ba2 263 fd = -1;
c9cb3e7d
JG
264 goto error;
265 }
266
267 /*
268 * Attempt to lock the file. If this fails, there is
269 * already a process using the same lock file running
270 * and we should exit.
271 */
77e7fddf
MJ
272 lock.l_whence = SEEK_SET;
273 lock.l_type = F_WRLCK;
274
275 ret = fcntl(fd, F_SETLK, &lock);
276 if (ret == -1) {
277 PERROR("fcntl lock file");
208ff148 278 ERR("Could not get lock file %s, another instance is running.",
c9cb3e7d 279 filepath);
ffb0b851
JG
280 if (close(fd)) {
281 PERROR("close lock file");
282 }
c9cb3e7d
JG
283 fd = ret;
284 goto error;
285 }
286
287error:
288 return fd;
289}
290
2d851108 291/*
d77dded2 292 * Create directory using the given path and mode.
2d851108
DG
293 *
294 * On success, return 0 else a negative error code.
295 */
d77dded2
JG
296int utils_mkdir(const char *path, mode_t mode, int uid, int gid)
297{
298 int ret;
cbf53d23 299 struct lttng_directory_handle *handle;
69e3a560 300 const struct lttng_credentials creds = {
a6bc4ca9
SM
301 .uid = LTTNG_OPTIONAL_INIT_VALUE((uid_t) uid),
302 .gid = LTTNG_OPTIONAL_INIT_VALUE((gid_t) gid),
18710679
JG
303 };
304
cbf53d23
JG
305 handle = lttng_directory_handle_create(NULL);
306 if (!handle) {
307 ret = -1;
fd774fc6
JG
308 goto end;
309 }
18710679 310 ret = lttng_directory_handle_create_subdirectory_as_user(
cbf53d23 311 handle, path, mode,
18710679 312 (uid >= 0 || gid >= 0) ? &creds : NULL);
fd774fc6 313end:
cbf53d23 314 lttng_directory_handle_put(handle);
2d851108
DG
315 return ret;
316}
fe4477ee 317
d77dded2
JG
318/*
319 * Recursively create directory using the given path and mode, under the
320 * provided uid and gid.
321 *
322 * On success, return 0 else a negative error code.
323 */
d77dded2
JG
324int utils_mkdir_recursive(const char *path, mode_t mode, int uid, int gid)
325{
326 int ret;
cbf53d23 327 struct lttng_directory_handle *handle;
69e3a560 328 const struct lttng_credentials creds = {
a6bc4ca9
SM
329 .uid = LTTNG_OPTIONAL_INIT_VALUE((uid_t) uid),
330 .gid = LTTNG_OPTIONAL_INIT_VALUE((gid_t) gid),
18710679
JG
331 };
332
cbf53d23
JG
333 handle = lttng_directory_handle_create(NULL);
334 if (!handle) {
335 ret = -1;
fd774fc6
JG
336 goto end;
337 }
18710679 338 ret = lttng_directory_handle_create_subdirectory_recursive_as_user(
cbf53d23 339 handle, path, mode,
18710679 340 (uid >= 0 || gid >= 0) ? &creds : NULL);
fd774fc6 341end:
cbf53d23 342 lttng_directory_handle_put(handle);
d77dded2
JG
343 return ret;
344}
345
fe4477ee 346/*
40804255 347 * out_stream_path is the output parameter.
fe4477ee
JD
348 *
349 * Return 0 on success or else a negative value.
350 */
40804255
JG
351int utils_stream_file_path(const char *path_name, const char *file_name,
352 uint64_t size, uint64_t count, const char *suffix,
353 char *out_stream_path, size_t stream_path_len)
fe4477ee 354{
7591bab1 355 int ret;
d6d89e4c 356 char count_str[MAX_INT_DEC_LEN(count) + 1] = {};
40804255 357 const char *path_separator;
fe4477ee 358
d248f3c2
MD
359 if (path_name && (path_name[0] == '\0' ||
360 path_name[strlen(path_name) - 1] == '/')) {
40804255
JG
361 path_separator = "";
362 } else {
363 path_separator = "/";
fe4477ee
JD
364 }
365
40804255
JG
366 path_name = path_name ? : "";
367 suffix = suffix ? : "";
368 if (size > 0) {
369 ret = snprintf(count_str, sizeof(count_str), "_%" PRIu64,
370 count);
a0377dfe 371 LTTNG_ASSERT(ret > 0 && ret < sizeof(count_str));
309167d2
JD
372 }
373
d6d89e4c 374 ret = snprintf(out_stream_path, stream_path_len, "%s%s%s%s%s",
40804255
JG
375 path_name, path_separator, file_name, count_str,
376 suffix);
377 if (ret < 0 || ret >= stream_path_len) {
378 ERR("Truncation occurred while formatting stream path");
379 ret = -1;
fe4477ee 380 } else {
40804255 381 ret = 0;
7591bab1 382 }
7591bab1
MD
383 return ret;
384}
385
70d0b120
SM
386/**
387 * Parse a string that represents a size in human readable format. It
5983a922 388 * supports decimal integers suffixed by 'k', 'K', 'M' or 'G'.
70d0b120
SM
389 *
390 * The suffix multiply the integer by:
391 * 'k': 1024
392 * 'M': 1024^2
393 * 'G': 1024^3
394 *
395 * @param str The string to parse.
5983a922 396 * @param size Pointer to a uint64_t that will be filled with the
cfa9a5a2 397 * resulting size.
70d0b120
SM
398 *
399 * @return 0 on success, -1 on failure.
400 */
5983a922 401int utils_parse_size_suffix(const char * const str, uint64_t * const size)
70d0b120 402{
70d0b120 403 int ret;
5983a922 404 uint64_t base_size;
70d0b120 405 long shift = 0;
5983a922
SM
406 const char *str_end;
407 char *num_end;
70d0b120
SM
408
409 if (!str) {
5983a922 410 DBG("utils_parse_size_suffix: received a NULL string.");
70d0b120
SM
411 ret = -1;
412 goto end;
413 }
414
5983a922
SM
415 /* strtoull will accept a negative number, but we don't want to. */
416 if (strchr(str, '-') != NULL) {
417 DBG("utils_parse_size_suffix: invalid size string, should not contain '-'.");
70d0b120 418 ret = -1;
5983a922 419 goto end;
70d0b120
SM
420 }
421
5983a922
SM
422 /* str_end will point to the \0 */
423 str_end = str + strlen(str);
70d0b120 424 errno = 0;
5983a922 425 base_size = strtoull(str, &num_end, 0);
70d0b120 426 if (errno != 0) {
5983a922 427 PERROR("utils_parse_size_suffix strtoull");
70d0b120 428 ret = -1;
5983a922
SM
429 goto end;
430 }
431
432 if (num_end == str) {
433 /* strtoull parsed nothing, not good. */
434 DBG("utils_parse_size_suffix: strtoull had nothing good to parse.");
435 ret = -1;
436 goto end;
437 }
438
439 /* Check if a prefix is present. */
440 switch (*num_end) {
441 case 'G':
442 shift = GIBI_LOG2;
443 num_end++;
444 break;
445 case 'M': /* */
446 shift = MEBI_LOG2;
447 num_end++;
448 break;
449 case 'K':
450 case 'k':
451 shift = KIBI_LOG2;
452 num_end++;
453 break;
454 case '\0':
455 break;
456 default:
457 DBG("utils_parse_size_suffix: invalid suffix.");
458 ret = -1;
459 goto end;
460 }
461
462 /* Check for garbage after the valid input. */
463 if (num_end != str_end) {
464 DBG("utils_parse_size_suffix: Garbage after size string.");
465 ret = -1;
466 goto end;
70d0b120
SM
467 }
468
469 *size = base_size << shift;
470
471 /* Check for overflow */
472 if ((*size >> shift) != base_size) {
5983a922 473 DBG("utils_parse_size_suffix: oops, overflow detected.");
70d0b120 474 ret = -1;
5983a922 475 goto end;
70d0b120
SM
476 }
477
478 ret = 0;
70d0b120
SM
479end:
480 return ret;
481}
cfa9a5a2 482
7010c033
SM
483/**
484 * Parse a string that represents a time in human readable format. It
81684730
JR
485 * supports decimal integers suffixed by:
486 * "us" for microsecond,
487 * "ms" for millisecond,
488 * "s" for second,
489 * "m" for minute,
490 * "h" for hour
7010c033
SM
491 *
492 * The suffix multiply the integer by:
81684730
JR
493 * "us" : 1
494 * "ms" : 1000
495 * "s" : 1000000
496 * "m" : 60000000
497 * "h" : 3600000000
7010c033
SM
498 *
499 * Note that unit-less numbers are assumed to be microseconds.
500 *
501 * @param str The string to parse, assumed to be NULL-terminated.
502 * @param time_us Pointer to a uint64_t that will be filled with the
503 * resulting time in microseconds.
504 *
505 * @return 0 on success, -1 on failure.
506 */
7010c033
SM
507int utils_parse_time_suffix(char const * const str, uint64_t * const time_us)
508{
509 int ret;
510 uint64_t base_time;
81684730 511 uint64_t multiplier = 1;
7010c033
SM
512 const char *str_end;
513 char *num_end;
514
515 if (!str) {
516 DBG("utils_parse_time_suffix: received a NULL string.");
517 ret = -1;
518 goto end;
519 }
520
521 /* strtoull will accept a negative number, but we don't want to. */
522 if (strchr(str, '-') != NULL) {
523 DBG("utils_parse_time_suffix: invalid time string, should not contain '-'.");
524 ret = -1;
525 goto end;
526 }
527
528 /* str_end will point to the \0 */
529 str_end = str + strlen(str);
530 errno = 0;
531 base_time = strtoull(str, &num_end, 10);
532 if (errno != 0) {
533 PERROR("utils_parse_time_suffix strtoull on string \"%s\"", str);
534 ret = -1;
535 goto end;
536 }
537
538 if (num_end == str) {
539 /* strtoull parsed nothing, not good. */
540 DBG("utils_parse_time_suffix: strtoull had nothing good to parse.");
541 ret = -1;
542 goto end;
543 }
544
545 /* Check if a prefix is present. */
546 switch (*num_end) {
547 case 'u':
81684730
JR
548 /*
549 * Microsecond (us)
550 *
551 * Skip the "us" if the string matches the "us" suffix,
552 * otherwise let the check for the end of the string handle
553 * the error reporting.
554 */
555 if (*(num_end + 1) == 's') {
556 num_end += 2;
557 }
7010c033
SM
558 break;
559 case 'm':
81684730
JR
560 if (*(num_end + 1) == 's') {
561 /* Millisecond (ms) */
562 multiplier = USEC_PER_MSEC;
563 /* Skip the 's' */
564 num_end++;
565 } else {
566 /* Minute (m) */
567 multiplier = USEC_PER_MINUTE;
568 }
569 num_end++;
7010c033
SM
570 break;
571 case 's':
81684730
JR
572 /* Second */
573 multiplier = USEC_PER_SEC;
574 num_end++;
575 break;
576 case 'h':
577 /* Hour */
578 multiplier = USEC_PER_HOURS;
7010c033
SM
579 num_end++;
580 break;
581 case '\0':
582 break;
583 default:
584 DBG("utils_parse_time_suffix: invalid suffix.");
585 ret = -1;
586 goto end;
587 }
588
589 /* Check for garbage after the valid input. */
590 if (num_end != str_end) {
591 DBG("utils_parse_time_suffix: Garbage after time string.");
592 ret = -1;
593 goto end;
594 }
595
596 *time_us = base_time * multiplier;
597
598 /* Check for overflow */
599 if ((*time_us / multiplier) != base_time) {
600 DBG("utils_parse_time_suffix: oops, overflow detected.");
601 ret = -1;
602 goto end;
603 }
604
605 ret = 0;
606end:
607 return ret;
608}
609
cfa9a5a2
DG
610/*
611 * fls: returns the position of the most significant bit.
612 * Returns 0 if no bit is set, else returns the position of the most
613 * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
614 */
615#if defined(__i386) || defined(__x86_64)
616static inline unsigned int fls_u32(uint32_t x)
617{
618 int r;
619
620 asm("bsrl %1,%0\n\t"
621 "jnz 1f\n\t"
622 "movl $-1,%0\n\t"
623 "1:\n\t"
624 : "=r" (r) : "rm" (x));
625 return r + 1;
626}
627#define HAS_FLS_U32
628#endif
629
a1e4ab8b 630#if defined(__x86_64) && defined(__LP64__)
db5be0a3
JG
631static inline
632unsigned int fls_u64(uint64_t x)
633{
634 long r;
635
636 asm("bsrq %1,%0\n\t"
637 "jnz 1f\n\t"
638 "movq $-1,%0\n\t"
639 "1:\n\t"
640 : "=r" (r) : "rm" (x));
641 return r + 1;
642}
643#define HAS_FLS_U64
644#endif
645
646#ifndef HAS_FLS_U64
647static __attribute__((unused))
648unsigned int fls_u64(uint64_t x)
649{
650 unsigned int r = 64;
651
652 if (!x)
653 return 0;
654
655 if (!(x & 0xFFFFFFFF00000000ULL)) {
656 x <<= 32;
657 r -= 32;
658 }
659 if (!(x & 0xFFFF000000000000ULL)) {
660 x <<= 16;
661 r -= 16;
662 }
663 if (!(x & 0xFF00000000000000ULL)) {
664 x <<= 8;
665 r -= 8;
666 }
667 if (!(x & 0xF000000000000000ULL)) {
668 x <<= 4;
669 r -= 4;
670 }
671 if (!(x & 0xC000000000000000ULL)) {
672 x <<= 2;
673 r -= 2;
674 }
675 if (!(x & 0x8000000000000000ULL)) {
676 x <<= 1;
677 r -= 1;
678 }
679 return r;
680}
681#endif
682
cfa9a5a2
DG
683#ifndef HAS_FLS_U32
684static __attribute__((unused)) unsigned int fls_u32(uint32_t x)
685{
686 unsigned int r = 32;
687
688 if (!x) {
689 return 0;
690 }
691 if (!(x & 0xFFFF0000U)) {
692 x <<= 16;
693 r -= 16;
694 }
695 if (!(x & 0xFF000000U)) {
696 x <<= 8;
697 r -= 8;
698 }
699 if (!(x & 0xF0000000U)) {
700 x <<= 4;
701 r -= 4;
702 }
703 if (!(x & 0xC0000000U)) {
704 x <<= 2;
705 r -= 2;
706 }
707 if (!(x & 0x80000000U)) {
708 x <<= 1;
709 r -= 1;
710 }
711 return r;
712}
713#endif
714
715/*
716 * Return the minimum order for which x <= (1UL << order).
717 * Return -1 if x is 0.
718 */
cfa9a5a2
DG
719int utils_get_count_order_u32(uint32_t x)
720{
721 if (!x) {
722 return -1;
723 }
724
725 return fls_u32(x - 1);
726}
feb0f3e5 727
db5be0a3
JG
728/*
729 * Return the minimum order for which x <= (1UL << order).
730 * Return -1 if x is 0.
731 */
db5be0a3
JG
732int utils_get_count_order_u64(uint64_t x)
733{
734 if (!x) {
735 return -1;
736 }
737
738 return fls_u64(x - 1);
739}
740
feb0f3e5
AM
741/**
742 * Obtain the value of LTTNG_HOME environment variable, if exists.
743 * Otherwise returns the value of HOME.
744 */
4f00620d 745const char *utils_get_home_dir(void)
feb0f3e5
AM
746{
747 char *val = NULL;
04135dbd
DG
748 struct passwd *pwd;
749
e8fa9fb0 750 val = lttng_secure_getenv(DEFAULT_LTTNG_HOME_ENV_VAR);
feb0f3e5 751 if (val != NULL) {
04135dbd
DG
752 goto end;
753 }
e8fa9fb0 754 val = lttng_secure_getenv(DEFAULT_LTTNG_FALLBACK_HOME_ENV_VAR);
04135dbd
DG
755 if (val != NULL) {
756 goto end;
feb0f3e5 757 }
04135dbd
DG
758
759 /* Fallback on the password file entry. */
760 pwd = getpwuid(getuid());
761 if (!pwd) {
762 goto end;
763 }
764 val = pwd->pw_dir;
765
766 DBG3("Home directory is '%s'", val);
767
768end:
769 return val;
feb0f3e5 770}
26fe5938 771
fb198a11
JG
772/**
773 * Get user's home directory. Dynamically allocated, must be freed
774 * by the caller.
775 */
fb198a11
JG
776char *utils_get_user_home_dir(uid_t uid)
777{
778 struct passwd pwd;
779 struct passwd *result;
780 char *home_dir = NULL;
781 char *buf = NULL;
782 long buflen;
783 int ret;
784
785 buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
786 if (buflen == -1) {
787 goto end;
788 }
789retry:
a6bc4ca9 790 buf = (char *) zmalloc(buflen);
fb198a11
JG
791 if (!buf) {
792 goto end;
793 }
794
795 ret = getpwuid_r(uid, &pwd, buf, buflen, &result);
796 if (ret || !result) {
797 if (ret == ERANGE) {
798 free(buf);
799 buflen *= 2;
800 goto retry;
801 }
802 goto end;
803 }
804
805 home_dir = strdup(pwd.pw_dir);
806end:
807 free(buf);
808 return home_dir;
809}
810
26fe5938
DG
811/*
812 * With the given format, fill dst with the time of len maximum siz.
813 *
814 * Return amount of bytes set in the buffer or else 0 on error.
815 */
26fe5938
DG
816size_t utils_get_current_time_str(const char *format, char *dst, size_t len)
817{
818 size_t ret;
819 time_t rawtime;
820 struct tm *timeinfo;
821
a0377dfe
FD
822 LTTNG_ASSERT(format);
823 LTTNG_ASSERT(dst);
26fe5938
DG
824
825 /* Get date and time for session path */
826 time(&rawtime);
827 timeinfo = localtime(&rawtime);
411b3154
SM
828 DIAGNOSTIC_PUSH
829 DIAGNOSTIC_IGNORE_FORMAT_NONLITERAL
26fe5938 830 ret = strftime(dst, len, format, timeinfo);
411b3154 831 DIAGNOSTIC_POP
26fe5938 832 if (ret == 0) {
68e6efdd 833 ERR("Unable to strftime with format %s at dst %p of len %zu", format,
26fe5938
DG
834 dst, len);
835 }
836
837 return ret;
838}
6c71277b
MD
839
840/*
28ab59d0
JR
841 * Return 0 on success and set *gid to the group_ID matching the passed name.
842 * Else -1 if it cannot be found or an error occurred.
6c71277b 843 */
28ab59d0 844int utils_get_group_id(const char *name, bool warn, gid_t *gid)
6c71277b 845{
28ab59d0
JR
846 static volatile int warn_once;
847 int ret;
848 long sys_len;
849 size_t len;
850 struct group grp;
851 struct group *result;
852 struct lttng_dynamic_buffer buffer;
853
854 /* Get the system limit, if it exists. */
855 sys_len = sysconf(_SC_GETGR_R_SIZE_MAX);
856 if (sys_len == -1) {
857 len = 1024;
858 } else {
859 len = (size_t) sys_len;
860 }
861
862 lttng_dynamic_buffer_init(&buffer);
863 ret = lttng_dynamic_buffer_set_size(&buffer, len);
864 if (ret) {
865 ERR("Failed to allocate group info buffer");
866 ret = -1;
867 goto error;
868 }
6c71277b 869
28ab59d0
JR
870 while ((ret = getgrnam_r(name, &grp, buffer.data, buffer.size, &result)) == ERANGE) {
871 const size_t new_len = 2 * buffer.size;
6c71277b 872
28ab59d0
JR
873 /* Buffer is not big enough, increase its size. */
874 if (new_len < buffer.size) {
875 ERR("Group info buffer size overflow");
876 ret = -1;
877 goto error;
878 }
879
880 ret = lttng_dynamic_buffer_set_size(&buffer, new_len);
881 if (ret) {
882 ERR("Failed to grow group info buffer to %zu bytes",
883 new_len);
884 ret = -1;
885 goto error;
6c71277b 886 }
6c71277b 887 }
28ab59d0 888 if (ret) {
9120e619
JG
889 if (ret == ESRCH) {
890 DBG("Could not find group file entry for group name '%s'",
891 name);
892 } else {
893 PERROR("Failed to get group file entry for group name '%s'",
894 name);
895 }
896
28ab59d0
JR
897 ret = -1;
898 goto error;
899 }
900
901 /* Group not found. */
902 if (!result) {
903 ret = -1;
904 goto error;
905 }
906
907 *gid = result->gr_gid;
908 ret = 0;
909
910error:
911 if (ret && warn && !warn_once) {
912 WARN("No tracing group detected");
913 warn_once = 1;
914 }
915 lttng_dynamic_buffer_reset(&buffer);
916 return ret;
6c71277b 917}
8db0dc00
JG
918
919/*
920 * Return a newly allocated option string. This string is to be used as the
921 * optstring argument of getopt_long(), see GETOPT(3). opt_count is the number
922 * of elements in the long_options array. Returns NULL if the string's
923 * allocation fails.
924 */
8db0dc00
JG
925char *utils_generate_optstring(const struct option *long_options,
926 size_t opt_count)
927{
928 int i;
929 size_t string_len = opt_count, str_pos = 0;
930 char *optstring;
931
932 /*
933 * Compute the necessary string length. One letter per option, two when an
934 * argument is necessary, and a trailing NULL.
935 */
936 for (i = 0; i < opt_count; i++) {
937 string_len += long_options[i].has_arg ? 1 : 0;
938 }
939
a6bc4ca9 940 optstring = (char *) zmalloc(string_len);
8db0dc00
JG
941 if (!optstring) {
942 goto end;
943 }
944
945 for (i = 0; i < opt_count; i++) {
946 if (!long_options[i].name) {
947 /* Got to the trailing NULL element */
948 break;
949 }
950
a596dcb9
JG
951 if (long_options[i].val != '\0') {
952 optstring[str_pos++] = (char) long_options[i].val;
953 if (long_options[i].has_arg) {
954 optstring[str_pos++] = ':';
955 }
8db0dc00
JG
956 }
957 }
958
959end:
960 return optstring;
961}
3d071855
MD
962
963/*
964 * Try to remove a hierarchy of empty directories, recursively. Don't unlink
9529ec1b 965 * any file. Try to rmdir any empty directory within the hierarchy.
3d071855 966 */
3d071855
MD
967int utils_recursive_rmdir(const char *path)
968{
93bed9fe 969 int ret;
cbf53d23 970 struct lttng_directory_handle *handle;
7a946beb 971
cbf53d23
JG
972 handle = lttng_directory_handle_create(NULL);
973 if (!handle) {
974 ret = -1;
93bed9fe 975 goto end;
3d071855 976 }
cbf53d23 977 ret = lttng_directory_handle_remove_subdirectory(handle, path);
3d071855 978end:
cbf53d23 979 lttng_directory_handle_put(handle);
3d071855
MD
980 return ret;
981}
93ec662e 982
93ec662e
JD
983int utils_truncate_stream_file(int fd, off_t length)
984{
985 int ret;
a5df8828 986 off_t lseek_ret;
93ec662e
JD
987
988 ret = ftruncate(fd, length);
989 if (ret < 0) {
990 PERROR("ftruncate");
991 goto end;
992 }
a5df8828
GL
993 lseek_ret = lseek(fd, length, SEEK_SET);
994 if (lseek_ret < 0) {
93ec662e 995 PERROR("lseek");
a5df8828 996 ret = -1;
93ec662e
JD
997 goto end;
998 }
93ec662e
JD
999end:
1000 return ret;
1001}
4ba92f18
PP
1002
1003static const char *get_man_bin_path(void)
1004{
b7dce40d 1005 char *env_man_path = lttng_secure_getenv(DEFAULT_MAN_BIN_PATH_ENV);
4ba92f18
PP
1006
1007 if (env_man_path) {
1008 return env_man_path;
1009 }
1010
1011 return DEFAULT_MAN_BIN_PATH;
1012}
1013
4fc83d94
PP
1014int utils_show_help(int section, const char *page_name,
1015 const char *help_msg)
4ba92f18
PP
1016{
1017 char section_string[8];
1018 const char *man_bin_path = get_man_bin_path();
4fc83d94
PP
1019 int ret = 0;
1020
1021 if (help_msg) {
1022 printf("%s", help_msg);
1023 goto end;
1024 }
4ba92f18
PP
1025
1026 /* Section integer -> section string */
1027 ret = sprintf(section_string, "%d", section);
a0377dfe 1028 LTTNG_ASSERT(ret > 0 && ret < 8);
4ba92f18
PP
1029
1030 /*
1031 * Execute man pager.
1032 *
b07e7ef0 1033 * We provide -M to man here because LTTng-tools can
4ba92f18
PP
1034 * be installed outside /usr, in which case its man pages are
1035 * not located in the default /usr/share/man directory.
1036 */
b07e7ef0 1037 ret = execlp(man_bin_path, "man", "-M", MANPATH,
4ba92f18 1038 section_string, page_name, NULL);
4fc83d94
PP
1039
1040end:
4ba92f18
PP
1041 return ret;
1042}
09b72f7a
FD
1043
1044static
13dd7782 1045int read_proc_meminfo_field(const char *field, uint64_t *value)
09b72f7a
FD
1046{
1047 int ret;
1048 FILE *proc_meminfo;
1049 char name[PROC_MEMINFO_FIELD_MAX_NAME_LEN] = {};
1050
1051 proc_meminfo = fopen(PROC_MEMINFO_PATH, "r");
1052 if (!proc_meminfo) {
1053 PERROR("Failed to fopen() " PROC_MEMINFO_PATH);
1054 ret = -1;
1055 goto fopen_error;
1056 }
1057
1058 /*
1059 * Read the contents of /proc/meminfo line by line to find the right
1060 * field.
1061 */
1062 while (!feof(proc_meminfo)) {
13dd7782 1063 uint64_t value_kb;
09b72f7a
FD
1064
1065 ret = fscanf(proc_meminfo,
13dd7782 1066 "%" MAX_NAME_LEN_SCANF_IS_A_BROKEN_API "s %" SCNu64 " kB\n",
09b72f7a
FD
1067 name, &value_kb);
1068 if (ret == EOF) {
1069 /*
1070 * fscanf() returning EOF can indicate EOF or an error.
1071 */
1072 if (ferror(proc_meminfo)) {
1073 PERROR("Failed to parse " PROC_MEMINFO_PATH);
1074 }
1075 break;
1076 }
1077
1078 if (ret == 2 && strcmp(name, field) == 0) {
1079 /*
1080 * This number is displayed in kilo-bytes. Return the
1081 * number of bytes.
1082 */
13dd7782
JR
1083 if (value_kb > UINT64_MAX / 1024) {
1084 ERR("Overflow on kb to bytes conversion");
1085 break;
1086 }
1087
1088 *value = value_kb * 1024;
09b72f7a
FD
1089 ret = 0;
1090 goto found;
1091 }
1092 }
1093 /* Reached the end of the file without finding the right field. */
1094 ret = -1;
1095
1096found:
1097 fclose(proc_meminfo);
1098fopen_error:
1099 return ret;
1100}
1101
1102/*
1103 * Returns an estimate of the number of bytes of memory available based on the
1104 * the information in `/proc/meminfo`. The number returned by this function is
1105 * a best guess.
1106 */
13dd7782 1107int utils_get_memory_available(uint64_t *value)
09b72f7a
FD
1108{
1109 return read_proc_meminfo_field(PROC_MEMINFO_MEMAVAILABLE_LINE, value);
1110}
1111
1112/*
1113 * Returns the total size of the memory on the system in bytes based on the
1114 * the information in `/proc/meminfo`.
1115 */
13dd7782 1116int utils_get_memory_total(uint64_t *value)
09b72f7a
FD
1117{
1118 return read_proc_meminfo_field(PROC_MEMINFO_MEMTOTAL_LINE, value);
1119}
ce9ee1fb 1120
ce9ee1fb
JR
1121int utils_change_working_directory(const char *path)
1122{
1123 int ret;
1124
a0377dfe 1125 LTTNG_ASSERT(path);
ce9ee1fb
JR
1126
1127 DBG("Changing working directory to \"%s\"", path);
1128 ret = chdir(path);
1129 if (ret) {
1130 PERROR("Failed to change working directory to \"%s\"", path);
1131 goto end;
1132 }
1133
1134 /* Check for write access */
1135 if (access(path, W_OK)) {
1136 if (errno == EACCES) {
1137 /*
1138 * Do not treat this as an error since the permission
1139 * might change in the lifetime of the process
1140 */
1141 DBG("Working directory \"%s\" is not writable", path);
1142 } else {
1143 PERROR("Failed to check if working directory \"%s\" is writable",
1144 path);
1145 }
1146 }
1147
1148end:
1149 return ret;
1150}
159b042f 1151
159b042f
JG
1152enum lttng_error_code utils_user_id_from_name(const char *user_name, uid_t *uid)
1153{
1154 struct passwd p, *pres;
1155 int ret;
1156 enum lttng_error_code ret_val = LTTNG_OK;
1157 char *buf = NULL;
1158 ssize_t buflen;
1159
1160 buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
1161 if (buflen < 0) {
1162 buflen = FALLBACK_USER_BUFLEN;
1163 }
1164
a6bc4ca9 1165 buf = (char *) zmalloc(buflen);
159b042f
JG
1166 if (!buf) {
1167 ret_val = LTTNG_ERR_NOMEM;
1168 goto end;
1169 }
1170
1171 for (;;) {
1172 ret = getpwnam_r(user_name, &p, buf, buflen, &pres);
1173 switch (ret) {
1174 case EINTR:
1175 continue;
1176 case ERANGE:
1177 buflen *= 2;
1178 free(buf);
a6bc4ca9 1179 buf = (char *) zmalloc(buflen);
159b042f
JG
1180 if (!buf) {
1181 ret_val = LTTNG_ERR_NOMEM;
1182 goto end;
1183 }
1184 continue;
1185 default:
1186 goto end_loop;
1187 }
1188 }
1189end_loop:
1190
1191 switch (ret) {
1192 case 0:
1193 if (pres == NULL) {
1194 ret_val = LTTNG_ERR_USER_NOT_FOUND;
1195 } else {
1196 *uid = p.pw_uid;
1197 DBG("Lookup of tracker UID/VUID: name '%s' maps to uid %" PRId64,
1198 user_name, (int64_t) *uid);
1199 ret_val = LTTNG_OK;
1200 }
1201 break;
1202 case ENOENT:
1203 case ESRCH:
1204 case EBADF:
1205 case EPERM:
1206 ret_val = LTTNG_ERR_USER_NOT_FOUND;
1207 break;
1208 default:
1209 ret_val = LTTNG_ERR_NOMEM;
1210 }
1211end:
1212 free(buf);
1213 return ret_val;
1214}
1215
159b042f
JG
1216enum lttng_error_code utils_group_id_from_name(
1217 const char *group_name, gid_t *gid)
1218{
1219 struct group g, *gres;
1220 int ret;
1221 enum lttng_error_code ret_val = LTTNG_OK;
1222 char *buf = NULL;
1223 ssize_t buflen;
1224
1225 buflen = sysconf(_SC_GETGR_R_SIZE_MAX);
1226 if (buflen < 0) {
1227 buflen = FALLBACK_GROUP_BUFLEN;
1228 }
1229
a6bc4ca9 1230 buf = (char *) zmalloc(buflen);
159b042f
JG
1231 if (!buf) {
1232 ret_val = LTTNG_ERR_NOMEM;
1233 goto end;
1234 }
1235
1236 for (;;) {
1237 ret = getgrnam_r(group_name, &g, buf, buflen, &gres);
1238 switch (ret) {
1239 case EINTR:
1240 continue;
1241 case ERANGE:
1242 buflen *= 2;
1243 free(buf);
a6bc4ca9 1244 buf = (char *) zmalloc(buflen);
159b042f
JG
1245 if (!buf) {
1246 ret_val = LTTNG_ERR_NOMEM;
1247 goto end;
1248 }
1249 continue;
1250 default:
1251 goto end_loop;
1252 }
1253 }
1254end_loop:
1255
1256 switch (ret) {
1257 case 0:
1258 if (gres == NULL) {
1259 ret_val = LTTNG_ERR_GROUP_NOT_FOUND;
1260 } else {
1261 *gid = g.gr_gid;
1262 DBG("Lookup of tracker GID/GUID: name '%s' maps to gid %" PRId64,
1263 group_name, (int64_t) *gid);
1264 ret_val = LTTNG_OK;
1265 }
1266 break;
1267 case ENOENT:
1268 case ESRCH:
1269 case EBADF:
1270 case EPERM:
1271 ret_val = LTTNG_ERR_GROUP_NOT_FOUND;
1272 break;
1273 default:
1274 ret_val = LTTNG_ERR_NOMEM;
1275 }
1276end:
1277 free(buf);
1278 return ret_val;
1279}
240baf2b 1280
240baf2b
JR
1281int utils_parse_unsigned_long_long(const char *str,
1282 unsigned long long *value)
1283{
1284 int ret;
1285 char *endptr;
1286
a0377dfe
FD
1287 LTTNG_ASSERT(str);
1288 LTTNG_ASSERT(value);
240baf2b
JR
1289
1290 errno = 0;
1291 *value = strtoull(str, &endptr, 10);
1292
1293 /* Conversion failed. Out of range? */
1294 if (errno != 0) {
1295 /* Don't print an error; allow the caller to log a better error. */
1296 DBG("Failed to parse string as unsigned long long number: string = '%s', errno = %d",
1297 str, errno);
1298 ret = -1;
1299 goto end;
1300 }
1301
1302 /* Not the end of the string or empty string. */
1303 if (*endptr || endptr == str) {
1304 DBG("Failed to parse string as unsigned long long number: string = '%s'",
1305 str);
1306 ret = -1;
1307 goto end;
1308 }
1309
1310 ret = 0;
1311
1312end:
1313 return ret;
1314}
This page took 0.131514 seconds and 4 git commands to generate.