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 <sys/types.h>
35 #define DBUS_SERVICE_SECTION "D-BUS Service"
36 #define DBUS_SERVICE_NAME "Name"
37 #define DBUS_SERVICE_EXEC "Exec"
42 DBusHashTable *entries;
43 DBusHashTable *pending_activations;
54 typedef struct BusPendingActivationEntry BusPendingActivationEntry;
56 struct BusPendingActivationEntry
58 DBusMessage *activation_message;
59 DBusConnection *connection;
66 } BusPendingActivation;
69 bus_pending_activation_entry_free (BusPendingActivationEntry *entry)
71 if (entry->activation_message)
72 dbus_message_unref (entry->activation_message);
74 if (entry->connection)
75 dbus_connection_unref (entry->connection);
81 bus_pending_activation_free (BusPendingActivation *activation)
88 dbus_free (activation->service_name);
90 link = _dbus_list_get_first_link (&activation->entries);
94 BusPendingActivationEntry *entry = link->data;
96 bus_pending_activation_entry_free (entry);
98 link = _dbus_list_get_next_link (&activation->entries, link);
100 _dbus_list_clear (&activation->entries);
102 dbus_free (activation);
106 bus_activation_entry_free (BusActivationEntry *entry)
111 dbus_free (entry->name);
112 dbus_free (entry->exec);
116 add_desktop_file_entry (BusActivation *activation,
117 BusDesktopFile *desktop_file,
121 BusActivationEntry *entry;
123 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
129 if (!bus_desktop_file_get_string (desktop_file,
130 DBUS_SERVICE_SECTION,
134 dbus_set_error (error, DBUS_ERROR_FAILED,
135 "No \""DBUS_SERVICE_NAME"\" key in .service file\n");
139 if (!bus_desktop_file_get_string (desktop_file,
140 DBUS_SERVICE_SECTION,
144 dbus_set_error (error, DBUS_ERROR_FAILED,
145 "No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
149 /* FIXME we need a better-defined algorithm for which service file to
150 * pick than "whichever one is first in the directory listing"
152 if (_dbus_hash_table_lookup_string (activation->entries, name))
154 dbus_set_error (error, DBUS_ERROR_FAILED,
155 "Service %s already exists in activation entry list\n", name);
159 entry = dbus_new0 (BusActivationEntry, 1);
169 if (!_dbus_hash_table_insert_string (activation->entries, entry->name, entry))
175 _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
187 /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
188 * hash entries it already added.
191 load_directory (BusActivation *activation,
192 const char *directory,
196 DBusString dir, filename;
197 DBusString full_path;
198 BusDesktopFile *desktop_file;
201 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
203 _dbus_string_init_const (&dir, directory);
208 if (!_dbus_string_init (&filename))
214 if (!_dbus_string_init (&full_path))
217 _dbus_string_free (&filename);
221 /* from this point it's safe to "goto failed" */
223 iter = _dbus_directory_open (&dir, error);
226 _dbus_verbose ("Failed to open directory %s: %s\n",
227 directory, error ? error->message : "unknown");
231 /* Now read the files */
232 dbus_error_init (&tmp_error);
233 while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
235 _dbus_assert (!dbus_error_is_set (&tmp_error));
237 _dbus_string_set_length (&full_path, 0);
239 if (!_dbus_string_append (&full_path, directory) ||
240 !_dbus_concat_dir_and_file (&full_path, &filename))
246 if (!_dbus_string_ends_with_c_str (&filename, ".service"))
248 _dbus_verbose ("Skipping non-.service file %s\n",
249 _dbus_string_get_const_data (&filename));
253 desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
255 if (desktop_file == NULL)
257 _dbus_verbose ("Could not load %s: %s\n",
258 _dbus_string_get_const_data (&full_path),
261 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
263 dbus_move_error (&tmp_error, error);
267 dbus_error_free (&tmp_error);
271 if (!add_desktop_file_entry (activation, desktop_file, &tmp_error))
273 bus_desktop_file_free (desktop_file);
276 _dbus_verbose ("Could not add %s to activation entry list: %s\n",
277 _dbus_string_get_const_data (&full_path), tmp_error.message);
279 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
281 dbus_move_error (&tmp_error, error);
285 dbus_error_free (&tmp_error);
290 bus_desktop_file_free (desktop_file);
296 if (dbus_error_is_set (&tmp_error))
298 dbus_move_error (&tmp_error, error);
305 _DBUS_ASSERT_ERROR_IS_SET (error);
308 _dbus_directory_close (iter);
310 bus_desktop_file_free (desktop_file);
311 _dbus_string_free (&filename);
312 _dbus_string_free (&full_path);
318 bus_activation_new (BusContext *context,
319 const DBusString *address,
320 DBusList **directories,
323 BusActivation *activation;
326 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
328 activation = dbus_new0 (BusActivation, 1);
329 if (activation == NULL)
335 activation->refcount = 1;
336 activation->context = context;
338 if (!_dbus_string_copy_data (address, &activation->server_address))
344 activation->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
345 (DBusFreeFunction)bus_activation_entry_free);
346 if (activation->entries == NULL)
352 activation->pending_activations = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
353 (DBusFreeFunction)bus_pending_activation_free);
355 if (activation->pending_activations == NULL)
361 /* Load service files */
362 link = _dbus_list_get_first_link (directories);
365 if (!load_directory (activation, link->data, error))
367 link = _dbus_list_get_next_link (directories, link);
373 bus_activation_unref (activation);
378 bus_activation_ref (BusActivation *activation)
380 _dbus_assert (activation->refcount > 0);
382 activation->refcount += 1;
386 bus_activation_unref (BusActivation *activation)
388 _dbus_assert (activation->refcount > 0);
390 activation->refcount -= 1;
392 if (activation->refcount == 0)
394 dbus_free (activation->server_address);
395 if (activation->entries)
396 _dbus_hash_table_unref (activation->entries);
397 if (activation->pending_activations)
398 _dbus_hash_table_unref (activation->pending_activations);
399 dbus_free (activation);
404 child_setup (void *data)
406 BusActivation *activation = data;
409 /* If no memory, we simply have the child exit, so it won't try
410 * to connect to the wrong thing.
412 if (!_dbus_setenv ("DBUS_ACTIVATION_ADDRESS", activation->server_address))
415 type = bus_context_get_type (activation->context);
418 if (!_dbus_setenv ("DBUS_BUS_TYPE", type))
424 bus_activation_service_created (BusActivation *activation,
425 const char *service_name,
426 BusTransaction *transaction,
429 BusPendingActivation *pending_activation;
430 DBusMessage *message;
433 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
435 /* Check if it's a pending activation */
436 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
438 if (!pending_activation)
441 link = _dbus_list_get_first_link (&pending_activation->entries);
444 BusPendingActivationEntry *entry = link->data;
445 DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
447 if (dbus_connection_get_is_connected (entry->connection))
449 message = dbus_message_new_reply (entry->activation_message);
456 if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
457 !dbus_message_append_args (message,
458 DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED,
461 dbus_message_unref (message);
466 if (!bus_transaction_send_message (transaction, entry->connection, message))
468 dbus_message_unref (message);
474 bus_pending_activation_entry_free (entry);
476 _dbus_list_remove_link (&pending_activation->entries, link);
480 _dbus_hash_table_remove_string (activation->pending_activations, service_name);
485 _dbus_hash_table_remove_string (activation->pending_activations, service_name);
490 bus_activation_activate_service (BusActivation *activation,
491 DBusConnection *connection,
492 BusTransaction *transaction,
493 DBusMessage *activation_message,
494 const char *service_name,
497 BusActivationEntry *entry;
498 BusPendingActivation *pending_activation;
499 BusPendingActivationEntry *pending_activation_entry;
500 DBusMessage *message;
501 DBusString service_str;
505 _DBUS_ASSERT_ERROR_IS_CLEAR (error);
507 entry = _dbus_hash_table_lookup_string (activation->entries, service_name);
511 dbus_set_error (error, DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND,
512 "The service %s was not found in the activation entry list",
517 /* Check if the service is active */
518 _dbus_string_init_const (&service_str, service_name);
519 if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL)
521 message = dbus_message_new_reply (activation_message);
529 if (!dbus_message_set_sender (message, DBUS_SERVICE_DBUS) ||
530 !dbus_message_append_args (message,
531 DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE,
535 dbus_message_unref (message);
539 retval = bus_transaction_send_message (transaction, connection, message);
540 dbus_message_unref (message);
547 pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1);
548 if (!pending_activation_entry)
554 pending_activation_entry->activation_message = activation_message;
555 dbus_message_ref (activation_message);
556 pending_activation_entry->connection = connection;
557 dbus_connection_ref (connection);
559 /* Check if the service is being activated */
560 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
561 if (pending_activation)
563 if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
566 bus_pending_activation_entry_free (pending_activation_entry);
573 pending_activation = dbus_new0 (BusPendingActivation, 1);
574 if (!pending_activation)
577 bus_pending_activation_entry_free (pending_activation_entry);
580 pending_activation->service_name = _dbus_strdup (service_name);
581 if (!pending_activation->service_name)
584 bus_pending_activation_free (pending_activation);
585 bus_pending_activation_entry_free (pending_activation_entry);
589 if (!_dbus_list_append (&pending_activation->entries, pending_activation_entry))
592 bus_pending_activation_free (pending_activation);
593 bus_pending_activation_entry_free (pending_activation_entry);
597 if (!_dbus_hash_table_insert_string (activation->pending_activations,
598 pending_activation->service_name, pending_activation))
601 bus_pending_activation_free (pending_activation);
606 /* FIXME we need to support a full command line, not just a single
610 /* Now try to spawn the process */
611 argv[0] = entry->exec;
614 if (!_dbus_spawn_async (argv,
615 child_setup, activation,
618 _dbus_hash_table_remove_string (activation->pending_activations,
619 pending_activation->service_name);