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