docs: Add supported versions and fix-backport policy
[lttng-tools.git] / src / common / spawn-viewer.cpp
CommitLineData
dd392e94 1/*
21cf9b6b 2 * Copyright (C) 2011 EfficiOS Inc.
dd392e94
FD
3 * Copyright (C) 2014 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
4 * Copyright (C) 2020 Francis Deslauriers <francis.deslauriers@efficios.com>
5 *
c922647d 6 * SPDX-License-Identifier: LGPL-2.1-only
dd392e94
FD
7 *
8 */
9
28ab034a
JG
10#include "error.hpp"
11#include "macros.hpp"
12#include "spawn-viewer.hpp"
13
14#include <common/compat/errno.hpp>
15
16#include <lttng/constant.h>
17
dd392e94
FD
18#include <stdbool.h>
19#include <sys/stat.h>
20#include <sys/types.h>
21#include <unistd.h>
dd392e94 22
dd392e94
FD
23/*
24 * Type is also use as the index in the viewers array. So please, make sure
25 * your enum value is in the right order in the array below.
26 */
27enum viewer_type {
28ab034a
JG
28 VIEWER_BABELTRACE = 0,
29 VIEWER_BABELTRACE2 = 1,
30 VIEWER_USER_DEFINED = 2,
dd392e94
FD
31};
32
f1494934
JG
33namespace {
34const char *babeltrace_bin = CONFIG_BABELTRACE_BIN;
35const char *babeltrace2_bin = CONFIG_BABELTRACE2_BIN;
36
37/*
38 * This is needed for each viewer since we are using execvp().
39 */
40const char *babeltrace_opts[] = { "babeltrace" };
41const char *babeltrace2_opts[] = { "babeltrace2" };
42
43const struct viewer {
dd392e94
FD
44 const char *exec_name;
45 enum viewer_type type;
46} viewers[] = {
47 { "babeltrace", VIEWER_BABELTRACE },
48 { "babeltrace2", VIEWER_BABELTRACE2 },
cd9adb8b 49 { nullptr, VIEWER_USER_DEFINED },
dd392e94 50};
f1494934 51} /* namespace */
dd392e94
FD
52
53static const struct viewer *parse_viewer_option(const char *opt_viewer)
54{
cd9adb8b 55 if (opt_viewer == nullptr) {
dd392e94
FD
56 /* Default is babeltrace2 */
57 return &(viewers[VIEWER_BABELTRACE2]);
58 }
59
60 return &(viewers[VIEWER_USER_DEFINED]);
61}
62
63/*
64 * Alloc an array of string pointer from a simple string having all options
65 * seperated by spaces. Also adds the trace path to the arguments.
66 *
67 * The returning pointer is ready to be passed to execvp().
68 */
69static char **alloc_argv_from_user_opts(char *opts, const char *trace_path)
70{
71 int i = 0, ignore_space = 0;
72 unsigned int num_opts = 1;
cd9adb8b 73 char **argv, *token = opts, *saveptr = nullptr;
dd392e94
FD
74
75 /* Count number of arguments. */
76 do {
77 if (*token == ' ') {
78 /* Use to ignore consecutive spaces */
79 if (!ignore_space) {
80 num_opts++;
81 }
82 ignore_space = 1;
83 } else {
84 ignore_space = 0;
85 }
86 token++;
87 } while (*token != '\0');
88
89 /* Add two here for the NULL terminating element and trace path */
64803277 90 argv = calloc<char *>(num_opts + 2);
cd9adb8b 91 if (argv == nullptr) {
dd392e94
FD
92 goto error;
93 }
94
77368158 95 token = strtok_r(opts, " ", &saveptr);
cd9adb8b 96 while (token != nullptr) {
dd392e94 97 argv[i] = strdup(token);
cd9adb8b 98 if (argv[i] == nullptr) {
dd392e94
FD
99 goto error;
100 }
cd9adb8b 101 token = strtok_r(nullptr, " ", &saveptr);
dd392e94
FD
102 i++;
103 }
104
105 argv[num_opts] = (char *) trace_path;
cd9adb8b 106 argv[num_opts + 1] = nullptr;
dd392e94
FD
107
108 return argv;
109
110error:
111 if (argv) {
112 for (i = 0; i < num_opts + 2; i++) {
113 free(argv[i]);
114 }
115 free(argv);
116 }
117
cd9adb8b 118 return nullptr;
dd392e94
FD
119}
120
121/*
122 * Alloc an array of string pointer from an array of strings. It also adds
123 * the trace path to the argv.
124 *
125 * The returning pointer is ready to be passed to execvp().
126 */
28ab034a
JG
127static char **alloc_argv_from_local_opts(const char **opts,
128 size_t opts_len,
129 const char *trace_path,
130 bool opt_live_mode)
dd392e94
FD
131{
132 char **argv;
64803277 133 size_t mem_len;
dd392e94
FD
134
135 /* Add one for the NULL terminating element. */
136 mem_len = opts_len + 1;
137 if (opt_live_mode) {
138 /* Add 3 option for the live mode being "-i lttng-live URL". */
139 mem_len += 3;
140 } else {
141 /* Add option for the trace path. */
142 mem_len += 1;
143 }
144
64803277 145 argv = calloc<char *>(mem_len);
cd9adb8b 146 if (argv == nullptr) {
dd392e94
FD
147 goto error;
148 }
149
150 memcpy(argv, opts, sizeof(char *) * opts_len);
151
152 if (opt_live_mode) {
153 argv[opts_len] = (char *) "-i";
154 argv[opts_len + 1] = (char *) "lttng-live";
155 argv[opts_len + 2] = (char *) trace_path;
cd9adb8b 156 argv[opts_len + 3] = nullptr;
dd392e94
FD
157 } else {
158 argv[opts_len] = (char *) trace_path;
cd9adb8b 159 argv[opts_len + 1] = nullptr;
dd392e94
FD
160 }
161
162error:
163 return argv;
164}
165
dd392e94
FD
166/*
167 * Spawn viewer with the trace directory path.
168 */
169int spawn_viewer(const char *trace_path, char *opt_viewer, bool opt_live_mode)
170{
171 int ret = 0;
172 struct stat status;
cd9adb8b 173 const char *viewer_bin = nullptr;
dd392e94 174 const struct viewer *viewer;
cd9adb8b 175 char **argv = nullptr;
dd392e94
FD
176
177 /* Check for --viewer option. */
178 viewer = parse_viewer_option(opt_viewer);
cd9adb8b 179 if (viewer == nullptr) {
dd392e94
FD
180 ret = -1;
181 goto error;
182 }
183
184retry_viewer:
185 switch (viewer->type) {
186 case VIEWER_BABELTRACE2:
187 if (stat(babeltrace2_bin, &status) == 0) {
188 viewer_bin = babeltrace2_bin;
189 } else {
190 viewer_bin = viewer->exec_name;
191 }
28ab034a
JG
192 argv = alloc_argv_from_local_opts(
193 babeltrace2_opts, ARRAY_SIZE(babeltrace2_opts), trace_path, opt_live_mode);
dd392e94
FD
194 break;
195 case VIEWER_BABELTRACE:
196 if (stat(babeltrace_bin, &status) == 0) {
197 viewer_bin = babeltrace_bin;
198 } else {
199 viewer_bin = viewer->exec_name;
200 }
28ab034a
JG
201 argv = alloc_argv_from_local_opts(
202 babeltrace_opts, ARRAY_SIZE(babeltrace_opts), trace_path, opt_live_mode);
dd392e94
FD
203 break;
204 case VIEWER_USER_DEFINED:
205 argv = alloc_argv_from_user_opts(opt_viewer, trace_path);
206 if (argv) {
207 viewer_bin = argv[0];
208 }
209 break;
210 default:
211 abort();
212 }
213
cd9adb8b 214 if (argv == nullptr || !viewer_bin) {
dd392e94
FD
215 ret = -1;
216 goto error;
217 }
218
219 DBG("Using %s viewer", viewer_bin);
220
221 ret = execvp(viewer_bin, argv);
222 if (ret) {
223 if (errno == ENOENT && viewer->exec_name) {
224 if (viewer->type == VIEWER_BABELTRACE2) {
225 /* Fallback to legacy babeltrace. */
226 DBG("Default viewer \"%s\" not installed on the system, falling back to \"%s\"",
28ab034a
JG
227 viewers[VIEWER_BABELTRACE2].exec_name,
228 viewers[VIEWER_BABELTRACE].exec_name);
dd392e94
FD
229 viewer = &viewers[VIEWER_BABELTRACE];
230 free(argv);
cd9adb8b 231 argv = nullptr;
dd392e94
FD
232 goto retry_viewer;
233 } else {
234 ERR("Default viewer \"%s\" (and fallback \"%s\") not found on the system",
28ab034a
JG
235 viewers[VIEWER_BABELTRACE2].exec_name,
236 viewers[VIEWER_BABELTRACE].exec_name);
dd392e94
FD
237 }
238 } else {
239 PERROR("Failed to launch \"%s\" viewer", viewer_bin);
240 }
241 ret = -1;
242 goto error;
243 }
244
245 /*
246 * This function should never return if successfull because `execvp(3)`
247 * onle returns if an error has occurred.
248 */
a0377dfe 249 LTTNG_ASSERT(ret != 0);
dd392e94
FD
250error:
251 free(argv);
252 return ret;
253}
This page took 0.066172 seconds and 4 git commands to generate.