daemon: fix memory corruption
[ladish.git] / daemon / cmd_load_studio.c
blob4e472b47b8742e8443de8ff0c3e80fe40ef25b39
1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*
3 * LADI Session Handler (ladish)
5 * Copyright (C) 2009 Nedko Arnaudov <nedko@arnaudov.name>
7 **************************************************************************
8 * This file contains implementation of the "load studio" command
9 **************************************************************************
11 * LADI Session Handler is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * LADI Session Handler is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with LADI Session Handler. If not, see <http://www.gnu.org/licenses/>
23 * or write to the Free Software Foundation, Inc.,
24 * 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
27 #include "common.h"
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <unistd.h>
33 #include <expat.h>
34 #include <limits.h>
36 #include "escape.h"
37 #include "cmd.h"
38 #include "studio_internal.h"
40 #define PARSE_CONTEXT_ROOT 0
41 #define PARSE_CONTEXT_STUDIO 1
42 #define PARSE_CONTEXT_JACK 2
43 #define PARSE_CONTEXT_CONF 3
44 #define PARSE_CONTEXT_PARAMETER 4
45 #define PARSE_CONTEXT_CLIENTS 5
46 #define PARSE_CONTEXT_CLIENT 6
47 #define PARSE_CONTEXT_PORTS 7
48 #define PARSE_CONTEXT_PORT 8
49 #define PARSE_CONTEXT_DICT 9
50 #define PARSE_CONTEXT_KEY 10
51 #define PARSE_CONTEXT_CONNECTIONS 11
52 #define PARSE_CONTEXT_CONNECTION 12
53 #define PARSE_CONTEXT_APPLICATIONS 13
54 #define PARSE_CONTEXT_APPLICATION 14
56 #define MAX_STACK_DEPTH 10
57 #define MAX_DATA_SIZE 10240
59 struct parse_context
61 XML_Bool error;
62 unsigned int element[MAX_STACK_DEPTH];
63 signed int depth;
64 char data[MAX_DATA_SIZE];
65 int data_used;
66 char * str;
67 ladish_client_handle client;
68 ladish_port_handle port;
69 ladish_dict_handle dict;
70 uint64_t connection_id;
71 bool terminal;
72 bool autorun;
73 uint8_t level;
76 #define context_ptr ((struct parse_context *)data)
78 static void callback_chrdata(void * data, const XML_Char * s, int len)
80 if (context_ptr->error)
82 return;
85 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER ||
86 context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_KEY ||
87 context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_APPLICATION)
89 if (context_ptr->data_used + len >= sizeof(context_ptr->data))
91 log_error("xml parse max char data length reached");
92 context_ptr->error = XML_TRUE;
93 return;
96 memcpy(context_ptr->data + context_ptr->data_used, s, len);
97 context_ptr->data_used += len;
101 static void callback_elstart(void * data, const char * el, const char ** attr)
103 uuid_t uuid;
104 uuid_t uuid2;
105 ladish_port_handle port1;
106 ladish_port_handle port2;
107 long int li_value;
108 char * end_ptr;
110 if (context_ptr->error)
112 return;
115 if (context_ptr->depth + 1 >= MAX_STACK_DEPTH)
117 log_error("xml parse max stack depth reached");
118 context_ptr->error = XML_TRUE;
119 return;
122 if (strcmp(el, "studio") == 0)
124 //log_info("<studio>");
125 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_STUDIO;
126 return;
129 if (strcmp(el, "jack") == 0)
131 //log_info("<jack>");
132 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_JACK;
133 return;
136 if (strcmp(el, "conf") == 0)
138 //log_info("<conf>");
139 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONF;
140 return;
143 if (strcmp(el, "parameter") == 0)
145 //log_info("<parameter>");
146 if ((attr[0] == NULL || attr[2] != NULL) || strcmp(attr[0], "path") != 0)
148 log_error("<parameter> XML element must contain exactly one attribute, named \"path\"");
149 context_ptr->error = XML_TRUE;
150 return;
153 context_ptr->str = strdup(attr[1]);
154 if (context_ptr->str == NULL)
156 log_error("strdup() failed");
157 context_ptr->error = XML_TRUE;
158 return;
161 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PARAMETER;
162 context_ptr->data_used = 0;
163 return;
166 if (strcmp(el, "clients") == 0)
168 //log_info("<clients>");
169 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CLIENTS;
170 return;
173 if (strcmp(el, "client") == 0)
175 //log_info("<client>");
176 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CLIENT;
178 if (context_ptr->client != NULL)
180 log_error("nested clients");
181 context_ptr->error = XML_TRUE;
182 return;
185 if (context_ptr->depth == 3 &&
186 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
187 context_ptr->element[1] == PARSE_CONTEXT_JACK &&
188 context_ptr->element[2] == PARSE_CONTEXT_CLIENTS)
190 if (attr[0] == NULL ||
191 attr[1] == NULL ||
192 attr[2] == NULL ||
193 attr[3] == NULL ||
194 attr[4] != NULL ||
195 strcmp(attr[0], "name") != 0 ||
196 strcmp(attr[2], "uuid") != 0)
198 log_error("studio/jack/clients/client XML element must contain exactly two attributes, named \"name\" and \"uuid\", in this order");
199 context_ptr->error = XML_TRUE;
200 return;
203 if (uuid_parse(attr[3], uuid) != 0)
205 log_error("cannot parse uuid \"%s\"", attr[3]);
206 context_ptr->error = XML_TRUE;
207 return;
210 log_info("jack client \"%s\" with uuid %s", attr[1], attr[3]);
212 if (!ladish_client_create(uuid, false, false, false, &context_ptr->client))
214 log_error("ladish_client_create() failed.");
215 context_ptr->error = XML_TRUE;
216 ASSERT(context_ptr->client == NULL);
217 return;
220 if (!ladish_graph_add_client(g_studio.jack_graph, context_ptr->client, attr[1], true))
222 log_error("ladish_graph_add_client() failed to add client '%s' to JACK graph", attr[1]);
223 context_ptr->error = XML_TRUE;
224 ladish_client_destroy(context_ptr->client);
225 context_ptr->client = NULL;
226 return;
229 else if (context_ptr->depth == 2 &&
230 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
231 context_ptr->element[1] == PARSE_CONTEXT_CLIENTS)
233 if (attr[0] == NULL ||
234 attr[1] == NULL ||
235 attr[2] == NULL ||
236 attr[3] == NULL ||
237 attr[4] != NULL ||
238 strcmp(attr[0], "name") != 0 ||
239 strcmp(attr[2], "uuid") != 0)
241 log_error("studio/clients/client XML element must contain exactly two attributes, named \"name\" and \"uuid\", in this order");
242 context_ptr->error = XML_TRUE;
243 return;
246 if (uuid_parse(attr[3], uuid) != 0)
248 log_error("cannot parse uuid \"%s\"", attr[3]);
249 context_ptr->error = XML_TRUE;
250 return;
253 log_info("studio client \"%s\" with uuid %s", attr[1], attr[3]);
255 if (!ladish_client_create(uuid, true, false, false, &context_ptr->client))
257 log_error("ladish_client_create() failed.");
258 context_ptr->error = XML_TRUE;
259 ASSERT(context_ptr->client == NULL);
260 return;
263 if (!ladish_graph_add_client(g_studio.studio_graph, context_ptr->client, attr[1], true))
265 log_error("ladish_graph_add_client() failed to add client '%s' to studio graph", attr[1]);
266 context_ptr->error = XML_TRUE;
267 ladish_client_destroy(context_ptr->client);
268 context_ptr->client = NULL;
269 return;
273 return;
276 if (strcmp(el, "ports") == 0)
278 //log_info("<ports>");
279 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PORTS;
280 return;
283 if (strcmp(el, "port") == 0)
285 //log_info("<port>");
286 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_PORT;
288 if (context_ptr->port != NULL)
290 log_error("nested ports");
291 context_ptr->error = XML_TRUE;
292 return;
295 if (context_ptr->client == NULL)
297 log_error("client-less port");
298 context_ptr->error = XML_TRUE;
299 return;
302 if (context_ptr->depth == 5 &&
303 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
304 context_ptr->element[1] == PARSE_CONTEXT_JACK &&
305 context_ptr->element[2] == PARSE_CONTEXT_CLIENTS &&
306 context_ptr->element[3] == PARSE_CONTEXT_CLIENT &&
307 context_ptr->element[4] == PARSE_CONTEXT_PORTS)
309 if (attr[0] == NULL ||
310 attr[1] == NULL ||
311 attr[2] == NULL ||
312 attr[3] == NULL ||
313 attr[4] != NULL ||
314 strcmp(attr[0], "name") != 0 ||
315 strcmp(attr[2], "uuid") != 0)
317 log_error("studio/jack/clients/client/ports/port XML element must contain exactly two attributes, named \"name\" and \"uuid\", in this order");
318 context_ptr->error = XML_TRUE;
319 return;
322 if (uuid_parse(attr[3], uuid) != 0)
324 log_error("cannot parse uuid \"%s\"", attr[3]);
325 context_ptr->error = XML_TRUE;
326 return;
329 log_info("jack port \"%s\" with uuid %s", attr[1], attr[3]);
331 if (!ladish_port_create(uuid, &context_ptr->port))
333 log_error("ladish_port_create() failed.");
334 return;
337 if (!ladish_graph_add_port(g_studio.jack_graph, context_ptr->client, context_ptr->port, attr[1], 0, 0, true))
339 log_error("ladish_graph_add_port() failed.");
340 ladish_port_destroy(context_ptr->port);
341 context_ptr->port = NULL;
342 return;
345 else if (context_ptr->depth == 4 &&
346 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
347 context_ptr->element[1] == PARSE_CONTEXT_CLIENTS &&
348 context_ptr->element[2] == PARSE_CONTEXT_CLIENT &&
349 context_ptr->element[3] == PARSE_CONTEXT_PORTS)
351 if (attr[0] == NULL ||
352 attr[1] == NULL ||
353 attr[2] == NULL ||
354 attr[3] == NULL ||
355 attr[4] != NULL ||
356 strcmp(attr[0], "name") != 0 ||
357 strcmp(attr[2], "uuid") != 0)
359 log_error("studio/clients/client/ports/port XML element must contain exactly two attributes, named \"name\" and \"uuid\", in this order");
360 context_ptr->error = XML_TRUE;
361 return;
364 if (uuid_parse(attr[3], uuid) != 0)
366 log_error("cannot parse uuid \"%s\"", attr[3]);
367 context_ptr->error = XML_TRUE;
368 return;
371 log_info("studio port \"%s\" with uuid %s", attr[1], attr[3]);
373 context_ptr->port = ladish_graph_find_port_by_uuid(g_studio.jack_graph, uuid);
374 if (context_ptr->port == NULL)
376 log_error("studio client with non-jack port %s", attr[3]);
377 context_ptr->error = XML_TRUE;
378 return;
381 if (!ladish_graph_add_port(g_studio.studio_graph, context_ptr->client, context_ptr->port, attr[1], 0, 0, true))
383 log_error("ladish_graph_add_port() failed.");
384 ladish_port_destroy(context_ptr->port);
385 context_ptr->port = NULL;
386 return;
390 return;
393 if (strcmp(el, "connections") == 0)
395 //log_info("<connections>");
396 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONNECTIONS;
397 return;
400 if (strcmp(el, "connection") == 0)
402 //log_info("<connection>");
403 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_CONNECTION;
405 if (attr[0] == NULL ||
406 attr[1] == NULL ||
407 attr[2] == NULL ||
408 attr[3] == NULL ||
409 attr[4] != NULL ||
410 strcmp(attr[0], "port1") != 0 ||
411 strcmp(attr[2], "port2") != 0)
413 log_error("studio/connections/connection XML element must contain exactly two attributes, named \"port1\" and \"port2\", in this order");
414 context_ptr->error = XML_TRUE;
415 return;
418 if (uuid_parse(attr[1], uuid) != 0)
420 log_error("cannot parse uuid \"%s\"", attr[1]);
421 context_ptr->error = XML_TRUE;
422 return;
425 if (uuid_parse(attr[3], uuid2) != 0)
427 log_error("cannot parse uuid \"%s\"", attr[3]);
428 context_ptr->error = XML_TRUE;
429 return;
432 log_info("studio connection between port %s and port %s", attr[1], attr[3]);
434 port1 = ladish_graph_find_port_by_uuid(g_studio.studio_graph, uuid);
435 if (port1 == NULL)
437 log_error("studio client with unknown port %s", attr[1]);
438 context_ptr->error = XML_TRUE;
439 return;
442 port2 = ladish_graph_find_port_by_uuid(g_studio.studio_graph, uuid2);
443 if (port2 == NULL)
445 log_error("studio client with unknown port %s", attr[3]);
446 context_ptr->error = XML_TRUE;
447 return;
450 context_ptr->connection_id = ladish_graph_add_connection(g_studio.studio_graph, port1, port2, true);
451 if (context_ptr->connection_id == 0)
453 log_error("ladish_graph_add_connection() failed.");
454 return;
457 return;
460 if (strcmp(el, "applications") == 0)
462 //log_info("<applications>");
463 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATIONS;
464 return;
467 if (strcmp(el, "application") == 0)
469 //log_info("<application>");
470 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_APPLICATION;
472 if (attr[0] == NULL ||
473 attr[1] == NULL ||
474 attr[2] == NULL ||
475 attr[3] == NULL ||
476 attr[4] == NULL ||
477 attr[5] == NULL ||
478 attr[6] == NULL ||
479 attr[7] == NULL ||
480 attr[8] != NULL ||
481 strcmp(attr[0], "name") != 0 ||
482 strcmp(attr[2], "terminal") != 0 ||
483 strcmp(attr[4], "level") != 0 ||
484 strcmp(attr[6], "autorun") != 0)
486 log_error("'application' XML element must contain exactly four attributes, named \"name\", \"terminal\", \"level\" and \"autorun\", in this order");
487 context_ptr->error = XML_TRUE;
488 return;
491 if (strcmp(attr[3], "true") != 0 && strcmp(attr[3], "false") != 0)
493 log_error("'application@terminal' XML attribute is boolean and the only valid values are \"true\" and \"false\"");
494 context_ptr->error = XML_TRUE;
495 return;
498 if (strcmp(attr[7], "true") != 0 && strcmp(attr[7], "false") != 0)
500 log_error("'application@autorun' XML attribute is boolean and the only valid values are \"true\" and \"false\"");
501 context_ptr->error = XML_TRUE;
502 return;
505 errno = 0; /* To distinguish success/failure after call */
506 li_value = strtol(attr[5], &end_ptr, 10);
507 if ((errno == ERANGE && (li_value == LONG_MAX || li_value == LONG_MIN)) || (errno != 0 && li_value == 0) || end_ptr == attr[5])
509 log_error("'application@level' XML attribute '%s' is not valid integer.", attr[5]);
510 context_ptr->error = XML_TRUE;
511 return;
514 if (li_value < 0 || li_value > 255)
516 log_error("'application@level' XML attribute '%s' is not valid uint8.", attr[5]);
517 context_ptr->error = XML_TRUE;
518 return;
521 context_ptr->str = strdup(attr[1]);
522 if (context_ptr->str == NULL)
524 log_error("strdup() failed");
525 context_ptr->error = XML_TRUE;
526 return;
529 context_ptr->terminal = strcmp(attr[3], "true") == 0;
530 context_ptr->autorun = strcmp(attr[7], "true") == 0;
531 context_ptr->level = (uint8_t)li_value;
533 context_ptr->data_used = 0;
534 return;
537 if (strcmp(el, "dict") == 0)
539 //log_info("<dict>");
540 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_DICT;
542 if (context_ptr->dict != NULL)
544 log_error("nested dicts");
545 context_ptr->error = XML_TRUE;
546 return;
549 if (context_ptr->depth == 1 &&
550 context_ptr->element[0] == PARSE_CONTEXT_STUDIO)
552 context_ptr->dict = ladish_graph_get_dict(g_studio.studio_graph);
553 ASSERT(context_ptr->dict != NULL);
555 else if (context_ptr->depth > 0 &&
556 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_CLIENT)
558 ASSERT(context_ptr->client != NULL);
559 context_ptr->dict = ladish_client_get_dict(context_ptr->client);
560 ASSERT(context_ptr->dict != NULL);
562 else if (context_ptr->depth > 0 &&
563 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_PORT)
565 ASSERT(context_ptr->port != NULL);
566 context_ptr->dict = ladish_port_get_dict(context_ptr->port);
567 ASSERT(context_ptr->dict != NULL);
569 else if (context_ptr->depth > 0 &&
570 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_CONNECTION)
572 ASSERT(context_ptr->port != NULL);
573 context_ptr->dict = ladish_graph_get_connection_dict(g_studio.studio_graph, context_ptr->connection_id);
574 ASSERT(context_ptr->dict != NULL);
576 else
578 log_error("unexpected dict XML element");
579 context_ptr->error = XML_TRUE;
580 return;
583 return;
586 if (strcmp(el, "key") == 0)
588 //log_info("<key>");
589 context_ptr->element[++context_ptr->depth] = PARSE_CONTEXT_KEY;
591 if (context_ptr->dict == NULL)
593 log_error("dict-less key");
594 context_ptr->error = XML_TRUE;
595 return;
598 if (attr[0] == NULL ||
599 attr[1] == NULL ||
600 attr[2] != NULL ||
601 strcmp(attr[0], "name") != 0)
603 log_error("dict/key XML element must contain exactly one attributes, named \"name\".");
604 context_ptr->error = XML_TRUE;
605 return;
608 context_ptr->str = strdup(attr[1]);
609 if (context_ptr->str == NULL)
611 log_error("strdup() failed");
612 context_ptr->error = XML_TRUE;
613 return;
616 context_ptr->data_used = 0;
618 return;
621 log_error("unknown element \"%s\"", el);
622 context_ptr->error = XML_TRUE;
625 static void callback_elend(void * data, const char * el)
627 char * src;
628 char * dst;
629 char * sep;
630 size_t src_len;
631 size_t dst_len;
632 char * address;
633 struct jack_parameter_variant parameter;
634 bool is_set;
636 if (context_ptr->error)
638 return;
641 //log_info("element end (depth = %d, element = %u)", context_ptr->depth, context_ptr->element[context_ptr->depth]);
643 if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PARAMETER &&
644 context_ptr->depth == 3 &&
645 context_ptr->element[0] == PARSE_CONTEXT_STUDIO &&
646 context_ptr->element[1] == PARSE_CONTEXT_JACK &&
647 context_ptr->element[2] == PARSE_CONTEXT_CONF)
649 context_ptr->data[context_ptr->data_used] = 0;
651 //log_info("'%s' with value '%s'", context_ptr->str, context_ptr->data);
653 dst = address = strdup(context_ptr->str);
654 src = context_ptr->str + 1;
655 while (*src != 0)
657 sep = strchr(src, '/');
658 if (sep == NULL)
660 src_len = strlen(src);
662 else
664 src_len = sep - src;
667 dst_len = unescape(src, src_len, dst);
668 dst[dst_len] = 0;
669 dst += dst_len + 1;
671 src += src_len;
672 ASSERT(*src == '/' || *src == 0);
673 if (sep != NULL)
675 ASSERT(*src == '/');
676 src++; /* skip separator */
678 else
680 ASSERT(*src == 0);
683 *dst = 0; /* ASCIZZ */
685 if (!jack_proxy_get_parameter_value(address, &is_set, &parameter))
687 log_error("jack_proxy_get_parameter_value() failed");
688 goto fail_free_address;
691 if (parameter.type == jack_string)
693 free(parameter.value.string);
696 switch (parameter.type)
698 case jack_boolean:
699 log_info("%s value is %s (boolean)", context_ptr->str, context_ptr->data);
700 if (strcmp(context_ptr->data, "true") == 0)
702 parameter.value.boolean = true;
704 else if (strcmp(context_ptr->data, "false") == 0)
706 parameter.value.boolean = false;
708 else
710 log_error("bad value for a bool jack param");
711 goto fail_free_address;
713 break;
714 case jack_string:
715 log_info("%s value is %s (string)", context_ptr->str, context_ptr->data);
716 parameter.value.string = context_ptr->data;
717 break;
718 case jack_byte:
719 log_debug("%s value is %u/%c (byte/char)", context_ptr->str, *context_ptr->data, *context_ptr->data);
720 if (context_ptr->data[0] == 0 ||
721 context_ptr->data[1] != 0)
723 log_error("bad value for a char jack param");
724 goto fail_free_address;
726 parameter.value.byte = context_ptr->data[0];
727 break;
728 case jack_uint32:
729 log_info("%s value is %s (uint32)", context_ptr->str, context_ptr->data);
730 if (sscanf(context_ptr->data, "%" PRIu32, &parameter.value.uint32) != 1)
732 log_error("bad value for an uint32 jack param");
733 goto fail_free_address;
735 break;
736 case jack_int32:
737 log_info("%s value is %s (int32)", context_ptr->str, context_ptr->data);
738 if (sscanf(context_ptr->data, "%" PRIi32, &parameter.value.int32) != 1)
740 log_error("bad value for an int32 jack param");
741 goto fail_free_address;
743 break;
744 default:
745 log_error("unknown jack parameter type %d of %s", (int)parameter.type, context_ptr->str);
746 goto fail_free_address;
749 if (!jack_proxy_set_parameter_value(address, &parameter))
751 log_error("jack_proxy_set_parameter_value() failed");
752 goto fail_free_address;
755 free(address);
757 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_KEY &&
758 context_ptr->depth > 0 &&
759 context_ptr->element[context_ptr->depth - 1] == PARSE_CONTEXT_DICT)
761 ASSERT(context_ptr->dict != NULL);
762 context_ptr->data[context_ptr->data_used] = 0;
763 log_info("dict key '%s' with value '%s'", context_ptr->str, context_ptr->data);
764 if (!ladish_dict_set(context_ptr->dict, context_ptr->str, context_ptr->data))
766 log_error("ladish_dict_set() failed");
767 context_ptr->error = XML_TRUE;
768 return;
771 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_DICT)
773 //log_info("</dict>");
774 ASSERT(context_ptr->dict != NULL);
775 context_ptr->dict = NULL;
777 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_CLIENT)
779 //log_info("</client>");
780 ASSERT(context_ptr->client != NULL);
781 context_ptr->client = NULL;
783 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_PORT)
785 //log_info("</port>");
786 ASSERT(context_ptr->port != NULL);
787 context_ptr->port = NULL;
789 else if (context_ptr->element[context_ptr->depth] == PARSE_CONTEXT_APPLICATION)
791 context_ptr->data[context_ptr->data_used] = 0;
792 log_info("application '%s' (%s, %s, level %u) with commandline '%s'", context_ptr->str, context_ptr->terminal ? "terminal" : "shell", context_ptr->autorun ? "autorun" : "stopped", (unsigned int)context_ptr->level, context_ptr->data);
794 if (!ladish_app_supervisor_add(g_studio.app_supervisor, context_ptr->str, context_ptr->autorun, context_ptr->data, context_ptr->terminal, context_ptr->level))
796 log_error("ladish_app_supervisor_add() failed.");
797 context_ptr->error = XML_TRUE;
801 context_ptr->depth--;
803 if (context_ptr->str != NULL)
805 free(context_ptr->str);
806 context_ptr->str = NULL;
809 return;
811 fail_free_address:
812 free(address);
813 context_ptr->error = XML_TRUE;
814 return;
817 #undef context_ptr
819 struct ladish_command_load_studio
821 struct ladish_command command;
822 char * studio_name;
825 #define cmd_ptr ((struct ladish_command_load_studio *)command_context)
827 static bool run(void * command_context)
829 char * path;
830 struct stat st;
831 XML_Parser parser;
832 int bytes_read;
833 void * buffer;
834 int fd;
835 enum XML_Status xmls;
836 struct parse_context parse_context;
838 ASSERT(cmd_ptr->command.state == LADISH_COMMAND_STATE_PENDING);
840 if (!studio_compose_filename(cmd_ptr->studio_name, &path, NULL))
842 log_error("failed to compose path of studio \%s\" file", cmd_ptr->studio_name);
843 return false;
846 log_info("Loading studio... ('%s')", path);
848 if (stat(path, &st) != 0)
850 log_error("failed to stat '%s': %d (%s)", path, errno, strerror(errno));
851 free(path);
852 return false;
855 g_studio.name = cmd_ptr->studio_name;
856 cmd_ptr->studio_name = NULL;
858 g_studio.filename = path;
860 if (!jack_reset_all_params())
862 log_error("jack_reset_all_params() failed");
863 return false;
866 fd = open(path, O_RDONLY);
867 if (fd == -1)
869 log_error("failed to open '%s': %d (%s)", path, errno, strerror(errno));
870 return false;
873 parser = XML_ParserCreate(NULL);
874 if (parser == NULL)
876 log_error("XML_ParserCreate() failed to create parser object.");
877 close(fd);
878 return false;
881 //log_info("conf file size is %llu bytes", (unsigned long long)st.st_size);
883 /* we are expecting that conf file has small enough size to fit in memory */
885 buffer = XML_GetBuffer(parser, st.st_size);
886 if (buffer == NULL)
888 log_error("XML_GetBuffer() failed.");
889 XML_ParserFree(parser);
890 close(fd);
891 return false;
894 bytes_read = read(fd, buffer, st.st_size);
895 if (bytes_read != st.st_size)
897 log_error("read() returned unexpected result.");
898 XML_ParserFree(parser);
899 close(fd);
900 return false;
903 parse_context.error = XML_FALSE;
904 parse_context.depth = -1;
905 parse_context.str = NULL;
906 parse_context.client = NULL;
907 parse_context.port = NULL;
908 parse_context.dict = NULL;
910 XML_SetElementHandler(parser, callback_elstart, callback_elend);
911 XML_SetCharacterDataHandler(parser, callback_chrdata);
912 XML_SetUserData(parser, &parse_context);
914 xmls = XML_ParseBuffer(parser, bytes_read, XML_TRUE);
915 if (xmls == XML_STATUS_ERROR)
917 if (!parse_context.error)
919 log_error("XML_ParseBuffer() failed.");
921 XML_ParserFree(parser);
922 close(fd);
923 return false;
926 XML_ParserFree(parser);
927 close(fd);
929 if (parse_context.error)
931 return false;
934 g_studio.persisted = true;
935 log_info("Studio loaded. ('%s')", path);
937 ladish_graph_dump(g_studio.jack_graph);
938 ladish_graph_dump(g_studio.studio_graph);
940 if (!studio_publish())
942 log_error("studio_publish() failed.");
943 return false;
946 cmd_ptr->command.state = LADISH_COMMAND_STATE_DONE;
947 return true;
950 static void destructor(void * command_context)
952 log_info("load studio command destructor");
953 if (cmd_ptr->studio_name != NULL)
955 free(cmd_ptr->studio_name);
959 #undef cmd_ptr
961 bool ladish_command_load_studio(void * call_ptr, struct ladish_cqueue * queue_ptr, const char * studio_name)
963 struct ladish_command_load_studio * cmd_ptr;
964 char * studio_name_dup;
966 studio_name_dup = strdup(studio_name);
967 if (studio_name_dup == NULL)
969 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "strdup('%s') failed.", studio_name);
970 goto fail;
973 if (!ladish_command_unload_studio(call_ptr, queue_ptr))
975 goto fail_free_name;
978 cmd_ptr = ladish_command_new(sizeof(struct ladish_command_load_studio));
979 if (cmd_ptr == NULL)
981 log_error("ladish_command_new() failed.");
982 goto fail_drop_unload_command;
985 cmd_ptr->command.run = run;
986 cmd_ptr->command.destructor = destructor;
987 cmd_ptr->studio_name = studio_name_dup;
989 if (!ladish_cqueue_add_command(queue_ptr, &cmd_ptr->command))
991 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "ladish_cqueue_add_command() failed.");
992 goto fail_destroy_command;
995 if (!ladish_command_start_studio(call_ptr, queue_ptr))
997 goto fail_drop_load_command;
1000 return true;
1002 fail_drop_load_command:
1003 ladish_cqueue_drop_command(queue_ptr);
1005 fail_destroy_command:
1006 free(cmd_ptr);
1008 fail_drop_unload_command:
1009 ladish_cqueue_drop_command(queue_ptr);
1011 fail_free_name:
1012 free(studio_name_dup);
1014 fail:
1015 return false;