hotplug_libhal.c

Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 2008
00005  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00006  *
00007  * $Id: hotplug_libhal.c 3304 2009-02-06 08:46:19Z rousseau $
00008  */
00009 
00015 #include "config.h"
00016 #ifdef HAVE_LIBHAL
00017 
00018 #include <string.h>
00019 #include <stdio.h>
00020 #include <dirent.h>
00021 #include <stdlib.h>
00022 #include <libhal.h>
00023 
00024 #include "misc.h"
00025 #include "wintypes.h"
00026 #include "pcscd.h"
00027 #include "debuglog.h"
00028 #include "parser.h"
00029 #include "readerfactory.h"
00030 #include "sys_generic.h"
00031 #include "hotplug.h"
00032 #include "thread_generic.h"
00033 #include "utils.h"
00034 
00035 #undef DEBUG_HOTPLUG
00036 #define ADD_SERIAL_NUMBER
00037 
00038 #define FALSE           0
00039 #define TRUE            1
00040 
00041 #define UDI_BASE "/org/freedesktop/Hal/devices/"
00042 
00043 extern PCSCLITE_MUTEX usbNotifierMutex;
00044 
00045 static PCSCLITE_THREAD_T usbNotifyThread;
00046 static int driverSize = -1;
00047 static char AraKiriHotPlug = FALSE;
00048 
00049 static DBusConnection *conn;
00050 static LibHalContext *hal_ctx;
00051 
00055 static struct _driverTracker
00056 {
00057     unsigned int manuID;
00058     unsigned int productID;
00059 
00060     char *bundleName;
00061     char *libraryPath;
00062     char *readerName;
00063     int ifdCapabilities;
00064 } *driverTracker = NULL;
00065 #define DRIVER_TRACKER_SIZE_STEP 8
00066 
00070 static struct _readerTracker
00071 {
00072     char *udi;  
00073     char *fullName; 
00074 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
00075 
00076 static LONG HPReadBundleValues(void);
00077 static void HPAddDevice(LibHalContext *ctx, const char *udi);
00078 static void HPRemoveDevice(LibHalContext *ctx, const char *udi);
00079 static void HPEstablishUSBNotifications(void);
00080 
00086 static const char *short_name(const char *udi)
00087 {
00088     return &udi[sizeof(UDI_BASE) - 1];
00089 } /* short_name */
00090 
00091 
00092 static LONG HPReadBundleValues(void)
00093 {
00094     LONG rv;
00095     DIR *hpDir;
00096     struct dirent *currFP = NULL;
00097     char fullPath[FILENAME_MAX];
00098     char fullLibPath[FILENAME_MAX];
00099     char keyValue[TOKEN_MAX_VALUE_SIZE];
00100     int listCount = 0;
00101 
00102     hpDir = opendir(PCSCLITE_HP_DROPDIR);
00103 
00104     if (NULL == hpDir)
00105     {
00106         Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
00107         Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
00108         return -1;
00109     }
00110 
00111     /* allocate a first array */
00112     driverTracker = calloc(DRIVER_TRACKER_SIZE_STEP, sizeof(*driverTracker));
00113     if (NULL == driverTracker)
00114     {
00115         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00116         return -1;
00117     }
00118     driverSize = DRIVER_TRACKER_SIZE_STEP;
00119 
00120     while ((currFP = readdir(hpDir)) != 0)
00121     {
00122         if (strstr(currFP->d_name, ".bundle") != 0)
00123         {
00124             int alias = 0;
00125 
00126             /*
00127              * The bundle exists - let's form a full path name and get the
00128              * vendor and product ID's for this particular bundle
00129              */
00130             (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
00131                 PCSCLITE_HP_DROPDIR, currFP->d_name);
00132             fullPath[sizeof(fullPath) - 1] = '\0';
00133 
00134             /* while we find a nth ifdVendorID in Info.plist */
00135             while (LTPBundleFindValueWithKey(fullPath, PCSCLITE_HP_MANUKEY_NAME,
00136                 keyValue, alias) == 0)
00137             {
00138                 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00139 
00140                 /* Get ifdVendorID */
00141                 rv = LTPBundleFindValueWithKey(fullPath,
00142                     PCSCLITE_HP_MANUKEY_NAME, keyValue, alias);
00143                 if (0 == rv)
00144                     driverTracker[listCount].manuID = strtol(keyValue, NULL, 16);
00145 
00146                 /* get ifdProductID */
00147                 rv = LTPBundleFindValueWithKey(fullPath,
00148                     PCSCLITE_HP_PRODKEY_NAME, keyValue, alias);
00149                 if (0 == rv)
00150                     driverTracker[listCount].productID =
00151                         strtol(keyValue, NULL, 16);
00152 
00153                 /* get ifdFriendlyName */
00154                 rv = LTPBundleFindValueWithKey(fullPath,
00155                     PCSCLITE_HP_NAMEKEY_NAME, keyValue, alias);
00156                 if (0 == rv)
00157                     driverTracker[listCount].readerName = strdup(keyValue);
00158 
00159                 /* get CFBundleExecutable */
00160                 rv = LTPBundleFindValueWithKey(fullPath,
00161                     PCSCLITE_HP_LIBRKEY_NAME, keyValue, 0);
00162                 if (0 == rv)
00163                 {
00164                     (void)snprintf(fullLibPath, sizeof(fullLibPath),
00165                         "%s/%s/Contents/%s/%s",
00166                         PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
00167                         keyValue);
00168                     fullLibPath[sizeof(fullLibPath) - 1] = '\0';
00169                     driverTracker[listCount].libraryPath = strdup(fullLibPath);
00170                 }
00171 
00172                 /* Get ifdCapabilities */
00173                 rv = LTPBundleFindValueWithKey(fullPath,
00174                     PCSCLITE_HP_CPCTKEY_NAME, keyValue, 0);
00175                 if (0 == rv)
00176                     driverTracker[listCount].ifdCapabilities = strtol(keyValue,
00177                         NULL, 16);
00178 
00179 #ifdef DEBUG_HOTPLUG
00180                 Log2(PCSC_LOG_INFO, "Found driver for: %s",
00181                     driverTracker[listCount].readerName);
00182 #endif
00183                 alias++;
00184 
00185                 if (NULL == driverTracker[listCount].readerName)
00186                     continue;
00187 
00188                 listCount++;
00189                 if (listCount >= driverSize)
00190                 {
00191                     int i;
00192 
00193                     /* increase the array size */
00194                     driverSize += DRIVER_TRACKER_SIZE_STEP;
00195 #ifdef DEBUG_HOTPLUG
00196                     Log2(PCSC_LOG_INFO,
00197                         "Increase driverTracker to %d entries", driverSize);
00198 #endif
00199                     driverTracker = realloc(driverTracker,
00200                         driverSize * sizeof(*driverTracker));
00201                     if (NULL == driverTracker)
00202                     {
00203                         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00204                         driverSize = -1;
00205                         return -1;
00206                     }
00207 
00208                     /* clean the newly allocated entries */
00209                     for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
00210                     {
00211                         driverTracker[i].manuID = 0;
00212                         driverTracker[i].productID = 0;
00213                         driverTracker[i].bundleName = NULL;
00214                         driverTracker[i].libraryPath = NULL;
00215                         driverTracker[i].readerName = NULL;
00216                         driverTracker[i].ifdCapabilities = 0;
00217                     }
00218                 }
00219             }
00220         }
00221     }
00222 
00223     driverSize = listCount;
00224     (void)closedir(hpDir);
00225 
00226 #ifdef DEBUG_HOTPLUG
00227     Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
00228 #endif
00229 
00230     return 0;
00231 } /* HPReadBundleValues */
00232 
00233 
00234 void HPEstablishUSBNotifications(void)
00235 {
00236     while (!AraKiriHotPlug && dbus_connection_read_write_dispatch(conn, -1))
00237     {
00238 #ifdef DEBUG_HOTPLUG
00239         Log0(PCSC_LOG_INFO);
00240 #endif
00241     }
00242 } /* HPEstablishUSBNotifications */
00243 
00244 
00245 /***
00246  * Start a thread waiting for hotplug events
00247  */
00248 LONG HPSearchHotPluggables(void)
00249 {
00250     int i;
00251 
00252     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00253     {
00254         readerTracker[i].udi = NULL;
00255         readerTracker[i].fullName = NULL;
00256     }
00257 
00258     return HPReadBundleValues();
00259 } /* HPSearchHotPluggables */
00260 
00261 
00265 LONG HPStopHotPluggables(void)
00266 {
00267     AraKiriHotPlug = TRUE;
00268 
00269     return 0;
00270 } /* HPStopHotPluggables */
00271 
00272 
00273 /*@null@*/ static struct _driverTracker *get_driver(LibHalContext *ctx,
00274     const char *udi)
00275 {
00276     DBusError error;
00277     int i;
00278     unsigned int idVendor, idProduct;
00279 
00280     if (!libhal_device_property_exists(ctx, udi, "usb.vendor_id", NULL))
00281         return NULL;
00282 
00283     dbus_error_init(&error);
00284 
00285     /* Vendor ID */
00286     idVendor = libhal_device_get_property_int(ctx, udi,
00287         "usb.vendor_id", &error);
00288     if (dbus_error_is_set(&error))
00289     {
00290         Log3(PCSC_LOG_ERROR, "libhal_device_get_property_int %s: %d",
00291             error.name, error.message);
00292         dbus_error_free(&error);
00293         return NULL;
00294     }
00295 
00296     /* Product ID */
00297     idProduct = libhal_device_get_property_int(ctx, udi,
00298         "usb.product_id", &error);
00299     if (dbus_error_is_set(&error))
00300     {
00301         Log3(PCSC_LOG_ERROR, "libhal_device_get_property_int %s: %d",
00302             error.name, error.message);
00303         dbus_error_free(&error);
00304         return NULL;
00305     }
00306 
00307     Log3(PCSC_LOG_DEBUG, "Looking a driver for VID: 0x%04X, PID: 0x%04X", idVendor, idProduct);
00308 
00309     /* check if the device is supported by one driver */
00310     for (i=0; i<driverSize; i++)
00311     {
00312         if (driverTracker[i].libraryPath != NULL &&
00313             idVendor == driverTracker[i].manuID &&
00314             idProduct == driverTracker[i].productID)
00315         {
00316             return &driverTracker[i];
00317         }
00318     }
00319 
00320     return NULL;
00321 }
00322 
00323 
00324 static void HPAddDevice(LibHalContext *ctx, const char *udi)
00325 {
00326     int i;
00327     char deviceName[MAX_DEVICENAME];
00328     DBusError error;
00329     struct _driverTracker *driver;
00330     LONG ret;
00331 
00332     driver = get_driver(ctx, udi);
00333     if (NULL == driver)
00334     {
00335         /* not a smart card reader */
00336 #ifdef DEBUG_HOTPLUG
00337         Log2(PCSC_LOG_DEBUG, "%s is not a reader", short_name(udi));
00338 #endif
00339         return;
00340     }
00341 
00342     Log2(PCSC_LOG_INFO, "Adding USB device: %s", short_name(udi));
00343 
00344     (void)snprintf(deviceName, sizeof(deviceName), "usb:%04x/%04x:libhal:%s",
00345         driver->manuID, driver->productID, udi);
00346     deviceName[sizeof(deviceName) -1] = '\0';
00347 
00348     /* wait until the device is visible by libusb/etc.  */
00349     (void)SYS_Sleep(1);
00350 
00351     (void)SYS_MutexLock(&usbNotifierMutex);
00352 
00353     /* find a free entry */
00354     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00355     {
00356         if (NULL == readerTracker[i].fullName)
00357             break;
00358     }
00359 
00360     if (PCSCLITE_MAX_READERS_CONTEXTS == i)
00361     {
00362         Log2(PCSC_LOG_ERROR,
00363             "Not enough reader entries. Already found %d readers", i);
00364         (void)SYS_MutexUnLock(&usbNotifierMutex);
00365         return;
00366     }
00367 
00368     readerTracker[i].udi = strdup(udi);
00369 
00370 #ifdef ADD_SERIAL_NUMBER
00371     dbus_error_init (&error);
00372 
00373     if (libhal_device_property_exists(ctx, udi, "usb.serial", &error))
00374     {
00375         char fullname[MAX_READERNAME];
00376         char *sSerialNumber;
00377 
00378         sSerialNumber = libhal_device_get_property_string(ctx, udi,
00379             "usb.serial", &error);
00380 
00381         (void)snprintf(fullname, sizeof(fullname), "%s (%s)",
00382             driver->readerName, sSerialNumber);
00383         readerTracker[i].fullName = strdup(fullname);
00384         if (sSerialNumber) {
00385             libhal_free_string(sSerialNumber);
00386         }
00387     }
00388     else
00389 #endif
00390         readerTracker[i].fullName = strdup(driver->readerName);
00391 #ifdef ADD_SERIAL_NUMBER
00392     if (dbus_error_is_set(&error))
00393         dbus_error_free(&error);
00394 #endif
00395 
00396     ret = RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
00397         driver->libraryPath, deviceName);
00398     if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
00399     {
00400         char *parent= NULL, *device_file;
00401         char *orig_device_file = NULL;
00402 
00403         /* get the parent descriptor, without the '_if0' */
00404         parent = libhal_device_get_property_string(ctx, udi,
00405             "info.parent", NULL);
00406         if (! parent)
00407             goto error;
00408 
00409         /* get the linux device file: i.e. '/dev/bus/usb/002/012' */
00410         device_file = libhal_device_get_property_string(ctx, parent,
00411             "linux.device_file", NULL);
00412         if (! device_file)
00413             goto error;
00414         orig_device_file = device_file;
00415 
00416         /* check the format looks correct */
00417 #define LIBUSB_HEADER "/dev/bus/usb/"
00418         if (strncmp(device_file, LIBUSB_HEADER, strlen(LIBUSB_HEADER)))
00419             goto error;
00420 
00421         device_file += strlen(LIBUSB_HEADER);
00422 
00423         (void)snprintf(deviceName, sizeof(deviceName),
00424             "usb:%04x/%04x:libusb:%s",
00425             driver->manuID, driver->productID, device_file);
00426         deviceName[sizeof(deviceName) -1] = '\0';
00427 
00428         /* replace the libusb separator '/' by ':' */
00429         if ('/' == deviceName[strlen(deviceName)-3-1])
00430             deviceName[strlen(deviceName)-3-1] = ':';
00431 
00432         Log2(PCSC_LOG_INFO, "trying libusb scheme with: %s", deviceName);
00433         ret = RFAddReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i,
00434             driver->libraryPath, deviceName);
00435 
00436         if (SCARD_S_SUCCESS != ret)
00437         {
00438 error:
00439             Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s", short_name(udi));
00440             free(readerTracker[i].fullName);
00441             readerTracker[i].fullName = NULL;
00442             free(readerTracker[i].udi);
00443             readerTracker[i].udi = NULL;
00444 
00445             (void)CheckForOpenCT();
00446         }
00447         if (parent) {
00448             libhal_free_string(parent);
00449         }
00450         if (orig_device_file) {
00451             libhal_free_string(orig_device_file);
00452         }
00453     }
00454 
00455     (void)SYS_MutexUnLock(&usbNotifierMutex);
00456 } /* HPAddDevice */
00457 
00458 
00459 static void HPRemoveDevice(/*@unused@*/ LibHalContext *ctx, const char *udi)
00460 {
00461     int i;
00462 
00463     (void)ctx;
00464     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00465     {
00466         if (readerTracker[i].udi && strcmp(readerTracker[i].udi, udi) == 0)
00467             break;
00468     }
00469     if (PCSCLITE_MAX_READERS_CONTEXTS == i)
00470     {
00471 #ifdef DEBUG_HOTPLUG
00472         Log2(PCSC_LOG_DEBUG, "USB device %s not already used", short_name(udi));
00473 #endif
00474         return;
00475     }
00476     Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", i,
00477         short_name(readerTracker[i].udi));
00478 
00479     (void)SYS_MutexLock(&usbNotifierMutex);
00480 
00481     (void)RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i);
00482     free(readerTracker[i].fullName);
00483     readerTracker[i].fullName = NULL;
00484     free(readerTracker[i].udi);
00485     readerTracker[i].udi = NULL;
00486 
00487     (void)SYS_MutexUnLock(&usbNotifierMutex);
00488 
00489     return;
00490 } /* HPRemoveDevice */
00491 
00492 
00496 ULONG HPRegisterForHotplugEvents(void)
00497 {
00498     char **device_names;
00499     int i, num_devices;
00500     DBusError error;
00501 
00502     if (driverSize <= 0)
00503     {
00504         Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
00505         Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
00506         return 1;
00507     }
00508 
00509     dbus_error_init(&error);
00510     conn = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
00511     if (conn == NULL)
00512     {
00513         Log3(PCSC_LOG_ERROR, "error: dbus_bus_get: %s: %s",
00514             error.name, error.message);
00515         if (dbus_error_is_set(&error))
00516             dbus_error_free(&error);
00517         return 1;
00518     }
00519 
00520     if ((hal_ctx = libhal_ctx_new()) == NULL)
00521     {
00522         Log1(PCSC_LOG_ERROR, "error: libhal_ctx_new");
00523         return 1;
00524     }
00525     if (!libhal_ctx_set_dbus_connection(hal_ctx, conn))
00526     {
00527         Log1(PCSC_LOG_ERROR, "error: libhal_ctx_set_dbus_connection");
00528         return 1;
00529     }
00530     if (!libhal_ctx_init(hal_ctx, &error))
00531     {
00532         if (dbus_error_is_set(&error))
00533         {
00534             Log3(PCSC_LOG_ERROR, "error: libhal_ctx_init: %s: %s",
00535                 error.name, error.message);
00536             if (dbus_error_is_set(&error))
00537                 dbus_error_free(&error);
00538         }
00539         Log1(PCSC_LOG_ERROR, "Could not initialise connection to hald.");
00540         Log1(PCSC_LOG_ERROR, "Normally this means the HAL daemon (hald) is not running or not ready.");
00541         return 1;
00542     }
00543 
00544     /* callback when device added */
00545     (void)libhal_ctx_set_device_added(hal_ctx, HPAddDevice);
00546 
00547     /* callback when device removed */
00548     (void)libhal_ctx_set_device_removed(hal_ctx, HPRemoveDevice);
00549 
00550     device_names = libhal_get_all_devices(hal_ctx, &num_devices, &error);
00551     if (device_names == NULL)
00552     {
00553         if (dbus_error_is_set(&error))
00554             dbus_error_free(&error);
00555         Log1(PCSC_LOG_ERROR, "Couldn't obtain list of devices");
00556         return 1;
00557     }
00558 
00559     /* try to add every present USB devices */
00560     for (i = 0; i < num_devices; i++)
00561         HPAddDevice(hal_ctx, device_names[i]);
00562 
00563     libhal_free_string_array(device_names);
00564 
00565     (void)SYS_ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
00566         (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, NULL);
00567 
00568     return 0;
00569 } /* HPRegisterForHotplugEvents */
00570 
00571 
00572 void HPReCheckSerialReaders(void)
00573 {
00574     /* nothing to do here */
00575 #ifdef DEBUG_HOTPLUG
00576     Log0(PCSC_LOG_ERROR);
00577 #endif
00578 } /* HPReCheckSerialReaders */
00579 
00580 #endif
00581 

Generated on 21 Mar 2017 for pcsc-lite by  doxygen 1.6.1