Commit | Line | Data |
---|---|---|
ebba3338 PP |
1 | /* |
2 | * Copyright 2017 Philippe Proulx <pproulx@efficios.com> | |
3 | * | |
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
5 | * of this software and associated documentation files (the "Software"), to deal | |
6 | * in the Software without restriction, including without limitation the rights | |
7 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
8 | * copies of the Software, and to permit persons to whom the Software is | |
9 | * furnished to do so, subject to the following conditions: | |
10 | * | |
11 | * The above copyright notice and this permission notice shall be included in | |
12 | * all copies or substantial portions of the Software. | |
13 | * | |
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
19 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
20 | * SOFTWARE. | |
21 | */ | |
22 | ||
23 | #include <babeltrace/values.h> | |
db0f160a | 24 | #include <babeltrace/common-internal.h> |
ebba3338 PP |
25 | #include "babeltrace-cfg.h" |
26 | #include "babeltrace-cfg-connect.h" | |
27 | ||
db0f160a | 28 | static bool all_named_and_printable_in_array(GPtrArray *comps) |
ebba3338 PP |
29 | { |
30 | size_t i; | |
db0f160a | 31 | bool all_named_and_printable = true; |
ebba3338 PP |
32 | |
33 | for (i = 0; i < comps->len; i++) { | |
34 | struct bt_config_component *comp = g_ptr_array_index(comps, i); | |
35 | ||
36 | if (comp->instance_name->len == 0) { | |
db0f160a PP |
37 | all_named_and_printable = false; |
38 | goto end; | |
39 | } | |
40 | ||
41 | if (!bt_common_string_is_printable(comp->instance_name->str)) { | |
42 | all_named_and_printable = false; | |
ebba3338 PP |
43 | goto end; |
44 | } | |
45 | } | |
46 | ||
47 | end: | |
db0f160a | 48 | return all_named_and_printable; |
ebba3338 PP |
49 | } |
50 | ||
db0f160a | 51 | static bool all_named_and_printable(struct bt_config *cfg) |
ebba3338 | 52 | { |
db0f160a PP |
53 | return all_named_and_printable_in_array(cfg->cmd_data.run.sources) && |
54 | all_named_and_printable_in_array(cfg->cmd_data.run.filters) && | |
55 | all_named_and_printable_in_array(cfg->cmd_data.run.sinks); | |
ebba3338 PP |
56 | } |
57 | ||
58 | void bt_config_connection_destroy(struct bt_config_connection *connection) | |
59 | { | |
60 | if (!connection) { | |
61 | return; | |
62 | } | |
63 | ||
64 | if (connection->src_instance_name) { | |
65 | g_string_free(connection->src_instance_name, TRUE); | |
66 | } | |
67 | ||
68 | if (connection->dst_instance_name) { | |
69 | g_string_free(connection->dst_instance_name, TRUE); | |
70 | } | |
71 | ||
72 | if (connection->src_port_name) { | |
73 | g_string_free(connection->src_port_name, TRUE); | |
74 | } | |
75 | ||
76 | if (connection->dst_port_name) { | |
77 | g_string_free(connection->dst_port_name, TRUE); | |
78 | } | |
79 | ||
80 | if (connection->arg) { | |
81 | g_string_free(connection->arg, TRUE); | |
82 | } | |
83 | ||
84 | g_free(connection); | |
85 | } | |
86 | ||
87 | static struct bt_config_connection *bt_config_connection_create(const char *arg) | |
88 | { | |
89 | struct bt_config_connection *cfg_connection; | |
90 | ||
91 | cfg_connection = g_new0(struct bt_config_connection, 1); | |
92 | if (!cfg_connection) { | |
93 | goto error; | |
94 | } | |
95 | ||
96 | cfg_connection->src_instance_name = g_string_new(NULL); | |
97 | if (!cfg_connection->src_instance_name) { | |
98 | goto error; | |
99 | } | |
100 | ||
101 | cfg_connection->dst_instance_name = g_string_new(NULL); | |
102 | if (!cfg_connection->dst_instance_name) { | |
103 | goto error; | |
104 | } | |
105 | ||
106 | cfg_connection->src_port_name = g_string_new(NULL); | |
107 | if (!cfg_connection->src_port_name) { | |
108 | goto error; | |
109 | } | |
110 | ||
111 | cfg_connection->dst_port_name = g_string_new(NULL); | |
112 | if (!cfg_connection->dst_port_name) { | |
113 | goto error; | |
114 | } | |
115 | ||
116 | cfg_connection->arg = g_string_new(arg); | |
117 | if (!cfg_connection->arg) { | |
118 | goto error; | |
119 | } | |
120 | ||
121 | goto end; | |
122 | ||
123 | error: | |
124 | g_free(cfg_connection); | |
125 | cfg_connection = NULL; | |
126 | ||
127 | end: | |
128 | return cfg_connection; | |
129 | } | |
130 | ||
ebba3338 PP |
131 | static struct bt_config_connection *cfg_connection_from_arg(const char *arg) |
132 | { | |
db0f160a PP |
133 | const char *at = arg; |
134 | size_t end_pos; | |
135 | struct bt_config_connection *cfg_conn = NULL; | |
136 | GString *gs = NULL; | |
ebba3338 | 137 | enum { |
db0f160a PP |
138 | SRC_NAME, |
139 | DST_NAME, | |
140 | SRC_PORT_NAME, | |
141 | DST_PORT_NAME, | |
142 | } state = SRC_NAME; | |
143 | ||
144 | if (!bt_common_string_is_printable(arg)) { | |
ebba3338 PP |
145 | goto error; |
146 | } | |
147 | ||
db0f160a PP |
148 | cfg_conn = bt_config_connection_create(arg); |
149 | if (!cfg_conn) { | |
ebba3338 PP |
150 | goto error; |
151 | } | |
152 | ||
ebba3338 | 153 | while (true) { |
ebba3338 | 154 | switch (state) { |
db0f160a PP |
155 | case SRC_NAME: |
156 | gs = bt_common_string_until(at, ".:\\", ".:", &end_pos); | |
157 | if (!gs || gs->len == 0) { | |
ebba3338 PP |
158 | goto error; |
159 | } | |
160 | ||
db0f160a PP |
161 | g_string_free(cfg_conn->src_instance_name, TRUE); |
162 | cfg_conn->src_instance_name = gs; | |
163 | gs = NULL; | |
ebba3338 | 164 | |
db0f160a PP |
165 | if (at[end_pos] == ':') { |
166 | state = DST_NAME; | |
167 | } else if (at[end_pos] == '.') { | |
168 | state = SRC_PORT_NAME; | |
169 | } else { | |
ebba3338 PP |
170 | goto error; |
171 | } | |
172 | ||
db0f160a | 173 | at += end_pos + 1; |
ebba3338 | 174 | break; |
db0f160a PP |
175 | case DST_NAME: |
176 | gs = bt_common_string_until(at, ".:\\", ".:", &end_pos); | |
177 | if (!gs || gs->len == 0) { | |
ebba3338 PP |
178 | goto error; |
179 | } | |
180 | ||
db0f160a PP |
181 | g_string_free(cfg_conn->dst_instance_name, TRUE); |
182 | cfg_conn->dst_instance_name = gs; | |
183 | gs = NULL; | |
184 | ||
185 | if (at[end_pos] == '.') { | |
186 | state = DST_PORT_NAME; | |
187 | } else if (at[end_pos] == '\0') { | |
188 | goto end; | |
189 | } else { | |
ebba3338 PP |
190 | goto error; |
191 | } | |
192 | ||
db0f160a | 193 | at += end_pos + 1; |
ebba3338 | 194 | break; |
db0f160a PP |
195 | case SRC_PORT_NAME: |
196 | gs = bt_common_string_until(at, ".:\\", ".:", &end_pos); | |
197 | if (!gs || gs->len == 0) { | |
ebba3338 PP |
198 | goto error; |
199 | } | |
200 | ||
db0f160a PP |
201 | g_string_free(cfg_conn->src_port_name, TRUE); |
202 | cfg_conn->src_port_name = gs; | |
203 | gs = NULL; | |
204 | ||
205 | if (at[end_pos] == ':') { | |
206 | state = DST_NAME; | |
207 | } else { | |
ebba3338 PP |
208 | goto error; |
209 | } | |
210 | ||
db0f160a | 211 | at += end_pos + 1; |
ebba3338 | 212 | break; |
db0f160a PP |
213 | case DST_PORT_NAME: |
214 | gs = bt_common_string_until(at, ".:\\", ".:", &end_pos); | |
215 | if (!gs || gs->len == 0) { | |
ebba3338 PP |
216 | goto error; |
217 | } | |
218 | ||
db0f160a PP |
219 | g_string_free(cfg_conn->dst_port_name, TRUE); |
220 | cfg_conn->dst_port_name = gs; | |
221 | gs = NULL; | |
222 | ||
223 | if (at[end_pos] == '\0') { | |
224 | goto end; | |
225 | } else { | |
226 | goto error; | |
227 | } | |
ebba3338 PP |
228 | break; |
229 | default: | |
db0f160a | 230 | assert(false); |
ebba3338 PP |
231 | } |
232 | } | |
233 | ||
ebba3338 | 234 | error: |
db0f160a PP |
235 | bt_config_connection_destroy(cfg_conn); |
236 | cfg_conn = NULL; | |
ebba3338 PP |
237 | |
238 | end: | |
db0f160a PP |
239 | if (gs) { |
240 | g_string_free(gs, TRUE); | |
ebba3338 PP |
241 | } |
242 | ||
db0f160a | 243 | return cfg_conn; |
ebba3338 PP |
244 | } |
245 | ||
246 | static struct bt_config_component *find_component_in_array(GPtrArray *comps, | |
247 | const char *name) | |
248 | { | |
249 | size_t i; | |
250 | struct bt_config_component *found_comp = NULL; | |
251 | ||
252 | for (i = 0; i < comps->len; i++) { | |
253 | struct bt_config_component *comp = g_ptr_array_index(comps, i); | |
254 | ||
255 | if (strcmp(name, comp->instance_name->str) == 0) { | |
256 | found_comp = bt_get(comp); | |
257 | goto end; | |
258 | } | |
259 | } | |
260 | ||
261 | end: | |
262 | return found_comp; | |
263 | } | |
264 | ||
265 | static struct bt_config_component *find_component(struct bt_config *cfg, | |
90de159b | 266 | const char *name) |
ebba3338 PP |
267 | { |
268 | struct bt_config_component *comp; | |
269 | ||
db0f160a | 270 | comp = find_component_in_array(cfg->cmd_data.run.sources, name); |
ebba3338 | 271 | if (comp) { |
ebba3338 PP |
272 | goto end; |
273 | } | |
274 | ||
db0f160a | 275 | comp = find_component_in_array(cfg->cmd_data.run.filters, name); |
ebba3338 | 276 | if (comp) { |
ebba3338 PP |
277 | goto end; |
278 | } | |
279 | ||
db0f160a | 280 | comp = find_component_in_array(cfg->cmd_data.run.sinks, name); |
ebba3338 | 281 | if (comp) { |
ebba3338 PP |
282 | goto end; |
283 | } | |
284 | ||
285 | end: | |
286 | return comp; | |
287 | } | |
288 | ||
289 | static int validate_all_endpoints_exist(struct bt_config *cfg, char *error_buf, | |
290 | size_t error_buf_size) | |
291 | { | |
292 | size_t i; | |
293 | int ret = 0; | |
294 | ||
db0f160a | 295 | for (i = 0; i < cfg->cmd_data.run.connections->len; i++) { |
ebba3338 | 296 | struct bt_config_connection *connection = |
db0f160a | 297 | g_ptr_array_index(cfg->cmd_data.run.connections, i); |
ebba3338 | 298 | struct bt_config_component *comp; |
ebba3338 | 299 | |
90de159b | 300 | comp = find_component(cfg, connection->src_instance_name->str); |
ebba3338 PP |
301 | bt_put(comp); |
302 | if (!comp) { | |
db0f160a PP |
303 | snprintf(error_buf, error_buf_size, |
304 | "Invalid connection: cannot find upstream component `%s`:\n %s\n", | |
305 | connection->src_instance_name->str, | |
306 | connection->arg->str); | |
307 | ret = -1; | |
308 | goto end; | |
309 | } | |
310 | ||
311 | comp = find_component(cfg, connection->dst_instance_name->str); | |
312 | bt_put(comp); | |
313 | if (!comp) { | |
314 | snprintf(error_buf, error_buf_size, | |
315 | "Invalid connection: cannot find downstream component `%s`:\n %s\n", | |
316 | connection->dst_instance_name->str, | |
317 | connection->arg->str); | |
318 | ret = -1; | |
319 | goto end; | |
ebba3338 PP |
320 | } |
321 | } | |
322 | ||
323 | end: | |
324 | return ret; | |
325 | } | |
326 | ||
327 | static int validate_connection_directions(struct bt_config *cfg, | |
328 | char *error_buf, size_t error_buf_size) | |
329 | { | |
330 | size_t i; | |
331 | int ret = 0; | |
332 | struct bt_config_component *src_comp = NULL; | |
333 | struct bt_config_component *dst_comp = NULL; | |
334 | ||
db0f160a | 335 | for (i = 0; i < cfg->cmd_data.run.connections->len; i++) { |
ebba3338 | 336 | struct bt_config_connection *connection = |
db0f160a | 337 | g_ptr_array_index(cfg->cmd_data.run.connections, i); |
ebba3338 PP |
338 | |
339 | src_comp = find_component(cfg, | |
90de159b | 340 | connection->src_instance_name->str); |
ebba3338 PP |
341 | assert(src_comp); |
342 | dst_comp = find_component(cfg, | |
90de159b | 343 | connection->dst_instance_name->str); |
ebba3338 PP |
344 | assert(dst_comp); |
345 | ||
90de159b PP |
346 | if (src_comp->type == BT_COMPONENT_CLASS_TYPE_SOURCE) { |
347 | if (dst_comp->type != BT_COMPONENT_CLASS_TYPE_FILTER && | |
348 | dst_comp->type != BT_COMPONENT_CLASS_TYPE_SINK) { | |
ebba3338 PP |
349 | snprintf(error_buf, error_buf_size, |
350 | "Invalid connection: source component `%s` not connected to filter or sink component:\n %s\n", | |
351 | connection->src_instance_name->str, | |
352 | connection->arg->str); | |
353 | ret = -1; | |
354 | goto end; | |
355 | } | |
90de159b PP |
356 | } else if (src_comp->type == BT_COMPONENT_CLASS_TYPE_FILTER) { |
357 | if (dst_comp->type != BT_COMPONENT_CLASS_TYPE_FILTER && | |
358 | dst_comp->type != BT_COMPONENT_CLASS_TYPE_SINK) { | |
ebba3338 PP |
359 | snprintf(error_buf, error_buf_size, |
360 | "Invalid connection: filter component `%s` not connected to filter or sink component:\n %s\n", | |
361 | connection->src_instance_name->str, | |
362 | connection->arg->str); | |
363 | ret = -1; | |
364 | goto end; | |
365 | } | |
366 | } else { | |
367 | snprintf(error_buf, error_buf_size, | |
368 | "Invalid connection: cannot connect sink component `%s` to component `%s`:\n %s\n", | |
369 | connection->src_instance_name->str, | |
370 | connection->dst_instance_name->str, | |
371 | connection->arg->str); | |
372 | ret = -1; | |
373 | goto end; | |
374 | } | |
375 | ||
376 | BT_PUT(src_comp); | |
377 | BT_PUT(dst_comp); | |
378 | } | |
379 | ||
380 | end: | |
381 | bt_put(src_comp); | |
382 | bt_put(dst_comp); | |
383 | return ret; | |
384 | } | |
385 | ||
db0f160a PP |
386 | static int validate_no_cycles_rec(struct bt_config *cfg, GPtrArray *path, |
387 | char *error_buf, size_t error_buf_size) | |
388 | { | |
389 | int ret = 0; | |
390 | size_t conn_i; | |
391 | const char *src_comp_name; | |
392 | ||
393 | assert(path && path->len > 0); | |
394 | src_comp_name = g_ptr_array_index(path, path->len - 1); | |
395 | ||
396 | for (conn_i = 0; conn_i < cfg->cmd_data.run.connections->len; conn_i++) { | |
397 | struct bt_config_connection *conn = | |
398 | g_ptr_array_index(cfg->cmd_data.run.connections, conn_i); | |
399 | ||
400 | if (strcmp(conn->src_instance_name->str, src_comp_name) == 0) { | |
401 | size_t path_i; | |
402 | ||
403 | for (path_i = 0; path_i < path->len; path_i++) { | |
404 | const char *comp_name = | |
405 | g_ptr_array_index(path, path_i); | |
406 | ||
407 | if (strcmp(comp_name, conn->dst_instance_name->str) == 0) { | |
408 | snprintf(error_buf, error_buf_size, | |
409 | "Invalid connection: connection forms a cycle:\n %s\n", | |
410 | conn->arg->str); | |
411 | ret = -1; | |
412 | goto end; | |
413 | } | |
414 | } | |
415 | ||
416 | g_ptr_array_add(path, conn->dst_instance_name->str); | |
417 | ret = validate_no_cycles_rec(cfg, path, error_buf, | |
418 | error_buf_size); | |
419 | if (ret) { | |
420 | goto end; | |
421 | } | |
422 | ||
423 | g_ptr_array_remove_index(path, path->len - 1); | |
424 | } | |
425 | } | |
426 | ||
427 | end: | |
428 | return ret; | |
429 | } | |
430 | ||
431 | static int validate_no_cycles(struct bt_config *cfg, char *error_buf, | |
ebba3338 PP |
432 | size_t error_buf_size) |
433 | { | |
434 | size_t i; | |
435 | int ret = 0; | |
db0f160a | 436 | GPtrArray *path; |
ebba3338 | 437 | |
db0f160a PP |
438 | path = g_ptr_array_new(); |
439 | if (!path) { | |
440 | ret = -1; | |
441 | goto end; | |
442 | } | |
ebba3338 | 443 | |
db0f160a PP |
444 | g_ptr_array_add(path, NULL); |
445 | ||
446 | for (i = 0; i < cfg->cmd_data.run.connections->len; i++) { | |
447 | struct bt_config_connection *conn = | |
448 | g_ptr_array_index(cfg->cmd_data.run.connections, i); | |
449 | ||
450 | g_ptr_array_index(path, 0) = conn->src_instance_name->str; | |
451 | ret = validate_no_cycles_rec(cfg, path, | |
452 | error_buf, error_buf_size); | |
453 | if (ret) { | |
ebba3338 PP |
454 | goto end; |
455 | } | |
456 | } | |
457 | ||
458 | end: | |
db0f160a PP |
459 | if (path) { |
460 | g_ptr_array_free(path, TRUE); | |
461 | } | |
462 | ||
ebba3338 PP |
463 | return ret; |
464 | } | |
465 | ||
466 | static int validate_all_components_connected_in_array(GPtrArray *comps, | |
467 | struct bt_value *connected_components, | |
468 | char *error_buf, size_t error_buf_size) | |
469 | { | |
470 | int ret = 0; | |
471 | size_t i; | |
472 | ||
473 | for (i = 0; i < comps->len; i++) { | |
474 | struct bt_config_component *comp = g_ptr_array_index(comps, i); | |
475 | ||
476 | if (!bt_value_map_has_key(connected_components, | |
477 | comp->instance_name->str)) { | |
478 | snprintf(error_buf, error_buf_size, | |
479 | "Component `%s` is not connected\n", | |
480 | comp->instance_name->str); | |
481 | ret = -1; | |
482 | goto end; | |
483 | } | |
484 | } | |
485 | ||
486 | end: | |
487 | return ret; | |
488 | } | |
489 | ||
490 | static int validate_all_components_connected(struct bt_config *cfg, | |
491 | char *error_buf, size_t error_buf_size) | |
492 | { | |
493 | size_t i; | |
494 | int ret = 0; | |
495 | struct bt_value *connected_components = bt_value_map_create(); | |
496 | ||
497 | if (!connected_components) { | |
498 | ret = -1; | |
499 | goto end; | |
500 | } | |
501 | ||
db0f160a | 502 | for (i = 0; i < cfg->cmd_data.run.connections->len; i++) { |
ebba3338 | 503 | struct bt_config_connection *connection = |
db0f160a | 504 | g_ptr_array_index(cfg->cmd_data.run.connections, i); |
ebba3338 PP |
505 | |
506 | ret = bt_value_map_insert(connected_components, | |
507 | connection->src_instance_name->str, bt_value_null); | |
508 | if (ret) { | |
509 | goto end; | |
510 | } | |
511 | ||
512 | ret = bt_value_map_insert(connected_components, | |
513 | connection->dst_instance_name->str, bt_value_null); | |
514 | if (ret) { | |
515 | goto end; | |
516 | } | |
517 | } | |
518 | ||
519 | ret = validate_all_components_connected_in_array( | |
db0f160a | 520 | cfg->cmd_data.run.sources, connected_components, |
ebba3338 PP |
521 | error_buf, error_buf_size); |
522 | if (ret) { | |
523 | goto end; | |
524 | } | |
525 | ||
526 | ret = validate_all_components_connected_in_array( | |
db0f160a | 527 | cfg->cmd_data.run.filters, connected_components, |
ebba3338 PP |
528 | error_buf, error_buf_size); |
529 | if (ret) { | |
530 | goto end; | |
531 | } | |
532 | ||
533 | ret = validate_all_components_connected_in_array( | |
db0f160a | 534 | cfg->cmd_data.run.sinks, connected_components, |
ebba3338 PP |
535 | error_buf, error_buf_size); |
536 | if (ret) { | |
537 | goto end; | |
538 | } | |
539 | ||
540 | end: | |
541 | bt_put(connected_components); | |
542 | return ret; | |
543 | } | |
544 | ||
545 | static int validate_no_duplicate_connection(struct bt_config *cfg, | |
546 | char *error_buf, size_t error_buf_size) | |
547 | { | |
548 | size_t i; | |
549 | int ret = 0; | |
550 | struct bt_value *flat_connection_names = bt_value_map_create(); | |
551 | GString *flat_connection_name = NULL; | |
552 | ||
553 | if (!flat_connection_names) { | |
554 | ret = -1; | |
555 | goto end; | |
556 | } | |
557 | ||
558 | flat_connection_name = g_string_new(NULL); | |
559 | if (!flat_connection_name) { | |
560 | ret = -1; | |
561 | goto end; | |
562 | } | |
563 | ||
db0f160a | 564 | for (i = 0; i < cfg->cmd_data.run.connections->len; i++) { |
ebba3338 | 565 | struct bt_config_connection *connection = |
db0f160a | 566 | g_ptr_array_index(cfg->cmd_data.run.connections, i); |
ebba3338 | 567 | |
db0f160a | 568 | g_string_printf(flat_connection_name, "%s\x01%s\x01%s\x01%s", |
ebba3338 PP |
569 | connection->src_instance_name->str, |
570 | connection->src_port_name->str, | |
571 | connection->dst_instance_name->str, | |
572 | connection->dst_port_name->str); | |
573 | ||
574 | if (bt_value_map_has_key(flat_connection_names, | |
575 | flat_connection_name->str)) { | |
576 | snprintf(error_buf, error_buf_size, | |
577 | "Duplicate connection:\n %s\n", | |
578 | connection->arg->str); | |
579 | ret = -1; | |
580 | goto end; | |
581 | } | |
582 | ||
583 | ret = bt_value_map_insert(flat_connection_names, | |
584 | flat_connection_name->str, bt_value_null); | |
585 | if (ret) { | |
586 | goto end; | |
587 | } | |
588 | } | |
589 | ||
590 | end: | |
591 | bt_put(flat_connection_names); | |
592 | ||
593 | if (flat_connection_name) { | |
594 | g_string_free(flat_connection_name, TRUE); | |
595 | } | |
596 | ||
597 | return ret; | |
598 | } | |
599 | ||
600 | static int validate_connections(struct bt_config *cfg, char *error_buf, | |
601 | size_t error_buf_size) | |
602 | { | |
603 | int ret; | |
604 | ||
605 | ret = validate_all_endpoints_exist(cfg, error_buf, error_buf_size); | |
606 | if (ret) { | |
607 | goto end; | |
608 | } | |
609 | ||
610 | ret = validate_connection_directions(cfg, error_buf, error_buf_size); | |
611 | if (ret) { | |
612 | goto end; | |
613 | } | |
614 | ||
ebba3338 PP |
615 | ret = validate_all_components_connected(cfg, error_buf, error_buf_size); |
616 | if (ret) { | |
617 | goto end; | |
618 | } | |
619 | ||
620 | ret = validate_no_duplicate_connection(cfg, error_buf, error_buf_size); | |
621 | if (ret) { | |
622 | goto end; | |
623 | } | |
624 | ||
db0f160a | 625 | ret = validate_no_cycles(cfg, error_buf, error_buf_size); |
ebba3338 PP |
626 | if (ret) { |
627 | goto end; | |
628 | } | |
629 | ||
ebba3338 | 630 | end: |
ebba3338 PP |
631 | return ret; |
632 | } | |
633 | ||
634 | int bt_config_create_connections(struct bt_config *cfg, | |
635 | struct bt_value *connection_args, | |
636 | char *error_buf, size_t error_buf_size) | |
637 | { | |
638 | int ret; | |
639 | size_t i; | |
640 | ||
db0f160a PP |
641 | if (!all_named_and_printable(cfg)) { |
642 | snprintf(error_buf, error_buf_size, | |
643 | "One or more components are unnamed (use --name) or contain a non-printable character\n"); | |
ebba3338 PP |
644 | goto error; |
645 | } | |
646 | ||
647 | for (i = 0; i < bt_value_array_size(connection_args); i++) { | |
648 | struct bt_value *arg_value = | |
649 | bt_value_array_get(connection_args, i); | |
650 | const char *arg; | |
651 | struct bt_config_connection *cfg_connection; | |
652 | ||
653 | ret = bt_value_string_get(arg_value, &arg); | |
654 | BT_PUT(arg_value); | |
655 | assert(ret == 0); | |
656 | cfg_connection = cfg_connection_from_arg(arg); | |
657 | if (!cfg_connection) { | |
658 | snprintf(error_buf, error_buf_size, "Cannot parse --connect option's argument:\n %s\n", | |
659 | arg); | |
660 | goto error; | |
661 | } | |
662 | ||
db0f160a | 663 | g_ptr_array_add(cfg->cmd_data.run.connections, |
ebba3338 PP |
664 | cfg_connection); |
665 | } | |
666 | ||
667 | ||
668 | ret = validate_connections(cfg, error_buf, error_buf_size); | |
669 | if (ret) { | |
670 | goto error; | |
671 | } | |
672 | ||
673 | goto end; | |
674 | ||
675 | error: | |
676 | ret = -1; | |
677 | ||
678 | end: | |
679 | return ret; | |
680 | } |