1 /* -*- Mode: C ; c-basic-offset: 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.
29 #include <sys/types.h>
35 #include "studio_internal.h"
44 #define STUDIO_HEADER_TEXT BASE_NAME " Studio configuration.\n"
47 write_string(int fd
, const char * string
)
53 if (write(fd
, string
, len
) != len
)
55 log_error("write() failed to write config file.");
66 struct jack_conf_parameter
* parameter_ptr
)
70 char path
[JACK_CONF_MAX_ADDRESS_SIZE
* 3]; /* encode each char in three bytes (percent encoding) */
74 /* compose the parameter path, percent-encode "bad" chars */
75 src
= parameter_ptr
->address
;
86 if (!write_string(fd
, indent
))
91 if (!write_string(fd
, "<parameter path=\""))
96 if (!write_string(fd
, path
))
101 if (!write_string(fd
, "\">"))
106 switch (parameter_ptr
->parameter
.type
)
109 content
= parameter_ptr
->parameter
.value
.boolean
? "true" : "false";
110 log_debug("%s value is %s (boolean)", path
, content
);
113 content
= parameter_ptr
->parameter
.value
.string
;
114 log_debug("%s value is %s (string)", path
, content
);
117 valbuf
[0] = (char)parameter_ptr
->parameter
.value
.byte
;
120 log_debug("%s value is %u/%c (byte/char)", path
, parameter_ptr
->parameter
.value
.byte
, (char)parameter_ptr
->parameter
.value
.byte
);
123 snprintf(valbuf
, sizeof(valbuf
), "%" PRIu32
, parameter_ptr
->parameter
.value
.uint32
);
125 log_debug("%s value is %s (uint32)", path
, content
);
128 snprintf(valbuf
, sizeof(valbuf
), "%" PRIi32
, parameter_ptr
->parameter
.value
.int32
);
130 log_debug("%s value is %s (int32)", path
, content
);
133 log_error("unknown jack parameter_ptr->parameter type %d (%s)", (int)parameter_ptr
->parameter
.type
, path
);
137 if (!write_string(fd
, content
))
142 if (!write_string(fd
, "</parameter>\n"))
161 ladish_dict_handle dict
)
163 struct save_context context
;
165 if (ladish_dict_is_empty(dict
))
170 if (!write_string(fd
, indent
))
176 context
.indent
= indent
;
178 if (!write_string(fd
, "<dict>\n"))
183 if (!ladish_dict_iterate(dict
, &context
, write_dict_entry
))
188 if (!write_string(fd
, indent
))
193 if (!write_string(fd
, "</dict>\n"))
201 #define fd (((struct save_context *)context)->fd)
202 #define indent (((struct save_context *)context)->indent)
211 if (!write_string(fd
, indent
))
216 if (!write_string(fd
, " <key name=\""))
221 if (!write_string(fd
, key
))
226 if (!write_string(fd
, "\">"))
231 if (!write_string(fd
, value
))
236 if (!write_string(fd
, "</key>\n"))
245 save_jack_client_begin(
247 ladish_client_handle client_handle
,
248 const char * client_name
,
249 void ** client_iteration_context_ptr_ptr
)
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=\""))
264 if (!write_string(fd
, client_name
))
269 if (!write_string(fd
, "\" uuid=\""))
274 if (!write_string(fd
, str
))
279 if (!write_string(fd
, "\">\n"))
284 if (!write_string(fd
, " <ports>\n"))
293 save_jack_client_end(
295 ladish_client_handle client_handle
,
296 const char * client_name
,
297 void * client_iteration_context_ptr
)
299 if (!write_string(fd
, " </ports>\n"))
304 if (!write_string(fd
, " </client>\n"))
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
,
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=\""))
336 if (!write_string(fd
, port_name
))
341 if (!write_string(fd
, "\" uuid=\""))
346 if (!write_string(fd
, str
))
351 if (!write_string(fd
, "\" />\n"))
360 save_studio_client_begin(
362 ladish_client_handle client_handle
,
363 const char * client_name
,
364 void ** client_iteration_context_ptr_ptr
)
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=\""))
379 if (!write_string(fd
, client_name
))
384 if (!write_string(fd
, "\" uuid=\""))
389 if (!write_string(fd
, str
))
394 if (!write_string(fd
, "\">\n"))
399 if (!write_string(fd
, " <ports>\n"))
408 save_studio_client_end(
410 ladish_client_handle client_handle
,
411 const char * client_name
,
412 void * client_iteration_context_ptr
)
414 if (!write_string(fd
, " </ports>\n"))
419 if (!write_dict(fd
, " ", ladish_client_get_dict(client_handle
)))
424 if (!write_string(fd
, " </client>\n"))
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
,
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=\""))
457 if (!write_string(fd
, port_name
))
462 if (!write_string(fd
, "\" uuid=\""))
467 if (!write_string(fd
, str
))
472 dict
= ladish_port_get_dict(port_handle
);
473 if (ladish_dict_is_empty(dict
))
475 if (!write_string(fd
, "\" />\n"))
482 if (!write_string(fd
, "\">\n"))
487 if (!write_dict(fd
, " ", dict
))
492 if (!write_string(fd
, " </port>\n"))
501 bool save_studio_connection(void * context
, ladish_port_handle port1_handle
, ladish_port_handle port2_handle
, ladish_dict_handle dict
)
506 log_info("saving studio connection");
508 if (!write_string(fd
, " <connection port1=\""))
513 ladish_port_get_uuid(port1_handle
, uuid
);
514 uuid_unparse(uuid
, str
);
516 if (!write_string(fd
, str
))
521 if (!write_string(fd
, "\" port2=\""))
526 ladish_port_get_uuid(port2_handle
, uuid
);
527 uuid_unparse(uuid
, str
);
529 if (!write_string(fd
, str
))
534 if (ladish_dict_is_empty(dict
))
536 if (!write_string(fd
, "\" />\n"))
543 if (!write_string(fd
, "\">\n"))
548 if (!write_dict(fd
, " ", dict
))
553 if (!write_string(fd
, " </connection>\n"))
562 bool save_studio_app(void * context
, const char * name
, bool running
, const char * command
, bool terminal
, uint8_t level
)
565 const char * unescaped_string
;
566 char * escaped_string
;
567 char * escaped_buffer
;
570 log_info("saving app: name='%s', %srunning, %s, level %u, commandline='%s'", name
, running
? "" : "not ", terminal
? "terminal" : "shell", (unsigned int)level
, command
);
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.");
581 if (!write_string(fd
, " <application name=\""))
586 unescaped_string
= name
;
587 escaped_string
= escaped_buffer
;
588 escape(&unescaped_string
, &escaped_string
);
590 if (!write_string(fd
, escaped_buffer
))
595 if (!write_string(fd
, "\" terminal=\""))
600 if (!write_string(fd
, terminal
? "true" : "false"))
605 if (!write_string(fd
, "\" level=\""))
610 sprintf(buf
, "%u", (unsigned int)level
);
612 if (!write_string(fd
, buf
))
617 if (!write_string(fd
, "\" autorun=\""))
622 if (!write_string(fd
, running
? "true" : "false"))
627 if (!write_string(fd
, "\">"))
632 unescaped_string
= command
;
633 escaped_string
= escaped_buffer
;
634 escape(&unescaped_string
, &escaped_string
);
636 if (!write_string(fd
, escaped_buffer
))
641 if (!write_string(fd
, "</application>\n"))
649 free(escaped_buffer
);
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
;
666 char timestamp_str
[26];
668 char * filename
; /* filename */
669 char * bak_filename
; /* filename of the backup file */
670 char * old_filename
; /* filename where studio was persisted before save */
672 struct save_context save_context
;
674 ASSERT(cmd_ptr
->state
== LADISH_COMMAND_STATE_PENDING
);
677 ctime_r(×tamp
, timestamp_str
);
678 timestamp_str
[24] = 0;
682 if (!studio_is_started())
684 log_error("Cannot save not-started studio");
688 if (!studio_compose_filename(g_studio
.name
, &filename
, &bak_filename
))
690 log_error("failed to compose studio filename");
694 if (g_studio
.filename
== NULL
)
696 /* saving studio for first time */
697 g_studio
.filename
= filename
;
702 else if (strcmp(g_studio
.filename
, filename
) == 0)
704 /* saving already persisted studio that was not renamed */
705 old_filename
= filename
;
709 /* saving renamed studio */
710 old_filename
= g_studio
.filename
;
711 g_studio
.filename
= filename
;
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
));
733 /* mark that there is no backup file */
739 log_info("saving studio... (%s)", g_studio
.filename
);
741 fd
= open(g_studio
.filename
, O_WRONLY
| O_TRUNC
| O_CREAT
, 0700);
744 log_error("open(%s) failed: %d (%s)", g_studio
.filename
, errno
, strerror(errno
));
748 if (!write_string(fd
, "<?xml version=\"1.0\"?>\n"))
753 if (!write_string(fd
, "<!--\n"))
758 if (!write_string(fd
, STUDIO_HEADER_TEXT
))
763 if (!write_string(fd
, "-->\n"))
768 if (!write_string(fd
, "<!-- "))
773 if (!write_string(fd
, timestamp_str
))
778 if (!write_string(fd
, " -->\n"))
783 if (!write_string(fd
, "<studio>\n"))
788 if (!write_string(fd
, " <jack>\n"))
793 if (!write_string(fd
, " <conf>\n"))
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
))
808 if (!write_string(fd
, " </conf>\n"))
813 if (!write_string(fd
, " <clients>\n"))
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");
826 if (!write_string(fd
, " </clients>\n"))
831 if (!write_string(fd
, " </jack>\n"))
836 if (!write_string(fd
, " <clients>\n"))
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");
847 if (!write_string(fd
, " </clients>\n"))
852 if (!write_string(fd
, " <connections>\n"))
857 if (!ladish_graph_iterate_connections(g_studio
.studio_graph
, &save_context
, save_studio_connection
))
859 log_error("ladish_graph_iterate_connections() failed");
863 if (!write_string(fd
, " </connections>\n"))
868 if (!write_string(fd
, " <applications>\n"))
873 if (!ladish_app_supervisor_enum(g_studio
.app_supervisor
, &save_context
, save_studio_app
))
878 if (!write_string(fd
, " </applications>\n"))
883 if (!write_dict(fd
, " ", ladish_graph_get_dict(g_studio
.studio_graph
)))
888 if (!write_string(fd
, "</studio>\n"))
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
;
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
));
915 if (bak_filename
!= NULL
)
920 if (old_filename
!= NULL
)
925 ASSERT(filename
== NULL
);
926 ASSERT(g_studio
.filename
!= NULL
);
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
));
941 log_error("ladish_command_new() failed.");
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
;
955 fail_destroy_command
: