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