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