Add file creation/unlinking utils to directory handle
[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
fd774fc6
JG
687 ret = lttng_directory_handle_init(&handle, NULL);
688 if (ret) {
689 goto end;
690 }
18710679
JG
691 ret = lttng_directory_handle_create_subdirectory_as_user(
692 &handle, path, mode,
693 (uid >= 0 || gid >= 0) ? &creds : NULL);
694 lttng_directory_handle_fini(&handle);
fd774fc6 695end:
2d851108
DG
696 return ret;
697}
fe4477ee 698
d77dded2
JG
699/*
700 * Recursively create directory using the given path and mode, under the
701 * provided uid and gid.
702 *
703 * On success, return 0 else a negative error code.
704 */
705LTTNG_HIDDEN
706int utils_mkdir_recursive(const char *path, mode_t mode, int uid, int gid)
707{
708 int ret;
18710679 709 struct lttng_directory_handle handle;
69e3a560 710 const struct lttng_credentials creds = {
18710679
JG
711 .uid = (uid_t) uid,
712 .gid = (gid_t) gid,
713 };
714
fd774fc6
JG
715 ret = lttng_directory_handle_init(&handle, NULL);
716 if (ret) {
717 goto end;
718 }
18710679
JG
719 ret = lttng_directory_handle_create_subdirectory_recursive_as_user(
720 &handle, path, mode,
721 (uid >= 0 || gid >= 0) ? &creds : NULL);
722 lttng_directory_handle_fini(&handle);
fd774fc6 723end:
d77dded2
JG
724 return ret;
725}
726
fe4477ee 727/*
d77dded2 728 * path is the output parameter. It needs to be PATH_MAX len.
fe4477ee
JD
729 *
730 * Return 0 on success or else a negative value.
731 */
7591bab1
MD
732static int utils_stream_file_name(char *path,
733 const char *path_name, const char *file_name,
734 uint64_t size, uint64_t count,
735 const char *suffix)
fe4477ee 736{
7591bab1
MD
737 int ret;
738 char full_path[PATH_MAX];
739 char *path_name_suffix = NULL;
309167d2 740 char *extra = NULL;
fe4477ee 741
fe4477ee
JD
742 ret = snprintf(full_path, sizeof(full_path), "%s/%s",
743 path_name, file_name);
744 if (ret < 0) {
745 PERROR("snprintf create output file");
746 goto error;
747 }
748
309167d2
JD
749 /* Setup extra string if suffix or/and a count is needed. */
750 if (size > 0 && suffix) {
751 ret = asprintf(&extra, "_%" PRIu64 "%s", count, suffix);
752 } else if (size > 0) {
753 ret = asprintf(&extra, "_%" PRIu64, count);
754 } else if (suffix) {
755 ret = asprintf(&extra, "%s", suffix);
756 }
757 if (ret < 0) {
758 PERROR("Allocating extra string to name");
759 goto error;
760 }
761
fe4477ee 762 /*
7591bab1
MD
763 * If we split the trace in multiple files, we have to add the count at
764 * the end of the tracefile name.
fe4477ee 765 */
309167d2
JD
766 if (extra) {
767 ret = asprintf(&path_name_suffix, "%s%s", full_path, extra);
fe4477ee 768 if (ret < 0) {
309167d2
JD
769 PERROR("Allocating path name with extra string");
770 goto error_free_suffix;
fe4477ee 771 }
7591bab1
MD
772 strncpy(path, path_name_suffix, PATH_MAX - 1);
773 path[PATH_MAX - 1] = '\0';
fe4477ee 774 } else {
072ede59
JG
775 ret = lttng_strncpy(path, full_path, PATH_MAX);
776 if (ret) {
777 ERR("Failed to copy stream file name");
778 goto error_free_suffix;
779 }
7591bab1
MD
780 }
781 path[PATH_MAX - 1] = '\0';
782 ret = 0;
783
784 free(path_name_suffix);
785error_free_suffix:
786 free(extra);
787error:
788 return ret;
789}
790
791/*
792 * Create the stream file on disk.
793 *
794 * Return 0 on success or else a negative value.
795 */
796LTTNG_HIDDEN
797int utils_create_stream_file(const char *path_name, char *file_name, uint64_t size,
798 uint64_t count, int uid, int gid, char *suffix)
799{
800 int ret, flags, mode;
801 char path[PATH_MAX];
802
803 ret = utils_stream_file_name(path, path_name, file_name,
804 size, count, suffix);
805 if (ret < 0) {
806 goto error;
fe4477ee
JD
807 }
808
d3ecc550
JD
809 /*
810 * With the session rotation feature on the relay, we might need to seek
811 * and truncate a tracefile, so we need read and write access.
812 */
813 flags = O_RDWR | O_CREAT | O_TRUNC;
0f907de1 814 /* Open with 660 mode */
be96a7d1
DG
815 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
816
817 if (uid < 0 || gid < 0) {
7591bab1 818 ret = open(path, flags, mode);
be96a7d1 819 } else {
7591bab1 820 ret = run_as_open(path, flags, mode, uid, gid);
be96a7d1 821 }
7591bab1 822 if (ret < 0) {
fe4477ee 823 PERROR("open stream path %s", path);
fe4477ee 824 }
7591bab1
MD
825error:
826 return ret;
827}
fe4477ee 828
7591bab1
MD
829/*
830 * Unlink the stream tracefile from disk.
831 *
832 * Return 0 on success or else a negative value.
833 */
834LTTNG_HIDDEN
835int utils_unlink_stream_file(const char *path_name, char *file_name, uint64_t size,
836 uint64_t count, int uid, int gid, char *suffix)
837{
838 int ret;
839 char path[PATH_MAX];
840
841 ret = utils_stream_file_name(path, path_name, file_name,
842 size, count, suffix);
843 if (ret < 0) {
844 goto error;
845 }
846 if (uid < 0 || gid < 0) {
847 ret = unlink(path);
848 } else {
849 ret = run_as_unlink(path, uid, gid);
7591bab1
MD
850 }
851 if (ret < 0) {
852 goto error;
853 }
fe4477ee 854error:
7591bab1 855 DBG("utils_unlink_stream_file %s returns %d", path, ret);
fe4477ee
JD
856 return ret;
857}
858
859/*
860 * Change the output tracefile according to the given size and count The
861 * new_count pointer is set during this operation.
862 *
863 * From the consumer, the stream lock MUST be held before calling this function
864 * because we are modifying the stream status.
865 *
866 * Return 0 on success or else a negative value.
867 */
bc182241 868LTTNG_HIDDEN
fe4477ee 869int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size,
309167d2
JD
870 uint64_t count, int uid, int gid, int out_fd, uint64_t *new_count,
871 int *stream_fd)
fe4477ee
JD
872{
873 int ret;
874
309167d2
JD
875 assert(stream_fd);
876
fe4477ee
JD
877 ret = close(out_fd);
878 if (ret < 0) {
879 PERROR("Closing tracefile");
880 goto error;
881 }
b5b0c181 882 *stream_fd = -1;
fe4477ee
JD
883
884 if (count > 0) {
7591bab1
MD
885 /*
886 * In tracefile rotation, for the relay daemon we need
887 * to unlink the old file if present, because it may
888 * still be open in reading by the live thread, and we
889 * need to ensure that we do not overwrite the content
890 * between get_index and get_packet. Since we have no
891 * way to verify integrity of the data content compared
892 * to the associated index, we need to ensure the reader
893 * has exclusive access to the file content, and that
894 * the open of the data file is performed in get_index.
895 * Unlinking the old file rather than overwriting it
896 * achieves this.
897 */
93ec662e
JD
898 if (new_count) {
899 *new_count = (*new_count + 1) % count;
900 }
901 ret = utils_unlink_stream_file(path_name, file_name, size,
902 new_count ? *new_count : 0, uid, gid, 0);
7591bab1
MD
903 if (ret < 0 && errno != ENOENT) {
904 goto error;
905 }
fe4477ee 906 } else {
93ec662e
JD
907 if (new_count) {
908 (*new_count)++;
909 }
fe4477ee
JD
910 }
911
93ec662e
JD
912 ret = utils_create_stream_file(path_name, file_name, size,
913 new_count ? *new_count : 0, uid, gid, 0);
309167d2
JD
914 if (ret < 0) {
915 goto error;
916 }
917 *stream_fd = ret;
918
919 /* Success. */
920 ret = 0;
921
fe4477ee
JD
922error:
923 return ret;
924}
70d0b120 925
70d0b120
SM
926
927/**
928 * Parse a string that represents a size in human readable format. It
5983a922 929 * supports decimal integers suffixed by 'k', 'K', 'M' or 'G'.
70d0b120
SM
930 *
931 * The suffix multiply the integer by:
932 * 'k': 1024
933 * 'M': 1024^2
934 * 'G': 1024^3
935 *
936 * @param str The string to parse.
5983a922 937 * @param size Pointer to a uint64_t that will be filled with the
cfa9a5a2 938 * resulting size.
70d0b120
SM
939 *
940 * @return 0 on success, -1 on failure.
941 */
00a52467 942LTTNG_HIDDEN
5983a922 943int utils_parse_size_suffix(const char * const str, uint64_t * const size)
70d0b120 944{
70d0b120 945 int ret;
5983a922 946 uint64_t base_size;
70d0b120 947 long shift = 0;
5983a922
SM
948 const char *str_end;
949 char *num_end;
70d0b120
SM
950
951 if (!str) {
5983a922 952 DBG("utils_parse_size_suffix: received a NULL string.");
70d0b120
SM
953 ret = -1;
954 goto end;
955 }
956
5983a922
SM
957 /* strtoull will accept a negative number, but we don't want to. */
958 if (strchr(str, '-') != NULL) {
959 DBG("utils_parse_size_suffix: invalid size string, should not contain '-'.");
70d0b120 960 ret = -1;
5983a922 961 goto end;
70d0b120
SM
962 }
963
5983a922
SM
964 /* str_end will point to the \0 */
965 str_end = str + strlen(str);
70d0b120 966 errno = 0;
5983a922 967 base_size = strtoull(str, &num_end, 0);
70d0b120 968 if (errno != 0) {
5983a922 969 PERROR("utils_parse_size_suffix strtoull");
70d0b120 970 ret = -1;
5983a922
SM
971 goto end;
972 }
973
974 if (num_end == str) {
975 /* strtoull parsed nothing, not good. */
976 DBG("utils_parse_size_suffix: strtoull had nothing good to parse.");
977 ret = -1;
978 goto end;
979 }
980
981 /* Check if a prefix is present. */
982 switch (*num_end) {
983 case 'G':
984 shift = GIBI_LOG2;
985 num_end++;
986 break;
987 case 'M': /* */
988 shift = MEBI_LOG2;
989 num_end++;
990 break;
991 case 'K':
992 case 'k':
993 shift = KIBI_LOG2;
994 num_end++;
995 break;
996 case '\0':
997 break;
998 default:
999 DBG("utils_parse_size_suffix: invalid suffix.");
1000 ret = -1;
1001 goto end;
1002 }
1003
1004 /* Check for garbage after the valid input. */
1005 if (num_end != str_end) {
1006 DBG("utils_parse_size_suffix: Garbage after size string.");
1007 ret = -1;
1008 goto end;
70d0b120
SM
1009 }
1010
1011 *size = base_size << shift;
1012
1013 /* Check for overflow */
1014 if ((*size >> shift) != base_size) {
5983a922 1015 DBG("utils_parse_size_suffix: oops, overflow detected.");
70d0b120 1016 ret = -1;
5983a922 1017 goto end;
70d0b120
SM
1018 }
1019
1020 ret = 0;
70d0b120
SM
1021end:
1022 return ret;
1023}
cfa9a5a2 1024
7010c033
SM
1025/**
1026 * Parse a string that represents a time in human readable format. It
81684730
JR
1027 * supports decimal integers suffixed by:
1028 * "us" for microsecond,
1029 * "ms" for millisecond,
1030 * "s" for second,
1031 * "m" for minute,
1032 * "h" for hour
7010c033
SM
1033 *
1034 * The suffix multiply the integer by:
81684730
JR
1035 * "us" : 1
1036 * "ms" : 1000
1037 * "s" : 1000000
1038 * "m" : 60000000
1039 * "h" : 3600000000
7010c033
SM
1040 *
1041 * Note that unit-less numbers are assumed to be microseconds.
1042 *
1043 * @param str The string to parse, assumed to be NULL-terminated.
1044 * @param time_us Pointer to a uint64_t that will be filled with the
1045 * resulting time in microseconds.
1046 *
1047 * @return 0 on success, -1 on failure.
1048 */
1049LTTNG_HIDDEN
1050int utils_parse_time_suffix(char const * const str, uint64_t * const time_us)
1051{
1052 int ret;
1053 uint64_t base_time;
81684730 1054 uint64_t multiplier = 1;
7010c033
SM
1055 const char *str_end;
1056 char *num_end;
1057
1058 if (!str) {
1059 DBG("utils_parse_time_suffix: received a NULL string.");
1060 ret = -1;
1061 goto end;
1062 }
1063
1064 /* strtoull will accept a negative number, but we don't want to. */
1065 if (strchr(str, '-') != NULL) {
1066 DBG("utils_parse_time_suffix: invalid time string, should not contain '-'.");
1067 ret = -1;
1068 goto end;
1069 }
1070
1071 /* str_end will point to the \0 */
1072 str_end = str + strlen(str);
1073 errno = 0;
1074 base_time = strtoull(str, &num_end, 10);
1075 if (errno != 0) {
1076 PERROR("utils_parse_time_suffix strtoull on string \"%s\"", str);
1077 ret = -1;
1078 goto end;
1079 }
1080
1081 if (num_end == str) {
1082 /* strtoull parsed nothing, not good. */
1083 DBG("utils_parse_time_suffix: strtoull had nothing good to parse.");
1084 ret = -1;
1085 goto end;
1086 }
1087
1088 /* Check if a prefix is present. */
1089 switch (*num_end) {
1090 case 'u':
81684730
JR
1091 /*
1092 * Microsecond (us)
1093 *
1094 * Skip the "us" if the string matches the "us" suffix,
1095 * otherwise let the check for the end of the string handle
1096 * the error reporting.
1097 */
1098 if (*(num_end + 1) == 's') {
1099 num_end += 2;
1100 }
7010c033
SM
1101 break;
1102 case 'm':
81684730
JR
1103 if (*(num_end + 1) == 's') {
1104 /* Millisecond (ms) */
1105 multiplier = USEC_PER_MSEC;
1106 /* Skip the 's' */
1107 num_end++;
1108 } else {
1109 /* Minute (m) */
1110 multiplier = USEC_PER_MINUTE;
1111 }
1112 num_end++;
7010c033
SM
1113 break;
1114 case 's':
81684730
JR
1115 /* Second */
1116 multiplier = USEC_PER_SEC;
1117 num_end++;
1118 break;
1119 case 'h':
1120 /* Hour */
1121 multiplier = USEC_PER_HOURS;
7010c033
SM
1122 num_end++;
1123 break;
1124 case '\0':
1125 break;
1126 default:
1127 DBG("utils_parse_time_suffix: invalid suffix.");
1128 ret = -1;
1129 goto end;
1130 }
1131
1132 /* Check for garbage after the valid input. */
1133 if (num_end != str_end) {
1134 DBG("utils_parse_time_suffix: Garbage after time string.");
1135 ret = -1;
1136 goto end;
1137 }
1138
1139 *time_us = base_time * multiplier;
1140
1141 /* Check for overflow */
1142 if ((*time_us / multiplier) != base_time) {
1143 DBG("utils_parse_time_suffix: oops, overflow detected.");
1144 ret = -1;
1145 goto end;
1146 }
1147
1148 ret = 0;
1149end:
1150 return ret;
1151}
1152
cfa9a5a2
DG
1153/*
1154 * fls: returns the position of the most significant bit.
1155 * Returns 0 if no bit is set, else returns the position of the most
1156 * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
1157 */
1158#if defined(__i386) || defined(__x86_64)
1159static inline unsigned int fls_u32(uint32_t x)
1160{
1161 int r;
1162
1163 asm("bsrl %1,%0\n\t"
1164 "jnz 1f\n\t"
1165 "movl $-1,%0\n\t"
1166 "1:\n\t"
1167 : "=r" (r) : "rm" (x));
1168 return r + 1;
1169}
1170#define HAS_FLS_U32
1171#endif
1172
db5be0a3
JG
1173#if defined(__x86_64)
1174static inline
1175unsigned int fls_u64(uint64_t x)
1176{
1177 long r;
1178
1179 asm("bsrq %1,%0\n\t"
1180 "jnz 1f\n\t"
1181 "movq $-1,%0\n\t"
1182 "1:\n\t"
1183 : "=r" (r) : "rm" (x));
1184 return r + 1;
1185}
1186#define HAS_FLS_U64
1187#endif
1188
1189#ifndef HAS_FLS_U64
1190static __attribute__((unused))
1191unsigned int fls_u64(uint64_t x)
1192{
1193 unsigned int r = 64;
1194
1195 if (!x)
1196 return 0;
1197
1198 if (!(x & 0xFFFFFFFF00000000ULL)) {
1199 x <<= 32;
1200 r -= 32;
1201 }
1202 if (!(x & 0xFFFF000000000000ULL)) {
1203 x <<= 16;
1204 r -= 16;
1205 }
1206 if (!(x & 0xFF00000000000000ULL)) {
1207 x <<= 8;
1208 r -= 8;
1209 }
1210 if (!(x & 0xF000000000000000ULL)) {
1211 x <<= 4;
1212 r -= 4;
1213 }
1214 if (!(x & 0xC000000000000000ULL)) {
1215 x <<= 2;
1216 r -= 2;
1217 }
1218 if (!(x & 0x8000000000000000ULL)) {
1219 x <<= 1;
1220 r -= 1;
1221 }
1222 return r;
1223}
1224#endif
1225
cfa9a5a2
DG
1226#ifndef HAS_FLS_U32
1227static __attribute__((unused)) unsigned int fls_u32(uint32_t x)
1228{
1229 unsigned int r = 32;
1230
1231 if (!x) {
1232 return 0;
1233 }
1234 if (!(x & 0xFFFF0000U)) {
1235 x <<= 16;
1236 r -= 16;
1237 }
1238 if (!(x & 0xFF000000U)) {
1239 x <<= 8;
1240 r -= 8;
1241 }
1242 if (!(x & 0xF0000000U)) {
1243 x <<= 4;
1244 r -= 4;
1245 }
1246 if (!(x & 0xC0000000U)) {
1247 x <<= 2;
1248 r -= 2;
1249 }
1250 if (!(x & 0x80000000U)) {
1251 x <<= 1;
1252 r -= 1;
1253 }
1254 return r;
1255}
1256#endif
1257
1258/*
1259 * Return the minimum order for which x <= (1UL << order).
1260 * Return -1 if x is 0.
1261 */
1262LTTNG_HIDDEN
1263int utils_get_count_order_u32(uint32_t x)
1264{
1265 if (!x) {
1266 return -1;
1267 }
1268
1269 return fls_u32(x - 1);
1270}
feb0f3e5 1271
db5be0a3
JG
1272/*
1273 * Return the minimum order for which x <= (1UL << order).
1274 * Return -1 if x is 0.
1275 */
1276LTTNG_HIDDEN
1277int utils_get_count_order_u64(uint64_t x)
1278{
1279 if (!x) {
1280 return -1;
1281 }
1282
1283 return fls_u64(x - 1);
1284}
1285
feb0f3e5
AM
1286/**
1287 * Obtain the value of LTTNG_HOME environment variable, if exists.
1288 * Otherwise returns the value of HOME.
1289 */
00a52467 1290LTTNG_HIDDEN
feb0f3e5
AM
1291char *utils_get_home_dir(void)
1292{
1293 char *val = NULL;
04135dbd
DG
1294 struct passwd *pwd;
1295
e8fa9fb0 1296 val = lttng_secure_getenv(DEFAULT_LTTNG_HOME_ENV_VAR);
feb0f3e5 1297 if (val != NULL) {
04135dbd
DG
1298 goto end;
1299 }
e8fa9fb0 1300 val = lttng_secure_getenv(DEFAULT_LTTNG_FALLBACK_HOME_ENV_VAR);
04135dbd
DG
1301 if (val != NULL) {
1302 goto end;
feb0f3e5 1303 }
04135dbd
DG
1304
1305 /* Fallback on the password file entry. */
1306 pwd = getpwuid(getuid());
1307 if (!pwd) {
1308 goto end;
1309 }
1310 val = pwd->pw_dir;
1311
1312 DBG3("Home directory is '%s'", val);
1313
1314end:
1315 return val;
feb0f3e5 1316}
26fe5938 1317
fb198a11
JG
1318/**
1319 * Get user's home directory. Dynamically allocated, must be freed
1320 * by the caller.
1321 */
1322LTTNG_HIDDEN
1323char *utils_get_user_home_dir(uid_t uid)
1324{
1325 struct passwd pwd;
1326 struct passwd *result;
1327 char *home_dir = NULL;
1328 char *buf = NULL;
1329 long buflen;
1330 int ret;
1331
1332 buflen = sysconf(_SC_GETPW_R_SIZE_MAX);
1333 if (buflen == -1) {
1334 goto end;
1335 }
1336retry:
1337 buf = zmalloc(buflen);
1338 if (!buf) {
1339 goto end;
1340 }
1341
1342 ret = getpwuid_r(uid, &pwd, buf, buflen, &result);
1343 if (ret || !result) {
1344 if (ret == ERANGE) {
1345 free(buf);
1346 buflen *= 2;
1347 goto retry;
1348 }
1349 goto end;
1350 }
1351
1352 home_dir = strdup(pwd.pw_dir);
1353end:
1354 free(buf);
1355 return home_dir;
1356}
1357
26fe5938
DG
1358/*
1359 * With the given format, fill dst with the time of len maximum siz.
1360 *
1361 * Return amount of bytes set in the buffer or else 0 on error.
1362 */
1363LTTNG_HIDDEN
1364size_t utils_get_current_time_str(const char *format, char *dst, size_t len)
1365{
1366 size_t ret;
1367 time_t rawtime;
1368 struct tm *timeinfo;
1369
1370 assert(format);
1371 assert(dst);
1372
1373 /* Get date and time for session path */
1374 time(&rawtime);
1375 timeinfo = localtime(&rawtime);
1376 ret = strftime(dst, len, format, timeinfo);
1377 if (ret == 0) {
68e6efdd 1378 ERR("Unable to strftime with format %s at dst %p of len %zu", format,
26fe5938
DG
1379 dst, len);
1380 }
1381
1382 return ret;
1383}
6c71277b
MD
1384
1385/*
28ab59d0
JR
1386 * Return 0 on success and set *gid to the group_ID matching the passed name.
1387 * Else -1 if it cannot be found or an error occurred.
6c71277b
MD
1388 */
1389LTTNG_HIDDEN
28ab59d0 1390int utils_get_group_id(const char *name, bool warn, gid_t *gid)
6c71277b 1391{
28ab59d0
JR
1392 static volatile int warn_once;
1393 int ret;
1394 long sys_len;
1395 size_t len;
1396 struct group grp;
1397 struct group *result;
1398 struct lttng_dynamic_buffer buffer;
1399
1400 /* Get the system limit, if it exists. */
1401 sys_len = sysconf(_SC_GETGR_R_SIZE_MAX);
1402 if (sys_len == -1) {
1403 len = 1024;
1404 } else {
1405 len = (size_t) sys_len;
1406 }
1407
1408 lttng_dynamic_buffer_init(&buffer);
1409 ret = lttng_dynamic_buffer_set_size(&buffer, len);
1410 if (ret) {
1411 ERR("Failed to allocate group info buffer");
1412 ret = -1;
1413 goto error;
1414 }
6c71277b 1415
28ab59d0
JR
1416 while ((ret = getgrnam_r(name, &grp, buffer.data, buffer.size, &result)) == ERANGE) {
1417 const size_t new_len = 2 * buffer.size;
6c71277b 1418
28ab59d0
JR
1419 /* Buffer is not big enough, increase its size. */
1420 if (new_len < buffer.size) {
1421 ERR("Group info buffer size overflow");
1422 ret = -1;
1423 goto error;
1424 }
1425
1426 ret = lttng_dynamic_buffer_set_size(&buffer, new_len);
1427 if (ret) {
1428 ERR("Failed to grow group info buffer to %zu bytes",
1429 new_len);
1430 ret = -1;
1431 goto error;
6c71277b 1432 }
6c71277b 1433 }
28ab59d0
JR
1434 if (ret) {
1435 PERROR("Failed to get group file entry for group name \"%s\"",
1436 name);
1437 ret = -1;
1438 goto error;
1439 }
1440
1441 /* Group not found. */
1442 if (!result) {
1443 ret = -1;
1444 goto error;
1445 }
1446
1447 *gid = result->gr_gid;
1448 ret = 0;
1449
1450error:
1451 if (ret && warn && !warn_once) {
1452 WARN("No tracing group detected");
1453 warn_once = 1;
1454 }
1455 lttng_dynamic_buffer_reset(&buffer);
1456 return ret;
6c71277b 1457}
8db0dc00
JG
1458
1459/*
1460 * Return a newly allocated option string. This string is to be used as the
1461 * optstring argument of getopt_long(), see GETOPT(3). opt_count is the number
1462 * of elements in the long_options array. Returns NULL if the string's
1463 * allocation fails.
1464 */
1465LTTNG_HIDDEN
1466char *utils_generate_optstring(const struct option *long_options,
1467 size_t opt_count)
1468{
1469 int i;
1470 size_t string_len = opt_count, str_pos = 0;
1471 char *optstring;
1472
1473 /*
1474 * Compute the necessary string length. One letter per option, two when an
1475 * argument is necessary, and a trailing NULL.
1476 */
1477 for (i = 0; i < opt_count; i++) {
1478 string_len += long_options[i].has_arg ? 1 : 0;
1479 }
1480
1481 optstring = zmalloc(string_len);
1482 if (!optstring) {
1483 goto end;
1484 }
1485
1486 for (i = 0; i < opt_count; i++) {
1487 if (!long_options[i].name) {
1488 /* Got to the trailing NULL element */
1489 break;
1490 }
1491
a596dcb9
JG
1492 if (long_options[i].val != '\0') {
1493 optstring[str_pos++] = (char) long_options[i].val;
1494 if (long_options[i].has_arg) {
1495 optstring[str_pos++] = ':';
1496 }
8db0dc00
JG
1497 }
1498 }
1499
1500end:
1501 return optstring;
1502}
3d071855
MD
1503
1504/*
1505 * Try to remove a hierarchy of empty directories, recursively. Don't unlink
9529ec1b 1506 * any file. Try to rmdir any empty directory within the hierarchy.
3d071855
MD
1507 */
1508LTTNG_HIDDEN
1509int utils_recursive_rmdir(const char *path)
1510{
1511 DIR *dir;
7a946beb 1512 size_t path_len;
9529ec1b 1513 int dir_fd, ret = 0, closeret, is_empty = 1;
3d071855
MD
1514 struct dirent *entry;
1515
1516 /* Open directory */
1517 dir = opendir(path);
1518 if (!dir) {
1519 PERROR("Cannot open '%s' path", path);
1520 return -1;
1521 }
5a2451c9 1522 dir_fd = lttng_dirfd(dir);
3d071855 1523 if (dir_fd < 0) {
5a2451c9 1524 PERROR("lttng_dirfd");
3d071855
MD
1525 return -1;
1526 }
1527
7a946beb 1528 path_len = strlen(path);
3d071855 1529 while ((entry = readdir(dir))) {
7a946beb
MJ
1530 struct stat st;
1531 size_t name_len;
1532 char filename[PATH_MAX];
1533
3763af87
JG
1534 if (!strcmp(entry->d_name, ".")
1535 || !strcmp(entry->d_name, "..")) {
1536 continue;
1537 }
1538
7a946beb
MJ
1539 name_len = strlen(entry->d_name);
1540 if (path_len + name_len + 2 > sizeof(filename)) {
1541 ERR("Failed to remove file: path name too long (%s/%s)",
1542 path, entry->d_name);
1543 continue;
1544 }
1545 if (snprintf(filename, sizeof(filename), "%s/%s",
1546 path, entry->d_name) < 0) {
1547 ERR("Failed to format path.");
1548 continue;
1549 }
1550
1551 if (stat(filename, &st)) {
1552 PERROR("stat");
1553 continue;
1554 }
1555
1556 if (S_ISDIR(st.st_mode)) {
3d071855
MD
1557 char subpath[PATH_MAX];
1558
1559 strncpy(subpath, path, PATH_MAX);
1560 subpath[PATH_MAX - 1] = '\0';
1561 strncat(subpath, "/",
1562 PATH_MAX - strlen(subpath) - 1);
1563 strncat(subpath, entry->d_name,
1564 PATH_MAX - strlen(subpath) - 1);
9529ec1b
MD
1565 if (utils_recursive_rmdir(subpath)) {
1566 is_empty = 0;
3d071855 1567 }
7a946beb 1568 } else if (S_ISREG(st.st_mode)) {
9529ec1b 1569 is_empty = 0;
7a946beb 1570 } else {
3d071855
MD
1571 ret = -EINVAL;
1572 goto end;
1573 }
1574 }
1575end:
1576 closeret = closedir(dir);
1577 if (closeret) {
1578 PERROR("closedir");
1579 }
9529ec1b 1580 if (is_empty) {
3d071855
MD
1581 DBG3("Attempting rmdir %s", path);
1582 ret = rmdir(path);
1583 }
1584 return ret;
1585}
93ec662e
JD
1586
1587LTTNG_HIDDEN
1588int utils_truncate_stream_file(int fd, off_t length)
1589{
1590 int ret;
a5df8828 1591 off_t lseek_ret;
93ec662e
JD
1592
1593 ret = ftruncate(fd, length);
1594 if (ret < 0) {
1595 PERROR("ftruncate");
1596 goto end;
1597 }
a5df8828
GL
1598 lseek_ret = lseek(fd, length, SEEK_SET);
1599 if (lseek_ret < 0) {
93ec662e 1600 PERROR("lseek");
a5df8828 1601 ret = -1;
93ec662e
JD
1602 goto end;
1603 }
93ec662e
JD
1604end:
1605 return ret;
1606}
4ba92f18
PP
1607
1608static const char *get_man_bin_path(void)
1609{
b7dce40d 1610 char *env_man_path = lttng_secure_getenv(DEFAULT_MAN_BIN_PATH_ENV);
4ba92f18
PP
1611
1612 if (env_man_path) {
1613 return env_man_path;
1614 }
1615
1616 return DEFAULT_MAN_BIN_PATH;
1617}
1618
1619LTTNG_HIDDEN
4fc83d94
PP
1620int utils_show_help(int section, const char *page_name,
1621 const char *help_msg)
4ba92f18
PP
1622{
1623 char section_string[8];
1624 const char *man_bin_path = get_man_bin_path();
4fc83d94
PP
1625 int ret = 0;
1626
1627 if (help_msg) {
1628 printf("%s", help_msg);
1629 goto end;
1630 }
4ba92f18
PP
1631
1632 /* Section integer -> section string */
1633 ret = sprintf(section_string, "%d", section);
1634 assert(ret > 0 && ret < 8);
1635
1636 /*
1637 * Execute man pager.
1638 *
b07e7ef0 1639 * We provide -M to man here because LTTng-tools can
4ba92f18
PP
1640 * be installed outside /usr, in which case its man pages are
1641 * not located in the default /usr/share/man directory.
1642 */
b07e7ef0 1643 ret = execlp(man_bin_path, "man", "-M", MANPATH,
4ba92f18 1644 section_string, page_name, NULL);
4fc83d94
PP
1645
1646end:
4ba92f18
PP
1647 return ret;
1648}
09b72f7a
FD
1649
1650static
1651int read_proc_meminfo_field(const char *field, size_t *value)
1652{
1653 int ret;
1654 FILE *proc_meminfo;
1655 char name[PROC_MEMINFO_FIELD_MAX_NAME_LEN] = {};
1656
1657 proc_meminfo = fopen(PROC_MEMINFO_PATH, "r");
1658 if (!proc_meminfo) {
1659 PERROR("Failed to fopen() " PROC_MEMINFO_PATH);
1660 ret = -1;
1661 goto fopen_error;
1662 }
1663
1664 /*
1665 * Read the contents of /proc/meminfo line by line to find the right
1666 * field.
1667 */
1668 while (!feof(proc_meminfo)) {
1669 unsigned long value_kb;
1670
1671 ret = fscanf(proc_meminfo,
1672 "%" MAX_NAME_LEN_SCANF_IS_A_BROKEN_API "s %lu kB\n",
1673 name, &value_kb);
1674 if (ret == EOF) {
1675 /*
1676 * fscanf() returning EOF can indicate EOF or an error.
1677 */
1678 if (ferror(proc_meminfo)) {
1679 PERROR("Failed to parse " PROC_MEMINFO_PATH);
1680 }
1681 break;
1682 }
1683
1684 if (ret == 2 && strcmp(name, field) == 0) {
1685 /*
1686 * This number is displayed in kilo-bytes. Return the
1687 * number of bytes.
1688 */
1689 *value = ((size_t) value_kb) * 1024;
1690 ret = 0;
1691 goto found;
1692 }
1693 }
1694 /* Reached the end of the file without finding the right field. */
1695 ret = -1;
1696
1697found:
1698 fclose(proc_meminfo);
1699fopen_error:
1700 return ret;
1701}
1702
1703/*
1704 * Returns an estimate of the number of bytes of memory available based on the
1705 * the information in `/proc/meminfo`. The number returned by this function is
1706 * a best guess.
1707 */
1708LTTNG_HIDDEN
1709int utils_get_memory_available(size_t *value)
1710{
1711 return read_proc_meminfo_field(PROC_MEMINFO_MEMAVAILABLE_LINE, value);
1712}
1713
1714/*
1715 * Returns the total size of the memory on the system in bytes based on the
1716 * the information in `/proc/meminfo`.
1717 */
1718LTTNG_HIDDEN
1719int utils_get_memory_total(size_t *value)
1720{
1721 return read_proc_meminfo_field(PROC_MEMINFO_MEMTOTAL_LINE, value);
1722}
This page took 0.210386 seconds and 4 git commands to generate.