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