X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Futils.c;h=f3718f00fa8ddabb7c921ac55287626dd83f45b8;hp=a18e906d7f6b303d834482b2b00ce7f93a1fcdf5;hb=70d0b120691e90d81de7b38af8b845e261b5b40c;hpb=90e535ef0d0433d31e805775f85e4d187b1cf82c diff --git a/src/common/utils.c b/src/common/utils.c index a18e906d7..f3718f00f 100644 --- a/src/common/utils.c +++ b/src/common/utils.c @@ -25,8 +25,11 @@ #include #include #include +#include +#include #include +#include #include "utils.h" @@ -301,3 +304,217 @@ int utils_mkdir_recursive(const char *path, mode_t mode) error: return ret; } + +/* + * Create the stream tracefile on disk. + * + * Return 0 on success or else a negative value. + */ +LTTNG_HIDDEN +int utils_create_stream_file(char *path_name, char *file_name, uint64_t size, + uint64_t count, int uid, int gid) +{ + int ret, out_fd, flags, mode; + char full_path[PATH_MAX], *path_name_id = NULL, *path; + + assert(path_name); + assert(file_name); + + ret = snprintf(full_path, sizeof(full_path), "%s/%s", + path_name, file_name); + if (ret < 0) { + PERROR("snprintf create output file"); + goto error; + } + + /* + * If we split the trace in multiple files, we have to add the count at the + * end of the tracefile name + */ + if (size > 0) { + ret = asprintf(&path_name_id, "%s_%" PRIu64, full_path, count); + if (ret < 0) { + PERROR("Allocating path name ID"); + goto error; + } + path = path_name_id; + } else { + path = full_path; + } + + flags = O_WRONLY | O_CREAT | O_TRUNC; + /* Open with 660 mode */ + mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP; + + if (uid < 0 || gid < 0) { + out_fd = open(path, flags, mode); + } else { + out_fd = run_as_open(path, flags, mode, uid, gid); + } + if (out_fd < 0) { + PERROR("open stream path %s", path); + goto error_open; + } + ret = out_fd; + +error_open: + free(path_name_id); +error: + return ret; +} + +/* + * Change the output tracefile according to the given size and count The + * new_count pointer is set during this operation. + * + * From the consumer, the stream lock MUST be held before calling this function + * because we are modifying the stream status. + * + * Return 0 on success or else a negative value. + */ +LTTNG_HIDDEN +int utils_rotate_stream_file(char *path_name, char *file_name, uint64_t size, + uint64_t count, int uid, int gid, int out_fd, uint64_t *new_count) +{ + int ret; + + ret = close(out_fd); + if (ret < 0) { + PERROR("Closing tracefile"); + goto error; + } + + if (count > 0) { + *new_count = (*new_count + 1) % count; + } else { + (*new_count)++; + } + + return utils_create_stream_file(path_name, file_name, size, *new_count, + uid, gid); +error: + return ret; +} + +/** + * Prints the error message corresponding to a regex error code. + * + * @param errcode The error code. + * @param regex The regex object that produced the error code. + */ +static void regex_print_error(int errcode, regex_t *regex) +{ + /* Get length of error message and allocate accordingly */ + size_t length; + char *buffer; + + assert(regex != NULL); + + length = regerror(errcode, regex, NULL, 0); + if (length == 0) { + ERR("regerror returned a length of 0"); + return; + } + + buffer = zmalloc(length); + if (!buffer) { + ERR("regex_print_error: zmalloc failed"); + return; + } + + /* Get and print error message */ + regerror(errcode, regex, buffer, length); + ERR("regex error: %s\n", buffer); + free(buffer); + +} + +/** + * Parse a string that represents a size in human readable format. It + * supports decimal integers suffixed by 'k', 'M' or 'G'. + * + * The suffix multiply the integer by: + * 'k': 1024 + * 'M': 1024^2 + * 'G': 1024^3 + * + * @param str The string to parse. + * @param size Pointer to a size_t that will be filled with the + * resulting size. + * + * @return 0 on success, -1 on failure. + */ +int utils_parse_size_suffix(char *str, uint64_t *size) +{ + regex_t regex; + int ret; + const int nmatch = 3; + regmatch_t suffix_match, matches[nmatch]; + unsigned long long base_size; + long shift = 0; + + if (!str) { + return 0; + } + + /* Compile regex */ + ret = regcomp(®ex, "^\\(0x\\)\\{0,1\\}[0-9][0-9]*\\([kKMG]\\{0,1\\}\\)$", 0); + if (ret != 0) { + regex_print_error(ret, ®ex); + ret = -1; + goto end; + } + + /* Match regex */ + ret = regexec(®ex, str, nmatch, matches, 0); + if (ret != 0) { + ret = -1; + goto free; + } + + /* There is a match ! */ + errno = 0; + base_size = strtoull(str, NULL, 0); + if (errno != 0) { + PERROR("strtoull"); + ret = -1; + goto free; + } + + /* Check if there is a suffix */ + suffix_match = matches[2]; + if (suffix_match.rm_eo - suffix_match.rm_so == 1) { + switch (*(str + suffix_match.rm_so)) { + case 'K': + case 'k': + shift = KIBI_LOG2; + break; + case 'M': + shift = MEBI_LOG2; + break; + case 'G': + shift = GIBI_LOG2; + break; + default: + ERR("parse_human_size: invalid suffix"); + ret = -1; + goto free; + } + } + + *size = base_size << shift; + + /* Check for overflow */ + if ((*size >> shift) != base_size) { + ERR("parse_size_suffix: oops, overflow detected."); + ret = -1; + goto free; + } + + ret = 0; + +free: + regfree(®ex); +end: + return ret; +}