common: move utils_create_lock_file to its own file
[lttng-tools.git] / src / common / utils.c
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 #include "common/macros.h"
10 #include <stdint.h>
11 #define _LGPL_SOURCE
12 #include <assert.h>
13 #include <ctype.h>
14 #include <fcntl.h>
15 #include <limits.h>
16 #include <stdlib.h>
17 #include <sys/stat.h>
18 #include <sys/types.h>
19 #include <unistd.h>
20 #include <inttypes.h>
21 #include <grp.h>
22 #include <pwd.h>
23 #include <sys/file.h>
24 #include <unistd.h>
25
26 #include <common/common.h>
27 #include <common/readwrite.h>
28 #include <common/runas.h>
29 #include <common/compat/getenv.h>
30 #include <common/compat/string.h>
31 #include <common/compat/dirent.h>
32 #include <common/compat/directory-handle.h>
33 #include <common/dynamic-buffer.h>
34 #include <common/string-utils/format.h>
35 #include <lttng/constant.h>
36
37 #include "utils.h"
38 #include "defaults.h"
39 #include "time.h"
40
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
54 #define FALLBACK_USER_BUFLEN 16384
55 #define FALLBACK_GROUP_BUFLEN 16384
56
57 /*
58 * Create a pipe in dst.
59 */
60 LTTNG_HIDDEN
61 int 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 */
83 LTTNG_HIDDEN
84 int 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
105 error:
106 return ret;
107 }
108
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 */
116 LTTNG_HIDDEN
117 int 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
147 error:
148 return ret;
149 }
150
151 /*
152 * Close both read and write side of the pipe.
153 */
154 LTTNG_HIDDEN
155 void 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 }
173 src[i] = -1;
174 }
175 }
176
177 /*
178 * Create a new string using two strings range.
179 */
180 LTTNG_HIDDEN
181 char *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
194 error:
195 return str;
196 }
197
198 /*
199 * Set CLOEXEC flag to the give file descriptor.
200 */
201 LTTNG_HIDDEN
202 int 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
217 end:
218 return ret;
219 }
220
221 /*
222 * Create pid file to the given path and filename.
223 */
224 LTTNG_HIDDEN
225 int utils_create_pid_file(pid_t pid, const char *filepath)
226 {
227 int ret, fd = -1;
228 FILE *fp = NULL;
229
230 assert(filepath);
231
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");
240 if (fp == NULL) {
241 PERROR("fdopen file %s", filepath);
242 ret = -1;
243 if (close(fd)) {
244 PERROR("Failed to close `%s` file descriptor while handling fdopen error", filepath);
245 }
246
247 goto error;
248 }
249
250 ret = fprintf(fp, "%d\n", (int) pid);
251 if (ret < 0) {
252 PERROR("fprintf file %s", filepath);
253 ret = -1;
254 goto error;
255 }
256
257 DBG("'%d' written in file %s", (int) pid, filepath);
258 ret = 0;
259
260 error:
261 if (fp && fclose(fp)) {
262 PERROR("fclose file %s", filepath);
263 }
264 return ret;
265 }
266
267 /*
268 * Create directory using the given path and mode.
269 *
270 * On success, return 0 else a negative error code.
271 */
272 LTTNG_HIDDEN
273 int utils_mkdir(const char *path, mode_t mode, int uid, int gid)
274 {
275 int ret;
276 struct lttng_directory_handle *handle;
277 const struct lttng_credentials creds = {
278 .uid = (uid_t) uid,
279 .gid = (gid_t) gid,
280 };
281
282 handle = lttng_directory_handle_create(NULL);
283 if (!handle) {
284 ret = -1;
285 goto end;
286 }
287 ret = lttng_directory_handle_create_subdirectory_as_user(
288 handle, path, mode,
289 (uid >= 0 || gid >= 0) ? &creds : NULL);
290 end:
291 lttng_directory_handle_put(handle);
292 return ret;
293 }
294
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 */
301 LTTNG_HIDDEN
302 int utils_mkdir_recursive(const char *path, mode_t mode, int uid, int gid)
303 {
304 int ret;
305 struct lttng_directory_handle *handle;
306 const struct lttng_credentials creds = {
307 .uid = (uid_t) uid,
308 .gid = (gid_t) gid,
309 };
310
311 handle = lttng_directory_handle_create(NULL);
312 if (!handle) {
313 ret = -1;
314 goto end;
315 }
316 ret = lttng_directory_handle_create_subdirectory_recursive_as_user(
317 handle, path, mode,
318 (uid >= 0 || gid >= 0) ? &creds : NULL);
319 end:
320 lttng_directory_handle_put(handle);
321 return ret;
322 }
323
324 /*
325 * out_stream_path is the output parameter.
326 *
327 * Return 0 on success or else a negative value.
328 */
329 LTTNG_HIDDEN
330 int 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)
333 {
334 int ret;
335 char count_str[MAX_INT_DEC_LEN(count) + 1] = {};
336 const char *path_separator;
337
338 if (path_name && (path_name[0] == '\0' ||
339 path_name[strlen(path_name) - 1] == '/')) {
340 path_separator = "";
341 } else {
342 path_separator = "/";
343 }
344
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));
351 }
352
353 ret = snprintf(out_stream_path, stream_path_len, "%s%s%s%s%s",
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;
359 } else {
360 ret = 0;
361 }
362 return ret;
363 }
364
365 /**
366 * Parse a string that represents a size in human readable format. It
367 * supports decimal integers suffixed by 'k', 'K', 'M' or 'G'.
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.
375 * @param size Pointer to a uint64_t that will be filled with the
376 * resulting size.
377 *
378 * @return 0 on success, -1 on failure.
379 */
380 LTTNG_HIDDEN
381 int utils_parse_size_suffix(const char * const str, uint64_t * const size)
382 {
383 int ret;
384 uint64_t base_size;
385 long shift = 0;
386 const char *str_end;
387 char *num_end;
388
389 if (!str) {
390 DBG("utils_parse_size_suffix: received a NULL string.");
391 ret = -1;
392 goto end;
393 }
394
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 '-'.");
398 ret = -1;
399 goto end;
400 }
401
402 /* str_end will point to the \0 */
403 str_end = str + strlen(str);
404 errno = 0;
405 base_size = strtoull(str, &num_end, 0);
406 if (errno != 0) {
407 PERROR("utils_parse_size_suffix strtoull");
408 ret = -1;
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;
447 }
448
449 *size = base_size << shift;
450
451 /* Check for overflow */
452 if ((*size >> shift) != base_size) {
453 DBG("utils_parse_size_suffix: oops, overflow detected.");
454 ret = -1;
455 goto end;
456 }
457
458 ret = 0;
459 end:
460 return ret;
461 }
462
463 /**
464 * Parse a string that represents a time in human readable format. It
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
471 *
472 * The suffix multiply the integer by:
473 * "us" : 1
474 * "ms" : 1000
475 * "s" : 1000000
476 * "m" : 60000000
477 * "h" : 3600000000
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 */
487 LTTNG_HIDDEN
488 int utils_parse_time_suffix(char const * const str, uint64_t * const time_us)
489 {
490 int ret;
491 uint64_t base_time;
492 uint64_t multiplier = 1;
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':
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 }
539 break;
540 case 'm':
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++;
551 break;
552 case 's':
553 /* Second */
554 multiplier = USEC_PER_SEC;
555 num_end++;
556 break;
557 case 'h':
558 /* Hour */
559 multiplier = USEC_PER_HOURS;
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;
587 end:
588 return ret;
589 }
590
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)
597 static 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
611 #if defined(__x86_64) && defined(__LP64__)
612 static inline
613 unsigned 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
628 static __attribute__((unused))
629 unsigned 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
664 #ifndef HAS_FLS_U32
665 static __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 */
700 LTTNG_HIDDEN
701 int utils_get_count_order_u32(uint32_t x)
702 {
703 if (!x) {
704 return -1;
705 }
706
707 return fls_u32(x - 1);
708 }
709
710 /*
711 * Return the minimum order for which x <= (1UL << order).
712 * Return -1 if x is 0.
713 */
714 LTTNG_HIDDEN
715 int 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
724 /**
725 * Obtain the value of LTTNG_HOME environment variable, if exists.
726 * Otherwise returns the value of HOME.
727 */
728 LTTNG_HIDDEN
729 const char *utils_get_home_dir(void)
730 {
731 char *val = NULL;
732 struct passwd *pwd;
733
734 val = lttng_secure_getenv(DEFAULT_LTTNG_HOME_ENV_VAR);
735 if (val != NULL) {
736 goto end;
737 }
738 val = lttng_secure_getenv(DEFAULT_LTTNG_FALLBACK_HOME_ENV_VAR);
739 if (val != NULL) {
740 goto end;
741 }
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
752 end:
753 return val;
754 }
755
756 /**
757 * Get user's home directory. Dynamically allocated, must be freed
758 * by the caller.
759 */
760 LTTNG_HIDDEN
761 char *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 }
774 retry:
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);
791 end:
792 free(buf);
793 return home_dir;
794 }
795
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 */
801 LTTNG_HIDDEN
802 size_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) {
816 ERR("Unable to strftime with format %s at dst %p of len %zu", format,
817 dst, len);
818 }
819
820 return ret;
821 }
822
823 /*
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.
826 */
827 LTTNG_HIDDEN
828 int utils_get_group_id(const char *name, bool warn, gid_t *gid)
829 {
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 }
853
854 while ((ret = getgrnam_r(name, &grp, buffer.data, buffer.size, &result)) == ERANGE) {
855 const size_t new_len = 2 * buffer.size;
856
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;
870 }
871 }
872 if (ret) {
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
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
894 error:
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;
901 }
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 */
909 LTTNG_HIDDEN
910 char *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
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 }
941 }
942 }
943
944 end:
945 return optstring;
946 }
947
948 /*
949 * Try to remove a hierarchy of empty directories, recursively. Don't unlink
950 * any file. Try to rmdir any empty directory within the hierarchy.
951 */
952 LTTNG_HIDDEN
953 int utils_recursive_rmdir(const char *path)
954 {
955 int ret;
956 struct lttng_directory_handle *handle;
957
958 handle = lttng_directory_handle_create(NULL);
959 if (!handle) {
960 ret = -1;
961 goto end;
962 }
963 ret = lttng_directory_handle_remove_subdirectory(handle, path);
964 end:
965 lttng_directory_handle_put(handle);
966 return ret;
967 }
968
969 LTTNG_HIDDEN
970 int utils_truncate_stream_file(int fd, off_t length)
971 {
972 int ret;
973 off_t lseek_ret;
974
975 ret = ftruncate(fd, length);
976 if (ret < 0) {
977 PERROR("ftruncate");
978 goto end;
979 }
980 lseek_ret = lseek(fd, length, SEEK_SET);
981 if (lseek_ret < 0) {
982 PERROR("lseek");
983 ret = -1;
984 goto end;
985 }
986 end:
987 return ret;
988 }
989
990 static const char *get_man_bin_path(void)
991 {
992 char *env_man_path = lttng_secure_getenv(DEFAULT_MAN_BIN_PATH_ENV);
993
994 if (env_man_path) {
995 return env_man_path;
996 }
997
998 return DEFAULT_MAN_BIN_PATH;
999 }
1000
1001 LTTNG_HIDDEN
1002 int utils_show_help(int section, const char *page_name,
1003 const char *help_msg)
1004 {
1005 char section_string[8];
1006 const char *man_bin_path = get_man_bin_path();
1007 int ret = 0;
1008
1009 if (help_msg) {
1010 printf("%s", help_msg);
1011 goto end;
1012 }
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 *
1021 * We provide -M to man here because LTTng-tools can
1022 * be installed outside /usr, in which case its man pages are
1023 * not located in the default /usr/share/man directory.
1024 */
1025 ret = execlp(man_bin_path, "man", "-M", MANPATH,
1026 section_string, page_name, NULL);
1027
1028 end:
1029 return ret;
1030 }
1031
1032 static
1033 int read_proc_meminfo_field(const char *field, uint64_t *value)
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)) {
1051 uint64_t value_kb;
1052
1053 ret = fscanf(proc_meminfo,
1054 "%" MAX_NAME_LEN_SCANF_IS_A_BROKEN_API "s %" SCNu64 " kB\n",
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 */
1071 if (value_kb > UINT64_MAX / 1024) {
1072 ERR("Overflow on kb to bytes conversion");
1073 break;
1074 }
1075
1076 *value = value_kb * 1024;
1077 ret = 0;
1078 goto found;
1079 }
1080 }
1081 /* Reached the end of the file without finding the right field. */
1082 ret = -1;
1083
1084 found:
1085 fclose(proc_meminfo);
1086 fopen_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 */
1095 LTTNG_HIDDEN
1096 int utils_get_memory_available(uint64_t *value)
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 */
1105 LTTNG_HIDDEN
1106 int utils_get_memory_total(uint64_t *value)
1107 {
1108 return read_proc_meminfo_field(PROC_MEMINFO_MEMTOTAL_LINE, value);
1109 }
1110
1111 LTTNG_HIDDEN
1112 int 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
1139 end:
1140 return ret;
1141 }
1142
1143 LTTNG_HIDDEN
1144 enum 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 }
1181 end_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 }
1203 end:
1204 free(buf);
1205 return ret_val;
1206 }
1207
1208 LTTNG_HIDDEN
1209 enum 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 }
1247 end_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 }
1269 end:
1270 free(buf);
1271 return ret_val;
1272 }
This page took 0.056666 seconds and 4 git commands to generate.