Fix: liblttng-ctl: non-packed structure used for tracker serialization
[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
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
c9e313bc
SM
17#include <common/compat/errno.hpp>
18#include "error.hpp"
19#include "macros.hpp"
20#include "spawn-viewer.hpp"
dd392e94
FD
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 */
64803277 88 argv = calloc<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;
64803277 129 size_t mem_len;
dd392e94
FD
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
64803277 141 argv = calloc<char *>(mem_len);
dd392e94
FD
142 if (argv == NULL) {
143 goto error;
144 }
145
146 memcpy(argv, opts, sizeof(char *) * opts_len);
147
148 if (opt_live_mode) {
149 argv[opts_len] = (char *) "-i";
150 argv[opts_len + 1] = (char *) "lttng-live";
151 argv[opts_len + 2] = (char *) trace_path;
152 argv[opts_len + 3] = NULL;
153 } else {
154 argv[opts_len] = (char *) trace_path;
155 argv[opts_len + 1] = NULL;
156 }
157
158error:
159 return argv;
160}
161
162
163/*
164 * Spawn viewer with the trace directory path.
165 */
166int spawn_viewer(const char *trace_path, char *opt_viewer, bool opt_live_mode)
167{
168 int ret = 0;
169 struct stat status;
170 const char *viewer_bin = NULL;
171 const struct viewer *viewer;
172 char **argv = NULL;
173
174 /* Check for --viewer option. */
175 viewer = parse_viewer_option(opt_viewer);
176 if (viewer == NULL) {
177 ret = -1;
178 goto error;
179 }
180
181retry_viewer:
182 switch (viewer->type) {
183 case VIEWER_BABELTRACE2:
184 if (stat(babeltrace2_bin, &status) == 0) {
185 viewer_bin = babeltrace2_bin;
186 } else {
187 viewer_bin = viewer->exec_name;
188 }
189 argv = alloc_argv_from_local_opts(babeltrace2_opts,
190 ARRAY_SIZE(babeltrace2_opts), trace_path,
191 opt_live_mode);
192 break;
193 case VIEWER_BABELTRACE:
194 if (stat(babeltrace_bin, &status) == 0) {
195 viewer_bin = babeltrace_bin;
196 } else {
197 viewer_bin = viewer->exec_name;
198 }
199 argv = alloc_argv_from_local_opts(babeltrace_opts,
200 ARRAY_SIZE(babeltrace_opts), trace_path,
201 opt_live_mode);
202 break;
203 case VIEWER_USER_DEFINED:
204 argv = alloc_argv_from_user_opts(opt_viewer, trace_path);
205 if (argv) {
206 viewer_bin = argv[0];
207 }
208 break;
209 default:
210 abort();
211 }
212
213 if (argv == NULL || !viewer_bin) {
214 ret = -1;
215 goto error;
216 }
217
218 DBG("Using %s viewer", viewer_bin);
219
220 ret = execvp(viewer_bin, argv);
221 if (ret) {
222 if (errno == ENOENT && viewer->exec_name) {
223 if (viewer->type == VIEWER_BABELTRACE2) {
224 /* Fallback to legacy babeltrace. */
225 DBG("Default viewer \"%s\" not installed on the system, falling back to \"%s\"",
226 viewers[VIEWER_BABELTRACE2].exec_name,
227 viewers[VIEWER_BABELTRACE].exec_name);
228 viewer = &viewers[VIEWER_BABELTRACE];
229 free(argv);
230 argv = NULL;
231 goto retry_viewer;
232 } else {
233 ERR("Default viewer \"%s\" (and fallback \"%s\") not found on the system",
234 viewers[VIEWER_BABELTRACE2].exec_name,
235 viewers[VIEWER_BABELTRACE].exec_name);
236 }
237 } else {
238 PERROR("Failed to launch \"%s\" viewer", viewer_bin);
239 }
240 ret = -1;
241 goto error;
242 }
243
244 /*
245 * This function should never return if successfull because `execvp(3)`
246 * onle returns if an error has occurred.
247 */
a0377dfe 248 LTTNG_ASSERT(ret != 0);
dd392e94
FD
249error:
250 free(argv);
251 return ret;
252}
This page took 0.047001 seconds and 4 git commands to generate.