Main Page | Modules | Data Structures | File List | Data Fields | Related Pages

callout.c

00001 /***************************************************************************
00002  * CVSID: $Id: callout.c,v 1.9 2004/04/21 21:40:45 joe Exp $
00003  *
00004  * callout.c : Call out to helper programs when devices are added/removed.
00005  *
00006  * Copyright (C) 2004 Novell, Inc.
00007  *
00008  * Licensed under the Academic Free License version 2.0
00009  *
00010  * This program is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2 of the License, or
00013  * (at your option) any later version.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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,    /* device or capability is being added */
00044     CALLOUT_REMOVE, /* device or capability is being removed */
00045     CALLOUT_MODIFY, /* property is being modified */
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     /* periods aren't valid in the environment, so replace them with
00074      * underscores. */
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         /* Not finished yet... */
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      * All the properties, plus any special env vars set up for this
00163      * type of callout, plus one for a trailing NULL.
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      * envp_index is incremented in the foreach, so afterward we're
00173      * pointing at the end of the array.
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     /* Directory doesn't exist.  This isn't an error, just exit
00196      * quietly. */
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     /* Directory doesn't exist.  This isn't an error, just exit
00255      * quietly. */
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     /* Directory doesn't exist.  This isn't an error, just exit
00317      * quietly. */
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 }

Generated on Sat Apr 24 19:57:44 2004 for HAL by doxygen 1.3.6-20040222