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