1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* activation.c Activation of services
4 * Copyright (C) 2003 CodeFactory AB
6 * Licensed under the Academic Free License version 1.2
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include "activation.h"
24 #include "desktop-file.h"
27 #include <dbus/dbus-internals.h>
28 #include <dbus/dbus-hash.h>
29 #include <dbus/dbus-list.h>
30 #include <sys/types.h>
34 #define DBUS_SERVICE_SECTION "D-BUS Service"
35 #define DBUS_SERVICE_NAME "Name"
36 #define DBUS_SERVICE_EXEC "Exec"
41 DBusHashTable *entries;
42 DBusHashTable *pending_activations;
53 typedef struct BusPendingActivationEntry BusPendingActivationEntry;
55 struct BusPendingActivationEntry
57 DBusMessage *activation_message;
58 DBusConnection *connection;
65 } BusPendingActivation;
68 bus_pending_activation_entry_free (BusPendingActivationEntry *entry)
70 if (entry->activation_message)
71 dbus_message_unref (entry->activation_message);
73 if (entry->connection)
74 dbus_connection_unref (entry->connection);
80 bus_pending_activation_free (BusPendingActivation *activation)
87 dbus_free (activation->service_name);
89 link = _dbus_list_get_first_link (&activation->entries);
93 BusPendingActivationEntry *entry = link->data;
95 bus_pending_activation_entry_free (entry);
97 link = _dbus_list_get_next_link (&activation->entries, link);
99 _dbus_list_clear (&activation->entries);
101 dbus_free (activation);
105 bus_activation_entry_free (BusActivationEntry *entry)
110 dbus_free (entry->name);
111 dbus_free (entry->exec);
115 add_desktop_file_entry (BusActivation *activation,
116 BusDesktopFile *desktop_file,
120 BusActivationEntry *entry;
122 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
128 if (!bus_desktop_file_get_string (desktop_file,
129 DBUS_SERVICE_SECTION,
133 dbus_set_error (error, DBUS_ERROR_FAILED,
134 "No \""DBUS_SERVICE_NAME"\" key in .service file\n");
138 if (!bus_desktop_file_get_string (desktop_file,
139 DBUS_SERVICE_SECTION,
143 dbus_set_error (error, DBUS_ERROR_FAILED,
144 "No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
148 /* FIXME we need a better-defined algorithm for which service file to
149 * pick than "whichever one is first in the directory listing"
151 if (_dbus_hash_table_lookup_string (activation->entries, name))
153 dbus_set_error (error, DBUS_ERROR_FAILED,
154 "Service %s already exists in activation entry list\n", name);
158 entry = dbus_new0 (BusActivationEntry, 1);
168 if (!_dbus_hash_table_insert_string (activation->entries, entry->name, entry))
174 _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
186 /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
187 * hash entries it already added.
190 load_directory (BusActivation *activation,
191 const char *directory,
195 DBusString dir, filename;
196 DBusString full_path;
197 BusDesktopFile *desktop_file;
200 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
202 _dbus_string_init_const (&dir, directory);
207 if (!_dbus_string_init (&filename))
213 if (!_dbus_string_init (&full_path))
216 _dbus_string_free (&filename);
220 /* from this point it's safe to "goto failed" */
222 iter = _dbus_directory_open (&dir, error);
225 _dbus_verbose ("Failed to open directory %s: %s\n",
226 directory, error ? error->message : "unknown");
230 /* Now read the files */
231 dbus_error_init (&tmp_error);
232 while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
234 _dbus_assert (!dbus_error_is_set (&tmp_error));
236 _dbus_string_set_length (&full_path, 0);
238 if (!_dbus_string_append (&full_path, directory) ||
239 !_dbus_concat_dir_and_file (&full_path, &filename))
245 if (!_dbus_string_ends_with_c_str (&filename, ".service"))
247 _dbus_verbose ("Skipping non-.service file %s\n",
248 _dbus_string_get_const_data (&filename));
252 desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
254 if (desktop_file == NULL)
256 _dbus_verbose ("Could not load %s: %s\n",
257 _dbus_string_get_const_data (&full_path),
260 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
262 dbus_move_error (&tmp_error, error);
266 dbus_error_free (&tmp_error);
270 if (!add_desktop_file_entry (activation, desktop_file, &tmp_error))
272 bus_desktop_file_free (desktop_file);
275 _dbus_verbose ("Could not add %s to activation entry list: %s\n",
276 _dbus_string_get_const_data (&full_path), tmp_error.message);
278 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
280 dbus_move_error (&tmp_error, error);
284 dbus_error_free (&tmp_error);
289 bus_desktop_file_free (desktop_file);
295 if (dbus_error_is_set (&tmp_error))
297 dbus_move_error (&tmp_error, error);
304 _DBUS_ASSERT_ERROR_IS_SET (error);
307 _dbus_directory_close (iter);
309 bus_desktop_file_free (desktop_file);
310 _dbus_string_free (&filename);
311 _dbus_string_free (&full_path);
317 bus_activation_new (BusContext *context,
318 const DBusString *address,
319 const char **directories,
323 BusActivation *activation;
325 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
327 activation = dbus_new0 (BusActivation, 1);
328 if (activation == NULL)
334 activation->refcount = 1;
335 activation->context = context;
337 if (!_dbus_string_copy_data (address, &activation->server_address))
343 activation->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
344 (DBusFreeFunction)bus_activation_entry_free);
345 if (activation->entries == NULL)
351 activation->pending_activations = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
352 (DBusFreeFunction)bus_pending_activation_free);
354 if (activation->pending_activations == NULL)
360 /* Load service files */
362 while (directories[i] != NULL)
364 if (!load_directory (activation, directories[i], error))
372 bus_activation_unref (activation);
377 bus_activation_ref (BusActivation *activation)
379 _dbus_assert (activation->refcount > 0);
381 activation->refcount += 1;
385 bus_activation_unref (BusActivation *activation)
387 _dbus_assert (activation->refcount > 0);
389 activation->refcount -= 1;
391 if (activation->refcount == 0)
393 dbus_free (activation->server_address);
394 if (activation->entries)
395 _dbus_hash_table_unref (activation->entries);
396 if (activation->pending_activations)
397 _dbus_hash_table_unref (activation->pending_activations);
398 dbus_free (activation);
403 child_setup (void *data)
405 BusActivation *activation = data;
407 /* If no memory, we simply have the child exit, so it won't try
408 * to connect to the wrong thing.
410 if (!_dbus_setenv ("DBUS_ADDRESS", activation->server_address))
415 bus_activation_service_created (BusActivation *activation,
416 const char *service_name,
419 BusPendingActivation *pending_activation;
420 DBusMessage *message;
423 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
425 /* Check if it's a pending activation */
426 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
428 if (!pending_activation)
431 link = _dbus_list_get_first_link (&pending_activation->entries);
434 BusPendingActivationEntry *entry = link->data;
435 DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
437 if (dbus_connection_get_is_connected (entry->connection))
439 message = dbus_message_new_reply (entry->activation_message);
446 if (!dbus_message_append_args (message,
447 DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED,
450 dbus_message_unref (message);
455 if (!dbus_connection_send (entry->connection, message, NULL))
457 dbus_message_unref (message);
463 bus_pending_activation_entry_free (entry);
465 _dbus_list_remove_link (&pending_activation->entries, link);
469 _dbus_hash_table_remove_string (activation->pending_activations, service_name);
474 _dbus_hash_table_remove_string (activation->pending_activations, service_name);
479 bus_activation_activate_service (BusActivation *activation,
480 DBusConnection *connection,
481 DBusMessage *activation_message,
482 const char *service_name,
485 BusActivationEntry *entry;
486 BusPendingActivation *pending_activation;
487 BusPendingActivationEntry *pending_activation_entry;
488 DBusMessage *message;
489 DBusString service_str;
493 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
495 entry = _dbus_hash_table_lookup_string (activation->entries, service_name);
499 dbus_set_error (error, DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND,
500 "The service %s was not found in the activation entry list",
505 /* Check if the service is active */
506 _dbus_string_init_const (&service_str, service_name);
507 if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL)
509 message = dbus_message_new_reply (activation_message);
517 if (!dbus_message_append_args (message,
518 DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE,
522 dbus_message_unref (message);
526 retval = dbus_connection_send (connection, message, NULL);
527 dbus_message_unref (message);
534 pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1);
535 if (!pending_activation_entry)
541 pending_activation_entry->activation_message = activation_message;
542 dbus_message_ref (activation_message);
543 pending_activation_entry->connection = connection;
544 dbus_connection_ref (connection);
546 /* Check if the service is being activated */
547 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
548 if (pending_activation)
550 if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
553 bus_pending_activation_entry_free (pending_activation_entry);
560 pending_activation = dbus_new0 (BusPendingActivation, 1);
561 if (!pending_activation)
564 bus_pending_activation_entry_free (pending_activation_entry);
567 pending_activation->service_name = _dbus_strdup (service_name);
568 if (!pending_activation->service_name)
571 bus_pending_activation_free (pending_activation);
572 bus_pending_activation_entry_free (pending_activation_entry);
576 if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
579 bus_pending_activation_free (pending_activation);
580 bus_pending_activation_entry_free (pending_activation_entry);
584 if (!_dbus_hash_table_insert_string (activation->pending_activations,
585 pending_activation->service_name, pending_activation))
588 bus_pending_activation_free (pending_activation);
593 /* FIXME we need to support a full command line, not just a single
597 /* Now try to spawn the process */
598 argv[0] = entry->exec;
601 if (!_dbus_spawn_async (argv,
602 child_setup, activation,
605 _dbus_hash_table_remove_string (activation->pending_activations,
606 pending_activation->service_name);