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