pcsc-lite 1.7.2

hotplug_libudev.c

Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 2011
00005  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00006  *
00007  * $Id: hotplug_libudev.c 5683 2011-03-31 19:01:51Z rousseau $
00008  */
00009 
00015 #include "config.h"
00016 #if defined(HAVE_LIBUDEV) && defined(USE_USB)
00017 
00018 #include <string.h>
00019 #include <stdio.h>
00020 #include <dirent.h>
00021 #include <stdlib.h>
00022 #include <pthread.h>
00023 #include <libudev.h>
00024 
00025 #include "debuglog.h"
00026 #include "parser.h"
00027 #include "readerfactory.h"
00028 #include "sys_generic.h"
00029 #include "hotplug.h"
00030 #include "utils.h"
00031 #include "strlcpycat.h"
00032 
00033 #undef DEBUG_HOTPLUG
00034 #define ADD_SERIAL_NUMBER
00035 #define ADD_INTERFACE_NAME
00036 
00037 #define FALSE           0
00038 #define TRUE            1
00039 
00040 pthread_mutex_t usbNotifierMutex;
00041 
00042 static pthread_t usbNotifyThread;
00043 static int driverSize = -1;
00044 static char AraKiriHotPlug = FALSE;
00045 
00049 static struct _driverTracker
00050 {
00051     unsigned int manuID;
00052     unsigned int productID;
00053 
00054     char *bundleName;
00055     char *libraryPath;
00056     char *readerName;
00057     char *CFBundleName;
00058 } *driverTracker = NULL;
00059 #define DRIVER_TRACKER_SIZE_STEP 10
00060 
00061 /* The CCID driver already supports 176 readers.
00062  * We start with a big array size to avoid reallocation. */
00063 #define DRIVER_TRACKER_INITIAL_SIZE 200
00064 
00065 typedef enum {
00066  READER_ABSENT,
00067  READER_PRESENT,
00068  READER_FAILED
00069 } readerState_t;
00070 
00074 static struct _readerTracker
00075 {
00076     readerState_t status;   
00077     char bInterfaceNumber;  
00078     char *devpath;  
00079     char *fullName; 
00080 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
00081 
00082 
00083 static LONG HPReadBundleValues(void)
00084 {
00085     LONG rv;
00086     DIR *hpDir;
00087     struct dirent *currFP = NULL;
00088     char fullPath[FILENAME_MAX];
00089     char fullLibPath[FILENAME_MAX];
00090     int listCount = 0;
00091 
00092     hpDir = opendir(PCSCLITE_HP_DROPDIR);
00093 
00094     if (NULL == hpDir)
00095     {
00096         Log1(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
00097         Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
00098         return -1;
00099     }
00100 
00101     /* allocate a first array */
00102     driverSize = DRIVER_TRACKER_INITIAL_SIZE;
00103     driverTracker = calloc(driverSize, sizeof(*driverTracker));
00104     if (NULL == driverTracker)
00105     {
00106         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00107         return -1;
00108     }
00109 
00110 #define GET_KEY(key, values) \
00111     rv = LTPBundleFindValueWithKey(&plist, key, values); \
00112     if (rv) \
00113     { \
00114         Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
00115             fullPath); \
00116         continue; \
00117     }
00118 
00119     while ((currFP = readdir(hpDir)) != 0)
00120     {
00121         if (strstr(currFP->d_name, ".bundle") != 0)
00122         {
00123             unsigned int alias;
00124             list_t plist, *values;
00125             list_t *manuIDs, *productIDs, *readerNames;
00126             char *CFBundleName;
00127             char *libraryPath;
00128 
00129             /*
00130              * The bundle exists - let's form a full path name and get the
00131              * vendor and product ID's for this particular bundle
00132              */
00133             (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
00134                 PCSCLITE_HP_DROPDIR, currFP->d_name);
00135             fullPath[sizeof(fullPath) - 1] = '\0';
00136 
00137             rv = bundleParse(fullPath, &plist);
00138             if (rv)
00139                 continue;
00140 
00141             /* get CFBundleExecutable */
00142             GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
00143             libraryPath = list_get_at(values, 0);
00144             (void)snprintf(fullLibPath, sizeof(fullLibPath),
00145                 "%s/%s/Contents/%s/%s",
00146                 PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
00147                 libraryPath);
00148             fullLibPath[sizeof(fullLibPath) - 1] = '\0';
00149 
00150             GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
00151             GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
00152             GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
00153 
00154             /* Get CFBundleName */
00155             rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
00156                 &values);
00157             if (rv)
00158                 CFBundleName = NULL;
00159             else
00160                 CFBundleName = strdup(list_get_at(values, 0));
00161 
00162             /* while we find a nth ifdVendorID in Info.plist */
00163             for (alias=0; alias<list_size(manuIDs); alias++)
00164             {
00165                 char *value;
00166 
00167                 /* variables entries */
00168                 value = list_get_at(manuIDs, alias);
00169                 driverTracker[listCount].manuID = strtol(value, NULL, 16);
00170 
00171                 value = list_get_at(productIDs, alias);
00172                 driverTracker[listCount].productID = strtol(value, NULL, 16);
00173 
00174                 driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
00175 
00176                 /* constant entries for a same driver */
00177                 driverTracker[listCount].bundleName = strdup(currFP->d_name);
00178                 driverTracker[listCount].libraryPath = strdup(fullLibPath);
00179                 driverTracker[listCount].CFBundleName = CFBundleName;
00180 
00181 #ifdef DEBUG_HOTPLUG
00182                 Log2(PCSC_LOG_INFO, "Found driver for: %s",
00183                     driverTracker[listCount].readerName);
00184 #endif
00185                 listCount++;
00186                 if (listCount >= driverSize)
00187                 {
00188                     int i;
00189 
00190                     /* increase the array size */
00191                     driverSize += DRIVER_TRACKER_SIZE_STEP;
00192 #ifdef DEBUG_HOTPLUG
00193                     Log2(PCSC_LOG_INFO,
00194                         "Increase driverTracker to %d entries", driverSize);
00195 #endif
00196                     driverTracker = realloc(driverTracker,
00197                         driverSize * sizeof(*driverTracker));
00198                     if (NULL == driverTracker)
00199                     {
00200                         Log1(PCSC_LOG_CRITICAL, "Not enough memory");
00201                         driverSize = -1;
00202                         return -1;
00203                     }
00204 
00205                     /* clean the newly allocated entries */
00206                     for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
00207                     {
00208                         driverTracker[i].manuID = 0;
00209                         driverTracker[i].productID = 0;
00210                         driverTracker[i].bundleName = NULL;
00211                         driverTracker[i].libraryPath = NULL;
00212                         driverTracker[i].readerName = NULL;
00213                         driverTracker[i].CFBundleName = NULL;
00214                     }
00215                 }
00216             }
00217             bundleRelease(&plist);
00218         }
00219     }
00220 
00221     driverSize = listCount;
00222     (void)closedir(hpDir);
00223 
00224 #ifdef DEBUG_HOTPLUG
00225     Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
00226 #endif
00227 
00228     return 0;
00229 } /* HPReadBundleValues */
00230 
00231 
00232 /*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
00233     const char *devpath, struct _driverTracker **classdriver)
00234 {
00235     int i;
00236     unsigned int idVendor, idProduct;
00237     static struct _driverTracker *driver;
00238     const char *str;
00239 
00240     str = udev_device_get_sysattr_value(dev, "idVendor");
00241     if (!str)
00242     {
00243         Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
00244         return NULL;
00245     }
00246     sscanf(str, "%X", &idVendor);
00247 
00248     str = udev_device_get_sysattr_value(dev, "idProduct");
00249     if (!str)
00250     {
00251         Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
00252         return NULL;
00253     }
00254     sscanf(str, "%X", &idProduct);
00255 
00256     Log4(PCSC_LOG_DEBUG,
00257         "Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
00258         idVendor, idProduct, devpath);
00259 
00260     *classdriver = NULL;
00261     driver = NULL;
00262     /* check if the device is supported by one driver */
00263     for (i=0; i<driverSize; i++)
00264     {
00265         if (driverTracker[i].libraryPath != NULL &&
00266             idVendor == driverTracker[i].manuID &&
00267             idProduct == driverTracker[i].productID)
00268         {
00269             if ((driverTracker[i].CFBundleName != NULL)
00270                 && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
00271                 *classdriver = &driverTracker[i];
00272             else
00273                 /* it is not a CCID Class driver */
00274                 driver = &driverTracker[i];
00275         }
00276     }
00277 
00278     /* if we found a specific driver */
00279     if (driver)
00280         return driver;
00281 
00282     /* else return the Class driver (if any) */
00283     return *classdriver;
00284 }
00285 
00286 
00287 static void HPAddDevice(struct udev_device *dev, struct udev_device *parent,
00288     const char *devpath)
00289 {
00290     int i;
00291     char deviceName[MAX_DEVICENAME];
00292     char fullname[MAX_READERNAME];
00293     struct _driverTracker *driver, *classdriver;
00294     const char *sSerialNumber = NULL, *sInterfaceName = NULL;
00295     LONG ret;
00296     int bInterfaceNumber;
00297 
00298     driver = get_driver(parent, devpath, &classdriver);
00299     if (NULL == driver)
00300     {
00301         /* not a smart card reader */
00302 #ifdef DEBUG_HOTPLUG
00303         Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
00304             devpath);
00305 #endif
00306         return;
00307     }
00308 
00309     Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
00310 
00311     bInterfaceNumber = atoi(udev_device_get_sysattr_value(dev,
00312         "bInterfaceNumber"));
00313     (void)snprintf(deviceName, sizeof(deviceName),
00314         "usb:%04x/%04x:libudev:%d:%s", driver->manuID, driver->productID,
00315         bInterfaceNumber, devpath);
00316     deviceName[sizeof(deviceName) -1] = '\0';
00317 
00318     (void)pthread_mutex_lock(&usbNotifierMutex);
00319 
00320     /* find a free entry */
00321     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00322     {
00323         if (NULL == readerTracker[i].fullName)
00324             break;
00325     }
00326 
00327     if (PCSCLITE_MAX_READERS_CONTEXTS == i)
00328     {
00329         Log2(PCSC_LOG_ERROR,
00330             "Not enough reader entries. Already found %d readers", i);
00331         (void)pthread_mutex_unlock(&usbNotifierMutex);
00332         return;
00333     }
00334 
00335 #ifdef ADD_INTERFACE_NAME
00336     sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
00337 #endif
00338 
00339 #ifdef ADD_SERIAL_NUMBER
00340     sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
00341 #endif
00342 
00343     /* name from the Info.plist file */
00344     strlcpy(fullname, driver->readerName, sizeof(fullname));
00345 
00346     /* interface name from the device (if any) */
00347     if (sInterfaceName)
00348     {
00349         strlcat(fullname, " [", sizeof(fullname));
00350         strlcat(fullname, sInterfaceName, sizeof(fullname));
00351         strlcat(fullname, "]", sizeof(fullname));
00352     }
00353 
00354     /* serial number from the device (if any) */
00355     if (sSerialNumber)
00356     {
00357         /* only add the serial number if it is not already present in the
00358          * interface name */
00359         if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
00360         {
00361             strlcat(fullname, " (", sizeof(fullname));
00362             strlcat(fullname, sSerialNumber, sizeof(fullname));
00363             strlcat(fullname, ")", sizeof(fullname));
00364         }
00365     }
00366 
00367     readerTracker[i].fullName = strdup(fullname);
00368     readerTracker[i].devpath = strdup(devpath);
00369     readerTracker[i].status = READER_PRESENT;
00370     readerTracker[i].bInterfaceNumber = bInterfaceNumber;
00371 
00372     ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i,
00373         driver->libraryPath, deviceName);
00374     if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
00375     {
00376         Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
00377             driver->readerName);
00378 
00379         if (classdriver && driver != classdriver)
00380         {
00381             /* the reader can also be used by the a class driver */
00382             ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + i,
00383                 classdriver->libraryPath, deviceName);
00384             if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
00385             {
00386                 Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
00387                         driver->readerName);
00388 
00389                 readerTracker[i].status = READER_FAILED;
00390 
00391                 (void)CheckForOpenCT();
00392             }
00393         }
00394         else
00395         {
00396             readerTracker[i].status = READER_FAILED;
00397 
00398             (void)CheckForOpenCT();
00399         }
00400     }
00401 
00402     (void)pthread_mutex_unlock(&usbNotifierMutex);
00403 } /* HPAddDevice */
00404 
00405 
00406 static void HPRescanUsbBus(struct udev *udev)
00407 {
00408     int i, j;
00409     struct udev_enumerate *enumerate;
00410     struct udev_list_entry *devices, *dev_list_entry;
00411 
00412     /* all reader are marked absent */
00413     for (i=0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
00414         readerTracker[i].status = READER_ABSENT;
00415 
00416     /* Create a list of the devices in the 'usb' subsystem. */
00417     enumerate = udev_enumerate_new(udev);
00418     udev_enumerate_add_match_subsystem(enumerate, "usb");
00419     udev_enumerate_scan_devices(enumerate);
00420     devices = udev_enumerate_get_list_entry(enumerate);
00421 
00422     /* For each item enumerated */
00423     udev_list_entry_foreach(dev_list_entry, devices)
00424     {
00425         const char *devpath;
00426         struct udev_device *dev, *parent;
00427         struct _driverTracker *driver, *classdriver;
00428         int newreader;
00429         int bInterfaceNumber;
00430         const char *interface;
00431 
00432         /* Get the filename of the /sys entry for the device
00433            and create a udev_device object (dev) representing it */
00434         devpath = udev_list_entry_get_name(dev_list_entry);
00435         dev = udev_device_new_from_syspath(udev, devpath);
00436 
00437         /* The device pointed to by dev contains information about
00438            the interface. In order to get information about the USB
00439            device, get the parent device with the subsystem/devtype pair
00440            of "usb"/"usb_device". This will be several levels up the
00441            tree, but the function will find it.*/
00442         parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
00443             "usb_device");
00444         if (!parent)
00445             continue;
00446 
00447         devpath = udev_device_get_devnode(parent);
00448         if (!devpath)
00449         {
00450             /* the device disapeared? */
00451             Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
00452             continue;
00453         }
00454 
00455         driver = get_driver(parent, devpath, &classdriver);
00456         if (NULL == driver)
00457             /* no driver known for this device */
00458             continue;
00459 
00460 #ifdef DEBUG_HOTPLUG
00461         Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
00462 #endif
00463 
00464         newreader = TRUE;
00465         bInterfaceNumber = 0;
00466         interface = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
00467         if (interface)
00468             bInterfaceNumber = atoi(interface);
00469 
00470         /* Check if the reader is a new one */
00471         for (j=0; j<PCSCLITE_MAX_READERS_CONTEXTS; j++)
00472         {
00473             if (readerTracker[j].devpath
00474                 && (strcmp(readerTracker[j].devpath, devpath) == 0)
00475                 && (bInterfaceNumber == readerTracker[j].bInterfaceNumber))
00476             {
00477                 /* The reader is already known */
00478                 readerTracker[j].status = READER_PRESENT;
00479                 newreader = FALSE;
00480 #ifdef DEBUG_HOTPLUG
00481                 Log2(PCSC_LOG_DEBUG, "Refresh USB device: %s", devpath);
00482 #endif
00483                 break;
00484             }
00485         }
00486 
00487         /* New reader found */
00488         if (newreader)
00489             HPAddDevice(dev, parent, devpath);
00490 
00491         /* free device */
00492         udev_device_unref(dev);
00493     }
00494 
00495     /* Free the enumerator object */
00496     udev_enumerate_unref(enumerate);
00497 
00498     /* check if all the previously found readers are still present */
00499     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00500     {
00501         if ((READER_ABSENT == readerTracker[i].status)
00502             && (readerTracker[i].fullName != NULL))
00503         {
00504             pthread_mutex_lock(&usbNotifierMutex);
00505 
00506             Log3(PCSC_LOG_INFO, "Removing USB device[%d]: %s", i,
00507                 readerTracker[i].devpath);
00508 
00509             RFRemoveReader(readerTracker[i].fullName,
00510                 PCSCLITE_HP_BASE_PORT + i);
00511 
00512             readerTracker[i].status = READER_ABSENT;
00513             free(readerTracker[i].devpath);
00514             readerTracker[i].devpath = NULL;
00515             free(readerTracker[i].fullName);
00516             readerTracker[i].fullName = NULL;
00517 
00518             pthread_mutex_unlock(&usbNotifierMutex);
00519         }
00520     }
00521 }
00522 
00523 static void HPEstablishUSBNotifications(struct udev *udev)
00524 {
00525     struct udev_monitor *udev_monitor;
00526     int r, i;
00527 
00528     udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
00529 
00530     /* filter only the interfaces */
00531     r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb",
00532         "usb_interface");
00533     if (r)
00534     {
00535         Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
00536         return;
00537     }
00538 
00539     r = udev_monitor_enable_receiving(udev_monitor);
00540     if (r)
00541     {
00542         Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
00543         return;
00544     }
00545 
00546     while (!AraKiriHotPlug)
00547     {
00548         struct udev_device *dev, *parent;
00549         const char *action, *devpath;
00550 
00551 #ifdef DEBUG_HOTPLUG
00552         Log0(PCSC_LOG_INFO);
00553 #endif
00554 
00555         dev = udev_monitor_receive_device(udev_monitor);
00556         if (!dev)
00557         {
00558             Log1(PCSC_LOG_ERROR, "udev_monitor_receive_device() error\n");
00559             return;
00560         }
00561 
00562         action = udev_device_get_action(dev);
00563         if (0 == strcmp("remove", action))
00564         {
00565             Log1(PCSC_LOG_INFO, "Device removed");
00566             HPRescanUsbBus(udev);
00567             continue;
00568         }
00569 
00570         if (strcmp("add", action))
00571             continue;
00572 
00573         parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
00574             "usb_device");
00575         devpath = udev_device_get_devnode(parent);
00576         if (!devpath)
00577         {
00578             /* the device disapeared? */
00579             Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
00580             continue;
00581         }
00582 
00583         HPAddDevice(dev, parent, devpath);
00584 
00585         /* free device */
00586         udev_device_unref(dev);
00587 
00588     }
00589 
00590     for (i=0; i<driverSize; i++)
00591     {
00592         /* free strings allocated by strdup() */
00593         free(driverTracker[i].bundleName);
00594         free(driverTracker[i].libraryPath);
00595         free(driverTracker[i].readerName);
00596     }
00597     free(driverTracker);
00598 
00599     Log1(PCSC_LOG_INFO, "Hotplug stopped");
00600 } /* HPEstablishUSBNotifications */
00601 
00602 
00603 /***
00604  * Start a thread waiting for hotplug events
00605  */
00606 LONG HPSearchHotPluggables(void)
00607 {
00608     int i;
00609 
00610     for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
00611     {
00612         readerTracker[i].status = READER_ABSENT;
00613         readerTracker[i].bInterfaceNumber = 0;
00614         readerTracker[i].devpath = NULL;
00615         readerTracker[i].fullName = NULL;
00616     }
00617 
00618     return HPReadBundleValues();
00619 } /* HPSearchHotPluggables */
00620 
00621 
00625 LONG HPStopHotPluggables(void)
00626 {
00627     AraKiriHotPlug = TRUE;
00628 
00629     return 0;
00630 } /* HPStopHotPluggables */
00631 
00632 
00636 ULONG HPRegisterForHotplugEvents(void)
00637 {
00638     struct udev *udev;
00639 
00640     (void)pthread_mutex_init(&usbNotifierMutex, NULL);
00641 
00642     if (driverSize <= 0)
00643     {
00644         Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: "
00645             PCSCLITE_HP_DROPDIR);
00646         Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
00647         return 0;
00648     }
00649 
00650     /* Create the udev object */
00651     udev = udev_new();
00652     if (!udev)
00653     {
00654         Log1(PCSC_LOG_ERROR, "udev_new() failed");
00655         return 0;
00656     }
00657 
00658     HPRescanUsbBus(udev);
00659 
00660     (void)ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
00661         (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev);
00662 
00663     return 0;
00664 } /* HPRegisterForHotplugEvents */
00665 
00666 
00667 void HPReCheckSerialReaders(void)
00668 {
00669     /* nothing to do here */
00670 #ifdef DEBUG_HOTPLUG
00671     Log0(PCSC_LOG_ERROR);
00672 #endif
00673 } /* HPReCheckSerialReaders */
00674 
00675 #endif
00676