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

hal_hotplug.c

00001 /***************************************************************************
00002  * CVSID: $Id: hal_hotplug.c,v 1.12 2004/04/14 21:05:08 joe Exp $
00003  *
00004  * hal_hotplug.c : Tiny program to transform a linux-hotplug event into
00005  *                 a D-BUS message
00006  *
00007  * Copyright (C) 2003 David Zeuthen, <david@fubar.dk>
00008  *
00009  * Licensed under the Academic Free License version 2.0
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  **************************************************************************/
00026 
00027 #ifdef HAVE_CONFIG_H
00028 #  include <config.h>
00029 #endif
00030 
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <sys/types.h>
00035 #include <sys/stat.h>
00036 #include <unistd.h>
00037 #include <mntent.h>
00038 #include <syslog.h>
00039 #include <linux/limits.h>
00040 
00041 #include <dbus/dbus.h>
00042 
00058 static char sysfs_mnt_path[PATH_MAX];
00059 
00065 static int
00066 get_sysfs_mnt_path ()
00067 {
00068     FILE *mnt;
00069     struct mntent *mntent;
00070     int ret = 0;
00071     size_t dirlen = 0;
00072 
00073     if ((mnt = setmntent ("/proc/mounts", "r")) == NULL) {
00074         return -1;
00075     }
00076 
00077     while (ret == 0 && dirlen == 0
00078            && (mntent = getmntent (mnt)) != NULL) {
00079         if (strcmp (mntent->mnt_type, "sysfs") == 0) {
00080             dirlen = strlen (mntent->mnt_dir);
00081             if (dirlen <= (PATH_MAX - 1)) {
00082                 strcpy (sysfs_mnt_path, mntent->mnt_dir);
00083             } else {
00084                 ret = -1;
00085             }
00086         }
00087     }
00088     endmntent (mnt);
00089 
00090     if (dirlen == 0 && ret == 0) {
00091         ret = -1;
00092     }
00093     return ret;
00094 }
00095 
00096 static const char *file_list_usb[] = {
00097     "idProduct",
00098     "idVendor",
00099     "bcdDevice",
00100     "bMaxPower",
00101     /*"serial", */
00102     "bmAttributes",
00103     "manufacturer",
00104     "product",
00105     "bDeviceClass",
00106     "bDeviceSubClass",
00107     "bDeviceProtocol",
00108     "bNumConfigurations",
00109     "bConfigurationValue",
00110     "bNumInterfaces",
00111     NULL
00112 };
00113 
00114 static const char *file_list_usbif[] = {
00115     "bInterfaceClass",
00116     "bInterfaceSubClass",
00117     "bInterfaceProtocol",
00118     "bInterfaceNumber",
00119     NULL
00120 };
00121 
00122 static const char *file_list_scsi_device[] = { NULL };
00123 
00124 static const char *file_list_scsi_generic[] = { NULL };
00125 
00126 static const char *file_list_scsi_host[] = { NULL };
00127 
00128 static const char *file_list_block[] = {
00129     "dev",
00130     "size",
00131     NULL
00132 };
00133 
00134 static const char *file_list_pci[] = {
00135     "device",
00136     "vendor",
00137     "subsystem_device",
00138     "subsystem_vendor",
00139     "class",
00140     NULL
00141 };
00142 
00143 /* safely strcat() at most the remaining space in 'dst' */
00144 #define strcat_len(dst, src) do { \
00145     dst[sizeof (dst) - 1] = '\0'; \
00146     strncat (dst, src, sizeof (dst) - strlen (dst) - 1); \
00147 } while(0)
00148 
00149 static int
00150 wait_for_sysfs_info (char *devpath, char *hotplug_type)
00151 {
00152     size_t devpath_len;
00153     const char **file_list;
00154     int num_tries;
00155     int rc;
00156     struct stat stat_buf;
00157     int i;
00158     char path[PATH_MAX];
00159 
00160     syslog (LOG_NOTICE, "waiting for %s info at %s",
00161         hotplug_type, devpath);
00162 
00163     devpath_len = strlen (devpath);
00164 
00165     file_list = NULL;
00166 
00167     if (strcmp (hotplug_type, "pci") == 0) {
00168         file_list = file_list_pci;
00169     } else if (strcmp (hotplug_type, "usb") == 0) {
00170         int is_interface = 0;
00171 
00172         for (i = devpath_len - 1; devpath[i] != '/' && i > 0; --i) {
00173             if (devpath[i] == ':') {
00174                 is_interface = TRUE;
00175                 break;
00176             }
00177         }
00178 
00179         if (is_interface) {
00180             syslog (LOG_NOTICE, "%s is an USB interface",
00181                 devpath);
00182             file_list = file_list_usbif;
00183         } else
00184             file_list = file_list_usb;
00185     } else if (strcmp (hotplug_type, "scsi_device") == 0) {
00186         file_list = file_list_scsi_device;
00187     } else if (strcmp (hotplug_type, "scsi_generic") == 0) {
00188         file_list = file_list_scsi_generic;
00189     } else if (strcmp (hotplug_type, "scsi_host") == 0) {
00190         file_list = file_list_scsi_host;
00191     } else if (strcmp (hotplug_type, "block") == 0) {
00192         file_list = file_list_block;
00193     }
00194 
00195     if (file_list == NULL) {
00196         syslog (LOG_WARNING, "Dont know how to wait for %s at %s; "
00197             "sleeping 1000 ms", hotplug_type, devpath);
00198         usleep (1000 * 1000);
00199         return -1;
00200     }
00201 
00202     num_tries = 0;
00203 
00204       try_again:
00205     if (num_tries > 0) {
00206         usleep (100 * 1000);
00207     }
00208 
00209     if (num_tries == 20 * 10) {
00210         syslog (LOG_NOTICE, "timed out for %s (waited %d ms)",
00211             devpath, num_tries * 100);
00212         return -1;
00213     }
00214 
00215     num_tries++;
00216 
00217     /* first, check directory */
00218     strncpy (path, sysfs_mnt_path, PATH_MAX);
00219     strcat_len (path, devpath);
00220 
00221     /*printf("path0 = %s\n", path); */
00222 
00223     rc = stat (path, &stat_buf);
00224     /*printf("rc0 = %d\n", rc); */
00225     if (rc != 0)
00226         goto try_again;
00227 
00228     /* second, check each requested file */
00229     for (i = 0; file_list[i] != NULL; i++) {
00230         const char *file;
00231 
00232         file = file_list[i];
00233         strncpy (path, sysfs_mnt_path, PATH_MAX);
00234         strcat_len (path, devpath);
00235         strcat_len (path, "/");
00236         strcat_len (path, file);
00237         /*printf("path1 = %s\n", path); */
00238 
00239         rc = stat (path, &stat_buf);
00240 
00241         /*printf("rc1 = %d\n", rc); */
00242 
00243         if (rc != 0)
00244             goto try_again;
00245     }
00246 
00247     syslog (LOG_NOTICE, "got info for %s (waited %d ms)",
00248         devpath, (num_tries - 1) * 100);
00249 
00250     return 0;
00251 }
00252 
00253 
00261 int
00262 main (int argc, char *argv[], char *envp[])
00263 {
00264     int i, j, len;
00265     char *str;
00266     char *hotplug_type;
00267     char *devpath;
00268     int is_add;
00269     DBusError error;
00270     DBusConnection *sysbus_connection;
00271     DBusMessage *message;
00272     DBusMessageIter iter;
00273     DBusMessageIter iter_dict;
00274 
00275     if (argc != 2)
00276         return 1;
00277 
00278     if (get_sysfs_mnt_path () != 0)
00279         return 1;
00280 
00281     openlog ("hal.hotplug", LOG_PID, LOG_USER);
00282 
00283     /* Connect to a well-known bus instance, the system bus */
00284     dbus_error_init (&error);
00285     sysbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
00286     if (sysbus_connection == NULL)
00287         return 1;
00288 
00289     /* service, object, interface, member */
00290     message = dbus_message_new_method_call (
00291         "org.freedesktop.Hal",
00292         "/org/freedesktop/Hal/Linux/Hotplug",
00293         "org.freedesktop.Hal.Linux.Hotplug",
00294         "HotplugEvent");
00295 
00296     /* not interested in a reply */
00297     dbus_message_set_no_reply (message, TRUE);
00298 
00299     hotplug_type = argv[1];
00300     devpath = NULL;
00301 
00302     is_add = FALSE;
00303 
00304     dbus_message_iter_init (message, &iter);
00305     dbus_message_iter_append_string (&iter, hotplug_type);
00306     dbus_message_iter_append_dict (&iter, &iter_dict);
00307     for (i = 0; envp[i] != NULL; i++) {
00308         str = envp[i];
00309         len = strlen (str);
00310         for (j = 0; j < len && str[j] != '='; j++);
00311         str[j] = '\0';
00312 
00313         dbus_message_iter_append_dict_key (&iter_dict, str);
00314         dbus_message_iter_append_string (&iter_dict, str + j + 1);
00315 
00316         if (strcmp (str, "DEVPATH") == 0) {
00317             devpath = str + j + 1;
00318         } else if (strcmp (str, "ACTION") == 0) {
00319             if (strcmp (str + j + 1, "add") == 0) {
00320                 is_add = TRUE;
00321             }
00322         }
00323     }
00324 
00325     if (devpath != NULL && is_add) {
00326         int rc;
00327 
00328         /* wait for information to be published in sysfs */
00329         rc = wait_for_sysfs_info (devpath, hotplug_type);
00330         if (rc != 0) {
00332         }
00333     } else {
00334         /* Do some sleep here so the kernel have time to publish it's
00335          * stuff in sysfs
00336          */
00337         /*usleep(1000*1000); */
00338     }
00339 
00340     usleep (1000 * 1000);
00341 
00342     if (!dbus_connection_send (sysbus_connection, message, NULL))
00343         return 1;
00344 
00345     dbus_message_unref (message);
00346     dbus_connection_flush (sysbus_connection);
00347 
00348     /* Do some sleep here so messages are not lost.. */
00349     usleep (500 * 1000);
00350 
00351     dbus_connection_disconnect (sysbus_connection);
00352 
00353     return 0;
00354 }
00355 

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