Backport: Relayd: introduce --group-output-by-session
[lttng-tools.git] / src / bin / lttng-relayd / utils.c
1 /*
2 * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
3 * David Goulet <dgoulet@efficios.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License, version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc., 51
16 * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17 */
18
19 #define _LGPL_SOURCE
20 #include <assert.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <regex.h>
25
26 #include <common/common.h>
27 #include <common/defaults.h>
28 #include <common/utils.h>
29
30 #include "lttng-relayd.h"
31 #include "utils.h"
32
33 #define DATETIME_STRING_SIZE 16
34
35 #define DATETIME_REGEX ".*-[0-9][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]$"
36
37 static char *get_filesystem_per_session(const char *path, const char *local_session_name) {
38 int ret;
39 char *local_copy = NULL;
40 char *session_name = NULL;
41 char *datetime = NULL;
42 char *extra_path = NULL;
43 char *hostname_ptr;
44 const char *second_token_ptr;
45 char *leftover_ptr;
46 char *filepath_per_session = NULL;
47 regex_t regex;
48
49 /* Get a local copy for strtok */
50 local_copy = strdup(path);
51 if (!local_copy) {
52 ERR("strdup of local copy failed");
53 goto error;
54 }
55
56 /*
57 * The use of strtok with '/' as delimiter is valid since we refuse '/'
58 * in session name and '/' is not a valid hostname character based on
59 * RFC-952 [1], RFC-921 [2] and refined in RFC-1123 [2].
60 * [1] https://tools.ietf.org/html/rfc952
61 * [2] https://tools.ietf.org/html/rfc921
62 * [3] https://tools.ietf.org/html/rfc1123#page-13
63 */
64
65 /*
66 * Get the hostname and possible session_name.
67 * Note that we can get the hostname and session name from the
68 * relay_session object we already have. Still, it is easier to
69 * tokenized the passed path to obtain the start of the path leftover.
70 */
71 hostname_ptr = strtok_r(local_copy, "/", &leftover_ptr);
72 if (!hostname_ptr) {
73 ERR("hostname token not found");
74 goto error;
75 }
76
77 second_token_ptr = strtok_r(NULL, "/", &leftover_ptr);
78 if (!second_token_ptr) {
79 ERR("Session name token not found");
80 goto error;
81 }
82
83 /*
84 * Check if the second token is a extra path set at url level. This is
85 * legal in streaming, live and snapshot [1]. Otherwise it is the
86 * session name with possibly a datetime attached [2]. Note that when
87 * "adding" snapshot output (lttng snapshot add-output), no session name
88 * is present in the path by default. The handling for "extra path" take
89 * care of this case as well.
90 * [1] e.g --set-url net://localhost/my_marvellous_path
91 * [2] Can be:
92 * <session_name>
93 * When using --snapshot on session create.
94 * <session_name>-<date>-<time>
95 * auto-<date>-<time>
96 */
97 if (strncmp(second_token_ptr, local_session_name, strlen(local_session_name)) != 0) {
98 /* Match */
99 extra_path = strdup(second_token_ptr);
100 /*
101 * Point the second token ptr to local_session_name for further
102 * information extraction based on the session name
103 */
104 second_token_ptr = local_session_name;
105 } else {
106 extra_path = strdup("");
107 }
108 if (!extra_path) {
109 ERR("strdup extra path failed");
110 goto error;
111 }
112
113 /*
114 * The recovery of the session datetime is a best effort here.
115 * We use a regex to validate that a datetime is present.
116 * We can end up in corner case were the end of a
117 * session name is the same format as our datetime but is not really a
118 * datetime. This is not so much of an issue since most of the time the
119 * datetime will be appended and result in the correct case.
120 * Possible cases:
121 * <session_name>
122 * <session_name>-<date>-<time>
123 * auto-<date>-<time>
124 */
125 ret = regcomp(&regex, DATETIME_REGEX, 0);
126 if (ret) {
127 ERR("Regex compilation failed with %d", ret);
128 goto error;
129 }
130
131 ret = regexec(&regex, second_token_ptr, 0, NULL, 0);
132 if (!ret) {
133 /* Match */
134 session_name = strndup(second_token_ptr, strlen(second_token_ptr) - DATETIME_STRING_SIZE);
135 datetime = strdup(&second_token_ptr[strlen(second_token_ptr) - DATETIME_STRING_SIZE +1]);
136 } else {
137 /* No datetime present */
138 session_name = strdup(second_token_ptr);
139 datetime = strdup("");
140 }
141
142 if (!session_name) {
143 ERR("strdup session_name on regex match failed");
144 goto error_regex;
145 }
146 if (!datetime) {
147 ERR("strdup datetime on regex match failed");
148 goto error_regex;
149 }
150
151 ret = asprintf(&filepath_per_session, "%s/%s%s%s/%s/%s", session_name,
152 hostname_ptr,
153 datetime[0] != '\0' ? "-" : "",
154 datetime, extra_path, leftover_ptr);
155 if (ret < 0) {
156 filepath_per_session = NULL;
157 goto error;
158 }
159 error_regex:
160 regfree(&regex);
161 error:
162 free(extra_path);
163 free(local_copy);
164 free(session_name);
165 free(datetime);
166 return filepath_per_session;
167 }
168
169 static char *create_output_path_auto(const char *path_name)
170 {
171 int ret;
172 char *traces_path = NULL;
173 char *alloc_path = NULL;
174 char *default_path;
175
176 default_path = utils_get_home_dir();
177 if (default_path == NULL) {
178 ERR("Home path not found.\n \
179 Please specify an output path using -o, --output PATH");
180 goto exit;
181 }
182 alloc_path = strdup(default_path);
183 if (alloc_path == NULL) {
184 PERROR("Path allocation");
185 goto exit;
186 }
187 ret = asprintf(&traces_path, "%s/" DEFAULT_TRACE_DIR_NAME
188 "/%s", alloc_path, path_name);
189 if (ret < 0) {
190 PERROR("asprintf trace dir name");
191 goto exit;
192 }
193 exit:
194 free(alloc_path);
195 return traces_path;
196 }
197
198 static char *create_output_path_noauto(char *path_name)
199 {
200 int ret;
201 char *traces_path = NULL;
202 char *full_path;
203
204 full_path = utils_expand_path(opt_output_path);
205 if (!full_path) {
206 goto exit;
207 }
208
209 ret = asprintf(&traces_path, "%s/%s", full_path, path_name);
210 if (ret < 0) {
211 PERROR("asprintf trace dir name");
212 goto exit;
213 }
214 exit:
215 free(full_path);
216 return traces_path;
217 }
218
219 /*
220 * Create the output trace directory path name string.
221 *
222 * Return the allocated string containing the path name or else NULL.
223 */
224 char *create_output_path(const char *path_name, char *session_name)
225 {
226 char *real_path = NULL;
227 char *return_path = NULL;
228 assert(path_name);
229
230 if (opt_group_output_by_session) {
231 real_path = get_filesystem_per_session(path_name, session_name);
232 } else if (opt_group_output_by_host) {
233 /* By default the output is by host */
234 real_path = strdup(path_name);
235 } else {
236 ERR("Configuration error");
237 assert(0);
238 }
239
240 if (!real_path) {
241 goto error;
242 }
243
244 if (opt_output_path == NULL) {
245 return_path = create_output_path_auto(real_path);
246 } else {
247 return_path = create_output_path_noauto(real_path);
248 }
249 error:
250 free(real_path);
251 return return_path;
252 }
This page took 0.035421 seconds and 5 git commands to generate.