Fix: utils.c: check str*dup OOM
[lttng-tools.git] / src / common / utils.c
CommitLineData
81b86775
DG
1/*
2 * Copyright (C) 2012 - David Goulet <dgoulet@efficios.com>
66495845 3 * Copyright (C) 2013 - Raphaël Beamonte <raphael.beamonte@gmail.com>
81b86775
DG
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License, version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51
16 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19#define _GNU_SOURCE
35f90c40 20#include <assert.h>
81b86775
DG
21#include <ctype.h>
22#include <fcntl.h>
23#include <limits.h>
24#include <stdlib.h>
25#include <string.h>
2d851108 26#include <sys/stat.h>
0c7bcad5 27#include <sys/types.h>
2d851108 28#include <unistd.h>
fe4477ee 29#include <inttypes.h>
6c71277b 30#include <grp.h>
cebdfb91 31#include <pwd.h>
52f740b8 32#include <sys/file.h>
81b86775
DG
33
34#include <common/common.h>
fe4477ee 35#include <common/runas.h>
81b86775
DG
36
37#include "utils.h"
feb0f3e5 38#include "defaults.h"
81b86775 39
5154230f
RB
40/*
41 * Return a partial realpath(3) of the path even if the full path does not
42 * exist. For instance, with /tmp/test1/test2/test3, if test2/ does not exist
43 * but the /tmp/test1 does, the real path for /tmp/test1 is concatened with
44 * /test2/test3 then returned. In normal time, realpath(3) fails if the end
45 * point directory does not exist.
46 * In case resolved_path is NULL, the string returned was allocated in the
47 * function and thus need to be freed by the caller. The size argument allows
48 * to specify the size of the resolved_path argument if given, or the size to
49 * allocate.
50 */
51LTTNG_HIDDEN
52char *utils_partial_realpath(const char *path, char *resolved_path, size_t size)
53{
54 char *cut_path, *try_path = NULL, *try_path_prev = NULL;
55 const char *next, *prev, *end;
56
57 /* Safety net */
58 if (path == NULL) {
59 goto error;
60 }
61
62 /*
63 * Identify the end of the path, we don't want to treat the
64 * last char if it is a '/', we will just keep it on the side
65 * to be added at the end, and return a value coherent with
66 * the path given as argument
67 */
68 end = path + strlen(path);
69 if (*(end-1) == '/') {
70 end--;
71 }
72
73 /* Initiate the values of the pointers before looping */
74 next = path;
75 prev = next;
76 /* Only to ensure try_path is not NULL to enter the while */
77 try_path = (char *)next;
78
79 /* Resolve the canonical path of the first part of the path */
80 while (try_path != NULL && next != end) {
81 /*
82 * If there is not any '/' left, we want to try with
83 * the full path
84 */
85 next = strpbrk(next + 1, "/");
86 if (next == NULL) {
87 next = end;
88 }
89
90 /* Cut the part we will be trying to resolve */
91 cut_path = strndup(path, next - path);
733ea905
MD
92 if (cut_path == NULL) {
93 PERROR("strndup");
94 goto error;
95 }
5154230f
RB
96
97 /* Try to resolve this part */
98 try_path = realpath((char *)cut_path, NULL);
99 if (try_path == NULL) {
100 /*
101 * There was an error, we just want to be assured it
102 * is linked to an unexistent directory, if it's another
103 * reason, we spawn an error
104 */
105 switch (errno) {
106 case ENOENT:
107 /* Ignore the error */
108 break;
109 default:
110 PERROR("realpath (partial_realpath)");
111 goto error;
112 break;
113 }
114 } else {
115 /* Save the place we are before trying the next step */
116 free(try_path_prev);
117 try_path_prev = try_path;
118 prev = next;
119 }
120
121 /* Free the allocated memory */
122 free(cut_path);
123 };
124
125 /* Allocate memory for the resolved path if necessary */
126 if (resolved_path == NULL) {
127 resolved_path = zmalloc(size);
128 if (resolved_path == NULL) {
129 PERROR("zmalloc resolved path");
130 goto error;
131 }
132 }
133
134 /*
135 * If we were able to solve at least partially the path, we can concatenate
136 * what worked and what didn't work
137 */
138 if (try_path_prev != NULL) {
139 /* If we risk to concatenate two '/', we remove one of them */
140 if (try_path_prev[strlen(try_path_prev) - 1] == '/' && prev[0] == '/') {
141 try_path_prev[strlen(try_path_prev) - 1] = '\0';
142 }
143
144 /*
145 * Duplicate the memory used by prev in case resolved_path and
146 * path are pointers for the same memory space
147 */
148 cut_path = strdup(prev);
733ea905
MD
149 if (cut_path == NULL) {
150 PERROR("strdup");
151 goto error;
152 }
5154230f
RB
153
154 /* Concatenate the strings */
155 snprintf(resolved_path, size, "%s%s", try_path_prev, cut_path);
156
157 /* Free the allocated memory */
158 free(cut_path);
159 free(try_path_prev);
160 /*
161 * Else, we just copy the path in our resolved_path to
162 * return it as is
163 */
164 } else {
165 strncpy(resolved_path, path, size);
166 }
167
168 /* Then we return the 'partially' resolved path */
169 return resolved_path;
170
171error:
172 free(resolved_path);
173 return NULL;
174}
175
81b86775 176/*
3d229795
RB
177 * Make a full resolution of the given path even if it doesn't exist.
178 * This function uses the utils_partial_realpath function to resolve
179 * symlinks and relatives paths at the start of the string, and
180 * implements functionnalities to resolve the './' and '../' strings
181 * in the middle of a path. This function is only necessary because
182 * realpath(3) does not accept to resolve unexistent paths.
183 * The returned string was allocated in the function, it is thus of
184 * the responsibility of the caller to free this memory.
81b86775 185 */
90e535ef 186LTTNG_HIDDEN
81b86775
DG
187char *utils_expand_path(const char *path)
188{
3d229795 189 char *next, *previous, *slash, *start_path, *absolute_path = NULL;
5de083f4
RB
190 char *last_token;
191 int is_dot, is_dotdot;
81b86775
DG
192
193 /* Safety net */
194 if (path == NULL) {
195 goto error;
196 }
197
3d229795
RB
198 /* Allocate memory for the absolute_path */
199 absolute_path = zmalloc(PATH_MAX);
200 if (absolute_path == NULL) {
81b86775
DG
201 PERROR("zmalloc expand path");
202 goto error;
203 }
204
3d229795
RB
205 /*
206 * If the path is not already absolute nor explicitly relative,
207 * consider we're in the current directory
208 */
209 if (*path != '/' && strncmp(path, "./", 2) != 0 &&
210 strncmp(path, "../", 3) != 0) {
211 snprintf(absolute_path, PATH_MAX, "./%s", path);
2dcd84b7 212 /* Else, we just copy the path */
116f95d9 213 } else {
3d229795
RB
214 strncpy(absolute_path, path, PATH_MAX);
215 }
116f95d9 216
3d229795
RB
217 /* Resolve partially our path */
218 absolute_path = utils_partial_realpath(absolute_path,
219 absolute_path, PATH_MAX);
116f95d9 220
3d229795
RB
221 /* As long as we find '/./' in the working_path string */
222 while ((next = strstr(absolute_path, "/./"))) {
116f95d9 223
3d229795
RB
224 /* We prepare the start_path not containing it */
225 start_path = strndup(absolute_path, next - absolute_path);
733ea905
MD
226 if (!start_path) {
227 PERROR("strndup");
228 goto error;
229 }
3d229795
RB
230 /* And we concatenate it with the part after this string */
231 snprintf(absolute_path, PATH_MAX, "%s%s", start_path, next + 2);
116f95d9 232
3d229795
RB
233 free(start_path);
234 }
116f95d9 235
3d229795
RB
236 /* As long as we find '/../' in the working_path string */
237 while ((next = strstr(absolute_path, "/../"))) {
238 /* We find the last level of directory */
239 previous = absolute_path;
240 while ((slash = strpbrk(previous, "/")) && slash != next) {
241 previous = slash + 1;
81b86775 242 }
81b86775 243
3d229795
RB
244 /* Then we prepare the start_path not containing it */
245 start_path = strndup(absolute_path, previous - absolute_path);
733ea905
MD
246 if (!start_path) {
247 PERROR("strndup");
248 goto error;
249 }
3d229795
RB
250
251 /* And we concatenate it with the part after the '/../' */
252 snprintf(absolute_path, PATH_MAX, "%s%s", start_path, next + 4);
253
254 /* We can free the memory used for the start path*/
255 free(start_path);
256
257 /* Then we verify for symlinks using partial_realpath */
258 absolute_path = utils_partial_realpath(absolute_path,
259 absolute_path, PATH_MAX);
116f95d9 260 }
81b86775 261
5de083f4
RB
262 /* Identify the last token */
263 last_token = strrchr(absolute_path, '/');
264
265 /* Verify that this token is not a relative path */
266 is_dotdot = (strcmp(last_token, "/..") == 0);
267 is_dot = (strcmp(last_token, "/.") == 0);
268
269 /* If it is, take action */
270 if (is_dot || is_dotdot) {
271 /* For both, remove this token */
272 *last_token = '\0';
273
274 /* If it was a reference to parent directory, go back one more time */
275 if (is_dotdot) {
276 last_token = strrchr(absolute_path, '/');
277
278 /* If there was only one level left, we keep the first '/' */
279 if (last_token == absolute_path) {
280 last_token++;
281 }
282
283 *last_token = '\0';
284 }
285 }
286
3d229795 287 return absolute_path;
81b86775
DG
288
289error:
3d229795 290 free(absolute_path);
81b86775
DG
291 return NULL;
292}
293
294/*
295 * Create a pipe in dst.
296 */
90e535ef 297LTTNG_HIDDEN
81b86775
DG
298int utils_create_pipe(int *dst)
299{
300 int ret;
301
302 if (dst == NULL) {
303 return -1;
304 }
305
306 ret = pipe(dst);
307 if (ret < 0) {
308 PERROR("create pipe");
309 }
310
311 return ret;
312}
313
314/*
315 * Create pipe and set CLOEXEC flag to both fd.
316 *
317 * Make sure the pipe opened by this function are closed at some point. Use
318 * utils_close_pipe().
319 */
90e535ef 320LTTNG_HIDDEN
81b86775
DG
321int utils_create_pipe_cloexec(int *dst)
322{
323 int ret, i;
324
325 if (dst == NULL) {
326 return -1;
327 }
328
329 ret = utils_create_pipe(dst);
330 if (ret < 0) {
331 goto error;
332 }
333
334 for (i = 0; i < 2; i++) {
335 ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC);
336 if (ret < 0) {
337 PERROR("fcntl pipe cloexec");
338 goto error;
339 }
340 }
341
342error:
343 return ret;
344}
345
094f381c
MD
346/*
347 * Create pipe and set fd flags to FD_CLOEXEC and O_NONBLOCK.
348 *
349 * Make sure the pipe opened by this function are closed at some point. Use
350 * utils_close_pipe(). Using pipe() and fcntl rather than pipe2() to
351 * support OSes other than Linux 2.6.23+.
352 */
353LTTNG_HIDDEN
354int utils_create_pipe_cloexec_nonblock(int *dst)
355{
356 int ret, i;
357
358 if (dst == NULL) {
359 return -1;
360 }
361
362 ret = utils_create_pipe(dst);
363 if (ret < 0) {
364 goto error;
365 }
366
367 for (i = 0; i < 2; i++) {
368 ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC);
369 if (ret < 0) {
370 PERROR("fcntl pipe cloexec");
371 goto error;
372 }
373 /*
374 * Note: we override any flag that could have been
375 * previously set on the fd.
376 */
377 ret = fcntl(dst[i], F_SETFL, O_NONBLOCK);
378 if (ret < 0) {
379 PERROR("fcntl pipe nonblock");
380 goto error;
381 }
382 }
383
384error:
385 return ret;
386}
387
81b86775
DG
388/*
389 * Close both read and write side of the pipe.
390 */
90e535ef 391LTTNG_HIDDEN
81b86775
DG
392void utils_close_pipe(int *src)
393{
394 int i, ret;
395
396 if (src == NULL) {
397 return;
398 }
399
400 for (i = 0; i < 2; i++) {
401 /* Safety check */
402 if (src[i] < 0) {
403 continue;
404 }
405
406 ret = close(src[i]);
407 if (ret) {
408 PERROR("close pipe");
409 }
410 }
411}
a4b92340
DG
412
413/*
414 * Create a new string using two strings range.
415 */
90e535ef 416LTTNG_HIDDEN
a4b92340
DG
417char *utils_strdupdelim(const char *begin, const char *end)
418{
419 char *str;
420
421 str = zmalloc(end - begin + 1);
422 if (str == NULL) {
423 PERROR("zmalloc strdupdelim");
424 goto error;
425 }
426
427 memcpy(str, begin, end - begin);
428 str[end - begin] = '\0';
429
430error:
431 return str;
432}
b662582b
DG
433
434/*
435 * Set CLOEXEC flag to the give file descriptor.
436 */
90e535ef 437LTTNG_HIDDEN
b662582b
DG
438int utils_set_fd_cloexec(int fd)
439{
440 int ret;
441
442 if (fd < 0) {
443 ret = -EINVAL;
444 goto end;
445 }
446
447 ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
448 if (ret < 0) {
449 PERROR("fcntl cloexec");
450 ret = -errno;
451 }
452
453end:
454 return ret;
455}
35f90c40
DG
456
457/*
458 * Create pid file to the given path and filename.
459 */
90e535ef 460LTTNG_HIDDEN
35f90c40
DG
461int utils_create_pid_file(pid_t pid, const char *filepath)
462{
463 int ret;
464 FILE *fp;
465
466 assert(filepath);
467
468 fp = fopen(filepath, "w");
469 if (fp == NULL) {
470 PERROR("open pid file %s", filepath);
471 ret = -1;
472 goto error;
473 }
474
475 ret = fprintf(fp, "%d\n", pid);
476 if (ret < 0) {
477 PERROR("fprintf pid file");
478 }
479
480 fclose(fp);
481 DBG("Pid %d written in file %s", pid, filepath);
482error:
483 return ret;
484}
2d851108 485
52f740b8
JG
486/*
487 * Create lock file to the given path and filename.
488 * Returns the associated file descriptor, -1 on error.
489 */
490LTTNG_HIDDEN
491int utils_create_lock_file(const char *filepath)
492{
493 int ret;
494 int fd;
495
496 assert(filepath);
497
498 fd = open(filepath, O_CREAT,
499 O_WRONLY | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
500 if (fd < 0) {
501 PERROR("open lock file %s", filepath);
502 ret = -1;
503 goto error;
504 }
505
506 /*
507 * Attempt to lock the file. If this fails, there is
508 * already a process using the same lock file running
509 * and we should exit.
510 */
511 ret = flock(fd, LOCK_EX | LOCK_NB);
512 if (ret) {
513 WARN("Could not get lock file %s, another instance is running.",
514 filepath);
515 close(fd);
516 fd = ret;
517 goto error;
518 }
519
520error:
521 return fd;
522}
523
2d851108
DG
524/*
525 * Recursively create directory using the given path and mode.
526 *
527 * On success, return 0 else a negative error code.
528 */
90e535ef 529LTTNG_HIDDEN
2d851108
DG
530int utils_mkdir_recursive(const char *path, mode_t mode)
531{
532 char *p, tmp[PATH_MAX];
2d851108
DG
533 size_t len;
534 int ret;
535
536 assert(path);
537
538 ret = snprintf(tmp, sizeof(tmp), "%s", path);
539 if (ret < 0) {
540 PERROR("snprintf mkdir");
541 goto error;
542 }
543
544 len = ret;
545 if (tmp[len - 1] == '/') {
546 tmp[len - 1] = 0;
547 }
548
549 for (p = tmp + 1; *p; p++) {
550 if (*p == '/') {
551 *p = 0;
552 if (tmp[strlen(tmp) - 1] == '.' &&
553 tmp[strlen(tmp) - 2] == '.' &&
554 tmp[strlen(tmp) - 3] == '/') {
555 ERR("Using '/../' is not permitted in the trace path (%s)",
556 tmp);
557 ret = -1;
558 goto error;
559 }
0c7bcad5 560 ret = mkdir(tmp, mode);
2d851108 561 if (ret < 0) {
0c7bcad5
MD
562 if (errno != EEXIST) {
563 PERROR("mkdir recursive");
564 ret = -errno;
565 goto error;
2d851108
DG
566 }
567 }
568 *p = '/';
569 }
570 }
571
572 ret = mkdir(tmp, mode);
573 if (ret < 0) {
574 if (errno != EEXIST) {
575 PERROR("mkdir recursive last piece");
576 ret = -errno;
577 } else {
578 ret = 0;
579 }
580 }
581
582error:
583 return ret;
584}
fe4477ee
JD
585
586/*
587 * Create the stream tracefile on disk.
588 *
589 * Return 0 on success or else a negative value.
590 */
bc182241 591LTTNG_HIDDEN
07b86b52 592int utils_create_stream_file(const char *path_name, char *file_name, uint64_t size,
309167d2 593 uint64_t count, int uid, int gid, char *suffix)
fe4477ee 594{
be96a7d1 595 int ret, out_fd, flags, mode;
309167d2
JD
596 char full_path[PATH_MAX], *path_name_suffix = NULL, *path;
597 char *extra = NULL;
fe4477ee
JD
598
599 assert(path_name);
600 assert(file_name);
601
602 ret = snprintf(full_path, sizeof(full_path), "%s/%s",
603 path_name, file_name);
604 if (ret < 0) {
605 PERROR("snprintf create output file");
606 goto error;
607 }
608
309167d2
JD
609 /* Setup extra string if suffix or/and a count is needed. */
610 if (size > 0 && suffix) {
611 ret = asprintf(&extra, "_%" PRIu64 "%s", count, suffix);
612 } else if (size > 0) {
613 ret = asprintf(&extra, "_%" PRIu64, count);
614 } else if (suffix) {
615 ret = asprintf(&extra, "%s", suffix);
616 }
617 if (ret < 0) {
618 PERROR("Allocating extra string to name");
619 goto error;
620 }
621
fe4477ee
JD
622 /*
623 * If we split the trace in multiple files, we have to add the count at the
624 * end of the tracefile name
625 */
309167d2
JD
626 if (extra) {
627 ret = asprintf(&path_name_suffix, "%s%s", full_path, extra);
fe4477ee 628 if (ret < 0) {
309167d2
JD
629 PERROR("Allocating path name with extra string");
630 goto error_free_suffix;
fe4477ee 631 }
309167d2 632 path = path_name_suffix;
fe4477ee
JD
633 } else {
634 path = full_path;
635 }
636
be96a7d1 637 flags = O_WRONLY | O_CREAT | O_TRUNC;
0f907de1 638 /* Open with 660 mode */
be96a7d1
DG
639 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
640
641 if (uid < 0 || gid < 0) {
642 out_fd = open(path, flags, mode);
643 } else {
644 out_fd = run_as_open(path, flags, mode, uid, gid);
645 }
fe4477ee
JD
646 if (out_fd < 0) {
647 PERROR("open stream path %s", path);
648 goto error_open;
649 }
650 ret = out_fd;
651
652error_open:
309167d2
JD
653 free(path_name_suffix);
654error_free_suffix:
655 free(extra);
fe4477ee
JD
656error:
657 return ret;
658}
659
660/*
661 * Change the output tracefile according to the given size and count The
662 * new_count pointer is set during this operation.
663 *
664 * From the consumer, the stream lock MUST be held before calling this function
665 * because we are modifying the stream status.
666 *
667 * Return 0 on success or else a negative value.
668 */
bc182241 669LTTNG_HIDDEN
fe4477ee 670int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size,
309167d2
JD
671 uint64_t count, int uid, int gid, int out_fd, uint64_t *new_count,
672 int *stream_fd)
fe4477ee
JD
673{
674 int ret;
675
309167d2
JD
676 assert(new_count);
677 assert(stream_fd);
678
fe4477ee
JD
679 ret = close(out_fd);
680 if (ret < 0) {
681 PERROR("Closing tracefile");
682 goto error;
683 }
684
685 if (count > 0) {
686 *new_count = (*new_count + 1) % count;
687 } else {
688 (*new_count)++;
689 }
690
309167d2
JD
691 ret = utils_create_stream_file(path_name, file_name, size, *new_count,
692 uid, gid, 0);
693 if (ret < 0) {
694 goto error;
695 }
696 *stream_fd = ret;
697
698 /* Success. */
699 ret = 0;
700
fe4477ee
JD
701error:
702 return ret;
703}
70d0b120 704
70d0b120
SM
705
706/**
707 * Parse a string that represents a size in human readable format. It
084ce647 708 * supports decimal integers suffixed by 'k', 'K', 'M' or 'G'.
70d0b120
SM
709 *
710 * The suffix multiply the integer by:
711 * 'k': 1024
712 * 'M': 1024^2
713 * 'G': 1024^3
714 *
715 * @param str The string to parse.
084ce647 716 * @param size Pointer to a uint64_t that will be filled with the
cfa9a5a2 717 * resulting size.
70d0b120
SM
718 *
719 * @return 0 on success, -1 on failure.
720 */
00a52467 721LTTNG_HIDDEN
084ce647 722int utils_parse_size_suffix(const char * const str, uint64_t * const size)
70d0b120 723{
70d0b120 724 int ret;
084ce647 725 uint64_t base_size;
70d0b120 726 long shift = 0;
084ce647
SM
727 const char *str_end;
728 char *num_end;
70d0b120
SM
729
730 if (!str) {
084ce647 731 DBG("utils_parse_size_suffix: received a NULL string.");
70d0b120
SM
732 ret = -1;
733 goto end;
734 }
735
084ce647
SM
736 /* strtoull will accept a negative number, but we don't want to. */
737 if (strchr(str, '-') != NULL) {
738 DBG("utils_parse_size_suffix: invalid size string, should not contain '-'.");
70d0b120 739 ret = -1;
084ce647 740 goto end;
70d0b120
SM
741 }
742
084ce647
SM
743 /* str_end will point to the \0 */
744 str_end = str + strlen(str);
70d0b120 745 errno = 0;
084ce647 746 base_size = strtoull(str, &num_end, 0);
70d0b120 747 if (errno != 0) {
084ce647 748 PERROR("utils_parse_size_suffix strtoull");
70d0b120 749 ret = -1;
084ce647
SM
750 goto end;
751 }
752
753 if (num_end == str) {
754 /* strtoull parsed nothing, not good. */
755 DBG("utils_parse_size_suffix: strtoull had nothing good to parse.");
756 ret = -1;
757 goto end;
758 }
759
760 /* Check if a prefix is present. */
761 switch (*num_end) {
762 case 'G':
763 shift = GIBI_LOG2;
764 num_end++;
765 break;
766 case 'M': /* */
767 shift = MEBI_LOG2;
768 num_end++;
769 break;
770 case 'K':
771 case 'k':
772 shift = KIBI_LOG2;
773 num_end++;
774 break;
775 case '\0':
776 break;
777 default:
778 DBG("utils_parse_size_suffix: invalid suffix.");
779 ret = -1;
780 goto end;
781 }
782
783 /* Check for garbage after the valid input. */
784 if (num_end != str_end) {
785 DBG("utils_parse_size_suffix: Garbage after size string.");
786 ret = -1;
787 goto end;
70d0b120
SM
788 }
789
790 *size = base_size << shift;
791
792 /* Check for overflow */
793 if ((*size >> shift) != base_size) {
084ce647 794 DBG("utils_parse_size_suffix: oops, overflow detected.");
70d0b120 795 ret = -1;
084ce647 796 goto end;
70d0b120
SM
797 }
798
799 ret = 0;
70d0b120
SM
800end:
801 return ret;
802}
cfa9a5a2
DG
803
804/*
805 * fls: returns the position of the most significant bit.
806 * Returns 0 if no bit is set, else returns the position of the most
807 * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
808 */
809#if defined(__i386) || defined(__x86_64)
810static inline unsigned int fls_u32(uint32_t x)
811{
812 int r;
813
814 asm("bsrl %1,%0\n\t"
815 "jnz 1f\n\t"
816 "movl $-1,%0\n\t"
817 "1:\n\t"
818 : "=r" (r) : "rm" (x));
819 return r + 1;
820}
821#define HAS_FLS_U32
822#endif
823
824#ifndef HAS_FLS_U32
825static __attribute__((unused)) unsigned int fls_u32(uint32_t x)
826{
827 unsigned int r = 32;
828
829 if (!x) {
830 return 0;
831 }
832 if (!(x & 0xFFFF0000U)) {
833 x <<= 16;
834 r -= 16;
835 }
836 if (!(x & 0xFF000000U)) {
837 x <<= 8;
838 r -= 8;
839 }
840 if (!(x & 0xF0000000U)) {
841 x <<= 4;
842 r -= 4;
843 }
844 if (!(x & 0xC0000000U)) {
845 x <<= 2;
846 r -= 2;
847 }
848 if (!(x & 0x80000000U)) {
849 x <<= 1;
850 r -= 1;
851 }
852 return r;
853}
854#endif
855
856/*
857 * Return the minimum order for which x <= (1UL << order).
858 * Return -1 if x is 0.
859 */
860LTTNG_HIDDEN
861int utils_get_count_order_u32(uint32_t x)
862{
863 if (!x) {
864 return -1;
865 }
866
867 return fls_u32(x - 1);
868}
feb0f3e5
AM
869
870/**
871 * Obtain the value of LTTNG_HOME environment variable, if exists.
872 * Otherwise returns the value of HOME.
873 */
00a52467 874LTTNG_HIDDEN
feb0f3e5
AM
875char *utils_get_home_dir(void)
876{
877 char *val = NULL;
7f273985
DG
878 struct passwd *pwd;
879
feb0f3e5
AM
880 val = getenv(DEFAULT_LTTNG_HOME_ENV_VAR);
881 if (val != NULL) {
7f273985
DG
882 goto end;
883 }
884 val = getenv(DEFAULT_LTTNG_FALLBACK_HOME_ENV_VAR);
885 if (val != NULL) {
886 goto end;
feb0f3e5 887 }
7f273985
DG
888
889 /* Fallback on the password file entry. */
890 pwd = getpwuid(getuid());
891 if (!pwd) {
892 goto end;
893 }
894 val = pwd->pw_dir;
895
896 DBG3("Home directory is '%s'", val);
897
898end:
899 return val;
feb0f3e5 900}
26fe5938
DG
901
902/*
903 * With the given format, fill dst with the time of len maximum siz.
904 *
905 * Return amount of bytes set in the buffer or else 0 on error.
906 */
907LTTNG_HIDDEN
908size_t utils_get_current_time_str(const char *format, char *dst, size_t len)
909{
910 size_t ret;
911 time_t rawtime;
912 struct tm *timeinfo;
913
914 assert(format);
915 assert(dst);
916
917 /* Get date and time for session path */
918 time(&rawtime);
919 timeinfo = localtime(&rawtime);
920 ret = strftime(dst, len, format, timeinfo);
921 if (ret == 0) {
e4c27a4b 922 ERR("Unable to strftime with format %s at dst %p of len %zu", format,
26fe5938
DG
923 dst, len);
924 }
925
926 return ret;
927}
6c71277b
MD
928
929/*
930 * Return the group ID matching name, else 0 if it cannot be found.
931 */
932LTTNG_HIDDEN
933gid_t utils_get_group_id(const char *name)
934{
935 struct group *grp;
936
937 grp = getgrnam(name);
938 if (!grp) {
939 static volatile int warn_once;
940
941 if (!warn_once) {
942 WARN("No tracing group detected");
943 warn_once = 1;
944 }
945 return 0;
946 }
947 return grp->gr_gid;
948}
This page took 0.070273 seconds and 4 git commands to generate.