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

hal_hotplug.c

00001 /***************************************************************************
00002  * CVSID: $Id: hal_hotplug.c,v 1.9 2004/03/03 17:56:56 david 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 
00040 #include <dbus/dbus.h>
00041 
00057 static char *sysfs_mnt_path[255];
00058 
00064 static int
00065 get_sysfs_mnt_path ()
00066 {
00067     FILE *mnt;
00068     struct mntent *mntent;
00069     int ret = 0;
00070     size_t dirlen = 0;
00071 
00072     if ((mnt = setmntent ("/proc/mounts", "r")) == NULL) {
00073         return -1;
00074     }
00075 
00076     while (ret == 0 && dirlen == 0
00077            && (mntent = getmntent (mnt)) != NULL) {
00078         if (strcmp (mntent->mnt_type, "sysfs") == 0) {
00079             dirlen = strlen (mntent->mnt_dir);
00080             if (dirlen <= (255 - 1)) {
00081                 strcpy (sysfs_mnt_path, mntent->mnt_dir);
00082             } else {
00083                 ret = -1;
00084             }
00085         }
00086     }
00087     endmntent (mnt);
00088 
00089     if (dirlen == 0 && ret == 0) {
00090         ret = -1;
00091     }
00092     return ret;
00093 }
00094 
00095 static char *file_list_usb[] = { "idProduct",
00096     "idVendor",
00097     "bcdDevice",
00098     "bMaxPower",
00099     /*"serial", */
00100     "bmAttributes",
00101     "manufacturer",
00102     "product",
00103     "bDeviceClass",
00104     "bDeviceSubClass",
00105     "bDeviceProtocol",
00106     "bNumConfigurations",
00107     "bConfigurationValue",
00108     "bNumInterfaces",
00109     NULL
00110 };
00111 
00112 static char *file_list_usbif[] = { "bInterfaceClass",
00113     "bInterfaceSubClass",
00114     "bInterfaceProtocol",
00115     "bInterfaceNumber",
00116     NULL
00117 };
00118 
00119 static char *file_list_scsi_device[] = { NULL };
00120 
00121 static char *file_list_scsi_host[] = { NULL };
00122 
00123 static char *file_list_block[] = { "dev",
00124     "size",
00125     NULL
00126 };
00127 
00128 static char *file_list_pci[] = { "device",
00129     "vendor",
00130     "subsystem_device",
00131     "subsystem_vendor",
00132     "class",
00133     NULL
00134 };
00135 
00136 static int
00137 wait_for_sysfs_info (char *devpath, char *hotplug_type)
00138 {
00139     size_t devpath_len;
00140     char **file_list;
00141     int num_tries;
00142     int rc;
00143     struct stat stat_buf;
00144     char *file;
00145     int i;
00146     char path[255];
00147 
00148     syslog (LOG_NOTICE, "waiting for %s info at %s",
00149         hotplug_type, devpath);
00150 
00151     devpath_len = strlen (devpath);
00152 
00153     file_list = NULL;
00154 
00155     if (strcmp (hotplug_type, "pci") == 0) {
00156         file_list = file_list_pci;
00157     } else if (strcmp (hotplug_type, "usb") == 0) {
00158         int is_interface = 0;
00159 
00160         for (i = devpath_len - 1; devpath[i] != '/' && i > 0; --i) {
00161             if (devpath[i] == ':') {
00162                 is_interface = TRUE;
00163                 break;
00164             }
00165         }
00166 
00167         if (is_interface) {
00168             syslog (LOG_NOTICE, "%s is an USB interface",
00169                 devpath);
00170             file_list = file_list_usbif;
00171         } else
00172             file_list = file_list_usb;
00173     } else if (strcmp (hotplug_type, "scsi_device") == 0) {
00174         file_list = file_list_scsi_device;
00175     } else if (strcmp (hotplug_type, "scsi_host") == 0) {
00176         file_list = file_list_scsi_host;
00177     } else if (strcmp (hotplug_type, "block") == 0) {
00178         file_list = file_list_block;
00179     }
00180 
00181     if (file_list == NULL) {
00182         syslog (LOG_WARNING, "Dont know how to wait for %s at %s; "
00183             "sleeping 1000 ms", hotplug_type, devpath);
00184         usleep (1000 * 1000);
00185         return -1;
00186     }
00187 
00188     num_tries = 0;
00189 
00190       try_again:
00191     if (num_tries > 0) {
00192         usleep (100 * 1000);
00193     }
00194 
00195     if (num_tries == 20 * 10) {
00196         syslog (LOG_NOTICE, "timed out for %s (waited %d ms)",
00197             devpath, num_tries * 100);
00198         return -1;
00199     }
00200 
00201     num_tries++;
00202 
00203     /* first, check directory */
00204     strncpy (path, sysfs_mnt_path, 255);
00205     strncat (path, devpath, 255);
00206 
00207     /*printf("path0 = %s\n", path); */
00208 
00209     rc = stat (path, &stat_buf);
00210     /*printf("rc0 = %d\n", rc); */
00211     if (rc != 0)
00212         goto try_again;
00213 
00214     /* second, check each requested file */
00215     for (i = 0; file_list[i] != NULL; i++) {
00216         file = file_list[i];
00217 
00218         strncpy (path, sysfs_mnt_path, 255);
00219         strncat (path, devpath, 255);
00220         strncat (path, "/", 255);
00221         strncat (path, file, 255);
00222 
00223         /*printf("path1 = %s\n", path); */
00224 
00225         rc = stat (path, &stat_buf);
00226 
00227         /*printf("rc1 = %d\n", rc); */
00228 
00229         if (rc != 0)
00230             goto try_again;
00231     }
00232 
00233     syslog (LOG_NOTICE, "got info for %s (waited %d ms)",
00234         devpath, (num_tries - 1) * 100);
00235 
00236     return 0;
00237 }
00238 
00239 
00247 int
00248 main (int argc, char *argv[], char *envp[])
00249 {
00250     int i, j, len;
00251     char *str;
00252     char *hotplug_type;
00253     char *devpath;
00254     int is_add;
00255     DBusError error;
00256     DBusConnection *sysbus_connection;
00257     DBusMessage *message;
00258     DBusMessageIter iter;
00259     DBusMessageIter iter_dict;
00260 
00261     if (argc != 2)
00262         return 1;
00263 
00264     if (get_sysfs_mnt_path () != 0)
00265         return 1;
00266 
00267     openlog ("hal.hotplug", LOG_PID, LOG_USER);
00268 
00269     /* Connect to a well-known bus instance, the system bus */
00270     dbus_error_init (&error);
00271     sysbus_connection = dbus_bus_get (DBUS_BUS_SYSTEM, &error);
00272     if (sysbus_connection == NULL)
00273         return 1;
00274 
00275     /* service, object, interface, member */
00276     message = dbus_message_new_method_call (
00277         "org.freedesktop.Hal",
00278         "/org/freedesktop/Hal/Linux/Hotplug",
00279         "org.freedesktop.Hal.Linux.Hotplug",
00280         "HotplugEvent");
00281 
00282     /* not interested in a reply */
00283     dbus_message_set_no_reply (message, TRUE);
00284 
00285     hotplug_type = argv[1];
00286     devpath = NULL;
00287 
00288     is_add = FALSE;
00289 
00290     dbus_message_iter_init (message, &iter);
00291     dbus_message_iter_append_string (&iter, hotplug_type);
00292     dbus_message_iter_append_dict (&iter, &iter_dict);
00293     for (i = 0; envp[i] != NULL; i++) {
00294         str = envp[i];
00295         len = strlen (str);
00296         for (j = 0; j < len && str[j] != '='; j++);
00297         str[j] = '\0';
00298 
00299         dbus_message_iter_append_dict_key (&iter_dict, str);
00300         dbus_message_iter_append_string (&iter_dict, str + j + 1);
00301 
00302         if (strcmp (str, "DEVPATH") == 0) {
00303             devpath = str + j + 1;
00304         } else if (strcmp (str, "ACTION") == 0) {
00305             if (strcmp (str + j + 1, "add") == 0) {
00306                 is_add = TRUE;
00307             }
00308         }
00309     }
00310 
00311     if (devpath != NULL && is_add) {
00312         int rc;
00313 
00314         /* wait for information to be published in sysfs */
00315         rc = wait_for_sysfs_info (devpath, hotplug_type);
00316         if (rc != 0) {
00318         }
00319     } else {
00320         /* Do some sleep here so the kernel have time to publish it's
00321          * stuff in sysfs
00322          */
00323         /*usleep(1000*1000); */
00324     }
00325 
00326     usleep (1000 * 1000);
00327 
00328     if (!dbus_connection_send (sysbus_connection, message, NULL))
00329         return 1;
00330 
00331     dbus_message_unref (message);
00332     dbus_connection_flush (sysbus_connection);
00333 
00334     /* Do some sleep here so messages are not lost.. */
00335     usleep (500 * 1000);
00336 
00337     dbus_connection_disconnect (sysbus_connection);
00338 
00339     return 0;
00340 }
00341 

Generated on Thu Mar 11 21:32:22 2004 for HAL by doxygen 1.3.6-20040222