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