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