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