+ goto error;
+ }
+
+ if (fclose(fp)) {
+ PERROR("fclose");
+ }
+ DBG("Pid %d written in file %s", (int) pid, filepath);
+ ret = 0;
+error:
+ return ret;
+}
+
+/*
+ * Create lock file to the given path and filename.
+ * Returns the associated file descriptor, -1 on error.
+ */
+LTTNG_HIDDEN
+int utils_create_lock_file(const char *filepath)
+{
+ int ret;
+ int fd;
+ struct flock lock;
+
+ assert(filepath);
+
+ memset(&lock, 0, sizeof(lock));
+ fd = open(filepath, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR |
+ S_IRGRP | S_IWGRP);
+ if (fd < 0) {
+ PERROR("open lock file %s", filepath);
+ fd = -1;
+ goto error;
+ }
+
+ /*
+ * Attempt to lock the file. If this fails, there is
+ * already a process using the same lock file running
+ * and we should exit.
+ */
+ lock.l_whence = SEEK_SET;
+ lock.l_type = F_WRLCK;
+
+ ret = fcntl(fd, F_SETLK, &lock);
+ if (ret == -1) {
+ PERROR("fcntl lock file");
+ ERR("Could not get lock file %s, another instance is running.",
+ filepath);
+ if (close(fd)) {
+ PERROR("close lock file");
+ }
+ fd = ret;
+ goto error;
+ }
+
+error:
+ return fd;
+}
+
+/*
+ * Create directory using the given path and mode.
+ *
+ * On success, return 0 else a negative error code.
+ */
+LTTNG_HIDDEN
+int utils_mkdir(const char *path, mode_t mode, int uid, int gid)
+{
+ int ret;
+ struct lttng_directory_handle *handle;
+ const struct lttng_credentials creds = {
+ .uid = (uid_t) uid,
+ .gid = (gid_t) gid,
+ };
+
+ handle = lttng_directory_handle_create(NULL);
+ if (!handle) {
+ ret = -1;
+ goto end;
+ }
+ ret = lttng_directory_handle_create_subdirectory_as_user(
+ handle, path, mode,
+ (uid >= 0 || gid >= 0) ? &creds : NULL);
+end:
+ lttng_directory_handle_put(handle);
+ return ret;
+}
+
+/*
+ * Recursively create directory using the given path and mode, under the
+ * provided uid and gid.
+ *
+ * On success, return 0 else a negative error code.
+ */
+LTTNG_HIDDEN
+int utils_mkdir_recursive(const char *path, mode_t mode, int uid, int gid)
+{
+ int ret;
+ struct lttng_directory_handle *handle;
+ const struct lttng_credentials creds = {
+ .uid = (uid_t) uid,
+ .gid = (gid_t) gid,
+ };
+
+ handle = lttng_directory_handle_create(NULL);
+ if (!handle) {
+ ret = -1;
+ goto end;
+ }
+ ret = lttng_directory_handle_create_subdirectory_recursive_as_user(
+ handle, path, mode,
+ (uid >= 0 || gid >= 0) ? &creds : NULL);
+end:
+ lttng_directory_handle_put(handle);
+ return ret;
+}
+
+/*
+ * out_stream_path is the output parameter.
+ *
+ * Return 0 on success or else a negative value.
+ */
+LTTNG_HIDDEN
+int utils_stream_file_path(const char *path_name, const char *file_name,
+ uint64_t size, uint64_t count, const char *suffix,
+ char *out_stream_path, size_t stream_path_len)
+{
+ int ret;
+ char count_str[MAX_INT_DEC_LEN(count) + 1] = {};
+ const char *path_separator;
+
+ if (path_name && (path_name[0] == '\0' ||
+ path_name[strlen(path_name) - 1] == '/')) {
+ path_separator = "";
+ } else {
+ path_separator = "/";
+ }
+
+ path_name = path_name ? : "";
+ suffix = suffix ? : "";
+ if (size > 0) {
+ ret = snprintf(count_str, sizeof(count_str), "_%" PRIu64,
+ count);
+ assert(ret > 0 && ret < sizeof(count_str));
+ }
+
+ ret = snprintf(out_stream_path, stream_path_len, "%s%s%s%s%s",
+ path_name, path_separator, file_name, count_str,
+ suffix);
+ if (ret < 0 || ret >= stream_path_len) {
+ ERR("Truncation occurred while formatting stream path");
+ ret = -1;
+ } else {
+ ret = 0;
+ }
+ return ret;
+}
+
+/**
+ * Parse a string that represents a size in human readable format. It
+ * supports decimal integers suffixed by 'k', '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 uint64_t that will be filled with the
+ * resulting size.
+ *
+ * @return 0 on success, -1 on failure.
+ */
+LTTNG_HIDDEN
+int utils_parse_size_suffix(const char * const str, uint64_t * const size)
+{
+ int ret;
+ uint64_t base_size;
+ long shift = 0;
+ const char *str_end;
+ char *num_end;
+
+ if (!str) {
+ DBG("utils_parse_size_suffix: received a NULL string.");
+ ret = -1;
+ goto end;
+ }
+
+ /* strtoull will accept a negative number, but we don't want to. */
+ if (strchr(str, '-') != NULL) {
+ DBG("utils_parse_size_suffix: invalid size string, should not contain '-'.");
+ ret = -1;
+ goto end;
+ }
+
+ /* str_end will point to the \0 */
+ str_end = str + strlen(str);
+ errno = 0;
+ base_size = strtoull(str, &num_end, 0);
+ if (errno != 0) {
+ PERROR("utils_parse_size_suffix strtoull");
+ ret = -1;
+ goto end;
+ }
+
+ if (num_end == str) {
+ /* strtoull parsed nothing, not good. */
+ DBG("utils_parse_size_suffix: strtoull had nothing good to parse.");
+ ret = -1;
+ goto end;
+ }
+
+ /* Check if a prefix is present. */
+ switch (*num_end) {
+ case 'G':
+ shift = GIBI_LOG2;
+ num_end++;
+ break;
+ case 'M': /* */
+ shift = MEBI_LOG2;
+ num_end++;
+ break;
+ case 'K':
+ case 'k':
+ shift = KIBI_LOG2;
+ num_end++;
+ break;
+ case '\0':
+ break;
+ default:
+ DBG("utils_parse_size_suffix: invalid suffix.");
+ ret = -1;
+ goto end;
+ }
+
+ /* Check for garbage after the valid input. */
+ if (num_end != str_end) {
+ DBG("utils_parse_size_suffix: Garbage after size string.");
+ ret = -1;
+ goto end;
+ }
+
+ *size = base_size << shift;
+
+ /* Check for overflow */
+ if ((*size >> shift) != base_size) {
+ DBG("utils_parse_size_suffix: oops, overflow detected.");
+ ret = -1;
+ goto end;
+ }
+
+ ret = 0;
+end:
+ return ret;
+}
+
+/**
+ * Parse a string that represents a time in human readable format. It
+ * supports decimal integers suffixed by:
+ * "us" for microsecond,
+ * "ms" for millisecond,
+ * "s" for second,
+ * "m" for minute,
+ * "h" for hour
+ *
+ * The suffix multiply the integer by:
+ * "us" : 1
+ * "ms" : 1000
+ * "s" : 1000000
+ * "m" : 60000000
+ * "h" : 3600000000
+ *
+ * Note that unit-less numbers are assumed to be microseconds.
+ *
+ * @param str The string to parse, assumed to be NULL-terminated.
+ * @param time_us Pointer to a uint64_t that will be filled with the
+ * resulting time in microseconds.
+ *
+ * @return 0 on success, -1 on failure.
+ */
+LTTNG_HIDDEN
+int utils_parse_time_suffix(char const * const str, uint64_t * const time_us)
+{
+ int ret;
+ uint64_t base_time;
+ uint64_t multiplier = 1;
+ const char *str_end;
+ char *num_end;
+
+ if (!str) {
+ DBG("utils_parse_time_suffix: received a NULL string.");
+ ret = -1;
+ goto end;