jackdbus.html: remove http-only badges
[jackdbus.git] / dbus / jackdbus.c
blob5f2000a377531cd648ed61cfc06532274f597def
1 /* -*- Mode: C ; c-basic-offset: 4 -*- */
2 /*
3 Copyright (C) 2007,2008,2010 Nedko Arnaudov
4 Copyright (C) 2007-2008 Juuso Alasuutari
5 Copyright (C) 2008 Marc-Olivier Barre
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #if defined(HAVE_CONFIG_H)
23 #include "config.h"
24 #endif
26 #include <stdbool.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30 #include <errno.h>
31 #include <sys/stat.h>
32 #include <signal.h>
33 #include <dbus/dbus.h>
34 #include <pthread.h>
35 #include <unistd.h>
37 #include "config.h"
39 #include "jackdbus.h"
40 #include "controller.h"
41 #include "jack/jack.h"
42 #include "jack/jslist.h"
43 #include "jack/control.h"
44 #include "sigsegv.h"
46 static char * g_log_filename;
47 static ino_t g_log_file_ino;
48 FILE *g_logfile;
49 char *g_jackdbus_config_dir;
50 size_t g_jackdbus_config_dir_len; /* without terminating '\0' char */
51 char *g_jackdbus_log_dir;
52 size_t g_jackdbus_log_dir_len; /* without terminating '\0' char */
53 int g_exit_command;
54 DBusConnection *g_connection;
56 void
57 jack_dbus_send_signal(
58 const char *sender_object_path,
59 const char *iface,
60 const char *signal_name,
61 int first_arg_type,
62 ...)
64 DBusMessage *message_ptr;
65 va_list ap;
67 va_start(ap, first_arg_type);
69 message_ptr = dbus_message_new_signal(sender_object_path, iface, signal_name);
70 if (message_ptr == NULL)
72 jack_error("dbus_message_new_signal() failed.");
73 goto exit;
76 if (!dbus_message_append_args_valist(message_ptr, first_arg_type, ap))
78 jack_error("dbus_message_append_args_valist() failed.");
79 goto unref;
82 /* Add message to outgoing message queue */
83 if (!dbus_connection_send(g_connection, message_ptr, NULL))
85 jack_error("dbus_connection_send() failed.");
86 goto unref;
89 unref:
90 dbus_message_unref(message_ptr);
92 exit:
93 va_end(ap);
97 * Send a method return.
99 * If call->reply is NULL (i.e. a message construct method failed
100 * due to lack of memory) attempt to send a void method return.
102 static
103 void
104 jack_dbus_send_method_return(
105 struct jack_dbus_method_call * call)
107 if (call->message == NULL)
109 /* async call */
110 return;
113 if (call->reply)
115 retry_send:
116 if (!dbus_connection_send (call->connection, call->reply, NULL))
118 jack_error ("Ran out of memory trying to queue method return");
121 dbus_connection_flush (call->connection);
122 dbus_message_unref (call->reply);
123 call->reply = NULL;
125 else
127 jack_error ("send_method_return() called with a NULL message,"
128 " trying to construct a void return...");
130 if ((call->reply = dbus_message_new_method_return (call->message)))
132 goto retry_send;
134 else
136 jack_error ("Failed to construct method return!");
141 #define object_ptr ((struct jack_dbus_object_descriptor *)data)
144 * The D-Bus message handler for object path /org/jackaudio/Controller.
146 DBusHandlerResult
147 jack_dbus_message_handler(
148 DBusConnection *connection,
149 DBusMessage *message,
150 void *data)
152 struct jack_dbus_method_call call;
153 const char *interface_name;
154 struct jack_dbus_interface_descriptor ** interface_ptr_ptr;
156 /* Check if the message is a method call. If not, ignore it. */
157 if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
159 goto handled;
162 /* Get the invoked method's name and make sure it's non-NULL. */
163 if (!(call.method_name = dbus_message_get_member (message)))
165 jack_dbus_error(
166 &call,
167 JACK_DBUS_ERROR_UNKNOWN_METHOD,
168 "Received method call with empty method name");
169 goto send_return;
172 /* Initialize our data. */
173 call.context = object_ptr->context;
174 call.connection = connection;
175 call.message = message;
176 call.reply = NULL;
178 /* Check if there's an interface specified for this method call. */
179 interface_name = dbus_message_get_interface (message);
180 if (interface_name != NULL)
182 /* Check if we can match the interface and method.
183 * The interface handler functions only return false if the
184 * method name was unknown, otherwise they run the specified
185 * method and return TRUE.
188 interface_ptr_ptr = object_ptr->interfaces;
190 while (*interface_ptr_ptr != NULL)
192 if (strcmp(interface_name, (*interface_ptr_ptr)->name) == 0)
194 if (!(*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
196 break;
199 goto send_return;
202 interface_ptr_ptr++;
205 else
207 /* No interface was specified so we have to try them all. This is
208 * dictated by the D-Bus specification which states that method calls
209 * omitting the interface must never be rejected.
212 interface_ptr_ptr = object_ptr->interfaces;
214 while (*interface_ptr_ptr != NULL)
216 if ((*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
218 goto send_return;
221 interface_ptr_ptr++;
225 jack_dbus_error(
226 &call,
227 JACK_DBUS_ERROR_UNKNOWN_METHOD,
228 "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist",
229 call.method_name,
230 dbus_message_get_signature(message),
231 interface_name);
233 send_return:
234 jack_dbus_send_method_return(&call);
236 handled:
237 return DBUS_HANDLER_RESULT_HANDLED;
240 void
241 jack_dbus_message_handler_unregister(
242 DBusConnection *connection,
243 void *data)
245 jack_info ("Message handler was unregistered");
248 #undef object_ptr
251 * Check if the supplied method name exists in org.jackaudio.JackConfigure,
252 * if it does execute it and return TRUE. Otherwise return FALSE.
254 bool
255 jack_dbus_run_method(
256 struct jack_dbus_method_call *call,
257 const struct jack_dbus_interface_method_descriptor * methods)
259 const struct jack_dbus_interface_method_descriptor * method_ptr;
261 method_ptr = methods;
263 while (method_ptr->name != NULL)
265 if (strcmp(call->method_name, method_ptr->name) == 0)
267 method_ptr->handler(call);
268 return TRUE;
271 method_ptr++;
274 return FALSE;
278 * Read arguments from a method call.
279 * If the operation fails construct an error and return false,
280 * otherwise return true.
282 bool
283 jack_dbus_get_method_args(
284 struct jack_dbus_method_call *call,
285 int type,
286 ...)
288 va_list args;
289 DBusError error;
290 bool retval = true;
292 va_start (args, type);
293 dbus_error_init (&error);
295 if (!dbus_message_get_args_valist (call->message, &error, type, args))
297 jack_dbus_error (call, JACK_DBUS_ERROR_INVALID_ARGS,
298 "Invalid arguments to method \"%s\"",
299 call->method_name);
300 retval = false;
303 dbus_error_free (&error);
304 va_end (args);
306 return retval;
310 * Read a string and a variant argument from a method call.
311 * If the operation fails construct an error and return false,
312 * otherwise return true.
314 bool
315 jack_dbus_get_method_args_string_and_variant(
316 struct jack_dbus_method_call *call,
317 const char **arg1,
318 message_arg_t *arg2,
319 int *type_ptr)
321 DBusMessageIter iter, sub_iter;
323 /* First we want a string... */
324 if (dbus_message_iter_init (call->message, &iter)
325 && dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING)
327 dbus_message_iter_get_basic (&iter, arg1);
328 dbus_message_iter_next (&iter);
330 /* ...and then a variant. */
331 if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_VARIANT)
333 dbus_message_iter_recurse (&iter, &sub_iter);
334 dbus_message_iter_get_basic (&sub_iter, arg2);
335 *type_ptr = dbus_message_iter_get_arg_type (&sub_iter);
337 /* Got what we wanted. */
338 return true;
342 jack_dbus_error (call, JACK_DBUS_ERROR_INVALID_ARGS,
343 "Invalid arguments to method \"%s\"",
344 call->method_name);
346 return false;
350 * Read two strings and a variant argument from a method call.
351 * If the operation fails construct an error and return false,
352 * otherwise return true.
354 bool
355 jack_dbus_get_method_args_two_strings_and_variant(
356 struct jack_dbus_method_call *call,
357 const char **arg1,
358 const char **arg2,
359 message_arg_t *arg3,
360 int *type_ptr)
362 DBusMessageIter iter, sub_iter;
364 /* First we want a string... */
365 if (dbus_message_iter_init (call->message, &iter)
366 && dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING)
368 dbus_message_iter_get_basic (&iter, arg1);
369 dbus_message_iter_next (&iter);
371 /* ...and then a second string. */
372 if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING)
374 return false;
377 /* Got what we wanted. */
378 dbus_message_iter_get_basic (&iter, arg2);
379 dbus_message_iter_next (&iter);
381 /* ...and then a variant. */
382 if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_VARIANT)
384 dbus_message_iter_recurse (&iter, &sub_iter);
385 dbus_message_iter_get_basic (&sub_iter, arg3);
386 *type_ptr = dbus_message_iter_get_arg_type (&sub_iter);
388 /* Got what we wanted. */
389 return true;
393 jack_dbus_error (call, JACK_DBUS_ERROR_INVALID_ARGS,
394 "Invalid arguments to method \"%s\"",
395 call->method_name);
397 return false;
401 * Append a variant type to a D-Bus message.
402 * Return false if something fails, true otherwise.
404 bool
405 jack_dbus_message_append_variant(
406 DBusMessageIter *iter,
407 int type,
408 const char *signature,
409 message_arg_t *arg)
411 DBusMessageIter sub_iter;
413 /* Open a variant container. */
414 if (!dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, signature, &sub_iter))
416 goto fail;
419 /* Append the supplied value. */
420 if (!dbus_message_iter_append_basic (&sub_iter, type, (const void *) arg))
422 dbus_message_iter_close_container (iter, &sub_iter);
423 goto fail;
426 /* Close the container. */
427 if (!dbus_message_iter_close_container (iter, &sub_iter))
429 goto fail;
432 return true;
434 fail:
435 return false;
439 * Construct an empty method return message.
441 * The operation can only fail due to lack of memory, in which case
442 * there's no sense in trying to construct an error return. Instead,
443 * call->reply will be set to NULL and handled in send_method_return().
445 void
446 jack_dbus_construct_method_return_empty(
447 struct jack_dbus_method_call * call)
449 call->reply = dbus_message_new_method_return (call->message);
451 if (call->reply == NULL)
453 jack_error ("Ran out of memory trying to construct method return");
458 * Construct a method return which holds a single argument or, if
459 * the type parameter is DBUS_TYPE_INVALID, no arguments at all
460 * (a void message).
462 * The operation can only fail due to lack of memory, in which case
463 * there's no sense in trying to construct an error return. Instead,
464 * call->reply will be set to NULL and handled in send_method_return().
466 void
467 jack_dbus_construct_method_return_single(
468 struct jack_dbus_method_call *call,
469 int type,
470 message_arg_t arg)
472 DBusMessageIter iter;
473 call->reply = dbus_message_new_method_return (call->message);
475 if (call->reply == NULL)
477 goto fail_no_mem;
480 /* Void method return requested by caller. */
481 if (type == DBUS_TYPE_INVALID)
483 return;
486 /* Prevent crash on NULL input string. */
487 else if (type == DBUS_TYPE_STRING && arg.string == NULL)
489 arg.string = "";
492 dbus_message_iter_init_append (call->reply, &iter);
494 if (!dbus_message_iter_append_basic (&iter, type, (const void *) &arg))
496 dbus_message_unref (call->reply);
497 call->reply = NULL;
498 goto fail_no_mem;
501 return;
503 fail_no_mem:
504 jack_error ("Ran out of memory trying to construct method return");
508 * Construct a method return which holds an array of strings.
510 * The operation can only fail due to lack of memory, in which case
511 * there's no sense in trying to construct an error return. Instead,
512 * call->reply will be set to NULL and handled in send_method_return().
514 void
515 jack_dbus_construct_method_return_array_of_strings(
516 struct jack_dbus_method_call *call,
517 unsigned int num_members,
518 const char **array)
520 DBusMessageIter iter, sub_iter;
521 unsigned int i;
523 call->reply = dbus_message_new_method_return (call->message);
524 if (!call->reply)
526 goto fail;
529 dbus_message_iter_init_append (call->reply, &iter);
531 if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
533 goto fail_unref;
536 for (i = 0; i < num_members; ++i)
538 if (!dbus_message_iter_append_basic (&sub_iter, DBUS_TYPE_STRING, (const void *) &array[i]))
540 dbus_message_iter_close_container (&iter, &sub_iter);
541 goto fail_unref;
545 if (!dbus_message_iter_close_container (&iter, &sub_iter))
547 goto fail_unref;
550 return;
552 fail_unref:
553 dbus_message_unref (call->reply);
554 call->reply = NULL;
556 fail:
557 jack_error ("Ran out of memory trying to construct method return");
560 static bool jack_dbus_log_open(void)
562 struct stat st;
563 int ret;
564 int retry;
566 if (g_logfile != NULL)
568 ret = stat(g_log_filename, &st);
569 if (ret != 0 || g_log_file_ino != st.st_ino)
571 fclose(g_logfile);
573 else
575 return true;
579 for (retry = 0; retry < 10; retry++)
581 g_logfile = fopen(g_log_filename, "a");
582 if (g_logfile == NULL)
584 fprintf(stderr, "Cannot open jackdbus log file \"%s\": %d (%s)\n", g_log_filename, errno, strerror(errno));
585 return false;
588 ret = stat(g_log_filename, &st);
589 if (ret == 0)
591 g_log_file_ino = st.st_ino;
592 return true;
595 fclose(g_logfile);
596 g_logfile = NULL;
599 fprintf(stderr, "Cannot stat just opened jackdbus log file \"%s\": %d (%s). %d retries\n", g_log_filename, errno, strerror(errno), retry);
600 return false;
603 void
604 jack_dbus_info_callback(const char *msg)
606 time_t timestamp;
607 char timestamp_str[26];
609 time(&timestamp);
610 ctime_r(&timestamp, timestamp_str);
611 timestamp_str[24] = 0;
613 if (jack_dbus_log_open())
615 fprintf(g_logfile, "%s: %s\n", timestamp_str, msg);
616 fflush(g_logfile);
620 #define ANSI_BOLD_ON "\033[1m"
621 #define ANSI_BOLD_OFF "\033[22m"
622 #define ANSI_COLOR_RED "\033[31m"
623 #define ANSI_RESET "\033[0m"
625 void
626 jack_dbus_error_callback(const char *msg)
628 time_t timestamp;
629 char timestamp_str[26];
631 time(&timestamp);
632 ctime_r(&timestamp, timestamp_str);
633 timestamp_str[24] = 0;
635 if (jack_dbus_log_open())
637 fprintf(g_logfile, "%s: " ANSI_BOLD_ON ANSI_COLOR_RED "ERROR: %s" ANSI_RESET "\n", timestamp_str, msg);
638 fflush(g_logfile);
642 bool
643 ensure_dir_exist(const char *dirname, int mode)
645 struct stat st;
646 if (stat(dirname, &st) != 0)
648 if (errno == ENOENT)
650 printf("Directory \"%s\" does not exist. Creating...\n", dirname);
651 if (mkdir(dirname, mode) != 0)
653 fprintf(stderr, "Failed to create \"%s\" directory: %d (%s)\n", dirname, errno, strerror(errno));
654 return false;
657 else
659 fprintf(stderr, "Failed to stat \"%s\": %d (%s)\n", dirname, errno, strerror(errno));
660 return false;
663 else
665 if (!S_ISDIR(st.st_mode))
667 fprintf(stderr, "\"%s\" exists but is not directory.\n", dirname);
668 return false;
671 return true;
674 char *
675 pathname_cat(const char *pathname_a, const char *pathname_b)
677 char *pathname;
678 int pathname_a_len, pathname_b_len, pathname_len;
679 pathname_a_len = strlen(pathname_a);
680 pathname_b_len = strlen(pathname_b);
681 pathname = malloc(pathname_a_len + pathname_b_len + 1);
682 if (pathname == NULL)
684 fprintf(stderr, "Out of memory\n");
685 return NULL;
687 memcpy(pathname, pathname_a, pathname_a_len);
688 memcpy(pathname + pathname_a_len, pathname_b, pathname_b_len);
689 pathname_len = pathname_a_len + pathname_b_len;
690 pathname[pathname_len] = 0;
691 return pathname;
694 bool
695 paths_init()
697 const char *home_dir, *xdg_config_home, *xdg_log_home;
699 home_dir = getenv("HOME");
700 if (home_dir == NULL)
702 fprintf(stderr, "Environment variable HOME not set\n");
703 goto fail;
706 xdg_config_home = getenv("XDG_CONFIG_HOME");
707 if (xdg_config_home == NULL)
709 if (!(xdg_config_home = pathname_cat(home_dir, DEFAULT_XDG_CONFIG))) goto fail;
712 if (!(xdg_log_home = pathname_cat(home_dir, DEFAULT_XDG_LOG))) goto fail;
714 if (!(g_jackdbus_config_dir = pathname_cat(xdg_config_home, JACKDBUS_DIR))) goto fail;
715 if (!(g_jackdbus_log_dir = pathname_cat(xdg_log_home, JACKDBUS_DIR))) goto fail;
717 if (!ensure_dir_exist(xdg_config_home, 0700))
719 goto fail;
722 if (!ensure_dir_exist(xdg_log_home, 0700))
724 goto fail;
727 if (!ensure_dir_exist(g_jackdbus_config_dir, 0700))
729 free(g_jackdbus_config_dir);
730 goto fail;
732 g_jackdbus_config_dir_len = strlen(g_jackdbus_config_dir);
734 if (!ensure_dir_exist(g_jackdbus_log_dir, 0700))
736 free(g_jackdbus_log_dir);
737 goto fail;
739 g_jackdbus_log_dir_len = strlen(g_jackdbus_log_dir);
741 return true;
743 fail:
744 return false;
747 void
748 paths_uninit()
750 free(g_jackdbus_config_dir);
751 free(g_jackdbus_log_dir);
754 static bool log_init(void)
756 size_t log_len;
758 log_len = strlen(JACKDBUS_LOG);
760 g_log_filename = malloc(g_jackdbus_log_dir_len + log_len + 1);
761 if (g_log_filename == NULL)
763 fprintf(stderr, "Out of memory\n");
764 return false;
767 memcpy(g_log_filename, g_jackdbus_log_dir, g_jackdbus_log_dir_len);
768 memcpy(g_log_filename + g_jackdbus_log_dir_len, JACKDBUS_LOG, log_len);
769 g_log_filename[g_jackdbus_log_dir_len + log_len] = 0;
771 if (!jack_dbus_log_open())
773 return false;
776 return true;
779 static void log_uninit(void)
781 if (g_logfile != NULL)
783 fclose(g_logfile);
786 free(g_log_filename);
789 void
790 jack_dbus_error(
791 void *dbus_call_context_ptr,
792 const char *error_name,
793 const char *format,
794 ...)
796 va_list ap;
797 char buffer[300];
799 va_start(ap, format);
801 vsnprintf(buffer, sizeof(buffer), format, ap);
803 jack_error_callback(buffer);
804 if (dbus_call_context_ptr != NULL)
806 if (((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply != NULL)
808 dbus_message_unref(((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply);
809 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply = NULL;
812 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply = dbus_message_new_error(
813 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->message,
814 error_name,
815 buffer);
818 va_end(ap);
821 void
822 jack_dbus_only_error(
823 void *dbus_call_context_ptr,
824 const char *error_name,
825 const char *format,
826 ...)
828 va_list ap;
829 char buffer[300];
831 va_start(ap, format);
833 vsnprintf(buffer, sizeof(buffer), format, ap);
835 if (((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply != NULL)
837 dbus_message_unref(((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply);
838 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply = NULL;
841 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply = dbus_message_new_error(
842 ((struct jack_dbus_method_call *)dbus_call_context_ptr)->message,
843 error_name,
844 buffer);
846 va_end(ap);
850 main (int argc, char **argv)
852 DBusError error;
853 int ret;
854 void *controller_ptr;
855 struct stat st;
856 char timestamp_str[26];
858 st.st_mtime = 0;
859 stat(argv[0], &st);
860 ctime_r(&st.st_mtime, timestamp_str);
861 timestamp_str[24] = 0;
863 if (!jack_controller_settings_init())
865 ret = 1;
866 goto fail;
869 if (argc != 2 || strcmp(argv[1], "auto") != 0)
871 ret = 0;
872 fprintf(
873 stderr,
874 "jackdbus should be auto-executed by D-Bus message bus daemon.\n"
875 "If you want to run it manually anyway, specify \"auto\" as only parameter\n");
876 goto fail_uninit_xml;
879 if (!paths_init())
881 ret = 1;
882 goto fail_uninit_xml;
885 if (!log_init())
887 ret = 1;
888 goto fail_uninit_paths;
891 #if !defined(DISABLE_SIGNAL_MAGIC)
892 jackctl_setup_signals(0);
893 #endif
895 jack_set_error_function(jack_dbus_error_callback);
896 jack_set_info_function(jack_dbus_info_callback);
898 /* setup our SIGSEGV magic that prints nice stack in our logfile */
899 setup_sigsegv();
901 jack_info("------------------");
902 jack_info("Controller activated. Version %s (%s) built on %s", jack_get_version_string(), JACK_VERSION, timestamp_str);
904 if (!dbus_threads_init_default())
906 jack_error("dbus_threads_init_default() failed");
907 ret = 1;
908 goto fail_uninit_log;
911 dbus_error_init (&error);
912 g_connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
913 if (dbus_error_is_set (&error))
915 jack_error("Cannot connect to D-Bus session bus: %s", error.message);
916 ret = 1;
917 goto fail_uninit_log;
920 ret = dbus_bus_request_name(
921 g_connection,
922 "org.jackaudio.service",
923 DBUS_NAME_FLAG_DO_NOT_QUEUE,
924 &error);
925 if (ret == -1)
927 jack_error("Cannot request service name: %s", error.message);
928 dbus_error_free(&error);
929 ret = 1;
930 goto fail_unref_connection;
932 else if (ret == DBUS_REQUEST_NAME_REPLY_EXISTS)
934 jack_error("Requested D-Bus service name already exists");
935 ret = 1;
936 goto fail_unref_connection;
939 controller_ptr = jack_controller_create(g_connection);
941 if (controller_ptr == NULL)
943 ret = 1;
944 goto fail_unref_connection;
947 jack_info("Listening for D-Bus messages");
949 g_exit_command = FALSE;
950 while (!g_exit_command && dbus_connection_read_write_dispatch (g_connection, 200))
952 jack_controller_run(controller_ptr);
955 jack_controller_destroy(controller_ptr);
957 jack_info("Controller deactivated.");
959 ret = 0;
961 fail_unref_connection:
962 dbus_connection_unref(g_connection);
964 fail_uninit_log:
965 log_uninit();
967 fail_uninit_paths:
968 paths_uninit();
970 fail_uninit_xml:
971 jack_controller_settings_uninit();
973 fail:
974 return ret;