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