2 * Copyright (C) 2013 - Julien Desfossez <jdesfossez@efficios.com>
3 * David Goulet <dgoulet@efficios.com>
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.
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
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.
26 #include <common/common.h>
27 #include <common/defaults.h>
28 #include <common/utils.h>
30 #include "lttng-relayd.h"
33 #define DATETIME_STRING_SIZE 16
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]$"
37 static char *get_filesystem_per_session(const char *path
, const char *local_session_name
) {
39 char *local_copy
= NULL
;
40 char *session_name
= NULL
;
41 char *datetime
= NULL
;
42 char *extra_path
= NULL
;
44 const char *second_token_ptr
;
46 char *filepath_per_session
= NULL
;
49 /* Get a local copy for strtok */
50 local_copy
= strdup(path
);
52 ERR("strdup of local copy failed");
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
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.
71 hostname_ptr
= strtok_r(local_copy
, "/", &leftover_ptr
);
73 ERR("hostname token not found");
77 second_token_ptr
= strtok_r(NULL
, "/", &leftover_ptr
);
78 if (!second_token_ptr
) {
79 ERR("Session name token not found");
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
93 * When using --snapshot on session create.
94 * <session_name>-<date>-<time>
97 if (strncmp(second_token_ptr
, local_session_name
, strlen(local_session_name
)) != 0) {
99 extra_path
= strdup(second_token_ptr
);
101 * Point the second token ptr to local_session_name for further
102 * information extraction based on the session name
104 second_token_ptr
= local_session_name
;
106 extra_path
= strdup("");
109 ERR("strdup extra path failed");
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.
122 * <session_name>-<date>-<time>
125 ret
= regcomp(®ex
, DATETIME_REGEX
, 0);
127 ERR("Regex compilation failed with %d", ret
);
131 ret
= regexec(®ex
, second_token_ptr
, 0, NULL
, 0);
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]);
137 /* No datetime present */
138 session_name
= strdup(second_token_ptr
);
139 datetime
= strdup("");
143 ERR("strdup session_name on regex match failed");
147 ERR("strdup datetime on regex match failed");
151 ret
= asprintf(&filepath_per_session
, "%s/%s%s%s/%s/%s", session_name
,
153 datetime
[0] != '\0' ? "-" : "",
154 datetime
, extra_path
, leftover_ptr
);
156 filepath_per_session
= NULL
;
166 return filepath_per_session
;
169 static char *create_output_path_auto(const char *path_name
)
172 char *traces_path
= NULL
;
173 char *alloc_path
= NULL
;
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");
182 alloc_path
= strdup(default_path
);
183 if (alloc_path
== NULL
) {
184 PERROR("Path allocation");
187 ret
= asprintf(&traces_path
, "%s/" DEFAULT_TRACE_DIR_NAME
188 "/%s", alloc_path
, path_name
);
190 PERROR("asprintf trace dir name");
198 static char *create_output_path_noauto(char *path_name
)
201 char *traces_path
= NULL
;
204 full_path
= utils_expand_path(opt_output_path
);
209 ret
= asprintf(&traces_path
, "%s/%s", full_path
, path_name
);
211 PERROR("asprintf trace dir name");
220 * Create the output trace directory path name string.
222 * Return the allocated string containing the path name or else NULL.
224 char *create_output_path(const char *path_name
, char *session_name
)
226 char *real_path
= NULL
;
227 char *return_path
= NULL
;
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
);
236 ERR("Configuration error");
244 if (opt_output_path
== NULL
) {
245 return_path
= create_output_path_auto(real_path
);
247 return_path
= create_output_path_noauto(real_path
);