1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* activation.c Activation of services
4 * Copyright (C) 2003 CodeFactory AB
5 * Copyright (C) 2003 Red Hat, Inc.
7 * Licensed under the Academic Free License version 1.2
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "activation.h"
25 #include "desktop-file.h"
28 #include <dbus/dbus-internals.h>
29 #include <dbus/dbus-hash.h>
30 #include <dbus/dbus-list.h>
31 #include <dbus/dbus-spawn.h>
32 #include <dbus/dbus-timeout.h>
33 #include <sys/types.h>
37 #define DBUS_SERVICE_SECTION "D-BUS Service"
38 #define DBUS_SERVICE_NAME "Name"
39 #define DBUS_SERVICE_EXEC "Exec"
44 DBusHashTable *entries;
45 DBusHashTable *pending_activations;
48 int n_pending_activations; /**< This is in fact the number of BusPendingActivationEntry,
49 * i.e. number of pending activation requests, not pending
60 typedef struct BusPendingActivationEntry BusPendingActivationEntry;
62 struct BusPendingActivationEntry
64 DBusMessage *activation_message;
65 DBusConnection *connection;
71 BusActivation *activation;
75 DBusBabysitter *babysitter;
77 unsigned int timeout_added : 1;
78 } BusPendingActivation;
81 bus_pending_activation_entry_free (BusPendingActivationEntry *entry)
83 if (entry->activation_message)
84 dbus_message_unref (entry->activation_message);
86 if (entry->connection)
87 dbus_connection_unref (entry->connection);
93 handle_timeout_callback (DBusTimeout *timeout,
96 BusPendingActivation *pending_activation = data;
98 while (!dbus_timeout_handle (pending_activation->timeout))
99 _dbus_wait_for_memory ();
102 static BusPendingActivation *
103 bus_pending_activation_ref (BusPendingActivation *pending_activation)
105 _dbus_assert (pending_activation->refcount > 0);
106 pending_activation->refcount += 1;
108 return pending_activation;
112 bus_pending_activation_unref (BusPendingActivation *pending_activation)
116 if (pending_activation == NULL) /* hash table requires this */
119 _dbus_assert (pending_activation->refcount > 0);
120 pending_activation->refcount -= 1;
122 if (pending_activation->refcount > 0)
125 if (pending_activation->timeout_added)
127 _dbus_loop_remove_timeout (bus_context_get_loop (pending_activation->activation->context),
128 pending_activation->timeout,
129 handle_timeout_callback, pending_activation);
130 pending_activation->timeout_added = FALSE;
133 if (pending_activation->timeout)
134 _dbus_timeout_unref (pending_activation->timeout);
136 if (pending_activation->babysitter)
138 if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter,
140 pending_activation->babysitter,
142 _dbus_assert_not_reached ("setting watch functions to NULL failed");
144 _dbus_babysitter_unref (pending_activation->babysitter);
147 dbus_free (pending_activation->service_name);
149 link = _dbus_list_get_first_link (&pending_activation->entries);
153 BusPendingActivationEntry *entry = link->data;
155 bus_pending_activation_entry_free (entry);
157 link = _dbus_list_get_next_link (&pending_activation->entries, link);
159 _dbus_list_clear (&pending_activation->entries);
161 pending_activation->activation->n_pending_activations -=
162 pending_activation->n_entries;
164 _dbus_assert (pending_activation->activation->n_pending_activations >= 0);
166 dbus_free (pending_activation);
170 bus_activation_entry_free (BusActivationEntry *entry)
175 dbus_free (entry->name);
176 dbus_free (entry->exec);
182 add_desktop_file_entry (BusActivation *activation,
183 BusDesktopFile *desktop_file,
187 BusActivationEntry *entry;
189 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
195 if (!bus_desktop_file_get_string (desktop_file,
196 DBUS_SERVICE_SECTION,
200 dbus_set_error (error, DBUS_ERROR_FAILED,
201 "No \""DBUS_SERVICE_NAME"\" key in .service file\n");
205 if (!bus_desktop_file_get_string (desktop_file,
206 DBUS_SERVICE_SECTION,
210 dbus_set_error (error, DBUS_ERROR_FAILED,
211 "No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
215 /* FIXME we need a better-defined algorithm for which service file to
216 * pick than "whichever one is first in the directory listing"
218 if (_dbus_hash_table_lookup_string (activation->entries, name))
220 dbus_set_error (error, DBUS_ERROR_FAILED,
221 "Service %s already exists in activation entry list\n", name);
225 entry = dbus_new0 (BusActivationEntry, 1);
235 if (!_dbus_hash_table_insert_string (activation->entries, entry->name, entry))
241 _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
253 /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
254 * hash entries it already added.
257 load_directory (BusActivation *activation,
258 const char *directory,
262 DBusString dir, filename;
263 DBusString full_path;
264 BusDesktopFile *desktop_file;
268 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
270 _dbus_string_init_const (&dir, directory);
275 if (!_dbus_string_init (&filename))
281 if (!_dbus_string_init (&full_path))
284 _dbus_string_free (&filename);
290 /* from this point it's safe to "goto out" */
292 iter = _dbus_directory_open (&dir, error);
295 _dbus_verbose ("Failed to open directory %s: %s\n",
296 directory, error ? error->message : "unknown");
300 /* Now read the files */
301 dbus_error_init (&tmp_error);
302 while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
304 _dbus_assert (!dbus_error_is_set (&tmp_error));
306 _dbus_string_set_length (&full_path, 0);
308 if (!_dbus_string_append (&full_path, directory) ||
309 !_dbus_concat_dir_and_file (&full_path, &filename))
315 if (!_dbus_string_ends_with_c_str (&filename, ".service"))
317 _dbus_verbose ("Skipping non-.service file %s\n",
318 _dbus_string_get_const_data (&filename));
322 desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
324 if (desktop_file == NULL)
326 _dbus_verbose ("Could not load %s: %s\n",
327 _dbus_string_get_const_data (&full_path),
330 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
332 dbus_move_error (&tmp_error, error);
336 dbus_error_free (&tmp_error);
340 if (!add_desktop_file_entry (activation, desktop_file, &tmp_error))
342 bus_desktop_file_free (desktop_file);
345 _dbus_verbose ("Could not add %s to activation entry list: %s\n",
346 _dbus_string_get_const_data (&full_path), tmp_error.message);
348 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
350 dbus_move_error (&tmp_error, error);
354 dbus_error_free (&tmp_error);
359 bus_desktop_file_free (desktop_file);
365 if (dbus_error_is_set (&tmp_error))
367 dbus_move_error (&tmp_error, error);
375 _DBUS_ASSERT_ERROR_IS_SET (error);
377 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
380 _dbus_directory_close (iter);
382 bus_desktop_file_free (desktop_file);
383 _dbus_string_free (&filename);
384 _dbus_string_free (&full_path);
390 bus_activation_new (BusContext *context,
391 const DBusString *address,
392 DBusList **directories,
395 BusActivation *activation;
398 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
400 activation = dbus_new0 (BusActivation, 1);
401 if (activation == NULL)
407 activation->refcount = 1;
408 activation->context = context;
409 activation->n_pending_activations = 0;
411 if (!_dbus_string_copy_data (address, &activation->server_address))
417 activation->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
418 (DBusFreeFunction)bus_activation_entry_free);
419 if (activation->entries == NULL)
425 activation->pending_activations = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
426 (DBusFreeFunction)bus_pending_activation_unref);
428 if (activation->pending_activations == NULL)
434 /* Load service files */
435 link = _dbus_list_get_first_link (directories);
438 if (!load_directory (activation, link->data, error))
440 link = _dbus_list_get_next_link (directories, link);
446 bus_activation_unref (activation);
451 bus_activation_ref (BusActivation *activation)
453 _dbus_assert (activation->refcount > 0);
455 activation->refcount += 1;
461 bus_activation_unref (BusActivation *activation)
463 _dbus_assert (activation->refcount > 0);
465 activation->refcount -= 1;
467 if (activation->refcount == 0)
469 dbus_free (activation->server_address);
470 if (activation->entries)
471 _dbus_hash_table_unref (activation->entries);
472 if (activation->pending_activations)
473 _dbus_hash_table_unref (activation->pending_activations);
474 dbus_free (activation);
479 child_setup (void *data)
481 BusActivation *activation = data;
484 /* If no memory, we simply have the child exit, so it won't try
485 * to connect to the wrong thing.
487 if (!_dbus_setenv ("DBUS_ACTIVATION_ADDRESS", activation->server_address))
490 type = bus_context_get_type (activation->context);
493 if (!_dbus_setenv ("DBUS_BUS_TYPE", type))
496 if (strcmp (type, "session") == 0)
498 if (!_dbus_setenv ("DBUS_SESSION_BUS_ADDRESS",
499 activation->server_address))
502 else if (strcmp (type, "system") == 0)
504 if (!_dbus_setenv ("DBUS_SYSTEM_BUS_ADDRESS",
505 activation->server_address))
513 BusPendingActivation *pending_activation;
514 DBusPreallocatedHash *hash_entry;
515 } RestorePendingData;
518 restore_pending (void *data)
520 RestorePendingData *d = data;
522 _dbus_assert (d->pending_activation != NULL);
523 _dbus_assert (d->hash_entry != NULL);
525 _dbus_verbose ("Restoring pending activation for service %s, has timeout = %d\n",
526 d->pending_activation->service_name,
527 d->pending_activation->timeout_added);
529 _dbus_hash_table_insert_string_preallocated (d->pending_activation->activation->pending_activations,
531 d->pending_activation->service_name, d->pending_activation);
533 bus_pending_activation_ref (d->pending_activation);
535 d->hash_entry = NULL;
539 free_pending_restore_data (void *data)
541 RestorePendingData *d = data;
544 _dbus_hash_table_free_preallocated_entry (d->pending_activation->activation->pending_activations,
547 bus_pending_activation_unref (d->pending_activation);
553 add_restore_pending_to_transaction (BusTransaction *transaction,
554 BusPendingActivation *pending_activation)
556 RestorePendingData *d;
558 d = dbus_new (RestorePendingData, 1);
562 d->pending_activation = pending_activation;
563 d->hash_entry = _dbus_hash_table_preallocate_entry (d->pending_activation->activation->pending_activations);
565 bus_pending_activation_ref (d->pending_activation);
567 if (d->hash_entry == NULL ||
568 !bus_transaction_add_cancel_hook (transaction, restore_pending, d,
569 free_pending_restore_data))
571 free_pending_restore_data (d);
575 _dbus_verbose ("Saved pending activation to be restored if the transaction fails\n");
581 bus_activation_service_created (BusActivation *activation,
582 const char *service_name,
583 BusTransaction *transaction,
586 BusPendingActivation *pending_activation;
587 DBusMessage *message;
590 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
592 /* Check if it's a pending activation */
593 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
595 if (!pending_activation)
598 link = _dbus_list_get_first_link (&pending_activation->entries);
601 BusPendingActivationEntry *entry = link->data;
602 DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
604 if (dbus_connection_get_is_connected (entry->connection))
606 message = dbus_message_new_method_return (entry->activation_message);
613 if (!dbus_message_append_args (message,
614 DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED,
617 dbus_message_unref (message);
622 if (!bus_transaction_send_from_driver (transaction, entry->connection, message))
624 dbus_message_unref (message);
629 dbus_message_unref (message);
635 if (!add_restore_pending_to_transaction (transaction, pending_activation))
637 _dbus_verbose ("Could not add cancel hook to transaction to revert removing pending activation\n");
642 _dbus_hash_table_remove_string (activation->pending_activations, service_name);
651 * FIXME @todo the error messages here would ideally be preallocated
652 * so we don't need to allocate memory to send them.
653 * Using the usual tactic, prealloc an OOM message, then
654 * if we can't alloc the real error send the OOM error instead.
657 try_send_activation_failure (BusPendingActivation *pending_activation,
658 const DBusError *how)
660 BusActivation *activation;
662 BusTransaction *transaction;
664 activation = pending_activation->activation;
666 transaction = bus_transaction_new (activation->context);
667 if (transaction == NULL)
670 link = _dbus_list_get_first_link (&pending_activation->entries);
673 BusPendingActivationEntry *entry = link->data;
674 DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
676 if (dbus_connection_get_is_connected (entry->connection))
678 if (!bus_transaction_send_error_reply (transaction,
681 entry->activation_message))
688 bus_transaction_execute_and_free (transaction);
694 bus_transaction_cancel_and_free (transaction);
699 * Free the pending activation and send an error message to all the
700 * connections that were waiting for it.
703 pending_activation_failed (BusPendingActivation *pending_activation,
704 const DBusError *how)
706 /* FIXME use preallocated OOM messages instead of bus_wait_for_memory() */
707 while (!try_send_activation_failure (pending_activation, how))
708 _dbus_wait_for_memory ();
710 /* Destroy this pending activation */
711 _dbus_hash_table_remove_string (pending_activation->activation->pending_activations,
712 pending_activation->service_name);
716 babysitter_watch_callback (DBusWatch *watch,
717 unsigned int condition,
720 BusPendingActivation *pending_activation = data;
722 DBusBabysitter *babysitter;
724 babysitter = pending_activation->babysitter;
726 _dbus_babysitter_ref (babysitter);
728 retval = dbus_watch_handle (watch, condition);
730 /* FIXME this is broken in the same way that
731 * connection watches used to be; there should be
732 * a separate callback for status change, instead
733 * of doing "if we handled a watch status might
736 * Fixing this lets us move dbus_watch_handle
737 * calls into dbus-mainloop.c
740 if (_dbus_babysitter_get_child_exited (babysitter))
744 dbus_error_init (&error);
745 _dbus_babysitter_set_child_exit_error (babysitter, &error);
747 /* Destroys the pending activation */
748 pending_activation_failed (pending_activation, &error);
750 dbus_error_free (&error);
753 _dbus_babysitter_unref (babysitter);
759 add_babysitter_watch (DBusWatch *watch,
762 BusPendingActivation *pending_activation = data;
764 return _dbus_loop_add_watch (bus_context_get_loop (pending_activation->activation->context),
765 watch, babysitter_watch_callback, pending_activation,
770 remove_babysitter_watch (DBusWatch *watch,
773 BusPendingActivation *pending_activation = data;
775 _dbus_loop_remove_watch (bus_context_get_loop (pending_activation->activation->context),
776 watch, babysitter_watch_callback, pending_activation);
780 pending_activation_timed_out (void *data)
782 BusPendingActivation *pending_activation = data;
785 /* Kill the spawned process, since it sucks
786 * (not sure this is what we want to do, but
787 * may as well try it for now)
789 _dbus_babysitter_kill_child (pending_activation->babysitter);
791 dbus_error_init (&error);
793 dbus_set_error (&error, DBUS_ERROR_TIMED_OUT,
794 "Activation of %s timed out",
795 pending_activation->service_name);
797 pending_activation_failed (pending_activation, &error);
799 dbus_error_free (&error);
805 cancel_pending (void *data)
807 BusPendingActivation *pending_activation = data;
809 _dbus_verbose ("Canceling pending activation of %s\n",
810 pending_activation->service_name);
812 if (pending_activation->babysitter)
813 _dbus_babysitter_kill_child (pending_activation->babysitter);
815 _dbus_hash_table_remove_string (pending_activation->activation->pending_activations,
816 pending_activation->service_name);
820 free_pending_cancel_data (void *data)
822 BusPendingActivation *pending_activation = data;
824 bus_pending_activation_unref (pending_activation);
828 add_cancel_pending_to_transaction (BusTransaction *transaction,
829 BusPendingActivation *pending_activation)
831 if (!bus_transaction_add_cancel_hook (transaction, cancel_pending,
833 free_pending_cancel_data))
836 bus_pending_activation_ref (pending_activation);
838 _dbus_verbose ("Saved pending activation to be canceled if the transaction fails\n");
844 bus_activation_activate_service (BusActivation *activation,
845 DBusConnection *connection,
846 BusTransaction *transaction,
847 DBusMessage *activation_message,
848 const char *service_name,
851 BusActivationEntry *entry;
852 BusPendingActivation *pending_activation;
853 BusPendingActivationEntry *pending_activation_entry;
854 DBusMessage *message;
855 DBusString service_str;
859 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
861 if (activation->n_pending_activations >=
862 bus_context_get_max_pending_activations (activation->context))
864 dbus_set_error (error, DBUS_ERROR_LIMITS_EXCEEDED,
865 "The maximum number of pending activations has been reached, activation of %s failed",
870 entry = _dbus_hash_table_lookup_string (activation->entries, service_name);
874 dbus_set_error (error, DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND,
875 "The service %s was not found in the activation entry list",
880 /* Check if the service is active */
881 _dbus_string_init_const (&service_str, service_name);
882 if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL)
884 _dbus_verbose ("Service \"%s\" is already active\n", service_name);
886 message = dbus_message_new_method_return (activation_message);
890 _dbus_verbose ("No memory to create reply to activate message\n");
895 if (!dbus_message_append_args (message,
896 DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE,
899 _dbus_verbose ("No memory to set args of reply to activate message\n");
901 dbus_message_unref (message);
905 retval = bus_transaction_send_from_driver (transaction, connection, message);
906 dbus_message_unref (message);
909 _dbus_verbose ("Failed to send reply\n");
916 pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1);
917 if (!pending_activation_entry)
919 _dbus_verbose ("Failed to create pending activation entry\n");
924 pending_activation_entry->activation_message = activation_message;
925 dbus_message_ref (activation_message);
926 pending_activation_entry->connection = connection;
927 dbus_connection_ref (connection);
929 /* Check if the service is being activated */
930 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
931 if (pending_activation)
933 if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
935 _dbus_verbose ("Failed to append a new entry to pending activation\n");
938 bus_pending_activation_entry_free (pending_activation_entry);
942 pending_activation->n_entries += 1;
943 pending_activation->activation->n_pending_activations += 1;
947 pending_activation = dbus_new0 (BusPendingActivation, 1);
948 if (!pending_activation)
950 _dbus_verbose ("Failed to create pending activation\n");
953 bus_pending_activation_entry_free (pending_activation_entry);
957 pending_activation->activation = activation;
958 pending_activation->refcount = 1;
960 pending_activation->service_name = _dbus_strdup (service_name);
961 if (!pending_activation->service_name)
963 _dbus_verbose ("Failed to copy service name for pending activation\n");
966 bus_pending_activation_unref (pending_activation);
967 bus_pending_activation_entry_free (pending_activation_entry);
971 pending_activation->timeout =
972 _dbus_timeout_new (bus_context_get_activation_timeout (activation->context),
973 pending_activation_timed_out,
976 if (!pending_activation->timeout)
978 _dbus_verbose ("Failed to create timeout for pending activation\n");
981 bus_pending_activation_unref (pending_activation);
982 bus_pending_activation_entry_free (pending_activation_entry);
986 if (!_dbus_loop_add_timeout (bus_context_get_loop (activation->context),
987 pending_activation->timeout,
988 handle_timeout_callback,
992 _dbus_verbose ("Failed to add timeout for pending activation\n");
995 bus_pending_activation_unref (pending_activation);
996 bus_pending_activation_entry_free (pending_activation_entry);
1000 pending_activation->timeout_added = TRUE;
1002 if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
1004 _dbus_verbose ("Failed to add entry to just-created pending activation\n");
1006 BUS_SET_OOM (error);
1007 bus_pending_activation_unref (pending_activation);
1008 bus_pending_activation_entry_free (pending_activation_entry);
1012 pending_activation->n_entries += 1;
1013 pending_activation->activation->n_pending_activations += 1;
1015 if (!_dbus_hash_table_insert_string (activation->pending_activations,
1016 pending_activation->service_name,
1017 pending_activation))
1019 _dbus_verbose ("Failed to put pending activation in hash table\n");
1021 BUS_SET_OOM (error);
1022 bus_pending_activation_unref (pending_activation);
1027 if (!add_cancel_pending_to_transaction (transaction, pending_activation))
1029 _dbus_verbose ("Failed to add pending activation cancel hook to transaction\n");
1030 BUS_SET_OOM (error);
1031 _dbus_hash_table_remove_string (activation->pending_activations,
1032 pending_activation->service_name);
1036 /* FIXME we need to support a full command line, not just a single
1040 /* Now try to spawn the process */
1041 argv[0] = entry->exec;
1044 if (!_dbus_spawn_async_with_babysitter (&pending_activation->babysitter, argv,
1045 child_setup, activation,
1048 _dbus_verbose ("Failed to spawn child\n");
1049 _DBUS_ASSERT_ERROR_IS_SET (error);
1053 _dbus_assert (pending_activation->babysitter != NULL);
1055 if (!_dbus_babysitter_set_watch_functions (pending_activation->babysitter,
1056 add_babysitter_watch,
1057 remove_babysitter_watch,
1062 BUS_SET_OOM (error);
1063 _dbus_verbose ("Failed to set babysitter watch functions\n");