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"
39 DBusHashTable *entries;
50 bus_activation_entry_free (BusActivationEntry *entry)
55 dbus_free (entry->name);
56 dbus_free (entry->exec);
60 add_desktop_file_entry (BusActivation *activation,
61 BusDesktopFile *desktop_file,
65 BusActivationEntry *entry;
71 if (!bus_desktop_file_get_string (desktop_file,
76 dbus_set_error (error, DBUS_ERROR_FAILED,
77 "No \""DBUS_SERVICE_NAME"\" key in .service file\n");
81 if (!bus_desktop_file_get_string (desktop_file,
86 dbus_set_error (error, DBUS_ERROR_FAILED,
87 "No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
91 /* FIXME we need a better-defined algorithm for which service file to
92 * pick than "whichever one is first in the directory listing"
94 if (_dbus_hash_table_lookup_string (activation->entries, name))
96 dbus_set_error (error, DBUS_ERROR_FAILED,
97 "Service %s already exists in activation entry list\n", name);
101 entry = dbus_new0 (BusActivationEntry, 1);
111 if (!_dbus_hash_table_insert_string (activation->entries, entry->name, entry))
117 _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
129 /* warning: this doesn't fully "undo" itself on failure, i.e. doesn't strip
130 * hash entries it already added.
133 load_directory (BusActivation *activation,
134 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 (activation, 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_new (const char *address,
268 const char **directories,
272 BusActivation *activation;
274 activation = dbus_new0 (BusActivation, 1);
275 if (activation == NULL)
281 activation->refcount = 1;
283 /* FIXME: We should split up the server addresses. */
284 activation->server_address = _dbus_strdup (address);
285 if (activation->server_address == NULL)
291 activation->entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
292 (DBusFreeFunction)bus_activation_entry_free);
293 if (activation->entries == NULL)
299 /* Load service files */
301 while (directories[i] != NULL)
303 if (!load_directory (activation, directories[i], error))
311 bus_activation_unref (activation);
316 bus_activation_ref (BusActivation *activation)
318 _dbus_assert (activation->refcount > 0);
320 activation->refcount += 1;
324 bus_activation_unref (BusActivation *activation)
326 _dbus_assert (activation->refcount > 0);
328 activation->refcount -= 1;
330 if (activation->refcount == 0)
332 dbus_free (activation->server_address);
333 if (activation->entries)
334 _dbus_hash_table_unref (activation->entries);
335 dbus_free (activation);
340 child_setup (void *data)
342 BusActivation *activation = data;
344 /* If no memory, we simply have the child exit, so it won't try
345 * to connect to the wrong thing.
347 if (!_dbus_setenv ("DBUS_ADDRESS", activation->server_address))
352 bus_activation_activate_service (BusActivation *activation,
353 const char *service_name,
356 BusActivationEntry *entry;
359 entry = _dbus_hash_table_lookup_string (activation->entries, service_name);
363 dbus_set_error (error, DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND,
364 "The service %s was not found in the activation entry list",
369 /* FIXME we need to support a full command line, not just a single
373 /* Now try to spawn the process */
374 argv[0] = entry->exec;
377 if (!_dbus_spawn_async (argv,
378 child_setup, activation,