Maintain a channel-per-session_id hash table in the consumers
[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>
8db0dc00 4 * Copyright (C) 2013 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
81b86775
DG
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License, version 2 only, as
8 * published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 51
17 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19
6c1c0768 20#define _LGPL_SOURCE
35f90c40 21#include <assert.h>
81b86775
DG
22#include <ctype.h>
23#include <fcntl.h>
24#include <limits.h>
25#include <stdlib.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>
fb198a11 31#include <pwd.h>
c9cb3e7d 32#include <sys/file.h>
a98e236e 33#include <unistd.h>
81b86775
DG
34
35#include <common/common.h>
09b72f7a 36#include <common/readwrite.h>
fe4477ee 37#include <common/runas.h>
e8fa9fb0 38#include <common/compat/getenv.h>
f5436bfc 39#include <common/compat/string.h>
5a2451c9 40#include <common/compat/dirent.h>
18710679 41#include <common/compat/directory-handle.h>
28ab59d0 42#include <common/dynamic-buffer.h>
d7c23421 43#include <lttng/constant.h>
81b86775
DG
44
45#include "utils.h"
feb0f3e5 46#include "defaults.h"
2daf6502 47#include "time.h"
81b86775 48
09b72f7a
FD
49#define PROC_MEMINFO_PATH "/proc/meminfo"
50#define PROC_MEMINFO_MEMAVAILABLE_LINE "MemAvailable:"
51#define PROC_MEMINFO_MEMTOTAL_LINE "MemTotal:"
52
53/* The length of the longest field of `/proc/meminfo`. */
54#define PROC_MEMINFO_FIELD_MAX_NAME_LEN 20
55
56#if (PROC_MEMINFO_FIELD_MAX_NAME_LEN == 20)
57#define MAX_NAME_LEN_SCANF_IS_A_BROKEN_API "19"
58#else
59#error MAX_NAME_LEN_SCANF_IS_A_BROKEN_API must be updated to match (PROC_MEMINFO_FIELD_MAX_NAME_LEN - 1)
60#endif
61
5154230f
RB
62/*
63 * Return a partial realpath(3) of the path even if the full path does not
64 * exist. For instance, with /tmp/test1/test2/test3, if test2/ does not exist
65 * but the /tmp/test1 does, the real path for /tmp/test1 is concatened with
66 * /test2/test3 then returned. In normal time, realpath(3) fails if the end
67 * point directory does not exist.
68 * In case resolved_path is NULL, the string returned was allocated in the
69 * function and thus need to be freed by the caller. The size argument allows
70 * to specify the size of the resolved_path argument if given, or the size to
71 * allocate.
72 */
73LTTNG_HIDDEN
74char *utils_partial_realpath(const char *path, char *resolved_path, size_t size)
75{
9482daac 76 char *cut_path = NULL, *try_path = NULL, *try_path_prev = NULL;
5154230f
RB
77 const char *next, *prev, *end;
78
79 /* Safety net */
80 if (path == NULL) {
81 goto error;
82 }
83
84 /*
85 * Identify the end of the path, we don't want to treat the
86 * last char if it is a '/', we will just keep it on the side
87 * to be added at the end, and return a value coherent with
88 * the path given as argument
89 */
90 end = path + strlen(path);
91 if (*(end-1) == '/') {
92 end--;
93 }
94
95 /* Initiate the values of the pointers before looping */
96 next = path;
97 prev = next;
98 /* Only to ensure try_path is not NULL to enter the while */
99 try_path = (char *)next;
100
101 /* Resolve the canonical path of the first part of the path */
102 while (try_path != NULL && next != end) {
d7c23421
JG
103 char *try_path_buf = NULL;
104
5154230f
RB
105 /*
106 * If there is not any '/' left, we want to try with
107 * the full path
108 */
109 next = strpbrk(next + 1, "/");
110 if (next == NULL) {
111 next = end;
112 }
113
114 /* Cut the part we will be trying to resolve */
f5436bfc 115 cut_path = lttng_strndup(path, next - path);
d9dbcf5e 116 if (cut_path == NULL) {
f5436bfc 117 PERROR("lttng_strndup");
d9dbcf5e
MD
118 goto error;
119 }
5154230f 120
d7c23421
JG
121 try_path_buf = zmalloc(LTTNG_PATH_MAX);
122 if (!try_path_buf) {
123 PERROR("zmalloc");
124 goto error;
125 }
126
5154230f 127 /* Try to resolve this part */
f3472d9a 128 try_path = realpath((char *) cut_path, try_path_buf);
5154230f 129 if (try_path == NULL) {
d7c23421 130 free(try_path_buf);
5154230f
RB
131 /*
132 * There was an error, we just want to be assured it
133 * is linked to an unexistent directory, if it's another
134 * reason, we spawn an error
135 */
136 switch (errno) {
137 case ENOENT:
138 /* Ignore the error */
139 break;
140 default:
141 PERROR("realpath (partial_realpath)");
142 goto error;
143 break;
144 }
145 } else {
146 /* Save the place we are before trying the next step */
d7c23421 147 try_path_buf = NULL;
5154230f
RB
148 free(try_path_prev);
149 try_path_prev = try_path;
150 prev = next;
151 }
152
153 /* Free the allocated memory */
154 free(cut_path);
c14cc491 155 cut_path = NULL;
494a8e99 156 }
5154230f
RB
157
158 /* Allocate memory for the resolved path if necessary */
159 if (resolved_path == NULL) {
160 resolved_path = zmalloc(size);
161 if (resolved_path == NULL) {
162 PERROR("zmalloc resolved path");
163 goto error;
164 }
165 }
166
167 /*
168 * If we were able to solve at least partially the path, we can concatenate
169 * what worked and what didn't work
170 */
171 if (try_path_prev != NULL) {
172 /* If we risk to concatenate two '/', we remove one of them */
173 if (try_path_prev[strlen(try_path_prev) - 1] == '/' && prev[0] == '/') {
174 try_path_prev[strlen(try_path_prev) - 1] = '\0';
175 }
176
177 /*
178 * Duplicate the memory used by prev in case resolved_path and
179 * path are pointers for the same memory space
180 */
181 cut_path = strdup(prev);
d9dbcf5e
MD
182 if (cut_path == NULL) {
183 PERROR("strdup");
184 goto error;
185 }
5154230f
RB
186
187 /* Concatenate the strings */
188 snprintf(resolved_path, size, "%s%s", try_path_prev, cut_path);
189
190 /* Free the allocated memory */
191 free(cut_path);
192 free(try_path_prev);
494a8e99
JG
193 cut_path = NULL;
194 try_path_prev = NULL;
5154230f
RB
195 /*
196 * Else, we just copy the path in our resolved_path to
197 * return it as is
198 */
199 } else {
200 strncpy(resolved_path, path, size);
201 }
202
203 /* Then we return the 'partially' resolved path */
204 return resolved_path;
205
206error:
207 free(resolved_path);
9482daac 208 free(cut_path);
b86d5f3f 209 free(try_path);
32bd4678
MJ
210 if (try_path_prev != try_path) {
211 free(try_path_prev);
212 }
5154230f
RB
213 return NULL;
214}
215
4b223a67 216static
6740483e 217int expand_double_slashes_dot_and_dotdot(char *path)
4b223a67
FD
218{
219 size_t expanded_path_len, path_len;
220 const char *curr_char, *path_last_char, *next_slash, *prev_slash;
221
222 path_len = strlen(path);
223 path_last_char = &path[path_len];
224
225 if (path_len == 0) {
4b223a67
FD
226 goto error;
227 }
228
229 expanded_path_len = 0;
230
231 /* We iterate over the provided path to expand the "//", "../" and "./" */
232 for (curr_char = path; curr_char <= path_last_char; curr_char = next_slash + 1) {
233 /* Find the next forward slash. */
234 size_t curr_token_len;
235
236 if (curr_char == path_last_char) {
237 expanded_path_len++;
238 break;
239 }
240
241 next_slash = memchr(curr_char, '/', path_last_char - curr_char);
242 if (next_slash == NULL) {
243 /* Reached the end of the provided path. */
244 next_slash = path_last_char;
245 }
246
247 /* Compute how long is the previous token. */
248 curr_token_len = next_slash - curr_char;
249 switch(curr_token_len) {
250 case 0:
251 /*
252 * The pointer has not move meaning that curr_char is
253 * pointing to a slash. It that case there is no token
254 * to copy, so continue the iteration to find the next
255 * token
256 */
257 continue;
258 case 1:
259 /*
260 * The pointer moved 1 character. Check if that
261 * character is a dot ('.'), if it is: omit it, else
262 * copy the token to the normalized path.
263 */
264 if (curr_char[0] == '.') {
265 continue;
266 }
267 break;
268 case 2:
269 /*
270 * The pointer moved 2 characters. Check if these
271 * characters are double dots ('..'). If that is the
272 * case, we need to remove the last token of the
273 * normalized path.
274 */
275 if (curr_char[0] == '.' && curr_char[1] == '.') {
276 /*
277 * Find the previous path component by
278 * using the memrchr function to find the
279 * previous forward slash and substract that
280 * len to the resulting path.
281 */
282 prev_slash = lttng_memrchr(path, '/', expanded_path_len);
283 /*
284 * If prev_slash is NULL, we reached the
285 * beginning of the path. We can't go back any
286 * further.
287 */
288 if (prev_slash != NULL) {
289 expanded_path_len = prev_slash - path;
290 }
291 continue;
292 }
293 break;
294 default:
295 break;
296 }
297
298 /*
299 * Copy the current token which is neither a '.' nor a '..'.
300 */
301 path[expanded_path_len++] = '/';
302 memcpy(&path[expanded_path_len], curr_char, curr_token_len);
303 expanded_path_len += curr_token_len;
304 }
305
306 if (expanded_path_len == 0) {
307 path[expanded_path_len++] = '/';
308 }
309
310 path[expanded_path_len] = '\0';
6740483e 311 return 0;
4b223a67 312error:
6740483e 313 return -1;
4b223a67
FD
314}
315
81b86775 316/*
3d229795
RB
317 * Make a full resolution of the given path even if it doesn't exist.
318 * This function uses the utils_partial_realpath function to resolve
319 * symlinks and relatives paths at the start of the string, and
320 * implements functionnalities to resolve the './' and '../' strings
321 * in the middle of a path. This function is only necessary because
322 * realpath(3) does not accept to resolve unexistent paths.
323 * The returned string was allocated in the function, it is thus of
324 * the responsibility of the caller to free this memory.
81b86775 325 */
90e535ef 326LTTNG_HIDDEN
4b223a67 327char *_utils_expand_path(const char *path, bool keep_symlink)
81b86775 328{
857f0d94 329 int ret;
4b223a67 330 char *absolute_path = NULL;
5de083f4 331 char *last_token;
6740483e 332 bool is_dot, is_dotdot;
81b86775
DG
333
334 /* Safety net */
335 if (path == NULL) {
336 goto error;
337 }
338
3d229795 339 /* Allocate memory for the absolute_path */
857f0d94 340 absolute_path = zmalloc(LTTNG_PATH_MAX);
3d229795 341 if (absolute_path == NULL) {
81b86775
DG
342 PERROR("zmalloc expand path");
343 goto error;
344 }
345
4b223a67 346 if (path[0] == '/') {
857f0d94
JG
347 ret = lttng_strncpy(absolute_path, path, LTTNG_PATH_MAX);
348 if (ret) {
349 ERR("Path exceeds maximal size of %i bytes", LTTNG_PATH_MAX);
350 goto error;
351 }
4b223a67
FD
352 } else {
353 /*
354 * This is a relative path. We need to get the present working
355 * directory and start the path walk from there.
356 */
857f0d94 357 char current_working_dir[LTTNG_PATH_MAX];
4b223a67 358 char *cwd_ret;
857f0d94 359
4b223a67
FD
360 cwd_ret = getcwd(current_working_dir, sizeof(current_working_dir));
361 if (!cwd_ret) {
d9dbcf5e
MD
362 goto error;
363 }
4b223a67
FD
364 /*
365 * Get the number of character in the CWD and allocate an array
366 * to can hold it and the path provided by the caller.
367 */
857f0d94
JG
368 ret = snprintf(absolute_path, LTTNG_PATH_MAX, "%s/%s",
369 current_working_dir, path);
370 if (ret >= LTTNG_PATH_MAX) {
371 ERR("Concatenating current working directory %s and path %s exceeds maximal size of %i bytes",
372 current_working_dir, path, LTTNG_PATH_MAX);
373 goto error;
374 }
3d229795 375 }
116f95d9 376
4b223a67
FD
377 if (keep_symlink) {
378 /* Resolve partially our path */
3d229795 379 absolute_path = utils_partial_realpath(absolute_path,
857f0d94 380 absolute_path, LTTNG_PATH_MAX);
116f95d9 381 }
81b86775 382
6740483e
JG
383 ret = expand_double_slashes_dot_and_dotdot(absolute_path);
384 if (ret) {
4b223a67
FD
385 goto error;
386 }
387
5de083f4
RB
388 /* Identify the last token */
389 last_token = strrchr(absolute_path, '/');
390
391 /* Verify that this token is not a relative path */
392 is_dotdot = (strcmp(last_token, "/..") == 0);
393 is_dot = (strcmp(last_token, "/.") == 0);
394
395 /* If it is, take action */
396 if (is_dot || is_dotdot) {
397 /* For both, remove this token */
398 *last_token = '\0';
399
400 /* If it was a reference to parent directory, go back one more time */
401 if (is_dotdot) {
402 last_token = strrchr(absolute_path, '/');
403
404 /* If there was only one level left, we keep the first '/' */
405 if (last_token == absolute_path) {
406 last_token++;
407 }
408
409 *last_token = '\0';
410 }
411 }
412
3d229795 413 return absolute_path;
81b86775
DG
414
415error:
3d229795 416 free(absolute_path);
81b86775
DG
417 return NULL;
418}
4b223a67
FD
419LTTNG_HIDDEN
420char *utils_expand_path(const char *path)
421{
422 return _utils_expand_path(path, true);
423}
81b86775 424
4b223a67
FD
425LTTNG_HIDDEN
426char *utils_expand_path_keep_symlink(const char *path)
427{
428 return _utils_expand_path(path, false);
429}
81b86775
DG
430/*
431 * Create a pipe in dst.
432 */
90e535ef 433LTTNG_HIDDEN
81b86775
DG
434int utils_create_pipe(int *dst)
435{
436 int ret;
437
438 if (dst == NULL) {
439 return -1;
440 }
441
442 ret = pipe(dst);
443 if (ret < 0) {
444 PERROR("create pipe");
445 }
446
447 return ret;
448}
449
450/*
451 * Create pipe and set CLOEXEC flag to both fd.
452 *
453 * Make sure the pipe opened by this function are closed at some point. Use
454 * utils_close_pipe().
455 */
90e535ef 456LTTNG_HIDDEN
81b86775
DG
457int utils_create_pipe_cloexec(int *dst)
458{
459 int ret, i;
460
461 if (dst == NULL) {
462 return -1;
463 }
464
465 ret = utils_create_pipe(dst);
466 if (ret < 0) {
467 goto error;
468 }
469
470 for (i = 0; i < 2; i++) {
471 ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC);
472 if (ret < 0) {
473 PERROR("fcntl pipe cloexec");
474 goto error;
475 }
476 }
477
478error:
479 return ret;
480}
481
094f381c
MD
482/*
483 * Create pipe and set fd flags to FD_CLOEXEC and O_NONBLOCK.
484 *
485 * Make sure the pipe opened by this function are closed at some point. Use
486 * utils_close_pipe(). Using pipe() and fcntl rather than pipe2() to
487 * support OSes other than Linux 2.6.23+.
488 */
489LTTNG_HIDDEN
490int utils_create_pipe_cloexec_nonblock(int *dst)
491{
492 int ret, i;
493
494 if (dst == NULL) {
495 return -1;
496 }
497
498 ret = utils_create_pipe(dst);
499 if (ret < 0) {
500 goto error;
501 }
502
503 for (i = 0; i < 2; i++) {
504 ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC);
505 if (ret < 0) {
506 PERROR("fcntl pipe cloexec");
507 goto error;
508 }
509 /*
510 * Note: we override any flag that could have been
511 * previously set on the fd.
512 */
513 ret = fcntl(dst[i], F_SETFL, O_NONBLOCK);
514 if (ret < 0) {
515 PERROR("fcntl pipe nonblock");
516 goto error;
517 }
518 }
519
520error:
521 return ret;
522}
523
81b86775
DG
524/*
525 * Close both read and write side of the pipe.
526 */
90e535ef 527LTTNG_HIDDEN
81b86775
DG
528void utils_close_pipe(int *src)
529{
530 int i, ret;
531
532 if (src == NULL) {
533 return;
534 }
535
536 for (i = 0; i < 2; i++) {
537 /* Safety check */
538 if (src[i] < 0) {
539 continue;
540 }
541
542 ret = close(src[i]);
543 if (ret) {
544 PERROR("close pipe");
545 }
546 }
547}
a4b92340
DG
548
549/*
550 * Create a new string using two strings range.
551 */
90e535ef 552LTTNG_HIDDEN
a4b92340
DG
553char *utils_strdupdelim(const char *begin, const char *end)
554{
555 char *str;
556
557 str = zmalloc(end - begin + 1);
558 if (str == NULL) {
559 PERROR("zmalloc strdupdelim");
560 goto error;
561 }
562
563 memcpy(str, begin, end - begin);
564 str[end - begin] = '\0';
565
566error:
567 return str;
568}
b662582b
DG
569
570/*
571 * Set CLOEXEC flag to the give file descriptor.
572 */
90e535ef 573LTTNG_HIDDEN
b662582b
DG
574int utils_set_fd_cloexec(int fd)
575{
576 int ret;
577
578 if (fd < 0) {
579 ret = -EINVAL;
580 goto end;
581 }
582
583 ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
584 if (ret < 0) {
585 PERROR("fcntl cloexec");
586 ret = -errno;
587 }
588
589end:
590 return ret;
591}
35f90c40
DG
592
593/*
594 * Create pid file to the given path and filename.
595 */
90e535ef 596LTTNG_HIDDEN
35f90c40
DG
597int utils_create_pid_file(pid_t pid, const char *filepath)
598{
599 int ret;
600 FILE *fp;
601
602 assert(filepath);
603
604 fp = fopen(filepath, "w");
605 if (fp == NULL) {
606 PERROR("open pid file %s", filepath);
607 ret = -1;
608 goto error;
609 }
610
d1f721c5 611 ret = fprintf(fp, "%d\n", (int) pid);
35f90c40
DG
612 if (ret < 0) {
613 PERROR("fprintf pid file");
e205d79b 614 goto error;
35f90c40
DG
615 }
616
e205d79b
MD
617 if (fclose(fp)) {
618 PERROR("fclose");
619 }
d1f721c5 620 DBG("Pid %d written in file %s", (int) pid, filepath);
e205d79b 621 ret = 0;
35f90c40
DG
622error:
623 return ret;
624}
2d851108 625
c9cb3e7d
JG
626/*
627 * Create lock file to the given path and filename.
628 * Returns the associated file descriptor, -1 on error.
629 */
630LTTNG_HIDDEN
631int utils_create_lock_file(const char *filepath)
632{
633 int ret;
634 int fd;
77e7fddf 635 struct flock lock;
c9cb3e7d
JG
636
637 assert(filepath);
638
77e7fddf
MJ
639 memset(&lock, 0, sizeof(lock));
640 fd = open(filepath, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR |
641 S_IRGRP | S_IWGRP);
c9cb3e7d
JG
642 if (fd < 0) {
643 PERROR("open lock file %s", filepath);
e6576ba2 644 fd = -1;
c9cb3e7d
JG
645 goto error;
646 }
647
648 /*
649 * Attempt to lock the file. If this fails, there is
650 * already a process using the same lock file running
651 * and we should exit.
652 */
77e7fddf
MJ
653 lock.l_whence = SEEK_SET;
654 lock.l_type = F_WRLCK;
655
656 ret = fcntl(fd, F_SETLK, &lock);
657 if (ret == -1) {
658 PERROR("fcntl lock file");
208ff148 659 ERR("Could not get lock file %s, another instance is running.",
c9cb3e7d 660 filepath);
ffb0b851
JG
661 if (close(fd)) {
662 PERROR("close lock file");
663 }
c9cb3e7d
JG
664 fd = ret;
665 goto error;
666 }
667
668error:
669 return fd;
670}
671
2d851108 672/*
d77dded2 673 * Create directory using the given path and mode.
2d851108
DG
674 *
675 * On success, return 0 else a negative error code.
676 */
90e535ef 677LTTNG_HIDDEN
d77dded2
JG
678int utils_mkdir(const char *path, mode_t mode, int uid, int gid)
679{
680 int ret;
18710679 681 struct lttng_directory_handle handle;
69e3a560 682 const struct lttng_credentials creds = {
18710679
JG
683 .uid = (uid_t) uid,
684 .gid = (gid_t) gid,
685 };
686
687 (void) lttng_directory_handle_init(&handle, NULL);
688 ret = lttng_directory_handle_create_subdirectory_as_user(
689 &handle, path, mode,
690 (uid >= 0 || gid >= 0) ? &creds : NULL);
691 lttng_directory_handle_fini(&handle);
2d851108
DG
692 return ret;
693}
fe4477ee 694
d77dded2
JG
695/*
696 * Recursively create directory using the given path and mode, under the
697 * provided uid and gid.
698 *
699 * On success, return 0 else a negative error code.
700 */
701LTTNG_HIDDEN
702int utils_mkdir_recursive(const char *path, mode_t mode, int uid, int gid)
703{
704 int ret;
18710679 705 struct lttng_directory_handle handle;
69e3a560 706 const struct lttng_credentials creds = {
18710679
JG
707 .uid = (uid_t) uid,
708 .gid = (gid_t) gid,
709 };
710
711 (void) lttng_directory_handle_init(&handle, NULL);
712 ret = lttng_directory_handle_create_subdirectory_recursive_as_user(
713 &handle, path, mode,
714 (uid >= 0 || gid >= 0) ? &creds : NULL);
715 lttng_directory_handle_fini(&handle);
d77dded2
JG
716 return ret;
717}
718
fe4477ee 719/*
d77dded2 720 * path is the output parameter. It needs to be PATH_MAX len.
fe4477ee
JD
721 *
722 * Return 0 on success or else a negative value.
723 */
7591bab1
MD
724static int utils_stream_file_name(char *path,
725 const char *path_name, const char *file_name,
726 uint64_t size, uint64_t count,
727 const char *suffix)
fe4477ee 728{
7591bab1
MD
729 int ret;
730 char full_path[PATH_MAX];
731 char *path_name_suffix = NULL;
309167d2 732 char *extra = NULL;
fe4477ee 733
fe4477ee
JD
734 ret = snprintf(full_path, sizeof(full_path), "%s/%s",
735 path_name, file_name);
736 if (ret < 0) {
737 PERROR("snprintf create output file");
738 goto error;
739 }
740
309167d2
JD
741 /* Setup extra string if suffix or/and a count is needed. */
742 if (size > 0 && suffix) {
743 ret = asprintf(&extra, "_%" PRIu64 "%s", count, suffix);
744 } else if (size > 0) {
745 ret = asprintf(&extra, "_%" PRIu64, count);
746 } else if (suffix) {
747 ret = asprintf(&extra, "%s", suffix);
748 }
749 if (ret < 0) {
750 PERROR("Allocating extra string to name");
751 goto error;
752 }
753
fe4477ee 754 /*
7591bab1
MD
755 * If we split the trace in multiple files, we have to add the count at
756 * the end of the tracefile name.
fe4477ee 757 */
309167d2
JD
758 if (extra) {
759 ret = asprintf(&path_name_suffix, "%s%s", full_path, extra);
fe4477ee 760 if (ret < 0) {
309167d2
JD
761 PERROR("Allocating path name with extra string");
762 goto error_free_suffix;
fe4477ee 763 }
7591bab1
MD
764 strncpy(path, path_name_suffix, PATH_MAX - 1);
765 path[PATH_MAX - 1] = '\0';
fe4477ee 766 } else {
072ede59
JG
767 ret = lttng_strncpy(path, full_path, PATH_MAX);
768 if (ret) {
769 ERR("Failed to copy stream file name");
770 goto error_free_suffix;
771 }
7591bab1
MD
772 }
773 path[PATH_MAX - 1] = '\0';
774 ret = 0;
775
776 free(path_name_suffix);
777error_free_suffix:
778 free(extra);
779error:
780 return ret;
781}
782
783/*
784 * Create the stream file on disk.
785 *
786 * Return 0 on success or else a negative value.
787 */
788LTTNG_HIDDEN
789int utils_create_stream_file(const char *path_name, char *file_name, uint64_t size,
790 uint64_t count, int uid, int gid, char *suffix)
791{
792 int ret, flags, mode;
793 char path[PATH_MAX];
794
795 ret = utils_stream_file_name(path, path_name, file_name,
796 size, count, suffix);
797 if (ret < 0) {
798 goto error;
fe4477ee
JD
799 }
800
d3ecc550
JD
801 /*
802 * With the session rotation feature on the relay, we might need to seek
803 * and truncate a tracefile, so we need read and write access.
804 */
805 flags = O_RDWR | O_CREAT | O_TRUNC;
0f907de1 806 /* Open with 660 mode */
be96a7d1
DG
807 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
808
809 if (uid < 0 || gid < 0) {
7591bab1 810 ret = open(path, flags, mode);
be96a7d1 811 } else {
7591bab1 812 ret = run_as_open(path, flags, mode, uid, gid);
be96a7d1 813 }
7591bab1 814 if (ret < 0) {
fe4477ee 815 PERROR("open stream path %s", path);
fe4477ee 816 }
7591bab1
MD
817error:
818 return ret;
819}
fe4477ee 820
7591bab1
MD
821/*
822 * Unlink the stream tracefile from disk.
823 *
824 * Return 0 on success or else a negative value.
825 */
826LTTNG_HIDDEN
827int utils_unlink_stream_file(const char *path_name, char *file_name, uint64_t size,
828 uint64_t count, int uid, int gid, char *suffix)
829{
830 int ret;
831 char path[PATH_MAX];
832
833 ret = utils_stream_file_name(path, path_name, file_name,
834 size, count, suffix);
835 if (ret < 0) {
836 goto error;
837 }
838 if (uid < 0 || gid < 0) {
839 ret = unlink(path);
840 } else {
841 ret = run_as_unlink(path, uid, gid);
7591bab1
MD
842 }
843 if (ret < 0) {
844 goto error;
845 }
fe4477ee 846error:
7591bab1 847 DBG("utils_unlink_stream_file %s returns %d", path, ret);
fe4477ee
JD
848 return ret;
849}
850
851/*
852 * Change the output tracefile according to the given size and count The
853 * new_count pointer is set during this operation.
854 *
855 * From the consumer, the stream lock MUST be held before calling this function
856 * because we are modifying the stream status.
857 *
858 * Return 0 on success or else a negative value.
859 */
bc182241 860LTTNG_HIDDEN
fe4477ee 861int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size,
309167d2
JD
862 uint64_t count, int uid, int gid, int out_fd, uint64_t *new_count,
863 int *stream_fd)
fe4477ee
JD
864{
865 int ret;
866
309167d2
JD
867 assert(stream_fd);
868
fe4477ee
JD
869 ret = close(out_fd);
870 if (ret < 0) {
871 PERROR("Closing tracefile");
872 goto error;
873 }
b5b0c181 874 *stream_fd = -1;
fe4477ee
JD
875
876 if (count > 0) {
7591bab1
MD
877 /*
878 * In tracefile rotation, for the relay daemon we need
879 * to unlink the old file if present, because it may
880 * still be open in reading by the live thread, and we
881 * need to ensure that we do not overwrite the content
882 * between get_index and get_packet. Since we have no
883 * way to verify integrity of the data content compared
884 * to the associated index, we need to ensure the reader
885 * has exclusive access to the file content, and that
886 * the open of the data file is performed in get_index.
887 * Unlinking the old file rather than overwriting it
888 * achieves this.
889 */
93ec662e
JD
890 if (new_count) {
891 *new_count = (*new_count + 1) % count;
892 }
893 ret = utils_unlink_stream_file(path_name, file_name, size,
894 new_count ? *new_count : 0, uid, gid, 0);
7591bab1
MD
895 if (ret < 0 && errno != ENOENT) {
896 goto error;
897 }
fe4477ee 898 } else {
93ec662e
JD
899 if (new_count) {
900 (*new_count)++;
901 }
fe4477ee
JD
902 }
903
93ec662e
JD
904 ret = utils_create_stream_file(path_name, file_name, size,
905 new_count ? *new_count : 0, uid, gid, 0);
309167d2
JD
906 if (ret < 0) {
907 goto error;
908 }
909 *stream_fd = ret;
910
911 /* Success. */
912 ret = 0;
913
fe4477ee
JD
914error:
915 return ret;
916}
70d0b120 917
70d0b120
SM
918
919/**
920 * Parse a string that represents a size in human readable format. It
5983a922 921 * supports decimal integers suffixed by 'k', 'K', 'M' or 'G'.
70d0b120
SM
922 *
923 * The suffix multiply the integer by:
924 * 'k': 1024
925 * 'M': 1024^2
926 * 'G': 1024^3
927 *
928 * @param str The string to parse.
5983a922 929 * @param size Pointer to a uint64_t that will be filled with the
cfa9a5a2 930 * resulting size.
70d0b120
SM
931 *
932 * @return 0 on success, -1 on failure.
933 */
00a52467 934LTTNG_HIDDEN
5983a922 935int utils_parse_size_suffix(const char * const str, uint64_t * const size)
70d0b120 936{
70d0b120 937 int ret;
5983a922 938 uint64_t base_size;
70d0b120 939 long shift = 0;
5983a922
SM
940 const char *str_end;
941 char *num_end;
70d0b120
SM
942
943 if (!str) {
5983a922 944 DBG("utils_parse_size_suffix: received a NULL string.");
70d0b120
SM
945 ret = -1;
946 goto end;
947 }
948
5983a922
SM
949 /* strtoull will accept a negative number, but we don't want to. */
950 if (strchr(str, '-') != NULL) {
951 DBG("utils_parse_size_suffix: invalid size string, should not contain '-'.");
70d0b120 952 ret = -1;
5983a922 953 goto end;
70d0b120
SM
954 }
955
5983a922
SM
956 /* str_end will point to the \0 */
957 str_end = str + strlen(str);
70d0b120 958 errno = 0;
5983a922 959 base_size = strtoull(str, &num_end, 0);
70d0b120 960 if (errno != 0) {
5983a922 961 PERROR("utils_parse_size_suffix strtoull");
70d0b120 962 ret = -1;
5983a922
SM
963 goto end;
964 }
965
966 if (num_end == str) {
967 /* strtoull parsed nothing, not good. */
968 DBG("utils_parse_size_suffix: strtoull had nothing good to parse.");
969 ret = -1;
970 goto end;
971 }
972
973 /* Check if a prefix is present. */
974 switch (*num_end) {
975 case 'G':
976 shift = GIBI_LOG2;
977 num_end++;
978 break;
979 case 'M': /* */
980 shift = MEBI_LOG2;
981 num_end++;
982 break;
983 case 'K':
984 case 'k':
985 shift = KIBI_LOG2;
986 num_end++;
987 break;
988 case '\0':
989 break;
990 default:
991 DBG("utils_parse_size_suffix: invalid suffix.");
992 ret = -1;
993 goto end;
994 }
995
996 /* Check for garbage after the valid input. */
997 if (num_end != str_end) {
998 DBG("utils_parse_size_suffix: Garbage after size string.");
999 ret = -1;
1000 goto end;
70d0b120
SM
1001 }
1002
1003 *size = base_size << shift;
1004
1005 /* Check for overflow */
1006 if ((*size >> shift) != base_size) {
5983a922 1007 DBG("utils_parse_size_suffix: oops, overflow detected.");
70d0b120 1008 ret = -1;
5983a922 1009 goto end;
70d0b120
SM
1010 }
1011
1012 ret = 0;
70d0b120
SM
1013end:
1014 return ret;
1015}
cfa9a5a2 1016
7010c033
SM
1017/**
1018 * Parse a string that represents a time in human readable format. It
81684730
JR
1019 * supports decimal integers suffixed by:
1020 * "us" for microsecond,
1021 * "ms" for millisecond,
1022 * "s" for second,
1023 * "m" for minute,
1024 * "h" for hour
7010c033
SM
1025 *
1026 * The suffix multiply the integer by:
81684730
JR
1027 * "us" : 1
1028 * "ms" : 1000
1029 * "s" : 1000000
1030 * "m" : 60000000
1031 * "h" : 3600000000
7010c033
SM
1032 *
1033 * Note that unit-less numbers are assumed to be microseconds.
1034 *
1035 * @param str The string to parse, assumed to be NULL-terminated.
1036 * @param time_us Pointer to a uint64_t that will be filled with the
1037 * resulting time in microseconds.
1038 *
1039 * @return 0 on success, -1 on failure.
1040 */
1041LTTNG_HIDDEN
1042int utils_parse_time_suffix(char const * const str, uint64_t * const time_us)
1043{
1044 int ret;
1045 uint64_t base_time;
81684730 1046 uint64_t multiplier = 1;
7010c033
SM
1047 const char *str_end;
1048 char *num_end;
1049
1050 if (!str) {
1051 DBG("utils_parse_time_suffix: received a NULL string.");
1052 ret = -1;
1053 goto end;
1054 }
1055
1056 /* strtoull will accept a negative number, but we don't want to. */
1057 if (strchr(str, '-') != NULL) {
1058 DBG("utils_parse_time_suffix: invalid time string, should not contain '-'.");
1059 ret = -1;
1060 goto end;
1061 }
1062
1063 /* str_end will point to the \0 */
1064 str_end = str + strlen(str);
1065 errno = 0;
1066 base_time = strtoull(str, &num_end, 10);
1067 if (errno != 0) {
1068 PERROR("utils_parse_time_suffix strtoull on string \"%s\"", str);
1069 ret = -1;
1070 goto end;
1071 }
1072
1073 if (num_end == str) {
1074 /* strtoull parsed nothing, not good. */
1075 DBG("utils_parse_time_suffix: strtoull had nothing good to parse.");
1076 ret = -1;
1077 goto end;
1078 }
1079
1080 /* Check if a prefix is present. */
1081 switch (*num_end) {
1082 case 'u':
81684730
JR
1083 /*
1084 * Microsecond (us)
1085 *
1086 * Skip the "us" if the string matches the "us" suffix,
1087 * otherwise let the check for the end of the string handle
1088 * the error reporting.
1089 */
1090 if (*(num_end + 1) == 's') {
1091 num_end += 2;
1092 }
7010c033
SM
1093 break;
1094 case 'm':
81684730
JR
1095 if (*(num_end + 1) == 's') {
1096 /* Millisecond (ms) */
1097 multiplier = USEC_PER_MSEC;
1098 /* Skip the 's' */
1099 num_end++;
1100 } else {
1101 /* Minute (m) */
1102 multiplier = USEC_PER_MINUTE;
1103 }
1104 num_end++;
7010c033
SM
1105 break;
1106 case 's':
81684730
JR
1107 /* Second */
1108 multiplier = USEC_PER_SEC;
1109 num_end++;
1110 break;
1111 case 'h':
1112 /* Hour */
1113 multiplier = USEC_PER_HOURS;
7010c033
SM
1114 num_end++;
1115 break;
1116 case '\0':
1117 break;
1118 default:
1119 DBG("utils_parse_time_suffix: invalid suffix.");
1120 ret = -1;
1121 goto end;
1122 }
1123
1124 /* Check for garbage after the valid input. */
1125 if (num_end != str_end) {
1126 DBG("utils_parse_time_suffix: Garbage after time string.");
1127 ret = -1;
1128 goto end;
1129 }
1130
1131 *time_us = base_time * multiplier;
1132
1133 /* Check for overflow */
1134 if ((*time_us / multiplier) != base_time) {
1135 DBG("utils_parse_time_suffix: oops, overflow detected.");
1136 ret = -1;
1137 goto end;
1138 }
1139
1140 ret = 0;
1141end:
1142 return ret;
1143}
1144
cfa9a5a2
DG
1145/*
1146 * fls: returns the position of the most significant bit.
1147 * Returns 0 if no bit is set, else returns the position of the most
1148 * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
1149 */
1150#if defined(__i386) || defined(__x86_64)
1151static inline unsigned int fls_u32(uint32_t x)
1152{
1153 int r;
1154
1155 asm("bsrl %1,%0\n\t"
1156 "jnz 1f\n\t"
1157 "movl $-1,%0\n\t"
1158 "1:\n\t"
1159 : "=r" (r) : "rm" (x));
1160 return r + 1;
1161}
1162#define HAS_FLS_U32
1163#endif
1164
db5be0a3
JG
1165#if defined(__x86_64)
1166static inline
1167unsigned int fls_u64(uint64_t x)
1168{
1169 long r;
1170
1171 asm("bsrq %1,%0\n\t"
1172 "jnz 1f\n\t"
1173 "movq $-1,%0\n\t"
1174 "1:\n\t"
1175 : "=r" (r) : "rm" (x));
1176 return r + 1;
1177}
1178#define HAS_FLS_U64
1179#endif
1180
1181#ifndef HAS_FLS_U64
1182static __attribute__((unused))
1183unsigned int fls_u64(uint64_t x)
1184{
1185 unsigned int r = 64;
1186
1187 if (!x)
1188 return 0;
1189
1190 if (!(x & 0xFFFFFFFF00000000ULL)) {
1191 x <<= 32;
1192 r -= 32;
1193 }
1194 if (!(x & 0xFFFF000000000000ULL)) {
1195 x <<= 16;
1196 r -= 16;
1197 }
1198 if (!(x & 0xFF00000000000000ULL)) {
1199 x <<= 8;
1200 r -= 8;
1201 }
1202 if (!(x & 0xF000000000000000ULL)) {
1203 x <<= 4;
1204 r -= 4;
1205 }
1206 if (!(x & 0xC000000000000000ULL)) {
1207 x <<= 2;
1208 r -= 2;
1209 }
1210 if (!(x & 0x8000000000000000ULL)) {
1211 x <<= 1;
1212 r -= 1;
1213 }
1214 return r;
1215}
1216#endif
1217
cfa9a5a2
DG
1218#ifndef HAS_FLS_U32
1219static __attribute__((unused)) unsigned int fls_u32(uint32_t x)
1220{
1221 unsigned int r = 32;
1222
1223 if (!x) {
1224 return 0;
1225 }
1226 if (!(x & 0xFFFF0000U)) {
1227 x <<= 16;
1228 r -= 16;
1229 }
1230 if (!(x & 0xFF000000U)) {
1231 x <<= 8;
1232 r -= 8;
1233 }
1234 if (!(x & 0xF0000000U)) {
1235 x <<= 4;
1236 r -= 4;
1237 }
1238 if (!(x & 0xC0000000U)) {
1239 x <<= 2;
1240 r -= 2;
1241 }
1242 if (!(x & 0x80000000U)) {
1243 x <<= 1;
1244 r -= 1;
1245 }
1246 return r;
1247}
1248#endif
1249
1250/*
1251 * Return the minimum order for which x <= (1UL << order).
1252 * Return -1 if x is 0.
1253 */
1254LTTNG_HIDDEN
1255int utils_get_count_order_u32(uint32_t x)
1256{
1257 if (!x) {
1258 return -1;
1259 }
1260
1261 return fls_u32(x - 1);
1262}
feb0f3e5 1263
db5be0a3
JG
1264/*
1265 * Return the minimum order for which x <= (1UL << order).
1266 * Return -1 if x is 0.
1267 */
1268LTTNG_HIDDEN
1269int utils_get_count_order_u64(uint64_t x)
1270{
1271 if (!x) {
1272 return -1;
1273 }
1274
1275 return fls_u64(x - 1);
1276}
1277
feb0f3e5
AM
1278/**
1279 * Obtain the value of LTTNG_HOME environment variable, if exists.
1280 * Otherwise returns the value of HOME.
1281 */
00a52467 1282LTTNG_HIDDEN
feb0f3e5
AM
1283char *utils_get_home_dir(void)
1284{
1285 char *val = NULL;
04135dbd
DG
1286 struct passwd *pwd;
1287
e8fa9fb0 1288 val = lttng_secure_getenv(DEFAULT_LTTNG_HOME_ENV_VAR);
feb0f3e5 1289 if (val != NULL) {
04135dbd
DG
1290 goto end;
1291 }
e8fa9fb0 1292 val = lttng_secure_getenv(DEFAULT_LTTNG_FALLBACK_HOME_ENV_VAR);
04135dbd
DG
1293 if (val != NULL) {
1294 goto end;
feb0f3e5 1295 }
04135dbd
DG
1296
1297 /* Fallback on the password file entry. */
1298 pwd = getpwuid(getuid());
1299 if (!pwd) {
1300 goto end;
1301 }
1302 val = pwd->pw_dir;
1303
1304 DBG3("Home directory is '%s'", val);
1305
1306end:
1307 return val;
feb0f3e5 1308}
26fe5938 1309
fb198a11
JG
1310/**
1311 * Get user's home directory. Dynamically allocated, must be freed
1312 * by the caller.
1313 */
1314LTTNG_HIDDEN
1315char *utils_get_user_home_dir(uid_t uid)
1316{
1317 struct passwd pwd;
1318 struct passwd *result;
1319 char *home_dir = NULL;
1320 char *buf = NULL;
1321 long buflen;
1322 int ret;
1323
1324 buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
1325 if (buflen == -1) {
1326 goto end;
1327 }
1328retry:
1329 buf = zmalloc(buflen);
1330 if (!buf) {
1331 goto end;
1332 }
1333
1334 ret = getpwuid_r(uid, &pwd, buf, buflen, &result);
1335 if (ret || !result) {
1336 if (ret == ERANGE) {
1337 free(buf);
1338 buflen *= 2;
1339 goto retry;
1340 }
1341 goto end;
1342 }
1343
1344 home_dir = strdup(pwd.pw_dir);
1345end:
1346 free(buf);
1347 return home_dir;
1348}
1349
26fe5938
DG
1350/*
1351 * With the given format, fill dst with the time of len maximum siz.
1352 *
1353 * Return amount of bytes set in the buffer or else 0 on error.
1354 */
1355LTTNG_HIDDEN
1356size_t utils_get_current_time_str(const char *format, char *dst, size_t len)
1357{
1358 size_t ret;
1359 time_t rawtime;
1360 struct tm *timeinfo;
1361
1362 assert(format);
1363 assert(dst);
1364
1365 /* Get date and time for session path */
1366 time(&rawtime);
1367 timeinfo = localtime(&rawtime);
1368 ret = strftime(dst, len, format, timeinfo);
1369 if (ret == 0) {
68e6efdd 1370 ERR("Unable to strftime with format %s at dst %p of len %zu", format,
26fe5938
DG
1371 dst, len);
1372 }
1373
1374 return ret;
1375}
6c71277b
MD
1376
1377/*
28ab59d0
JR
1378 * Return 0 on success and set *gid to the group_ID matching the passed name.
1379 * Else -1 if it cannot be found or an error occurred.
6c71277b
MD
1380 */
1381LTTNG_HIDDEN
28ab59d0 1382int utils_get_group_id(const char *name, bool warn, gid_t *gid)
6c71277b 1383{
28ab59d0
JR
1384 static volatile int warn_once;
1385 int ret;
1386 long sys_len;
1387 size_t len;
1388 struct group grp;
1389 struct group *result;
1390 struct lttng_dynamic_buffer buffer;
1391
1392 /* Get the system limit, if it exists. */
1393 sys_len = sysconf(_SC_GETGR_R_SIZE_MAX);
1394 if (sys_len == -1) {
1395 len = 1024;
1396 } else {
1397 len = (size_t) sys_len;
1398 }
1399
1400 lttng_dynamic_buffer_init(&buffer);
1401 ret = lttng_dynamic_buffer_set_size(&buffer, len);
1402 if (ret) {
1403 ERR("Failed to allocate group info buffer");
1404 ret = -1;
1405 goto error;
1406 }
6c71277b 1407
28ab59d0
JR
1408 while ((ret = getgrnam_r(name, &grp, buffer.data, buffer.size, &result)) == ERANGE) {
1409 const size_t new_len = 2 * buffer.size;
6c71277b 1410
28ab59d0
JR
1411 /* Buffer is not big enough, increase its size. */
1412 if (new_len < buffer.size) {
1413 ERR("Group info buffer size overflow");
1414 ret = -1;
1415 goto error;
1416 }
1417
1418 ret = lttng_dynamic_buffer_set_size(&buffer, new_len);
1419 if (ret) {
1420 ERR("Failed to grow group info buffer to %zu bytes",
1421 new_len);
1422 ret = -1;
1423 goto error;
6c71277b 1424 }
6c71277b 1425 }
28ab59d0
JR
1426 if (ret) {
1427 PERROR("Failed to get group file entry for group name \"%s\"",
1428 name);
1429 ret = -1;
1430 goto error;
1431 }
1432
1433 /* Group not found. */
1434 if (!result) {
1435 ret = -1;
1436 goto error;
1437 }
1438
1439 *gid = result->gr_gid;
1440 ret = 0;
1441
1442error:
1443 if (ret && warn && !warn_once) {
1444 WARN("No tracing group detected");
1445 warn_once = 1;
1446 }
1447 lttng_dynamic_buffer_reset(&buffer);
1448 return ret;
6c71277b 1449}
8db0dc00
JG
1450
1451/*
1452 * Return a newly allocated option string. This string is to be used as the
1453 * optstring argument of getopt_long(), see GETOPT(3). opt_count is the number
1454 * of elements in the long_options array. Returns NULL if the string's
1455 * allocation fails.
1456 */
1457LTTNG_HIDDEN
1458char *utils_generate_optstring(const struct option *long_options,
1459 size_t opt_count)
1460{
1461 int i;
1462 size_t string_len = opt_count, str_pos = 0;
1463 char *optstring;
1464
1465 /*
1466 * Compute the necessary string length. One letter per option, two when an
1467 * argument is necessary, and a trailing NULL.
1468 */
1469 for (i = 0; i < opt_count; i++) {
1470 string_len += long_options[i].has_arg ? 1 : 0;
1471 }
1472
1473 optstring = zmalloc(string_len);
1474 if (!optstring) {
1475 goto end;
1476 }
1477
1478 for (i = 0; i < opt_count; i++) {
1479 if (!long_options[i].name) {
1480 /* Got to the trailing NULL element */
1481 break;
1482 }
1483
a596dcb9
JG
1484 if (long_options[i].val != '\0') {
1485 optstring[str_pos++] = (char) long_options[i].val;
1486 if (long_options[i].has_arg) {
1487 optstring[str_pos++] = ':';
1488 }
8db0dc00
JG
1489 }
1490 }
1491
1492end:
1493 return optstring;
1494}
3d071855
MD
1495
1496/*
1497 * Try to remove a hierarchy of empty directories, recursively. Don't unlink
9529ec1b 1498 * any file. Try to rmdir any empty directory within the hierarchy.
3d071855
MD
1499 */
1500LTTNG_HIDDEN
1501int utils_recursive_rmdir(const char *path)
1502{
1503 DIR *dir;
7a946beb 1504 size_t path_len;
9529ec1b 1505 int dir_fd, ret = 0, closeret, is_empty = 1;
3d071855
MD
1506 struct dirent *entry;
1507
1508 /* Open directory */
1509 dir = opendir(path);
1510 if (!dir) {
1511 PERROR("Cannot open '%s' path", path);
1512 return -1;
1513 }
5a2451c9 1514 dir_fd = lttng_dirfd(dir);
3d071855 1515 if (dir_fd < 0) {
5a2451c9 1516 PERROR("lttng_dirfd");
3d071855
MD
1517 return -1;
1518 }
1519
7a946beb 1520 path_len = strlen(path);
3d071855 1521 while ((entry = readdir(dir))) {
7a946beb
MJ
1522 struct stat st;
1523 size_t name_len;
1524 char filename[PATH_MAX];
1525
3763af87
JG
1526 if (!strcmp(entry->d_name, ".")
1527 || !strcmp(entry->d_name, "..")) {
1528 continue;
1529 }
1530
7a946beb
MJ
1531 name_len = strlen(entry->d_name);
1532 if (path_len + name_len + 2 > sizeof(filename)) {
1533 ERR("Failed to remove file: path name too long (%s/%s)",
1534 path, entry->d_name);
1535 continue;
1536 }
1537 if (snprintf(filename, sizeof(filename), "%s/%s",
1538 path, entry->d_name) < 0) {
1539 ERR("Failed to format path.");
1540 continue;
1541 }
1542
1543 if (stat(filename, &st)) {
1544 PERROR("stat");
1545 continue;
1546 }
1547
1548 if (S_ISDIR(st.st_mode)) {
3d071855
MD
1549 char subpath[PATH_MAX];
1550
1551 strncpy(subpath, path, PATH_MAX);
1552 subpath[PATH_MAX - 1] = '\0';
1553 strncat(subpath, "/",
1554 PATH_MAX - strlen(subpath) - 1);
1555 strncat(subpath, entry->d_name,
1556 PATH_MAX - strlen(subpath) - 1);
9529ec1b
MD
1557 if (utils_recursive_rmdir(subpath)) {
1558 is_empty = 0;
3d071855 1559 }
7a946beb 1560 } else if (S_ISREG(st.st_mode)) {
9529ec1b 1561 is_empty = 0;
7a946beb 1562 } else {
3d071855
MD
1563 ret = -EINVAL;
1564 goto end;
1565 }
1566 }
1567end:
1568 closeret = closedir(dir);
1569 if (closeret) {
1570 PERROR("closedir");
1571 }
9529ec1b 1572 if (is_empty) {
3d071855
MD
1573 DBG3("Attempting rmdir %s", path);
1574 ret = rmdir(path);
1575 }
1576 return ret;
1577}
93ec662e
JD
1578
1579LTTNG_HIDDEN
1580int utils_truncate_stream_file(int fd, off_t length)
1581{
1582 int ret;
a5df8828 1583 off_t lseek_ret;
93ec662e
JD
1584
1585 ret = ftruncate(fd, length);
1586 if (ret < 0) {
1587 PERROR("ftruncate");
1588 goto end;
1589 }
a5df8828
GL
1590 lseek_ret = lseek(fd, length, SEEK_SET);
1591 if (lseek_ret < 0) {
93ec662e 1592 PERROR("lseek");
a5df8828 1593 ret = -1;
93ec662e
JD
1594 goto end;
1595 }
93ec662e
JD
1596end:
1597 return ret;
1598}
4ba92f18
PP
1599
1600static const char *get_man_bin_path(void)
1601{
b7dce40d 1602 char *env_man_path = lttng_secure_getenv(DEFAULT_MAN_BIN_PATH_ENV);
4ba92f18
PP
1603
1604 if (env_man_path) {
1605 return env_man_path;
1606 }
1607
1608 return DEFAULT_MAN_BIN_PATH;
1609}
1610
1611LTTNG_HIDDEN
4fc83d94
PP
1612int utils_show_help(int section, const char *page_name,
1613 const char *help_msg)
4ba92f18
PP
1614{
1615 char section_string[8];
1616 const char *man_bin_path = get_man_bin_path();
4fc83d94
PP
1617 int ret = 0;
1618
1619 if (help_msg) {
1620 printf("%s", help_msg);
1621 goto end;
1622 }
4ba92f18
PP
1623
1624 /* Section integer -> section string */
1625 ret = sprintf(section_string, "%d", section);
1626 assert(ret > 0 && ret < 8);
1627
1628 /*
1629 * Execute man pager.
1630 *
b07e7ef0 1631 * We provide -M to man here because LTTng-tools can
4ba92f18
PP
1632 * be installed outside /usr, in which case its man pages are
1633 * not located in the default /usr/share/man directory.
1634 */
b07e7ef0 1635 ret = execlp(man_bin_path, "man", "-M", MANPATH,
4ba92f18 1636 section_string, page_name, NULL);
4fc83d94
PP
1637
1638end:
4ba92f18
PP
1639 return ret;
1640}
09b72f7a
FD
1641
1642static
1643int read_proc_meminfo_field(const char *field, size_t *value)
1644{
1645 int ret;
1646 FILE *proc_meminfo;
1647 char name[PROC_MEMINFO_FIELD_MAX_NAME_LEN] = {};
1648
1649 proc_meminfo = fopen(PROC_MEMINFO_PATH, "r");
1650 if (!proc_meminfo) {
1651 PERROR("Failed to fopen() " PROC_MEMINFO_PATH);
1652 ret = -1;
1653 goto fopen_error;
1654 }
1655
1656 /*
1657 * Read the contents of /proc/meminfo line by line to find the right
1658 * field.
1659 */
1660 while (!feof(proc_meminfo)) {
1661 unsigned long value_kb;
1662
1663 ret = fscanf(proc_meminfo,
1664 "%" MAX_NAME_LEN_SCANF_IS_A_BROKEN_API "s %lu kB\n",
1665 name, &value_kb);
1666 if (ret == EOF) {
1667 /*
1668 * fscanf() returning EOF can indicate EOF or an error.
1669 */
1670 if (ferror(proc_meminfo)) {
1671 PERROR("Failed to parse " PROC_MEMINFO_PATH);
1672 }
1673 break;
1674 }
1675
1676 if (ret == 2 && strcmp(name, field) == 0) {
1677 /*
1678 * This number is displayed in kilo-bytes. Return the
1679 * number of bytes.
1680 */
1681 *value = ((size_t) value_kb) * 1024;
1682 ret = 0;
1683 goto found;
1684 }
1685 }
1686 /* Reached the end of the file without finding the right field. */
1687 ret = -1;
1688
1689found:
1690 fclose(proc_meminfo);
1691fopen_error:
1692 return ret;
1693}
1694
1695/*
1696 * Returns an estimate of the number of bytes of memory available based on the
1697 * the information in `/proc/meminfo`. The number returned by this function is
1698 * a best guess.
1699 */
1700LTTNG_HIDDEN
1701int utils_get_memory_available(size_t *value)
1702{
1703 return read_proc_meminfo_field(PROC_MEMINFO_MEMAVAILABLE_LINE, value);
1704}
1705
1706/*
1707 * Returns the total size of the memory on the system in bytes based on the
1708 * the information in `/proc/meminfo`.
1709 */
1710LTTNG_HIDDEN
1711int utils_get_memory_total(size_t *value)
1712{
1713 return read_proc_meminfo_field(PROC_MEMINFO_MEMTOTAL_LINE, value);
1714}
This page took 0.141364 seconds and 5 git commands to generate.