b4acd0f347d3a47064f93f67b39cb8c715871f3d
[platform/upstream/dbus.git] / bus / activation.c
1 /* -*- mode: C; c-file-style: "gnu" -*- */
2 /* activation.c  Activation of services
3  *
4  * Copyright (C) 2003  CodeFactory AB
5  *
6  * Licensed under the Academic Free License version 1.2
7  * 
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.
12  *
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.
17  * 
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
21  *
22  */
23 #include "activation.h"
24 #include "desktop-file.h"
25 #include "utils.h"
26 #include <dbus/dbus-internals.h>
27 #include <dbus/dbus-hash.h>
28 #include <sys/types.h>
29 #include <dirent.h>
30 #include <errno.h>
31
32 #define DBUS_SERVICE_SECTION "D-BUS Service"
33 #define DBUS_SERVICE_NAME "Name"
34 #define DBUS_SERVICE_EXEC "Exec"
35
36 static DBusHashTable *activation_entries = NULL;
37
38 typedef struct
39 {
40   char *name;
41   char *exec;
42 } BusActivationEntry;
43
44 static DBusHashTable *pending_activations = NULL;
45 typedef struct
46 {
47   char *service;
48 } BusPendingActivation;
49
50 static void
51 bus_activation_entry_free (BusActivationEntry *entry)
52 {
53   if (!entry)
54     return;
55   
56   dbus_free (entry->name);
57   dbus_free (entry->exec);
58 }
59
60 static dbus_bool_t
61 add_desktop_file_entry (BusDesktopFile *desktop_file)
62 {
63   char *name, *exec;
64   BusActivationEntry *entry;
65   
66   if (!bus_desktop_file_get_string (desktop_file,
67                                     DBUS_SERVICE_SECTION,
68                                     DBUS_SERVICE_NAME,
69                                     &name))
70     {
71       _dbus_verbose ("No \""DBUS_SERVICE_NAME"\" key in .service file\n");
72       return FALSE;
73     }
74
75   if (!bus_desktop_file_get_string (desktop_file,
76                                     DBUS_SERVICE_SECTION,
77                                     DBUS_SERVICE_EXEC,
78                                     &exec))
79     {
80       _dbus_verbose ("No \""DBUS_SERVICE_EXEC"\" key in .service file\n");
81       
82       dbus_free (name);
83       return FALSE;
84     }
85
86   if (_dbus_hash_table_lookup_string (activation_entries, name))
87     {
88       _dbus_verbose ("Service %s already exists in activation entry list\n", name);
89       dbus_free (name);
90       dbus_free (exec);
91
92       return FALSE;
93     }
94   
95   BUS_HANDLE_OOM (entry = dbus_malloc0 (sizeof (BusActivationEntry)));
96   entry->name = name;
97   entry->exec = exec;
98
99   BUS_HANDLE_OOM (_dbus_hash_table_insert_string (activation_entries, entry->name, entry));
100
101   _dbus_verbose ("Added \"%s\" to list of services\n", entry->name);
102   
103   return TRUE;
104 }
105
106 static void
107 load_directory (const char *directory)
108 {
109   DBusDirIter *iter;
110   DBusString dir, filename;
111   DBusResultCode result;
112
113   _dbus_string_init_const (&dir, directory);
114   
115   iter = _dbus_directory_open (&dir, &result);
116   if (iter == NULL)
117     {
118       _dbus_verbose ("Failed to open directory %s: &s\n", directory,
119                      result);
120     return;
121     }
122
123   BUS_HANDLE_OOM (_dbus_string_init (&filename, _DBUS_INT_MAX));
124   
125   /* Now read the files */
126   while (_dbus_directory_get_next_file (iter, &filename, &result))
127     {
128       DBusString full_path;
129       BusDesktopFile *desktop_file;
130       DBusError error;
131       
132       if (!_dbus_string_ends_with_c_str (&filename, ".service"))
133         {
134           const char *filename_c;
135           _dbus_string_get_const_data (&filename, &filename_c);
136           _dbus_verbose ("Skipping non-.service file %s\n",
137                          filename_c);
138           continue;
139         }
140       
141       BUS_HANDLE_OOM (_dbus_string_init (&full_path, _DBUS_INT_MAX));
142       BUS_HANDLE_OOM (_dbus_string_append (&full_path, directory));
143
144       BUS_HANDLE_OOM (_dbus_concat_dir_and_file (&full_path, &filename));
145
146       desktop_file = bus_desktop_file_load (&full_path, &error);
147
148       if (!desktop_file)
149         {
150           const char *full_path_c;
151
152           _dbus_string_get_const_data (&full_path, &full_path_c);
153           
154           _dbus_verbose ("Could not load %s: %s\n", full_path_c,
155                          error.message);
156           dbus_error_free (&error);
157           _dbus_string_free (&full_path);
158           continue;
159         }
160
161       if (!add_desktop_file_entry (desktop_file))
162         {
163           const char *full_path_c;
164
165           _dbus_string_get_const_data (&full_path, &full_path_c);
166           
167           _dbus_verbose ("Could not add %s to activation entry list.\n", full_path_c);
168         }
169
170       bus_desktop_file_free (desktop_file);
171       _dbus_string_free (&full_path);
172     }
173 }
174
175
176 void
177 bus_activation_init (const char **directories)
178 {
179   int i;
180
181   BUS_HANDLE_OOM (activation_entries = _dbus_hash_table_new (DBUS_HASH_STRING, NULL,
182                                                              (DBusFreeFunction)bus_activation_entry_free));
183
184   i = 0;
185
186   /* Load service files */
187   while (directories[i] != NULL)
188     {
189       load_directory (directories[i]);
190       i++;
191     }
192 }
193
194 dbus_bool_t
195 bus_activation_activate_service (const char  *service_name,
196                                  DBusError   *error)
197 {
198   BusActivationEntry *entry;
199   char *argv[2];
200   
201   entry = _dbus_hash_table_lookup_string (activation_entries, service_name);
202
203   if (!entry)
204     {
205       dbus_set_error (error, DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND,
206                       "The service %s was not found in the activation entry list",
207                       service_name);
208       return FALSE;
209     }
210
211   /* Now try to spawn the process */
212   argv[0] = entry->exec;
213   argv[1] = NULL;
214
215   if (!_dbus_spawn_async (argv, error))
216     return FALSE;
217
218   return TRUE;
219 }