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