00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #ifdef HAVE_CONFIG_H
00027 # include <config.h>
00028 #endif
00029
00030 #include <sys/types.h>
00031 #include <sys/wait.h>
00032 #include <errno.h>
00033 #include <string.h>
00034
00035 #include "callout.h"
00036 #include "logger.h"
00037
00038 #define DEVICE_CALLOUT_DIR PACKAGE_SYSCONF_DIR "/hal/device.d"
00039 #define CAPABILITY_CALLOUT_DIR PACKAGE_SYSCONF_DIR "/hal/capability.d"
00040 #define PROPERTY_CALLOUT_DIR PACKAGE_SYSCONF_DIR "/hal/property.d"
00041
00042 enum {
00043 CALLOUT_ADD,
00044 CALLOUT_REMOVE,
00045 CALLOUT_MODIFY,
00046 };
00047
00048 typedef struct {
00049 const char *working_dir;
00050 char *filename;
00051 int action;
00052 HalDevice *device;
00053 char **envp;
00054 int envp_index;
00055 int pid;
00056 } Callout;
00057
00058 static void process_callouts (void);
00059
00060 static GSList *pending_callouts = NULL;
00061 static gboolean processing_callouts = FALSE;
00062
00063 static gboolean
00064 add_property_to_env (HalDevice *device, HalProperty *property,
00065 gpointer user_data)
00066 {
00067 Callout *callout = user_data;
00068 char *prop_upper, *value;
00069 char *c;
00070
00071 prop_upper = g_ascii_strup (hal_property_get_key (property), -1);
00072
00073
00074
00075 for (c = prop_upper; *c; c++) {
00076 if (*c == '.')
00077 *c = '_';
00078 }
00079
00080 value = hal_property_to_string (property);
00081
00082 callout->envp[callout->envp_index] =
00083 g_strdup_printf ("HAL_PROP_%s=%s",
00084 prop_upper,
00085 value);
00086
00087 g_free (value);
00088 g_free (prop_upper);
00089
00090 callout->envp_index++;
00091
00092 return TRUE;
00093 }
00094
00095 static gboolean
00096 wait_for_callout (gpointer user_data)
00097 {
00098 Callout *callout = user_data;
00099 int status;
00100
00101 status = waitpid (callout->pid, NULL, WNOHANG);
00102
00103 if (status == 0) {
00104
00105 return TRUE;
00106 } else if (status == -1) {
00107 if (errno == EINTR)
00108 return TRUE;
00109 else {
00110 HAL_WARNING (("waitpid errno %d: %s", errno,
00111 strerror (errno)));
00112 }
00113 } else {
00114 g_free (callout->filename);
00115 g_strfreev (callout->envp);
00116 g_object_unref (callout->device);
00117 g_free (callout);
00118
00119 process_callouts ();
00120 }
00121
00122 return FALSE;
00123 }
00124
00125 static void
00126 process_callouts (void)
00127 {
00128 Callout *callout;
00129 char *argv[3];
00130 GError *err = NULL;
00131 int num_props;
00132
00133 if (pending_callouts == NULL) {
00134 processing_callouts = FALSE;
00135 return;
00136 }
00137
00138 processing_callouts = TRUE;
00139
00140 callout = (Callout *) pending_callouts->data;
00141 pending_callouts = g_slist_remove (pending_callouts, callout);
00142
00143 argv[0] = callout->filename;
00144
00145 switch (callout->action) {
00146 case CALLOUT_ADD:
00147 argv[1] = "add";
00148 break;
00149 case CALLOUT_REMOVE:
00150 argv[1] = "remove";
00151 break;
00152 case CALLOUT_MODIFY:
00153 argv[1] = "modify";
00154 break;
00155 }
00156
00157 argv[2] = NULL;
00158
00159 num_props = hal_device_num_properties (callout->device);
00160
00161
00162
00163
00164
00165 callout->envp = g_renew (char *, callout->envp,
00166 num_props + callout->envp_index + 1);
00167
00168 hal_device_property_foreach (callout->device, add_property_to_env,
00169 callout);
00170
00171
00172
00173
00174
00175 callout->envp[callout->envp_index] = NULL;
00176
00177 if (!g_spawn_async (callout->working_dir, argv, callout->envp,
00178 G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL,
00179 &callout->pid, &err)) {
00180 HAL_WARNING (("Couldn't invoke %s: %s", argv[0],
00181 err->message));
00182 g_error_free (err);
00183 }
00184
00185 g_timeout_add (250, wait_for_callout, callout);
00186 }
00187
00188 void
00189 hal_callout_device (HalDevice *device, gboolean added)
00190 {
00191 GDir *dir;
00192 GError *err = NULL;
00193 const char *filename;
00194
00195
00196
00197 if (!g_file_test (DEVICE_CALLOUT_DIR, G_FILE_TEST_EXISTS))
00198 return;
00199
00200 dir = g_dir_open (DEVICE_CALLOUT_DIR, 0, &err);
00201
00202 if (dir == NULL) {
00203 HAL_WARNING (("Unable to open device callout directory: %s",
00204 err->message));
00205 g_error_free (err);
00206 return;
00207 }
00208
00209 while ((filename = g_dir_read_name (dir)) != NULL) {
00210 char *full_filename;
00211 Callout *callout;
00212 int num_props;
00213
00214 full_filename = g_build_filename (DEVICE_CALLOUT_DIR,
00215 filename, NULL);
00216
00217 if (!g_file_test (full_filename, G_FILE_TEST_IS_EXECUTABLE)) {
00218 g_free (full_filename);
00219 continue;
00220 }
00221
00222 g_free (full_filename);
00223
00224 callout = g_new0 (Callout, 1);
00225
00226 callout->working_dir = DEVICE_CALLOUT_DIR;
00227 callout->filename = g_strdup (filename);
00228 callout->action = added ? CALLOUT_ADD : CALLOUT_REMOVE;
00229 callout->device = g_object_ref (device);
00230
00231 num_props = hal_device_num_properties (device);
00232
00233 callout->envp_index = 1;
00234 callout->envp = g_new (char *, callout->envp_index);
00235
00236 callout->envp[0] = g_strdup_printf ("UDI=%s",
00237 hal_device_get_udi (device));
00238 pending_callouts = g_slist_append (pending_callouts, callout);
00239 }
00240
00241 g_dir_close (dir);
00242
00243 if (pending_callouts != NULL && !processing_callouts)
00244 process_callouts ();
00245 }
00246
00247 void
00248 hal_callout_capability (HalDevice *device, const char *capability, gboolean added)
00249 {
00250 GDir *dir;
00251 GError *err = NULL;
00252 const char *filename;
00253
00254
00255
00256 if (!g_file_test (CAPABILITY_CALLOUT_DIR, G_FILE_TEST_EXISTS))
00257 return;
00258
00259 dir = g_dir_open (CAPABILITY_CALLOUT_DIR, 0, &err);
00260
00261 if (dir == NULL) {
00262 HAL_WARNING (("Unable to open capability callout directory: "
00263 "%s", err->message));
00264 g_error_free (err);
00265 return;
00266 }
00267
00268 while ((filename = g_dir_read_name (dir)) != NULL) {
00269 char *full_filename;
00270 Callout *callout;
00271 int num_props;
00272
00273 full_filename = g_build_filename (CAPABILITY_CALLOUT_DIR,
00274 filename, NULL);
00275
00276 if (!g_file_test (full_filename, G_FILE_TEST_IS_EXECUTABLE)) {
00277 g_free (full_filename);
00278 continue;
00279 }
00280
00281 g_free (full_filename);
00282
00283 callout = g_new0 (Callout, 1);
00284
00285 callout->working_dir = CAPABILITY_CALLOUT_DIR;
00286 callout->filename = g_strdup (filename);
00287 callout->action = added ? CALLOUT_ADD : CALLOUT_REMOVE;
00288 callout->device = g_object_ref (device);
00289
00290 num_props = hal_device_num_properties (device);
00291
00292 callout->envp_index = 2;
00293 callout->envp = g_new (char *, callout->envp_index);
00294
00295 callout->envp[0] = g_strdup_printf ("UDI=%s",
00296 hal_device_get_udi (device));
00297 callout->envp[1] = g_strdup_printf ("CAPABILITY=%s",
00298 capability);
00299
00300 pending_callouts = g_slist_append (pending_callouts, callout);
00301 }
00302
00303 g_dir_close (dir);
00304
00305 if (pending_callouts != NULL && !processing_callouts)
00306 process_callouts ();
00307 }
00308
00309 void
00310 hal_callout_property (HalDevice *device, const char *key)
00311 {
00312 GDir *dir;
00313 GError *err = NULL;
00314 const char *filename;
00315
00316
00317
00318 if (!g_file_test (PROPERTY_CALLOUT_DIR, G_FILE_TEST_EXISTS))
00319 return;
00320
00321 dir = g_dir_open (PROPERTY_CALLOUT_DIR, 0, &err);
00322
00323 if (dir == NULL) {
00324 HAL_WARNING (("Unable to open capability callout directory: "
00325 "%s", err->message));
00326 g_error_free (err);
00327 return;
00328 }
00329
00330 while ((filename = g_dir_read_name (dir)) != NULL) {
00331 char *full_filename, *value;
00332 Callout *callout;
00333 int num_props;
00334
00335 full_filename = g_build_filename (PROPERTY_CALLOUT_DIR,
00336 filename, NULL);
00337
00338 if (!g_file_test (full_filename, G_FILE_TEST_IS_EXECUTABLE)) {
00339 g_free (full_filename);
00340 continue;
00341 }
00342
00343 g_free (full_filename);
00344
00345 callout = g_new0 (Callout, 1);
00346
00347 callout->working_dir = PROPERTY_CALLOUT_DIR;
00348 callout->filename = g_strdup (filename);
00349 callout->action = CALLOUT_MODIFY;
00350 callout->device = g_object_ref (device);
00351
00352 num_props = hal_device_num_properties (device);
00353
00354 value = hal_device_property_to_string (device, key);
00355
00356 callout->envp_index = 3;
00357 callout->envp = g_new (char *, callout->envp_index);
00358
00359 callout->envp[0] = g_strdup_printf ("UDI=%s",
00360 hal_device_get_udi (device));
00361 callout->envp[1] = g_strdup_printf ("PROPERTY=%s", key);
00362 callout->envp[2] = g_strdup_printf ("VALUE=%s", value);
00363
00364 pending_callouts = g_slist_append (pending_callouts, callout);
00365
00366 g_free (value);
00367 }
00368
00369 g_dir_close (dir);
00370
00371 if (pending_callouts != NULL && !processing_callouts)
00372 process_callouts ();
00373 }