daemon: escape app strings (name, command) whens storing them in xml. Closes #27
[ladish.git] / daemon / cmd_save_studio.c
blob77bf20112fc7d6d409bcae7b23b524e59ab80a8e
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 "save 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>
34 #include "escape.h"
35 #include "studio_internal.h"
36 #include "cmd.h"
38 struct save_context
40 int fd;
41 const char * indent;
44 #define STUDIO_HEADER_TEXT BASE_NAME " Studio configuration.\n"
46 bool
47 write_string(int fd, const char * string)
49 size_t len;
51 len = strlen(string);
53 if (write(fd, string, len) != len)
55 log_error("write() failed to write config file.");
56 return false;
59 return true;
62 bool
63 write_jack_parameter(
64 int fd,
65 const char * indent,
66 struct jack_conf_parameter * parameter_ptr)
68 const char * src;
69 char * dst;
70 char path[JACK_CONF_MAX_ADDRESS_SIZE * 3]; /* encode each char in three bytes (percent encoding) */
71 const char * content;
72 char valbuf[100];
74 /* compose the parameter path, percent-encode "bad" chars */
75 src = parameter_ptr->address;
76 dst = path;
79 *dst++ = '/';
80 escape(&src, &dst);
81 src++;
83 while (*src != 0);
84 *dst = 0;
86 if (!write_string(fd, indent))
88 return false;
91 if (!write_string(fd, "<parameter path=\""))
93 return false;
96 if (!write_string(fd, path))
98 return false;
101 if (!write_string(fd, "\">"))
103 return false;
106 switch (parameter_ptr->parameter.type)
108 case jack_boolean:
109 content = parameter_ptr->parameter.value.boolean ? "true" : "false";
110 log_debug("%s value is %s (boolean)", path, content);
111 break;
112 case jack_string:
113 content = parameter_ptr->parameter.value.string;
114 log_debug("%s value is %s (string)", path, content);
115 break;
116 case jack_byte:
117 valbuf[0] = (char)parameter_ptr->parameter.value.byte;
118 valbuf[1] = 0;
119 content = valbuf;
120 log_debug("%s value is %u/%c (byte/char)", path, parameter_ptr->parameter.value.byte, (char)parameter_ptr->parameter.value.byte);
121 break;
122 case jack_uint32:
123 snprintf(valbuf, sizeof(valbuf), "%" PRIu32, parameter_ptr->parameter.value.uint32);
124 content = valbuf;
125 log_debug("%s value is %s (uint32)", path, content);
126 break;
127 case jack_int32:
128 snprintf(valbuf, sizeof(valbuf), "%" PRIi32, parameter_ptr->parameter.value.int32);
129 content = valbuf;
130 log_debug("%s value is %s (int32)", path, content);
131 break;
132 default:
133 log_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr->parameter.type, path);
134 return false;
137 if (!write_string(fd, content))
139 return false;
142 if (!write_string(fd, "</parameter>\n"))
144 return false;
147 return true;
150 static
151 bool
152 write_dict_entry(
153 void * context,
154 const char * key,
155 const char * value);
157 bool
158 write_dict(
159 int fd,
160 const char * indent,
161 ladish_dict_handle dict)
163 struct save_context context;
165 if (ladish_dict_is_empty(dict))
167 return true;
170 if (!write_string(fd, indent))
172 return false;
175 context.fd = fd;
176 context.indent = indent;
178 if (!write_string(fd, "<dict>\n"))
180 return false;
183 if (!ladish_dict_iterate(dict, &context, write_dict_entry))
185 return false;
188 if (!write_string(fd, indent))
190 return false;
193 if (!write_string(fd, "</dict>\n"))
195 return false;
198 return true;
201 #define fd (((struct save_context *)context)->fd)
202 #define indent (((struct save_context *)context)->indent)
204 static
205 bool
206 write_dict_entry(
207 void * context,
208 const char * key,
209 const char * value)
211 if (!write_string(fd, indent))
213 return false;
216 if (!write_string(fd, " <key name=\""))
218 return false;
221 if (!write_string(fd, key))
223 return false;
226 if (!write_string(fd, "\">"))
228 return false;
231 if (!write_string(fd, value))
233 return false;
236 if (!write_string(fd, "</key>\n"))
238 return false;
241 return true;
244 bool
245 save_jack_client_begin(
246 void * context,
247 ladish_client_handle client_handle,
248 const char * client_name,
249 void ** client_iteration_context_ptr_ptr)
251 uuid_t uuid;
252 char str[37];
254 ladish_client_get_uuid(client_handle, uuid);
255 uuid_unparse(uuid, str);
257 log_info("saving jack client '%s' (%s)", client_name, str);
259 if (!write_string(fd, " <client name=\""))
261 return false;
264 if (!write_string(fd, client_name))
266 return false;
269 if (!write_string(fd, "\" uuid=\""))
271 return false;
274 if (!write_string(fd, str))
276 return false;
279 if (!write_string(fd, "\">\n"))
281 return false;
284 if (!write_string(fd, " <ports>\n"))
286 return false;
289 return true;
292 bool
293 save_jack_client_end(
294 void * context,
295 ladish_client_handle client_handle,
296 const char * client_name,
297 void * client_iteration_context_ptr)
299 if (!write_string(fd, " </ports>\n"))
301 return false;
304 if (!write_string(fd, " </client>\n"))
306 return false;
309 return true;
312 bool
313 save_jack_port(
314 void * context,
315 void * client_iteration_context_ptr,
316 ladish_client_handle client_handle,
317 const char * client_name,
318 ladish_port_handle port_handle,
319 const char * port_name,
320 uint32_t port_type,
321 uint32_t port_flags)
323 uuid_t uuid;
324 char str[37];
326 ladish_port_get_uuid(port_handle, uuid);
327 uuid_unparse(uuid, str);
329 log_info("saving jack port '%s':'%s' (%s)", client_name, port_name, str);
331 if (!write_string(fd, " <port name=\""))
333 return false;
336 if (!write_string(fd, port_name))
338 return false;
341 if (!write_string(fd, "\" uuid=\""))
343 return false;
346 if (!write_string(fd, str))
348 return false;
351 if (!write_string(fd, "\" />\n"))
353 return false;
356 return true;
359 bool
360 save_studio_client_begin(
361 void * context,
362 ladish_client_handle client_handle,
363 const char * client_name,
364 void ** client_iteration_context_ptr_ptr)
366 uuid_t uuid;
367 char str[37];
369 ladish_client_get_uuid(client_handle, uuid);
370 uuid_unparse(uuid, str);
372 log_info("saving studio client '%s' (%s)", client_name, str);
374 if (!write_string(fd, " <client name=\""))
376 return false;
379 if (!write_string(fd, client_name))
381 return false;
384 if (!write_string(fd, "\" uuid=\""))
386 return false;
389 if (!write_string(fd, str))
391 return false;
394 if (!write_string(fd, "\">\n"))
396 return false;
399 if (!write_string(fd, " <ports>\n"))
401 return false;
404 return true;
407 bool
408 save_studio_client_end(
409 void * context,
410 ladish_client_handle client_handle,
411 const char * client_name,
412 void * client_iteration_context_ptr)
414 if (!write_string(fd, " </ports>\n"))
416 return false;
419 if (!write_dict(fd, " ", ladish_client_get_dict(client_handle)))
421 return false;
424 if (!write_string(fd, " </client>\n"))
426 return false;
429 return true;
432 bool
433 save_studio_port(
434 void * context,
435 void * client_iteration_context_ptr,
436 ladish_client_handle client_handle,
437 const char * client_name,
438 ladish_port_handle port_handle,
439 const char * port_name,
440 uint32_t port_type,
441 uint32_t port_flags)
443 uuid_t uuid;
444 char str[37];
445 ladish_dict_handle dict;
447 ladish_port_get_uuid(port_handle, uuid);
448 uuid_unparse(uuid, str);
450 log_info("saving studio port '%s':'%s' (%s)", client_name, port_name, str);
452 if (!write_string(fd, " <port name=\""))
454 return false;
457 if (!write_string(fd, port_name))
459 return false;
462 if (!write_string(fd, "\" uuid=\""))
464 return false;
467 if (!write_string(fd, str))
469 return false;
472 dict = ladish_port_get_dict(port_handle);
473 if (ladish_dict_is_empty(dict))
475 if (!write_string(fd, "\" />\n"))
477 return false;
480 else
482 if (!write_string(fd, "\">\n"))
484 return false;
487 if (!write_dict(fd, " ", dict))
489 return false;
492 if (!write_string(fd, " </port>\n"))
494 return false;
498 return true;
501 bool save_studio_connection(void * context, ladish_port_handle port1_handle, ladish_port_handle port2_handle, ladish_dict_handle dict)
503 uuid_t uuid;
504 char str[37];
506 log_info("saving studio connection");
508 if (!write_string(fd, " <connection port1=\""))
510 return false;
513 ladish_port_get_uuid(port1_handle, uuid);
514 uuid_unparse(uuid, str);
516 if (!write_string(fd, str))
518 return false;
521 if (!write_string(fd, "\" port2=\""))
523 return false;
526 ladish_port_get_uuid(port2_handle, uuid);
527 uuid_unparse(uuid, str);
529 if (!write_string(fd, str))
531 return false;
534 if (ladish_dict_is_empty(dict))
536 if (!write_string(fd, "\" />\n"))
538 return false;
541 else
543 if (!write_string(fd, "\">\n"))
545 return false;
548 if (!write_dict(fd, " ", dict))
550 return false;
553 if (!write_string(fd, " </connection>\n"))
555 return false;
559 return true;
562 bool save_studio_app(void * context, const char * name, bool running, const char * command, bool terminal, uint8_t level)
564 char buf[100];
565 const char * unescaped_string;
566 char * escaped_string;
567 char * escaped_buffer;
568 bool ret;
570 log_info("saving app: name='%s', %srunning, %s, level %u, commandline='%s'", name, running ? "" : "not ", terminal ? "terminal" : "shell", (unsigned int)level, command);
572 ret = false;
574 escaped_buffer = malloc(ladish_max(strlen(name), strlen(command)) * 3 + 1); /* encode each char in three bytes (percent encoding) */
575 if (escaped_buffer == NULL)
577 log_error("malloc() failed.");
578 goto exit;
581 if (!write_string(fd, " <application name=\""))
583 goto free_buffer;
586 unescaped_string = name;
587 escaped_string = escaped_buffer;
588 escape(&unescaped_string, &escaped_string);
589 *escaped_string = 0;
590 if (!write_string(fd, escaped_buffer))
592 goto free_buffer;
595 if (!write_string(fd, "\" terminal=\""))
597 goto free_buffer;
600 if (!write_string(fd, terminal ? "true" : "false"))
602 goto free_buffer;
605 if (!write_string(fd, "\" level=\""))
607 goto free_buffer;
610 sprintf(buf, "%u", (unsigned int)level);
612 if (!write_string(fd, buf))
614 goto free_buffer;
617 if (!write_string(fd, "\" autorun=\""))
619 goto free_buffer;
622 if (!write_string(fd, running ? "true" : "false"))
624 goto free_buffer;
627 if (!write_string(fd, "\">"))
629 goto free_buffer;
632 unescaped_string = command;
633 escaped_string = escaped_buffer;
634 escape(&unescaped_string, &escaped_string);
635 *escaped_string = 0;
636 if (!write_string(fd, escaped_buffer))
638 goto free_buffer;
641 if (!write_string(fd, "</application>\n"))
643 goto free_buffer;
646 ret = true;
648 free_buffer:
649 free(escaped_buffer);
651 exit:
652 return ret;
655 #undef indent
656 #undef fd
658 #define cmd_ptr ((struct ladish_command *)command_context)
660 static bool run(void * command_context)
662 struct list_head * node_ptr;
663 struct jack_conf_parameter * parameter_ptr;
664 int fd;
665 time_t timestamp;
666 char timestamp_str[26];
667 bool ret;
668 char * filename; /* filename */
669 char * bak_filename; /* filename of the backup file */
670 char * old_filename; /* filename where studio was persisted before save */
671 struct stat st;
672 struct save_context save_context;
674 ASSERT(cmd_ptr->state == LADISH_COMMAND_STATE_PENDING);
676 time(&timestamp);
677 ctime_r(&timestamp, timestamp_str);
678 timestamp_str[24] = 0;
680 ret = false;
682 if (!studio_is_started())
684 log_error("Cannot save not-started studio");
685 goto exit;
688 if (!studio_compose_filename(g_studio.name, &filename, &bak_filename))
690 log_error("failed to compose studio filename");
691 goto exit;
694 if (g_studio.filename == NULL)
696 /* saving studio for first time */
697 g_studio.filename = filename;
698 free(bak_filename);
699 bak_filename = NULL;
700 old_filename = NULL;
702 else if (strcmp(g_studio.filename, filename) == 0)
704 /* saving already persisted studio that was not renamed */
705 old_filename = filename;
707 else
709 /* saving renamed studio */
710 old_filename = g_studio.filename;
711 g_studio.filename = filename;
714 filename = NULL;
715 ASSERT(g_studio.filename != NULL);
716 ASSERT(g_studio.filename != old_filename);
717 ASSERT(g_studio.filename != bak_filename);
719 if (bak_filename != NULL)
721 ASSERT(old_filename != NULL);
723 if (stat(old_filename, &st) == 0) /* if old filename does not exist, rename with fail */
725 if (rename(old_filename, bak_filename) != 0)
727 log_error("rename(%s, %s) failed: %d (%s)", old_filename, bak_filename, errno, strerror(errno));
728 goto free_filenames;
731 else
733 /* mark that there is no backup file */
734 free(bak_filename);
735 bak_filename = NULL;
739 log_info("saving studio... (%s)", g_studio.filename);
741 fd = open(g_studio.filename, O_WRONLY | O_TRUNC | O_CREAT, 0700);
742 if (fd == -1)
744 log_error("open(%s) failed: %d (%s)", g_studio.filename, errno, strerror(errno));
745 goto rename_back;
748 if (!write_string(fd, "<?xml version=\"1.0\"?>\n"))
750 goto close;
753 if (!write_string(fd, "<!--\n"))
755 goto close;
758 if (!write_string(fd, STUDIO_HEADER_TEXT))
760 goto close;
763 if (!write_string(fd, "-->\n"))
765 goto close;
768 if (!write_string(fd, "<!-- "))
770 goto close;
773 if (!write_string(fd, timestamp_str))
775 goto close;
778 if (!write_string(fd, " -->\n"))
780 goto close;
783 if (!write_string(fd, "<studio>\n"))
785 goto close;
788 if (!write_string(fd, " <jack>\n"))
790 goto close;
793 if (!write_string(fd, " <conf>\n"))
795 goto close;
798 list_for_each(node_ptr, &g_studio.jack_params)
800 parameter_ptr = list_entry(node_ptr, struct jack_conf_parameter, leaves);
802 if (!write_jack_parameter(fd, " ", parameter_ptr))
804 goto close;
808 if (!write_string(fd, " </conf>\n"))
810 goto close;
813 if (!write_string(fd, " <clients>\n"))
815 goto close;
818 save_context.fd = fd;
820 if (!ladish_graph_iterate_nodes(g_studio.jack_graph, &save_context, save_jack_client_begin, save_jack_port, save_jack_client_end))
822 log_error("ladish_graph_iterate_nodes() failed");
823 goto close;
826 if (!write_string(fd, " </clients>\n"))
828 goto close;
831 if (!write_string(fd, " </jack>\n"))
833 goto close;
836 if (!write_string(fd, " <clients>\n"))
838 goto close;
841 if (!ladish_graph_iterate_nodes(g_studio.studio_graph, &save_context, save_studio_client_begin, save_studio_port, save_studio_client_end))
843 log_error("ladish_graph_iterate_nodes() failed");
844 goto close;
847 if (!write_string(fd, " </clients>\n"))
849 goto close;
852 if (!write_string(fd, " <connections>\n"))
854 goto close;
857 if (!ladish_graph_iterate_connections(g_studio.studio_graph, &save_context, save_studio_connection))
859 log_error("ladish_graph_iterate_connections() failed");
860 goto close;
863 if (!write_string(fd, " </connections>\n"))
865 goto close;
868 if (!write_string(fd, " <applications>\n"))
870 goto close;
873 if (!ladish_app_supervisor_enum(g_studio.app_supervisor, &save_context, save_studio_app))
875 goto close;
878 if (!write_string(fd, " </applications>\n"))
880 goto close;
883 if (!write_dict(fd, " ", ladish_graph_get_dict(g_studio.studio_graph)))
885 goto close;
888 if (!write_string(fd, "</studio>\n"))
890 goto close;
893 log_info("studio saved. (%s)", g_studio.filename);
894 g_studio.persisted = true;
895 g_studio.automatic = false; /* even if it was automatic, it is not anymore because it is saved */
897 cmd_ptr->state = LADISH_COMMAND_STATE_DONE;
899 ret = true;
901 close:
902 close(fd);
904 rename_back:
905 if (!ret && bak_filename != NULL)
907 /* save failed - try to rename the backup file back */
908 if (rename(bak_filename, g_studio.filename) != 0)
910 log_error("rename(%s, %s) failed: %d (%s)", bak_filename, g_studio.filename, errno, strerror(errno));
914 free_filenames:
915 if (bak_filename != NULL)
917 free(bak_filename);
920 if (old_filename != NULL)
922 free(old_filename);
925 ASSERT(filename == NULL);
926 ASSERT(g_studio.filename != NULL);
928 exit:
929 return ret;
932 #undef cmd_ptr
934 bool ladish_command_save_studio(void * call_ptr, struct ladish_cqueue * queue_ptr)
936 struct ladish_command * cmd_ptr;
938 cmd_ptr = ladish_command_new(sizeof(struct ladish_command));
939 if (cmd_ptr == NULL)
941 log_error("ladish_command_new() failed.");
942 goto fail;
945 cmd_ptr->run = run;
947 if (!ladish_cqueue_add_command(queue_ptr, cmd_ptr))
949 lash_dbus_error(call_ptr, LASH_DBUS_ERROR_GENERIC, "ladish_cqueue_add_command() failed.");
950 goto fail_destroy_command;
953 return true;
955 fail_destroy_command:
956 free(cmd_ptr);
958 fail:
959 return false;