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;
126 if (!bus_desktop_file_get_string (desktop_file,
127 DBUS_SERVICE_SECTION,
131 dbus_set_error (error, DBUS_ERROR_FAILED,
132 "No \""DBUS_SERVICE_NAME"\" key in .service file\n");
136 if (!bus_desktop_file_get_string (desktop_file,
137 DBUS_SERVICE_SECTION,
141 dbus_set_error (error, DBUS_ERROR_FAILED,
142 "No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
146 /* FIXME we need a better-defined algorithm for which service file to
147 * pick than "whichever one is first in the directory listing"
149 if (_dbus_hash_table_lookup_string (activation->entries, name))
151 dbus_set_error (error, DBUS_ERROR_FAILED,
152 "Service %s already exists in activation entry list\n", name);
156 entry = dbus_new0 (BusActivationEntry, 1);
166 if (!_dbus_hash_table_insert_string (activation->entries, entry->name, entry))
172 _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
184 /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
185 * hash entries it already added.
188 load_directory (BusActivation *activation,
189 const char *directory,
193 DBusString dir, filename;
194 DBusString full_path;
195 BusDesktopFile *desktop_file;
198 _dbus_string_init_const (&dir, directory);
203 if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
209 if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
212 _dbus_string_free (&filename);
216 /* from this point it's safe to "goto failed" */
218 iter = _dbus_directory_open (&dir, error);
221 _dbus_verbose ("Failed to open directory %s: %s\n",
222 directory, error ? error->message : "unknown");
226 /* Now read the files */
227 dbus_error_init (&tmp_error);
228 while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
230 _dbus_assert (!dbus_error_is_set (&tmp_error));
232 _dbus_string_set_length (&full_path, 0);
234 if (!_dbus_string_append (&full_path, directory) ||
235 !_dbus_concat_dir_and_file (&full_path, &filename))
241 if (!_dbus_string_ends_with_c_str (&filename, ".service"))
243 const char *filename_c;
244 _dbus_string_get_const_data (&filename, &filename_c);
245 _dbus_verbose ("Skipping non-.service file %s\n",
250 desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
252 if (desktop_file == NULL)
254 const char *full_path_c;
256 _dbus_string_get_const_data (&full_path, &full_path_c);
258 _dbus_verbose ("Could not load %s: %s\n", full_path_c,
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 const char *full_path_c;
275 bus_desktop_file_free (desktop_file);
278 _dbus_string_get_const_data (&full_path, &full_path_c);
280 _dbus_verbose ("Could not add %s to activation entry list: %s\n",
281 full_path_c, tmp_error.message);
283 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
285 dbus_move_error (&tmp_error, error);
289 dbus_error_free (&tmp_error);
294 bus_desktop_file_free (desktop_file);
300 if (dbus_error_is_set (&tmp_error))
302 dbus_move_error (&tmp_error, error);
309 _DBUS_ASSERT_ERROR_IS_SET (error);
312 _dbus_directory_close (iter);
314 bus_desktop_file_free (desktop_file);
315 _dbus_string_free (&filename);
316 _dbus_string_free (&full_path);
322 bus_activation_new (BusContext *context,
324 const char **directories,
328 BusActivation *activation;
330 activation = dbus_new0 (BusActivation, 1);
331 if (activation == NULL)
337 activation->refcount = 1;
338 activation->context = context;
340 /* FIXME: We should split up the server addresses. */
341 activation->server_address = _dbus_strdup (address);
342 if (activation->server_address == NULL)
348 activation->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
349 (DBusFreeFunction)bus_activation_entry_free);
350 if (activation->entries == NULL)
356 activation->pending_activations = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
357 (DBusFreeFunction)bus_pending_activation_free);
359 if (activation->pending_activations == NULL)
365 /* Load service files */
367 while (directories[i] != NULL)
369 if (!load_directory (activation, directories[i], error))
377 bus_activation_unref (activation);
382 bus_activation_ref (BusActivation *activation)
384 _dbus_assert (activation->refcount > 0);
386 activation->refcount += 1;
390 bus_activation_unref (BusActivation *activation)
392 _dbus_assert (activation->refcount > 0);
394 activation->refcount -= 1;
396 if (activation->refcount == 0)
398 dbus_free (activation->server_address);
399 if (activation->entries)
400 _dbus_hash_table_unref (activation->entries);
401 if (activation->pending_activations)
402 _dbus_hash_table_unref (activation->pending_activations);
403 dbus_free (activation);
408 child_setup (void *data)
410 BusActivation *activation = data;
412 /* If no memory, we simply have the child exit, so it won't try
413 * to connect to the wrong thing.
415 if (!_dbus_setenv ("DBUS_ADDRESS", activation->server_address))
420 bus_activation_service_created (BusActivation *activation,
421 const char *service_name,
424 BusPendingActivation *pending_activation;
425 DBusMessage *message;
428 /* Check if it's a pending activation */
429 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
431 if (!pending_activation)
434 link = _dbus_list_get_first_link (&pending_activation->entries);
437 BusPendingActivationEntry *entry = link->data;
438 DBusList *next = _dbus_list_get_next_link (&pending_activation->entries, link);
440 if (dbus_connection_get_is_connected (entry->connection))
442 message = dbus_message_new_reply (entry->activation_message);
449 if (!dbus_message_append_args (message,
450 DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ACTIVATED,
453 dbus_message_unref (message);
458 if (!dbus_connection_send (entry->connection, message, NULL))
460 dbus_message_unref (message);
466 bus_pending_activation_entry_free (entry);
468 _dbus_list_remove_link (&pending_activation->entries, link);
472 _dbus_hash_table_remove_string (activation->pending_activations, service_name);
477 _dbus_hash_table_remove_string (activation->pending_activations, service_name);
482 bus_activation_activate_service (BusActivation *activation,
483 DBusConnection *connection,
484 DBusMessage *activation_message,
485 const char *service_name,
488 BusActivationEntry *entry;
489 BusPendingActivation *pending_activation;
490 BusPendingActivationEntry *pending_activation_entry;
491 DBusMessage *message;
492 DBusString service_str;
496 entry = _dbus_hash_table_lookup_string (activation->entries, service_name);
500 dbus_set_error (error, DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND,
501 "The service %s was not found in the activation entry list",
506 /* Check if the service is active */
507 _dbus_string_init_const (&service_str, service_name);
508 if (bus_registry_lookup (bus_context_get_registry (activation->context), &service_str) != NULL)
510 message = dbus_message_new_reply (activation_message);
518 if (!dbus_message_append_args (message,
519 DBUS_TYPE_UINT32, DBUS_ACTIVATION_REPLY_ALREADY_ACTIVE,
523 dbus_message_unref (message);
527 retval = dbus_connection_send (connection, message, NULL);
528 dbus_message_unref (message);
535 pending_activation_entry = dbus_new0 (BusPendingActivationEntry, 1);
536 if (!pending_activation_entry)
542 pending_activation_entry->activation_message = activation_message;
543 dbus_message_ref (activation_message);
544 pending_activation_entry->connection = connection;
545 dbus_connection_ref (connection);
547 /* Check if the service is being activated */
548 pending_activation = _dbus_hash_table_lookup_string (activation->pending_activations, service_name);
549 if (pending_activation)
551 if (!_dbus_list_append (&pending_activation->entries, entry))
554 bus_pending_activation_entry_free (pending_activation_entry);
561 pending_activation = dbus_new0 (BusPendingActivation, 1);
562 if (!pending_activation)
565 bus_pending_activation_entry_free (pending_activation_entry);
568 pending_activation->service_name = _dbus_strdup (service_name);
569 if (!pending_activation->service_name)
572 bus_pending_activation_free (pending_activation);
573 bus_pending_activation_entry_free (pending_activation_entry);
577 if (!_dbus_list_append (&pending_activation->entries, entry))
580 bus_pending_activation_free (pending_activation);
581 bus_pending_activation_entry_free (pending_activation_entry);
585 if (!_dbus_hash_table_insert_string (activation->pending_activations,
586 pending_activation->service_name, pending_activation))
589 bus_pending_activation_free (pending_activation);
594 /* FIXME we need to support a full command line, not just a single
598 /* Now try to spawn the process */
599 argv[0] = entry->exec;
602 if (!_dbus_spawn_async (argv,
603 child_setup, activation,
606 _dbus_hash_table_remove_string (activation->pending_activations,
607 pending_activation->service_name);