jack2 codebase
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

834 lines
20KB

  1. /* -*- Mode: C ; c-basic-offset: 4 -*- */
  2. /*
  3. Copyright (C) 2007,2008 Nedko Arnaudov
  4. Copyright (C) 2007-2008 Juuso Alasuutari
  5. Copyright (C) 2008 Marc-Olivier Barre
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 2 of the License.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. */
  17. #if defined(HAVE_CONFIG_H)
  18. #include "config.h"
  19. #endif
  20. #include <stdbool.h>
  21. #include <stdlib.h>
  22. #include <stdio.h>
  23. #include <string.h>
  24. #include <errno.h>
  25. #include <sys/stat.h>
  26. #include <signal.h>
  27. #include <dbus/dbus.h>
  28. #include <pthread.h>
  29. #include <unistd.h>
  30. #include "config.h"
  31. #include "jackdbus.h"
  32. #include "controller.h"
  33. #include "jack/jack.h"
  34. #include "jack/jslist.h"
  35. #include "jack/control.h"
  36. #include "sigsegv.h"
  37. FILE *g_logfile;
  38. char *g_jackdbus_config_dir;
  39. size_t g_jackdbus_config_dir_len; /* without terminating '\0' char */
  40. char *g_jackdbus_log_dir;
  41. size_t g_jackdbus_log_dir_len; /* without terminating '\0' char */
  42. int g_exit_command;
  43. DBusConnection *g_connection;
  44. void
  45. jack_dbus_send_signal(
  46. const char *sender_object_path,
  47. const char *iface,
  48. const char *signal_name,
  49. int first_arg_type,
  50. ...)
  51. {
  52. DBusMessage *message_ptr;
  53. va_list ap;
  54. va_start(ap, first_arg_type);
  55. message_ptr = dbus_message_new_signal(sender_object_path, iface, signal_name);
  56. if (message_ptr == NULL)
  57. {
  58. jack_error("dbus_message_new_signal() failed.");
  59. goto exit;
  60. }
  61. if (!dbus_message_append_args_valist(message_ptr, first_arg_type, ap))
  62. {
  63. jack_error("dbus_message_append_args_valist() failed.");
  64. goto unref;
  65. }
  66. /* Add message to outgoing message queue */
  67. if (!dbus_connection_send(g_connection, message_ptr, NULL))
  68. {
  69. jack_error("dbus_connection_send() failed.");
  70. goto unref;
  71. }
  72. unref:
  73. dbus_message_unref(message_ptr);
  74. exit:
  75. va_end(ap);
  76. }
  77. /*
  78. * Send a method return.
  79. *
  80. * If call->reply is NULL (i.e. a message construct method failed
  81. * due to lack of memory) attempt to send a void method return.
  82. */
  83. static
  84. void
  85. jack_dbus_send_method_return(
  86. struct jack_dbus_method_call * call)
  87. {
  88. if (call->reply)
  89. {
  90. retry_send:
  91. if (!dbus_connection_send (call->connection, call->reply, NULL))
  92. {
  93. jack_error ("Ran out of memory trying to queue method return");
  94. }
  95. dbus_connection_flush (call->connection);
  96. dbus_message_unref (call->reply);
  97. call->reply = NULL;
  98. }
  99. else
  100. {
  101. jack_error ("send_method_return() called with a NULL message,"
  102. " trying to construct a void return...");
  103. if ((call->reply = dbus_message_new_method_return (call->message)))
  104. {
  105. goto retry_send;
  106. }
  107. else
  108. {
  109. jack_error ("Failed to construct method return!");
  110. }
  111. }
  112. }
  113. #define object_ptr ((struct jack_dbus_object_descriptor *)data)
  114. /*
  115. * The D-Bus message handler for object path /org/jackaudio/Controller.
  116. */
  117. DBusHandlerResult
  118. jack_dbus_message_handler(
  119. DBusConnection *connection,
  120. DBusMessage *message,
  121. void *data)
  122. {
  123. struct jack_dbus_method_call call;
  124. const char *interface_name;
  125. struct jack_dbus_interface_descriptor ** interface_ptr_ptr;
  126. /* Check if the message is a method call. If not, ignore it. */
  127. if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_METHOD_CALL)
  128. {
  129. goto handled;
  130. }
  131. /* Get the invoked method's name and make sure it's non-NULL. */
  132. if (!(call.method_name = dbus_message_get_member (message)))
  133. {
  134. jack_dbus_error(
  135. &call,
  136. JACK_DBUS_ERROR_UNKNOWN_METHOD,
  137. "Received method call with empty method name");
  138. goto send_return;
  139. }
  140. /* Initialize our data. */
  141. call.context = object_ptr->context;
  142. call.connection = connection;
  143. call.message = message;
  144. call.reply = NULL;
  145. /* Check if there's an interface specified for this method call. */
  146. interface_name = dbus_message_get_interface (message);
  147. if (interface_name != NULL)
  148. {
  149. /* Check if we can match the interface and method.
  150. * The inteface handler functions only return false if the
  151. * method name was unknown, otherwise they run the specified
  152. * method and return TRUE.
  153. */
  154. interface_ptr_ptr = object_ptr->interfaces;
  155. while (*interface_ptr_ptr != NULL)
  156. {
  157. if (strcmp(interface_name, (*interface_ptr_ptr)->name) == 0)
  158. {
  159. if (!(*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
  160. {
  161. break;
  162. }
  163. goto send_return;
  164. }
  165. interface_ptr_ptr++;
  166. }
  167. }
  168. else
  169. {
  170. /* No interface was specified so we have to try them all. This is
  171. * dictated by the D-Bus specification which states that method calls
  172. * omitting the interface must never be rejected.
  173. */
  174. interface_ptr_ptr = object_ptr->interfaces;
  175. while (*interface_ptr_ptr != NULL)
  176. {
  177. if ((*interface_ptr_ptr)->handler(&call, (*interface_ptr_ptr)->methods))
  178. {
  179. goto send_return;
  180. }
  181. interface_ptr_ptr++;
  182. }
  183. }
  184. jack_dbus_error(
  185. &call,
  186. JACK_DBUS_ERROR_UNKNOWN_METHOD,
  187. "Method \"%s\" with signature \"%s\" on interface \"%s\" doesn't exist",
  188. call.method_name,
  189. dbus_message_get_signature(message),
  190. interface_name);
  191. send_return:
  192. jack_dbus_send_method_return(&call);
  193. handled:
  194. return DBUS_HANDLER_RESULT_HANDLED;
  195. }
  196. void
  197. jack_dbus_message_handler_unregister(
  198. DBusConnection *connection,
  199. void *data)
  200. {
  201. jack_info ("Message handler was unregistered");
  202. }
  203. #undef object_ptr
  204. /*
  205. * Check if the supplied method name exists in org.jackaudio.JackConfigure,
  206. * if it does execute it and return TRUE. Otherwise return FALSE.
  207. */
  208. bool
  209. jack_dbus_run_method(
  210. struct jack_dbus_method_call *call,
  211. const struct jack_dbus_interface_method_descriptor * methods)
  212. {
  213. const struct jack_dbus_interface_method_descriptor * method_ptr;
  214. method_ptr = methods;
  215. while (method_ptr->name != NULL)
  216. {
  217. if (strcmp(call->method_name, method_ptr->name) == 0)
  218. {
  219. method_ptr->handler(call);
  220. return TRUE;
  221. }
  222. method_ptr++;
  223. }
  224. return FALSE;
  225. }
  226. /*
  227. * Read arguments from a method call.
  228. * If the operation fails construct an error and return false,
  229. * otherwise return true.
  230. */
  231. bool
  232. jack_dbus_get_method_args(
  233. struct jack_dbus_method_call *call,
  234. int type,
  235. ...)
  236. {
  237. va_list args;
  238. DBusError error;
  239. bool retval = true;
  240. va_start (args, type);
  241. dbus_error_init (&error);
  242. if (!dbus_message_get_args_valist (call->message, &error, type, args))
  243. {
  244. jack_dbus_error (call, JACK_DBUS_ERROR_INVALID_ARGS,
  245. "Invalid arguments to method \"%s\"",
  246. call->method_name);
  247. retval = false;
  248. }
  249. dbus_error_free (&error);
  250. va_end (args);
  251. return retval;
  252. }
  253. /*
  254. * Read a string and a variant argument from a method call.
  255. * If the operation fails construct an error and return false,
  256. * otherwise return true.
  257. */
  258. bool
  259. jack_dbus_get_method_args_string_and_variant(
  260. struct jack_dbus_method_call *call,
  261. const char **arg1,
  262. message_arg_t *arg2,
  263. int *type_ptr)
  264. {
  265. DBusMessageIter iter, sub_iter;
  266. /* First we want a string... */
  267. if (dbus_message_iter_init (call->message, &iter)
  268. && dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_STRING)
  269. {
  270. dbus_message_iter_get_basic (&iter, arg1);
  271. dbus_message_iter_next (&iter);
  272. /* ...and then a variant. */
  273. if (dbus_message_iter_get_arg_type (&iter) == DBUS_TYPE_VARIANT)
  274. {
  275. dbus_message_iter_recurse (&iter, &sub_iter);
  276. dbus_message_iter_get_basic (&sub_iter, arg2);
  277. *type_ptr = dbus_message_iter_get_arg_type (&sub_iter);
  278. /* Got what we wanted. */
  279. return true;
  280. }
  281. }
  282. jack_dbus_error (call, JACK_DBUS_ERROR_INVALID_ARGS,
  283. "Invalid arguments to method \"%s\"",
  284. call->method_name);
  285. return false;
  286. }
  287. /*
  288. * Append a variant type to a D-Bus message.
  289. * Return false if something fails, true otherwise.
  290. */
  291. bool
  292. jack_dbus_message_append_variant(
  293. DBusMessageIter *iter,
  294. int type,
  295. const char *signature,
  296. message_arg_t *arg)
  297. {
  298. DBusMessageIter sub_iter;
  299. /* Open a variant container. */
  300. if (!dbus_message_iter_open_container (iter, DBUS_TYPE_VARIANT, signature, &sub_iter))
  301. {
  302. goto fail;
  303. }
  304. /* Append the supplied value. */
  305. if (!dbus_message_iter_append_basic (&sub_iter, type, (const void *) arg))
  306. {
  307. dbus_message_iter_close_container (iter, &sub_iter);
  308. goto fail;
  309. }
  310. /* Close the container. */
  311. if (!dbus_message_iter_close_container (iter, &sub_iter))
  312. {
  313. goto fail;
  314. }
  315. return true;
  316. fail:
  317. return false;
  318. }
  319. /*
  320. * Construct an empty method return message.
  321. *
  322. * The operation can only fail due to lack of memory, in which case
  323. * there's no sense in trying to construct an error return. Instead,
  324. * call->reply will be set to NULL and handled in send_method_return().
  325. */
  326. void
  327. jack_dbus_construct_method_return_empty(
  328. struct jack_dbus_method_call * call)
  329. {
  330. call->reply = dbus_message_new_method_return (call->message);
  331. if (call->reply == NULL)
  332. {
  333. jack_error ("Ran out of memory trying to construct method return");
  334. }
  335. }
  336. /*
  337. * Construct a method return which holds a single argument or, if
  338. * the type parameter is DBUS_TYPE_INVALID, no arguments at all
  339. * (a void message).
  340. *
  341. * The operation can only fail due to lack of memory, in which case
  342. * there's no sense in trying to construct an error return. Instead,
  343. * call->reply will be set to NULL and handled in send_method_return().
  344. */
  345. void
  346. jack_dbus_construct_method_return_single(
  347. struct jack_dbus_method_call *call,
  348. int type,
  349. message_arg_t arg)
  350. {
  351. DBusMessageIter iter;
  352. call->reply = dbus_message_new_method_return (call->message);
  353. if (call->reply == NULL)
  354. {
  355. goto fail_no_mem;
  356. }
  357. /* Void method return requested by caller. */
  358. if (type == DBUS_TYPE_INVALID)
  359. {
  360. return;
  361. }
  362. /* Prevent crash on NULL input string. */
  363. else if (type == DBUS_TYPE_STRING && arg.string == NULL)
  364. {
  365. arg.string = "";
  366. }
  367. dbus_message_iter_init_append (call->reply, &iter);
  368. if (!dbus_message_iter_append_basic (&iter, type, (const void *) &arg))
  369. {
  370. dbus_message_unref (call->reply);
  371. call->reply = NULL;
  372. goto fail_no_mem;
  373. }
  374. return;
  375. fail_no_mem:
  376. jack_error ("Ran out of memory trying to construct method return");
  377. }
  378. /*
  379. * Construct a method return which holds an array of strings.
  380. *
  381. * The operation can only fail due to lack of memory, in which case
  382. * there's no sense in trying to construct an error return. Instead,
  383. * call->reply will be set to NULL and handled in send_method_return().
  384. */
  385. void
  386. jack_dbus_construct_method_return_array_of_strings(
  387. struct jack_dbus_method_call *call,
  388. unsigned int num_members,
  389. const char **array)
  390. {
  391. DBusMessageIter iter, sub_iter;
  392. unsigned int i;
  393. call->reply = dbus_message_new_method_return (call->message);
  394. if (!call->reply)
  395. {
  396. goto fail;
  397. }
  398. dbus_message_iter_init_append (call->reply, &iter);
  399. if (!dbus_message_iter_open_container (&iter, DBUS_TYPE_ARRAY, "s", &sub_iter))
  400. {
  401. goto fail_unref;
  402. }
  403. for (i = 0; i < num_members; ++i)
  404. {
  405. if (!dbus_message_iter_append_basic (&sub_iter, DBUS_TYPE_STRING, (const void *) &array[i]))
  406. {
  407. dbus_message_iter_close_container (&iter, &sub_iter);
  408. goto fail_unref;
  409. }
  410. }
  411. if (!dbus_message_iter_close_container (&iter, &sub_iter))
  412. {
  413. goto fail_unref;
  414. }
  415. return;
  416. fail_unref:
  417. dbus_message_unref (call->reply);
  418. call->reply = NULL;
  419. fail:
  420. jack_error ("Ran out of memory trying to construct method return");
  421. }
  422. void
  423. jack_dbus_info_callback(const char *msg)
  424. {
  425. time_t timestamp;
  426. char timestamp_str[26];
  427. time(&timestamp);
  428. ctime_r(&timestamp, timestamp_str);
  429. timestamp_str[24] = 0;
  430. fprintf(g_logfile, "%s: %s\n", timestamp_str, msg);
  431. fflush(g_logfile);
  432. }
  433. #define ANSI_BOLD_ON "\033[1m"
  434. #define ANSI_BOLD_OFF "\033[22m"
  435. #define ANSI_COLOR_RED "\033[31m"
  436. #define ANSI_RESET "\033[0m"
  437. void
  438. jack_dbus_error_callback(const char *msg)
  439. {
  440. time_t timestamp;
  441. char timestamp_str[26];
  442. time(&timestamp);
  443. ctime_r(&timestamp, timestamp_str);
  444. timestamp_str[24] = 0;
  445. fprintf(g_logfile, "%s: " ANSI_BOLD_ON ANSI_COLOR_RED "ERROR: %s" ANSI_RESET "\n", timestamp_str, msg);
  446. fflush(g_logfile);
  447. }
  448. bool
  449. ensure_dir_exist(const char *dirname, int mode)
  450. {
  451. struct stat st;
  452. if (stat(dirname, &st) != 0)
  453. {
  454. if (errno == ENOENT)
  455. {
  456. printf("Directory \"%s\" does not exist. Creating...\n", dirname);
  457. if (mkdir(dirname, mode) != 0)
  458. {
  459. fprintf(stderr, "Failed to create \"%s\" directory: %d (%s)\n", dirname, errno, strerror(errno));
  460. return false;
  461. }
  462. }
  463. else
  464. {
  465. fprintf(stderr, "Failed to stat \"%s\": %d (%s)\n", dirname, errno, strerror(errno));
  466. return false;
  467. }
  468. }
  469. else
  470. {
  471. if (!S_ISDIR(st.st_mode))
  472. {
  473. fprintf(stderr, "\"%s\" exists but is not directory.\n", dirname);
  474. return false;
  475. }
  476. }
  477. return true;
  478. }
  479. char *
  480. pathname_cat(const char *pathname_a, const char *pathname_b)
  481. {
  482. char *pathname;
  483. int pathname_a_len, pathname_b_len, pathname_len;
  484. pathname_a_len = strlen(pathname_a);
  485. pathname_b_len = strlen(pathname_b);
  486. pathname = malloc(pathname_a_len + pathname_b_len + 1);
  487. if (pathname == NULL)
  488. {
  489. fprintf(stderr, "Out of memory\n");
  490. return NULL;
  491. }
  492. memcpy(pathname, pathname_a, pathname_a_len);
  493. memcpy(pathname + pathname_a_len, pathname_b, pathname_b_len);
  494. pathname_len = pathname_a_len + pathname_b_len;
  495. pathname[pathname_len] = 0;
  496. return pathname;
  497. }
  498. bool
  499. paths_init()
  500. {
  501. const char *home_dir, *xdg_config_home, *xdg_log_home;
  502. home_dir = getenv("HOME");
  503. if (home_dir == NULL)
  504. {
  505. fprintf(stderr, "Environment variable HOME not set\n");
  506. goto fail;
  507. }
  508. xdg_config_home = getenv("XDG_CONFIG_HOME");
  509. if (xdg_config_home == NULL)
  510. {
  511. if (!(xdg_config_home = pathname_cat(home_dir, DEFAULT_XDG_CONFIG))) goto fail;
  512. }
  513. if (!(xdg_log_home = pathname_cat(home_dir, DEFAULT_XDG_LOG))) goto fail;
  514. if (!(g_jackdbus_config_dir = pathname_cat(xdg_config_home, JACKDBUS_DIR))) goto fail;
  515. if (!(g_jackdbus_log_dir = pathname_cat(xdg_log_home, JACKDBUS_DIR))) goto fail;
  516. if (!ensure_dir_exist(xdg_config_home, 0700))
  517. {
  518. goto fail;
  519. }
  520. if (!ensure_dir_exist(xdg_log_home, 0700))
  521. {
  522. goto fail;
  523. }
  524. if (!ensure_dir_exist(g_jackdbus_config_dir, 0700))
  525. {
  526. free(g_jackdbus_config_dir);
  527. goto fail;
  528. }
  529. g_jackdbus_config_dir_len = strlen(g_jackdbus_config_dir);
  530. if (!ensure_dir_exist(g_jackdbus_log_dir, 0700))
  531. {
  532. free(g_jackdbus_log_dir);
  533. goto fail;
  534. }
  535. g_jackdbus_log_dir_len = strlen(g_jackdbus_log_dir);
  536. return true;
  537. fail:
  538. return false;
  539. }
  540. void
  541. paths_uninit()
  542. {
  543. free(g_jackdbus_config_dir);
  544. free(g_jackdbus_log_dir);
  545. }
  546. int
  547. log_init()
  548. {
  549. char *log_filename;
  550. size_t log_len;
  551. log_len = strlen(JACKDBUS_LOG);
  552. log_filename = malloc(g_jackdbus_log_dir_len + log_len + 1);
  553. if (log_filename == NULL)
  554. {
  555. fprintf(stderr, "Out of memory\n");
  556. return FALSE;
  557. }
  558. memcpy(log_filename, g_jackdbus_log_dir, g_jackdbus_log_dir_len);
  559. memcpy(log_filename + g_jackdbus_log_dir_len, JACKDBUS_LOG, log_len);
  560. log_filename[g_jackdbus_log_dir_len + log_len] = 0;
  561. g_logfile = fopen(log_filename, "a");
  562. if (g_logfile == NULL)
  563. {
  564. fprintf(stderr, "Cannot open jackdbus log file \"%s\": %d (%s)\n", log_filename, errno, strerror(errno));
  565. free(log_filename);
  566. return FALSE;
  567. }
  568. free(log_filename);
  569. return TRUE;
  570. }
  571. void
  572. log_uninit()
  573. {
  574. fclose(g_logfile);
  575. }
  576. void
  577. jack_dbus_error(
  578. void *dbus_call_context_ptr,
  579. const char *error_name,
  580. const char *format,
  581. ...)
  582. {
  583. va_list ap;
  584. char buffer[300];
  585. va_start(ap, format);
  586. vsnprintf(buffer, sizeof(buffer), format, ap);
  587. jack_error_callback(buffer);
  588. if (dbus_call_context_ptr != NULL)
  589. {
  590. ((struct jack_dbus_method_call *)dbus_call_context_ptr)->reply = dbus_message_new_error(
  591. ((struct jack_dbus_method_call *)dbus_call_context_ptr)->message,
  592. error_name,
  593. buffer);
  594. }
  595. va_end(ap);
  596. }
  597. int
  598. main (int argc, char **argv)
  599. {
  600. DBusError error;
  601. int ret;
  602. void *controller_ptr;
  603. struct stat st;
  604. char timestamp_str[26];
  605. st.st_mtime = 0;
  606. stat(argv[0], &st);
  607. ctime_r(&st.st_mtime, timestamp_str);
  608. timestamp_str[24] = 0;
  609. if (!jack_controller_settings_init())
  610. {
  611. ret = 1;
  612. goto fail;
  613. }
  614. if (argc != 2 || strcmp(argv[1], "auto") != 0)
  615. {
  616. ret = 0;
  617. fprintf(
  618. stderr,
  619. "jackdbus should be auto-executed by D-Bus message bus daemon.\n"
  620. "If you want to run it manually anyway, specify \"auto\" as only parameter\n");
  621. goto fail_uninit_xml;
  622. }
  623. if (!paths_init())
  624. {
  625. ret = 1;
  626. goto fail_uninit_xml;
  627. }
  628. if (!log_init())
  629. {
  630. ret = 1;
  631. goto fail_uninit_paths;
  632. }
  633. #if !defined(DISABLE_SIGNAL_MAGIC)
  634. jackctl_setup_signals(0);
  635. #endif
  636. jack_set_error_function(jack_dbus_error_callback);
  637. jack_set_info_function(jack_dbus_info_callback);
  638. /* setup our SIGSEGV magic that prints nice stack in our logfile */
  639. setup_sigsegv();
  640. jack_info("------------------");
  641. jack_info("Controller activated. Version %s (%s) built on %s", jack_get_version_string(), JACK_SVNREVISION, timestamp_str);
  642. if (!dbus_threads_init_default())
  643. {
  644. jack_error("dbus_threads_init_default() failed");
  645. ret = 1;
  646. goto fail_uninit_log;
  647. }
  648. dbus_error_init (&error);
  649. g_connection = dbus_bus_get (DBUS_BUS_SESSION, &error);
  650. if (dbus_error_is_set (&error))
  651. {
  652. jack_error("Cannot connect to D-Bus session bus: %s", error.message);
  653. ret = 1;
  654. goto fail_uninit_log;
  655. }
  656. ret = dbus_bus_request_name(
  657. g_connection,
  658. "org.jackaudio.service",
  659. DBUS_NAME_FLAG_DO_NOT_QUEUE,
  660. &error);
  661. if (ret == -1)
  662. {
  663. jack_error("Cannot request service name: %s", error.message);
  664. dbus_error_free(&error);
  665. ret = 1;
  666. goto fail_unref_connection;
  667. }
  668. else if (ret == DBUS_REQUEST_NAME_REPLY_EXISTS)
  669. {
  670. jack_error("Requested D-Bus service name already exists");
  671. ret = 1;
  672. goto fail_unref_connection;
  673. }
  674. controller_ptr = jack_controller_create(g_connection);
  675. if (controller_ptr == NULL)
  676. {
  677. ret = 1;
  678. goto fail_unref_connection;
  679. }
  680. jack_info("Listening for D-Bus messages");
  681. g_exit_command = FALSE;
  682. while (!g_exit_command && dbus_connection_read_write_dispatch (g_connection, 200));
  683. jack_controller_destroy(controller_ptr);
  684. jack_info("Controller deactivated.");
  685. ret = 0;
  686. fail_unref_connection:
  687. dbus_connection_unref(g_connection);
  688. fail_uninit_log:
  689. log_uninit();
  690. fail_uninit_paths:
  691. paths_uninit();
  692. fail_uninit_xml:
  693. jack_controller_settings_uninit();
  694. fail:
  695. return ret;
  696. }