Introduce utils_create_pipe_cloexec_nonblock()
[lttng-tools.git] / src / common / utils.c
CommitLineData
81b86775
DG
1/*
2 * Copyright (C) 2012 - David Goulet <dgoulet@efficios.com>
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License, version 2 only, as
6 * published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 51
15 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18#define _GNU_SOURCE
35f90c40 19#include <assert.h>
81b86775
DG
20#include <ctype.h>
21#include <fcntl.h>
22#include <limits.h>
23#include <stdlib.h>
24#include <string.h>
2d851108 25#include <sys/stat.h>
0c7bcad5 26#include <sys/types.h>
2d851108 27#include <unistd.h>
fe4477ee 28#include <inttypes.h>
70d0b120 29#include <regex.h>
81b86775
DG
30
31#include <common/common.h>
fe4477ee 32#include <common/runas.h>
81b86775
DG
33
34#include "utils.h"
feb0f3e5 35#include "defaults.h"
81b86775
DG
36
37/*
38 * Return the realpath(3) of the path even if the last directory token does not
39 * exist. For example, with /tmp/test1/test2, if test2/ does not exist but the
40 * /tmp/test1 does, the real path is returned. In normal time, realpath(3)
41 * fails if the end point directory does not exist.
42 */
90e535ef 43LTTNG_HIDDEN
81b86775
DG
44char *utils_expand_path(const char *path)
45{
46 const char *end_path = path;
47 char *next, *cut_path = NULL, *expanded_path = NULL;
48
49 /* Safety net */
50 if (path == NULL) {
51 goto error;
52 }
53
54 /* Find last token delimited by '/' */
55 while ((next = strpbrk(end_path + 1, "/"))) {
56 end_path = next;
57 }
58
59 /* Cut last token from original path */
60 cut_path = strndup(path, end_path - path);
61
62 expanded_path = zmalloc(PATH_MAX);
63 if (expanded_path == NULL) {
64 PERROR("zmalloc expand path");
65 goto error;
66 }
67
68 expanded_path = realpath((char *)cut_path, expanded_path);
69 if (expanded_path == NULL) {
70 switch (errno) {
71 case ENOENT:
72 ERR("%s: No such file or directory", cut_path);
73 break;
74 default:
75 PERROR("realpath utils expand path");
76 break;
77 }
78 goto error;
79 }
80
81 /* Add end part to expanded path */
c30ce0b3 82 strncat(expanded_path, end_path, PATH_MAX - strlen(expanded_path) - 1);
81b86775
DG
83
84 free(cut_path);
85 return expanded_path;
86
87error:
88 free(expanded_path);
89 free(cut_path);
90 return NULL;
91}
92
93/*
94 * Create a pipe in dst.
95 */
90e535ef 96LTTNG_HIDDEN
81b86775
DG
97int utils_create_pipe(int *dst)
98{
99 int ret;
100
101 if (dst == NULL) {
102 return -1;
103 }
104
105 ret = pipe(dst);
106 if (ret < 0) {
107 PERROR("create pipe");
108 }
109
110 return ret;
111}
112
113/*
114 * Create pipe and set CLOEXEC flag to both fd.
115 *
116 * Make sure the pipe opened by this function are closed at some point. Use
117 * utils_close_pipe().
118 */
90e535ef 119LTTNG_HIDDEN
81b86775
DG
120int utils_create_pipe_cloexec(int *dst)
121{
122 int ret, i;
123
124 if (dst == NULL) {
125 return -1;
126 }
127
128 ret = utils_create_pipe(dst);
129 if (ret < 0) {
130 goto error;
131 }
132
133 for (i = 0; i < 2; i++) {
134 ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC);
135 if (ret < 0) {
136 PERROR("fcntl pipe cloexec");
137 goto error;
138 }
139 }
140
141error:
142 return ret;
143}
144
094f381c
MD
145/*
146 * Create pipe and set fd flags to FD_CLOEXEC and O_NONBLOCK.
147 *
148 * Make sure the pipe opened by this function are closed at some point. Use
149 * utils_close_pipe(). Using pipe() and fcntl rather than pipe2() to
150 * support OSes other than Linux 2.6.23+.
151 */
152LTTNG_HIDDEN
153int utils_create_pipe_cloexec_nonblock(int *dst)
154{
155 int ret, i;
156
157 if (dst == NULL) {
158 return -1;
159 }
160
161 ret = utils_create_pipe(dst);
162 if (ret < 0) {
163 goto error;
164 }
165
166 for (i = 0; i < 2; i++) {
167 ret = fcntl(dst[i], F_SETFD, FD_CLOEXEC);
168 if (ret < 0) {
169 PERROR("fcntl pipe cloexec");
170 goto error;
171 }
172 /*
173 * Note: we override any flag that could have been
174 * previously set on the fd.
175 */
176 ret = fcntl(dst[i], F_SETFL, O_NONBLOCK);
177 if (ret < 0) {
178 PERROR("fcntl pipe nonblock");
179 goto error;
180 }
181 }
182
183error:
184 return ret;
185}
186
81b86775
DG
187/*
188 * Close both read and write side of the pipe.
189 */
90e535ef 190LTTNG_HIDDEN
81b86775
DG
191void utils_close_pipe(int *src)
192{
193 int i, ret;
194
195 if (src == NULL) {
196 return;
197 }
198
199 for (i = 0; i < 2; i++) {
200 /* Safety check */
201 if (src[i] < 0) {
202 continue;
203 }
204
205 ret = close(src[i]);
206 if (ret) {
207 PERROR("close pipe");
208 }
209 }
210}
a4b92340
DG
211
212/*
213 * Create a new string using two strings range.
214 */
90e535ef 215LTTNG_HIDDEN
a4b92340
DG
216char *utils_strdupdelim(const char *begin, const char *end)
217{
218 char *str;
219
220 str = zmalloc(end - begin + 1);
221 if (str == NULL) {
222 PERROR("zmalloc strdupdelim");
223 goto error;
224 }
225
226 memcpy(str, begin, end - begin);
227 str[end - begin] = '\0';
228
229error:
230 return str;
231}
b662582b
DG
232
233/*
234 * Set CLOEXEC flag to the give file descriptor.
235 */
90e535ef 236LTTNG_HIDDEN
b662582b
DG
237int utils_set_fd_cloexec(int fd)
238{
239 int ret;
240
241 if (fd < 0) {
242 ret = -EINVAL;
243 goto end;
244 }
245
246 ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
247 if (ret < 0) {
248 PERROR("fcntl cloexec");
249 ret = -errno;
250 }
251
252end:
253 return ret;
254}
35f90c40
DG
255
256/*
257 * Create pid file to the given path and filename.
258 */
90e535ef 259LTTNG_HIDDEN
35f90c40
DG
260int utils_create_pid_file(pid_t pid, const char *filepath)
261{
262 int ret;
263 FILE *fp;
264
265 assert(filepath);
266
267 fp = fopen(filepath, "w");
268 if (fp == NULL) {
269 PERROR("open pid file %s", filepath);
270 ret = -1;
271 goto error;
272 }
273
274 ret = fprintf(fp, "%d\n", pid);
275 if (ret < 0) {
276 PERROR("fprintf pid file");
277 }
278
279 fclose(fp);
280 DBG("Pid %d written in file %s", pid, filepath);
281error:
282 return ret;
283}
2d851108
DG
284
285/*
286 * Recursively create directory using the given path and mode.
287 *
288 * On success, return 0 else a negative error code.
289 */
90e535ef 290LTTNG_HIDDEN
2d851108
DG
291int utils_mkdir_recursive(const char *path, mode_t mode)
292{
293 char *p, tmp[PATH_MAX];
2d851108
DG
294 size_t len;
295 int ret;
296
297 assert(path);
298
299 ret = snprintf(tmp, sizeof(tmp), "%s", path);
300 if (ret < 0) {
301 PERROR("snprintf mkdir");
302 goto error;
303 }
304
305 len = ret;
306 if (tmp[len - 1] == '/') {
307 tmp[len - 1] = 0;
308 }
309
310 for (p = tmp + 1; *p; p++) {
311 if (*p == '/') {
312 *p = 0;
313 if (tmp[strlen(tmp) - 1] == '.' &&
314 tmp[strlen(tmp) - 2] == '.' &&
315 tmp[strlen(tmp) - 3] == '/') {
316 ERR("Using '/../' is not permitted in the trace path (%s)",
317 tmp);
318 ret = -1;
319 goto error;
320 }
0c7bcad5 321 ret = mkdir(tmp, mode);
2d851108 322 if (ret < 0) {
0c7bcad5
MD
323 if (errno != EEXIST) {
324 PERROR("mkdir recursive");
325 ret = -errno;
326 goto error;
2d851108
DG
327 }
328 }
329 *p = '/';
330 }
331 }
332
333 ret = mkdir(tmp, mode);
334 if (ret < 0) {
335 if (errno != EEXIST) {
336 PERROR("mkdir recursive last piece");
337 ret = -errno;
338 } else {
339 ret = 0;
340 }
341 }
342
343error:
344 return ret;
345}
fe4477ee
JD
346
347/*
348 * Create the stream tracefile on disk.
349 *
350 * Return 0 on success or else a negative value.
351 */
bc182241 352LTTNG_HIDDEN
07b86b52 353int utils_create_stream_file(const char *path_name, char *file_name, uint64_t size,
fe4477ee
JD
354 uint64_t count, int uid, int gid)
355{
be96a7d1 356 int ret, out_fd, flags, mode;
fe4477ee
JD
357 char full_path[PATH_MAX], *path_name_id = NULL, *path;
358
359 assert(path_name);
360 assert(file_name);
361
362 ret = snprintf(full_path, sizeof(full_path), "%s/%s",
363 path_name, file_name);
364 if (ret < 0) {
365 PERROR("snprintf create output file");
366 goto error;
367 }
368
369 /*
370 * If we split the trace in multiple files, we have to add the count at the
371 * end of the tracefile name
372 */
373 if (size > 0) {
374 ret = asprintf(&path_name_id, "%s_%" PRIu64, full_path, count);
375 if (ret < 0) {
376 PERROR("Allocating path name ID");
377 goto error;
378 }
379 path = path_name_id;
380 } else {
381 path = full_path;
382 }
383
be96a7d1 384 flags = O_WRONLY | O_CREAT | O_TRUNC;
0f907de1 385 /* Open with 660 mode */
be96a7d1
DG
386 mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP;
387
388 if (uid < 0 || gid < 0) {
389 out_fd = open(path, flags, mode);
390 } else {
391 out_fd = run_as_open(path, flags, mode, uid, gid);
392 }
fe4477ee
JD
393 if (out_fd < 0) {
394 PERROR("open stream path %s", path);
395 goto error_open;
396 }
397 ret = out_fd;
398
399error_open:
400 free(path_name_id);
401error:
402 return ret;
403}
404
405/*
406 * Change the output tracefile according to the given size and count The
407 * new_count pointer is set during this operation.
408 *
409 * From the consumer, the stream lock MUST be held before calling this function
410 * because we are modifying the stream status.
411 *
412 * Return 0 on success or else a negative value.
413 */
bc182241 414LTTNG_HIDDEN
fe4477ee
JD
415int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size,
416 uint64_t count, int uid, int gid, int out_fd, uint64_t *new_count)
417{
418 int ret;
419
420 ret = close(out_fd);
421 if (ret < 0) {
422 PERROR("Closing tracefile");
423 goto error;
424 }
425
426 if (count > 0) {
427 *new_count = (*new_count + 1) % count;
428 } else {
429 (*new_count)++;
430 }
431
432 return utils_create_stream_file(path_name, file_name, size, *new_count,
433 uid, gid);
434error:
435 return ret;
436}
70d0b120
SM
437
438/**
439 * Prints the error message corresponding to a regex error code.
440 *
441 * @param errcode The error code.
442 * @param regex The regex object that produced the error code.
443 */
444static void regex_print_error(int errcode, regex_t *regex)
445{
446 /* Get length of error message and allocate accordingly */
447 size_t length;
448 char *buffer;
449
450 assert(regex != NULL);
451
452 length = regerror(errcode, regex, NULL, 0);
453 if (length == 0) {
454 ERR("regerror returned a length of 0");
455 return;
456 }
457
458 buffer = zmalloc(length);
459 if (!buffer) {
460 ERR("regex_print_error: zmalloc failed");
461 return;
462 }
463
464 /* Get and print error message */
465 regerror(errcode, regex, buffer, length);
466 ERR("regex error: %s\n", buffer);
467 free(buffer);
468
469}
470
471/**
472 * Parse a string that represents a size in human readable format. It
473 * supports decimal integers suffixed by 'k', 'M' or 'G'.
474 *
475 * The suffix multiply the integer by:
476 * 'k': 1024
477 * 'M': 1024^2
478 * 'G': 1024^3
479 *
480 * @param str The string to parse.
481 * @param size Pointer to a size_t that will be filled with the
cfa9a5a2 482 * resulting size.
70d0b120
SM
483 *
484 * @return 0 on success, -1 on failure.
485 */
00a52467 486LTTNG_HIDDEN
70d0b120
SM
487int utils_parse_size_suffix(char *str, uint64_t *size)
488{
489 regex_t regex;
490 int ret;
491 const int nmatch = 3;
492 regmatch_t suffix_match, matches[nmatch];
493 unsigned long long base_size;
494 long shift = 0;
495
496 if (!str) {
497 return 0;
498 }
499
500 /* Compile regex */
501 ret = regcomp(&regex, "^\\(0x\\)\\{0,1\\}[0-9][0-9]*\\([kKMG]\\{0,1\\}\\)$", 0);
502 if (ret != 0) {
503 regex_print_error(ret, &regex);
504 ret = -1;
505 goto end;
506 }
507
508 /* Match regex */
509 ret = regexec(&regex, str, nmatch, matches, 0);
510 if (ret != 0) {
511 ret = -1;
512 goto free;
513 }
514
515 /* There is a match ! */
516 errno = 0;
517 base_size = strtoull(str, NULL, 0);
518 if (errno != 0) {
519 PERROR("strtoull");
520 ret = -1;
521 goto free;
522 }
523
524 /* Check if there is a suffix */
525 suffix_match = matches[2];
526 if (suffix_match.rm_eo - suffix_match.rm_so == 1) {
527 switch (*(str + suffix_match.rm_so)) {
528 case 'K':
529 case 'k':
530 shift = KIBI_LOG2;
531 break;
532 case 'M':
533 shift = MEBI_LOG2;
534 break;
535 case 'G':
536 shift = GIBI_LOG2;
537 break;
538 default:
539 ERR("parse_human_size: invalid suffix");
540 ret = -1;
541 goto free;
542 }
543 }
544
545 *size = base_size << shift;
546
547 /* Check for overflow */
548 if ((*size >> shift) != base_size) {
549 ERR("parse_size_suffix: oops, overflow detected.");
550 ret = -1;
551 goto free;
552 }
553
554 ret = 0;
555
556free:
557 regfree(&regex);
558end:
559 return ret;
560}
cfa9a5a2
DG
561
562/*
563 * fls: returns the position of the most significant bit.
564 * Returns 0 if no bit is set, else returns the position of the most
565 * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
566 */
567#if defined(__i386) || defined(__x86_64)
568static inline unsigned int fls_u32(uint32_t x)
569{
570 int r;
571
572 asm("bsrl %1,%0\n\t"
573 "jnz 1f\n\t"
574 "movl $-1,%0\n\t"
575 "1:\n\t"
576 : "=r" (r) : "rm" (x));
577 return r + 1;
578}
579#define HAS_FLS_U32
580#endif
581
582#ifndef HAS_FLS_U32
583static __attribute__((unused)) unsigned int fls_u32(uint32_t x)
584{
585 unsigned int r = 32;
586
587 if (!x) {
588 return 0;
589 }
590 if (!(x & 0xFFFF0000U)) {
591 x <<= 16;
592 r -= 16;
593 }
594 if (!(x & 0xFF000000U)) {
595 x <<= 8;
596 r -= 8;
597 }
598 if (!(x & 0xF0000000U)) {
599 x <<= 4;
600 r -= 4;
601 }
602 if (!(x & 0xC0000000U)) {
603 x <<= 2;
604 r -= 2;
605 }
606 if (!(x & 0x80000000U)) {
607 x <<= 1;
608 r -= 1;
609 }
610 return r;
611}
612#endif
613
614/*
615 * Return the minimum order for which x <= (1UL << order).
616 * Return -1 if x is 0.
617 */
618LTTNG_HIDDEN
619int utils_get_count_order_u32(uint32_t x)
620{
621 if (!x) {
622 return -1;
623 }
624
625 return fls_u32(x - 1);
626}
feb0f3e5
AM
627
628/**
629 * Obtain the value of LTTNG_HOME environment variable, if exists.
630 * Otherwise returns the value of HOME.
631 */
00a52467 632LTTNG_HIDDEN
feb0f3e5
AM
633char *utils_get_home_dir(void)
634{
635 char *val = NULL;
636 val = getenv(DEFAULT_LTTNG_HOME_ENV_VAR);
637 if (val != NULL) {
638 return val;
639 }
640 return getenv(DEFAULT_LTTNG_FALLBACK_HOME_ENV_VAR);
641}
26fe5938
DG
642
643/*
644 * With the given format, fill dst with the time of len maximum siz.
645 *
646 * Return amount of bytes set in the buffer or else 0 on error.
647 */
648LTTNG_HIDDEN
649size_t utils_get_current_time_str(const char *format, char *dst, size_t len)
650{
651 size_t ret;
652 time_t rawtime;
653 struct tm *timeinfo;
654
655 assert(format);
656 assert(dst);
657
658 /* Get date and time for session path */
659 time(&rawtime);
660 timeinfo = localtime(&rawtime);
661 ret = strftime(dst, len, format, timeinfo);
662 if (ret == 0) {
663 ERR("Unable to strftime with format %s at dst %p of len %lu", format,
664 dst, len);
665 }
666
667 return ret;
668}
This page took 0.064834 seconds and 5 git commands to generate.