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