docs: Add supported versions and fix-backport policy
[lttng-tools.git] / src / bin / lttng-relayd / backward-compatibility-group-by.cpp
CommitLineData
2a635488 1/*
ab5be9fa 2 * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
2a635488 3 *
ab5be9fa 4 * SPDX-License-Identifier: GPL-2.0-only
2a635488 5 *
2a635488
JR
6 */
7
28ab034a 8#include "backward-compatibility-group-by.hpp"
c9e313bc 9#include "common/time.hpp"
2a635488 10
c9e313bc
SM
11#include <common/common.hpp>
12#include <common/defaults.hpp>
13#include <common/utils.hpp>
2a635488 14
28ab034a
JG
15#include <regex.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <string.h>
2a635488 19
28ab034a 20#define DATETIME_REGEX ".*-[1-2][0-9][0-9][0-9][0-1][0-9][0-3][0-9]-[0-2][0-9][0-5][0-9][0-5][0-9]$"
2a635488
JR
21
22/*
23 * Provide support for --group-output-by-session for producer >= 2.4 and < 2.11.
24 * Take the stream path, extract all available information, craft a new path to
25 * the best of our ability enforcing the group by session.
26 *
27 * Return the allocated string containing the new stream path or else NULL.
28 */
d2cb4a90 29char *backward_compat_group_by_session(const char *path,
28ab034a
JG
30 const char *local_session_name,
31 time_t relay_session_creation_time)
2a635488
JR
32{
33 int ret;
34 size_t len;
35 char *leftover_ptr;
cd9adb8b
JG
36 char *local_copy = nullptr;
37 char *datetime = nullptr;
38 char *partial_base_path = nullptr;
39 char *filepath_per_session = nullptr;
2a635488
JR
40 const char *second_token_ptr;
41 const char *leftover_second_token_ptr;
42 const char *hostname_ptr;
43 regex_t regex;
44
a0377dfe
FD
45 LTTNG_ASSERT(path);
46 LTTNG_ASSERT(local_session_name);
47 LTTNG_ASSERT(local_session_name[0] != '\0');
2a635488
JR
48
49 DBG("Parsing path \"%s\" of session \"%s\" to create a new path that is grouped by session",
28ab034a
JG
50 path,
51 local_session_name);
2a635488
JR
52
53 /* Get a local copy for strtok */
54 local_copy = strdup(path);
55 if (!local_copy) {
56 PERROR("Failed to parse session path: couldn't copy input path");
57 goto error;
58 }
59
60 /*
61 * The use of strtok with '/' as delimiter is valid since we refuse '/'
62 * in session name and '/' is not a valid hostname character based on
4f173935 63 * RFC-952 [1], RFC-921 [2] and refined in RFC-1123 [3].
2a635488
JR
64 * [1] https://tools.ietf.org/html/rfc952
65 * [2] https://tools.ietf.org/html/rfc921
66 * [3] https://tools.ietf.org/html/rfc1123#page-13
67 */
68
69 /*
70 * Get the hostname and possible session_name.
71 * Note that we can get the hostname and session name from the
72 * relay_session object we already have. Still, it is easier to
73 * tokenized the passed path to obtain the start of the path leftover.
74 */
75 hostname_ptr = strtok_r(local_copy, "/", &leftover_ptr);
76 if (!hostname_ptr) {
28ab034a 77 ERR("Failed to parse session path \"%s\": couldn't identify hostname", path);
2a635488
JR
78 goto error;
79 }
80
cd9adb8b 81 second_token_ptr = strtok_r(nullptr, "/", &leftover_ptr);
2a635488 82 if (!second_token_ptr) {
28ab034a 83 ERR("Failed to parse session path \"%s\": couldn't identify session name", path);
2a635488
JR
84 goto error;
85 }
86
87 /*
88 * Check if the second token is a base path set at url level. This is
89 * legal in streaming, live and snapshot [1]. Otherwise it is the
90 * session name with possibly a datetime attached [2]. Note that when
91 * "adding" snapshot output (lttng snapshot add-output), no session name
92 * is present in the path by default. The handling for "base path" take
93 * care of this case as well.
94 * [1] e.g --set-url net://localhost/my_marvellous_path
95 * [2] Can be:
96 * <session_name>
97 * When using --snapshot on session create.
98 * <session_name>-<date>-<time>
99 * <auto>-<date>-<time>
100 */
28ab034a 101 if (strncmp(second_token_ptr, local_session_name, strlen(local_session_name)) != 0) {
2a635488
JR
102 /*
103 * Token does not start with session name.
104 * This mean this is an extra path scenario.
105 * Duplicate the current token since it is part of an
106 * base_path.
107 * Set secDuplicate the current token since it is part of an
108 * base_path. The rest is the leftover.
109 * Set second_token_ptr to the local_session_name for further
110 * processing.
111 */
112 partial_base_path = strdup(second_token_ptr);
113 if (!partial_base_path) {
114 PERROR("Failed to parse session path: couldn't copy partial base path");
115 goto error;
116 }
117
118 second_token_ptr = local_session_name;
119 }
120
121 /*
122 * Based on the previous test, we can move inside the token ptr to
123 * remove the "local_session_name" and inspect the rest of the token.
124 * We are looking into extracting the creation datetime from either the
125 * session_name or the token. We need to to all this gymnastic because
126 * an extra path could decide to append a datetime to its first
127 * subdirectory.
128 * Possible scenario:
129 * <session_name>
130 * <session_name>-<date>-<time>
131 * <auto>-<date>-<time>
132 * <session_name>_base_path_foo_bar
133 * <session_name>-<false date>-<false-time> (via a base path)
134 *
135 * We have no way to discern from the basic scenario of:
136 * <session_name>-<date>-<time>
137 * and one done using a base path with the exact format we normally
138 * expect.
139 *
140 * e.g:
141 * lttng create my_session -U
142 * net://localhost/my_session-19910319-120000/
143 */
144 ret = regcomp(&regex, DATETIME_REGEX, 0);
145 if (ret) {
146 ERR("Failed to parse session path: regex compilation failed with code %d", ret);
147 goto error;
148 }
149
28ab034a 150 leftover_second_token_ptr = second_token_ptr + strlen(local_session_name);
2a635488
JR
151 len = strlen(leftover_second_token_ptr);
152 if (len == 0) {
153 /*
154 * We are either dealing with an auto session name or only the
155 * session_name. If this is a auto session name, we need to
156 * fetch the creation datetime.
157 */
cd9adb8b 158 ret = regexec(&regex, local_session_name, 0, nullptr, 0);
2a635488
JR
159 if (ret == 0) {
160 const ssize_t local_session_name_offset =
28ab034a 161 strlen(local_session_name) - DATETIME_STR_LEN + 1;
2a635488 162
a0377dfe 163 LTTNG_ASSERT(local_session_name_offset >= 0);
28ab034a 164 datetime = strdup(local_session_name + local_session_name_offset);
2a635488
JR
165 if (!datetime) {
166 PERROR("Failed to parse session path: couldn't copy datetime on regex match");
167 goto error_regex;
168 }
d2cb4a90 169 } else {
64803277 170 datetime = calloc<char>(DATETIME_STR_LEN);
d2cb4a90
JG
171 if (!datetime) {
172 PERROR("Failed to allocate DATETIME string");
173 goto error;
174 }
175
28ab034a
JG
176 ret = time_to_datetime_str(
177 relay_session_creation_time, datetime, DATETIME_STR_LEN);
d2cb4a90
JG
178 if (ret) {
179 /* time_to_datetime_str already logs errors. */
180 goto error;
181 }
2a635488 182 }
d2cb4a90 183 } else if (len == DATETIME_STR_LEN &&
cd9adb8b 184 !regexec(&regex, leftover_second_token_ptr, 0, nullptr, 0)) {
2a635488
JR
185 /*
186 * The leftover from the second token is of format
187 * "-<datetime>", use it as the creation time.
188 * Ignore leading "-".
189 */
190 datetime = strdup(&leftover_second_token_ptr[1]);
191 if (!datetime) {
192 PERROR("Failed to parse session path: couldn't copy datetime on regex match");
193 goto error_regex;
194 }
195 } else {
196 /*
197 * Base path scenario.
198 * We cannot try to extract the datetime from the session name
199 * since nothing prevent a user to name a session in the
200 * "name-<datetime>" format. Using the datetime from such a
201 * session would be invalid.
202 * */
cd9adb8b
JG
203 LTTNG_ASSERT(partial_base_path == nullptr);
204 LTTNG_ASSERT(datetime == nullptr);
2a635488
JR
205
206 partial_base_path = strdup(second_token_ptr);
207 if (!partial_base_path) {
208 PERROR("Failed to parse session path: couldn't copy partial base path");
209 goto error_regex;
210 }
211 }
212
28ab034a
JG
213 ret = asprintf(&filepath_per_session,
214 "%s/%s%s%s/%s%s%s",
215 local_session_name,
216 hostname_ptr,
217 datetime ? "-" : "",
218 datetime ? datetime : "",
219 partial_base_path ? partial_base_path : "",
220 partial_base_path ? "/" : "",
221 leftover_ptr);
2a635488 222 if (ret < 0) {
cd9adb8b 223 filepath_per_session = nullptr;
2a635488
JR
224 goto error;
225 }
226error_regex:
227 regfree(&regex);
228error:
229 free(local_copy);
230 free(partial_base_path);
231 free(datetime);
232 return filepath_per_session;
233}
This page took 0.059832 seconds and 4 git commands to generate.