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"
26 #include <dbus/dbus-internals.h>
27 #include <dbus/dbus-hash.h>
28 #include <sys/types.h>
32 #define DBUS_SERVICE_SECTION "D-BUS Service"
33 #define DBUS_SERVICE_NAME "Name"
34 #define DBUS_SERVICE_EXEC "Exec"
36 static DBusHashTable *activation_entries = NULL;
37 static char *server_address = NULL;
45 static DBusHashTable *pending_activations = NULL;
49 } BusPendingActivation;
52 bus_activation_entry_free (BusActivationEntry *entry)
57 dbus_free (entry->name);
58 dbus_free (entry->exec);
62 add_desktop_file_entry (BusDesktopFile *desktop_file,
66 BusActivationEntry *entry;
72 if (!bus_desktop_file_get_string (desktop_file,
77 dbus_set_error (error, DBUS_ERROR_FAILED,
78 "No \""DBUS_SERVICE_NAME"\" key in .service file\n");
82 if (!bus_desktop_file_get_string (desktop_file,
87 dbus_set_error (error, DBUS_ERROR_FAILED,
88 "No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
92 /* FIXME we need a better-defined algorithm for which service file to
93 * pick than "whichever one is first in the directory listing"
95 if (_dbus_hash_table_lookup_string (activation_entries, name))
97 dbus_set_error (error, DBUS_ERROR_FAILED,
98 "Service %s already exists in activation entry list\n", name);
102 entry = dbus_new0 (BusActivationEntry, 1);
112 if (!_dbus_hash_table_insert_string (activation_entries, entry->name, entry))
118 _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
130 /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
131 * hash entries it already added.
134 load_directory (const char *directory,
138 DBusString dir, filename;
139 DBusString full_path;
140 BusDesktopFile *desktop_file;
143 _dbus_string_init_const (&dir, directory);
148 if (!_dbus_string_init (&filename, _DBUS_INT_MAX))
154 if (!_dbus_string_init (&full_path, _DBUS_INT_MAX))
157 _dbus_string_free (&filename);
161 /* from this point it's safe to "goto failed" */
163 iter = _dbus_directory_open (&dir, error);
166 _dbus_verbose ("Failed to open directory %s: %s\n",
167 directory, error ? error->message : "unknown");
171 /* Now read the files */
172 dbus_error_init (&tmp_error);
173 while (_dbus_directory_get_next_file (iter, &filename, &tmp_error))
175 _dbus_assert (!dbus_error_is_set (&tmp_error));
177 _dbus_string_set_length (&full_path, 0);
179 if (!_dbus_string_append (&full_path, directory) ||
180 !_dbus_concat_dir_and_file (&full_path, &filename))
186 if (!_dbus_string_ends_with_c_str (&filename, ".service"))
188 const char *filename_c;
189 _dbus_string_get_const_data (&filename, &filename_c);
190 _dbus_verbose ("Skipping non-.service file %s\n",
195 desktop_file = bus_desktop_file_load (&full_path, &tmp_error);
197 if (desktop_file == NULL)
199 const char *full_path_c;
201 _dbus_string_get_const_data (&full_path, &full_path_c);
203 _dbus_verbose ("Could not load %s: %s\n", full_path_c,
206 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
208 dbus_move_error (&tmp_error, error);
212 dbus_error_free (&tmp_error);
216 if (!add_desktop_file_entry (desktop_file, &tmp_error))
218 const char *full_path_c;
220 bus_desktop_file_free (desktop_file);
223 _dbus_string_get_const_data (&full_path, &full_path_c);
225 _dbus_verbose ("Could not add %s to activation entry list: %s\n",
226 full_path_c, tmp_error.message);
228 if (dbus_error_has_name (&tmp_error, DBUS_ERROR_NO_MEMORY))
230 dbus_move_error (&tmp_error, error);
234 dbus_error_free (&tmp_error);
239 bus_desktop_file_free (desktop_file);
245 if (dbus_error_is_set (&tmp_error))
247 dbus_move_error (&tmp_error, error);
254 _DBUS_ASSERT_ERROR_IS_SET (error);
257 _dbus_directory_close (iter);
259 bus_desktop_file_free (desktop_file);
260 _dbus_string_free (&filename);
261 _dbus_string_free (&full_path);
267 bus_activation_init (const char *address,
268 const char **directories,
273 _dbus_assert (server_address == NULL);
274 _dbus_assert (activation_entries == NULL);
276 /* FIXME: We should split up the server addresses. */
277 server_address = _dbus_strdup (address);
278 if (server_address == NULL)
284 activation_entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
285 (DBusFreeFunction)bus_activation_entry_free);
286 if (activation_entries == NULL)
292 /* Load service files */
294 while (directories[i] != NULL)
296 if (!load_directory (directories[i], error))
304 dbus_free (server_address);
305 if (activation_entries)
306 _dbus_hash_table_unref (activation_entries);
312 child_setup (void *data)
314 /* If no memory, we simply have the child exit, so it won't try
315 * to connect to the wrong thing.
317 if (!_dbus_setenv ("DBUS_ADDRESS", server_address))
322 bus_activation_activate_service (const char *service_name,
325 BusActivationEntry *entry;
328 entry = _dbus_hash_table_lookup_string (activation_entries, service_name);
332 dbus_set_error (error, DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND,
333 "The service %s was not found in the activation entry list",
338 /* FIXME we need to support a full command line, not just a single
342 /* Now try to spawn the process */
343 argv[0] = entry->exec;
346 if (!_dbus_spawn_async (argv,