pcsc-lite  2.5.0
hotplug_libudev.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 2011-2026
5  * Ludovic Rousseau <ludovic.rousseau@free.fr>
6  * Copyright (C) 2014
7  * Stefani Seibold <stefani@seibold.net>
8  *
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12 
13 1. Redistributions of source code must retain the above copyright
14  notice, this list of conditions and the following disclaimer.
15 2. Redistributions in binary form must reproduce the above copyright
16  notice, this list of conditions and the following disclaimer in the
17  documentation and/or other materials provided with the distribution.
18 3. The name of the author may not be used to endorse or promote products
19  derived from this software without specific prior written permission.
20 
21 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32 
38 #include "config.h"
39 #if defined(HAVE_LIBUDEV) && defined(USE_USB)
40 
41 #define _GNU_SOURCE /* for asprintf(3) */
42 #include <string.h>
43 #include <stdio.h>
44 #include <dirent.h>
45 #include <stdlib.h>
46 #include <pthread.h>
47 #include <libudev.h>
48 #include <poll.h>
49 #include <ctype.h>
50 #include <stdbool.h>
51 
52 #include "debuglog.h"
53 #include "parser.h"
54 #include "readerfactory.h"
55 #include "sys_generic.h"
56 #include "hotplug.h"
57 #include "utils.h"
58 
59 #ifndef TEMP_FAILURE_RETRY
60 #define TEMP_FAILURE_RETRY(expression) \
61  (__extension__ \
62  ({ long int __result; \
63  do __result = (long int) (expression); \
64  while (__result == -1L && errno == EINTR); \
65  __result; }))
66 #endif
67 
68 #undef DEBUG_HOTPLUG
69 
70 extern bool Add_Interface_In_Name;
71 extern bool Add_Serial_In_Name;
72 
73 static pthread_t usbNotifyThread;
74 static int driverSize = -1;
75 static struct udev *Udev;
76 static struct udev_monitor *Udev_monitor;
77 
78 
82 static struct _driverTracker
83 {
84  unsigned int manuID;
85  unsigned int productID;
86 
87  char *bundleName;
88  char *libraryPath;
89  char *readerName;
90  char *CFBundleName;
91 } *driverTracker = NULL;
92 #define DRIVER_TRACKER_SIZE_STEP 10
93 
94 /* The CCID driver already supports 176 readers.
95  * We start with a big array size to avoid reallocation. */
96 #define DRIVER_TRACKER_INITIAL_SIZE 200
97 
101 struct _readerTracker
102 {
103  char *devpath;
104  char *fullName;
105  char *sysname;
106 };
107 struct _readerTracker *readerTracker = NULL;
108 int readerTrackerNbEntries = -1;
109 
110 
111 static LONG HPReadBundleValues(const char * hpDirPath)
112 {
113  LONG rv;
114  DIR *hpDir;
115  struct dirent *currFP = NULL;
116  char fullPath[FILENAME_MAX];
117  char fullLibPath[FILENAME_MAX];
118  int listCount = 0;
119 
120  hpDir = opendir(hpDirPath);
121 
122  if (NULL == hpDir)
123  {
124  Log2(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: %s", hpDirPath);
125  Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
126  return 0;
127  }
128 
129  /* allocate a first array */
130  driverSize = DRIVER_TRACKER_INITIAL_SIZE;
131  driverTracker = calloc(driverSize, sizeof(*driverTracker));
132  if (NULL == driverTracker)
133  {
134  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
135  (void)closedir(hpDir);
136  return -1;
137  }
138 
139 #define GET_KEY(key, values) \
140  rv = LTPBundleFindValueWithKey(&plist, key, values); \
141  if (rv) \
142  { \
143  Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
144  fullPath); \
145  continue; \
146  }
147 
148  while ((currFP = readdir(hpDir)) != 0)
149  {
150  if (strstr(currFP->d_name, ".bundle") != 0)
151  {
152  unsigned int alias;
153  list_t plist, *values;
154  list_t *manuIDs, *productIDs, *readerNames;
155  char *CFBundleName;
156  char *libraryPath;
157 
158  /*
159  * The bundle exists - let's form a full path name and get the
160  * vendor and product ID's for this particular bundle
161  */
162  (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
163  hpDirPath, currFP->d_name);
164  fullPath[sizeof(fullPath) - 1] = '\0';
165 
166  rv = bundleParse(fullPath, &plist);
167  if (rv)
168  continue;
169 
170  /* get CFBundleExecutable */
171  GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
172  libraryPath = list_get_at(values, 0);
173  (void)snprintf(fullLibPath, sizeof(fullLibPath),
174  "%s/%s/Contents/%s/%s",
175  hpDirPath, currFP->d_name, PCSC_ARCH,
176  libraryPath);
177  fullLibPath[sizeof(fullLibPath) - 1] = '\0';
178 
179  GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
180  GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
181  GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
182 
183  if ((list_size(manuIDs) != list_size(productIDs))
184  || (list_size(manuIDs) != list_size(readerNames)))
185  {
186  Log2(PCSC_LOG_CRITICAL, "Error parsing %s", fullPath);
187  (void)closedir(hpDir);
188  return -1;
189  }
190 
191  /* Get CFBundleName */
192  rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
193  &values);
194  if (rv)
195  CFBundleName = NULL;
196  else
197  CFBundleName = list_get_at(values, 0);
198 
199  /* while we find a nth ifdVendorID in Info.plist */
200  for (alias=0; alias<list_size(manuIDs); alias++)
201  {
202  char *value;
203 
204  /* variables entries */
205  value = list_get_at(manuIDs, alias);
206  driverTracker[listCount].manuID = strtol(value, NULL, 16);
207 
208  value = list_get_at(productIDs, alias);
209  driverTracker[listCount].productID = strtol(value, NULL, 16);
210 
211  driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
212 
213  /* constant entries for a same driver */
214  driverTracker[listCount].bundleName = strdup(currFP->d_name);
215  driverTracker[listCount].libraryPath = strdup(fullLibPath);
216  driverTracker[listCount].CFBundleName = CFBundleName ? strdup(CFBundleName) : NULL;
217 
218 #ifdef DEBUG_HOTPLUG
219  Log2(PCSC_LOG_INFO, "Found driver for: %s",
220  driverTracker[listCount].readerName);
221 #endif
222  listCount++;
223  if (listCount >= driverSize)
224  {
225  int i;
226 
227  /* increase the array size */
228  driverSize += DRIVER_TRACKER_SIZE_STEP;
229 #ifdef DEBUG_HOTPLUG
230  Log2(PCSC_LOG_INFO,
231  "Increase driverTracker to %d entries", driverSize);
232 #endif
233 
234  void* tmp = realloc(driverTracker,
235  driverSize * sizeof(*driverTracker));
236 
237  if (NULL == tmp)
238  {
239  free(driverTracker);
240  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
241  driverSize = -1;
242  (void)closedir(hpDir);
243  return -1;
244  }
245  driverTracker = tmp;
246 
247  /* clean the newly allocated entries */
248  for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
249  {
250  driverTracker[i].manuID = 0;
251  driverTracker[i].productID = 0;
252  driverTracker[i].bundleName = NULL;
253  driverTracker[i].libraryPath = NULL;
254  driverTracker[i].readerName = NULL;
255  driverTracker[i].CFBundleName = NULL;
256  }
257  }
258  }
259  bundleRelease(&plist);
260  }
261  }
262 
263  driverSize = listCount;
264  (void)closedir(hpDir);
265 
266 #ifdef DEBUG_HOTPLUG
267  Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
268 #endif
269 
270  return 0;
271 } /* HPReadBundleValues */
272 
273 
274 /*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
275  const char *devpath, struct _driverTracker **classdriver)
276 {
277  int i;
278  unsigned int idVendor, idProduct;
279  static struct _driverTracker *driver;
280  const char *str;
281 
282  str = udev_device_get_sysattr_value(dev, "idVendor");
283  if (!str)
284  {
285  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
286  return NULL;
287  }
288  idVendor = strtol(str, NULL, 16);
289 
290  str = udev_device_get_sysattr_value(dev, "idProduct");
291  if (!str)
292  {
293  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
294  return NULL;
295  }
296  idProduct = strtol(str, NULL, 16);
297 
298 #ifdef NO_LOG
299  (void)devpath;
300 #endif
301  Log4(PCSC_LOG_DEBUG,
302  "Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
303  idVendor, idProduct, devpath);
304 
305  *classdriver = NULL;
306  driver = NULL;
307  /* check if the device is supported by one driver */
308  for (i=0; i<driverSize; i++)
309  {
310  if (driverTracker[i].libraryPath != NULL &&
311  idVendor == driverTracker[i].manuID &&
312  idProduct == driverTracker[i].productID)
313  {
314  if ((driverTracker[i].CFBundleName != NULL)
315  && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
316  *classdriver = &driverTracker[i];
317  else
318  /* it is not a CCID Class driver */
319  driver = &driverTracker[i];
320  }
321  }
322 
323  /* if we found a specific driver */
324  if (driver)
325  return driver;
326 
327  /* else return the Class driver (if any) */
328  return *classdriver;
329 }
330 
331 
332 static void HPRemoveDevice(struct udev_device *dev)
333 {
334  int i;
335  const char *sysname;
336 
337  sysname = udev_device_get_sysname(dev);
338  if (!sysname)
339  {
340  Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
341  return;
342  }
343 
344  for (i=0; i<readerTrackerNbEntries; i++)
345  {
346  if (readerTracker[i].fullName && !strcmp(sysname, readerTracker[i].sysname))
347  {
348  Log4(PCSC_LOG_INFO, "Removing USB device[%d]: %s at %s", i,
349  readerTracker[i].fullName, readerTracker[i].devpath);
350 
351  RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i, REMOVE_READER_FLAG_REMOVED);
352 
353  free(readerTracker[i].devpath);
354  readerTracker[i].devpath = NULL;
355  free(readerTracker[i].fullName);
356  readerTracker[i].fullName = NULL;
357  free(readerTracker[i].sysname);
358  readerTracker[i].sysname = NULL;
359  break;
360  }
361  }
362 }
363 
364 
365 static void HPAddDevice(struct udev_device *dev)
366 {
367  int index, a;
368  char *deviceName = NULL;
369  char *fullname = NULL;
370  struct _driverTracker *driver, *classdriver;
371  const char *sSerialNumber = NULL, *sInterfaceName = NULL;
372  const char *sInterfaceNumber;
373  LONG ret;
374  int bInterfaceNumber;
375  const char *devpath;
376  struct udev_device *parent;
377  const char *sysname;
378  const char *ignoreprop;
379 
380  /* The device pointed to by dev contains information about
381  the interface. In order to get information about the USB
382  device, get the parent device with the subsystem/devtype pair
383  of "usb"/"usb_device". This will be several levels up the
384  tree, but the function will find it.*/
385  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
386  "usb_device");
387  if (!parent)
388  return;
389 
390  devpath = udev_device_get_devnode(parent);
391  if (!devpath)
392  {
393  /* the device disappeared? */
394  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
395  return;
396  }
397 
398  driver = get_driver(parent, devpath, &classdriver);
399  if (NULL == driver)
400  {
401  /* not a smart card reader */
402 #ifdef DEBUG_HOTPLUG
403  Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
404  devpath);
405 #endif
406  return;
407  }
408 
409  sysname = udev_device_get_sysname(dev);
410  if (!sysname)
411  {
412  Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
413  return;
414  }
415 
416  ignoreprop = udev_device_get_property_value(parent, "PCSCLITE_IGNORE");
417  if (ignoreprop && !strcmp(ignoreprop, "1"))
418  {
419  Log4(PCSC_LOG_ERROR,
420  "Device %s at %s (%s) has PCSCLITE_IGNORE set: ignored",
421  driver->readerName, devpath, sysname);
422  return;
423  }
424 
425  /* check for duplicated add */
426  for (index=0; index<readerTrackerNbEntries; index++)
427  {
428  if (readerTracker[index].fullName && !strcmp(sysname, readerTracker[index].sysname))
429  return;
430  }
431 
432  Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
433 
434  sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
435  if (sInterfaceNumber)
436  bInterfaceNumber = atoi(sInterfaceNumber);
437  else
438  bInterfaceNumber = 0;
439 
440  a = asprintf(&deviceName, "usb:%04x/%04x:libudev:%d:%s",
441  driver->manuID, driver->productID, bInterfaceNumber, devpath);
442  if (-1 == a)
443  {
444  Log1(PCSC_LOG_ERROR, "asprintf() failed");
445  return;
446  }
447 
448  /* find a free entry */
449  for (index=0; index<readerTrackerNbEntries; index++)
450  {
451  if (NULL == readerTracker[index].fullName)
452  break;
453  }
454 
455  /* the array is full? */
456  if (readerTrackerNbEntries == index)
457  {
458  int new_size = readerTrackerNbEntries + 2;
459  Log3(PCSC_LOG_DEBUG, "increase from %d to %d readers", readerTrackerNbEntries, new_size);
460  readerTracker = realloc(readerTracker, new_size * sizeof(*readerTracker));
461  for (int i=readerTrackerNbEntries; i<new_size; i++)
462  {
463  readerTracker[i].devpath = NULL;
464  readerTracker[i].fullName = NULL;
465  readerTracker[i].sysname = NULL;
466  }
467 
468  index = readerTrackerNbEntries; /* new free index */
469  readerTrackerNbEntries = new_size;
470  }
471 
472  if (Add_Interface_In_Name)
473  sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
474 
475  if (Add_Serial_In_Name)
476  sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
477 
478  /* name from the Info.plist file */
479  fullname = strdup(driver->readerName);
480 
481  /* interface name from the device (if any) */
482  if (sInterfaceName)
483  {
484  char *result;
485 
486  char *tmpInterfaceName = strdup(sInterfaceName);
487 
488  /* check the interface name contains only valid ASCII codes */
489  for (size_t i=0; i<strlen(tmpInterfaceName); i++)
490  {
491  if (! isascii(tmpInterfaceName[i]))
492  tmpInterfaceName[i] = '.';
493  }
494 
495  /* create a new name */
496  a = asprintf(&result, "%s [%s]", fullname, tmpInterfaceName);
497  if (-1 == a)
498  {
499  Log1(PCSC_LOG_ERROR, "asprintf() failed");
500  free(tmpInterfaceName);
501  goto exit;
502  }
503 
504  free(fullname);
505  free(tmpInterfaceName);
506  fullname = result;
507  }
508 
509  /* serial number from the device (if any) */
510  if (sSerialNumber)
511  {
512  /* only add the serial number if it is not already present in the
513  * interface name */
514  if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
515  {
516  char *result;
517 
518  /* create a new name */
519  a = asprintf(&result, "%s (%s)", fullname, sSerialNumber);
520  if (-1 == a)
521  {
522  Log1(PCSC_LOG_ERROR, "asprintf() failed");
523  goto exit;
524  }
525 
526  free(fullname);
527  fullname = result;
528  }
529  }
530 
531  readerTracker[index].fullName = strdup(fullname);
532  readerTracker[index].devpath = strdup(devpath);
533  readerTracker[index].sysname = strdup(sysname);
534 
535  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
536  driver->libraryPath, deviceName);
537  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
538  {
539  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
540  driver->readerName);
541 
542  if (classdriver && driver != classdriver)
543  {
544  /* the reader can also be used by the a class driver */
545  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
546  classdriver->libraryPath, deviceName);
547  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
548  {
549  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
550  driver->readerName);
551  (void)CheckForOpenCT();
552  }
553  }
554  else
555  {
556  (void)CheckForOpenCT();
557  }
558  }
559 
560  if (SCARD_S_SUCCESS != ret)
561  {
562  /* adding the reader failed */
563  free(readerTracker[index].devpath);
564  readerTracker[index].devpath = NULL;
565  free(readerTracker[index].fullName);
566  readerTracker[index].fullName = NULL;
567  free(readerTracker[index].sysname);
568  readerTracker[index].sysname = NULL;
569  }
570 
571 exit:
572  free(fullname);
573  free(deviceName);
574 } /* HPAddDevice */
575 
576 
577 static void HPScanUSB(struct udev *udev)
578 {
579  struct udev_enumerate *enumerate;
580  struct udev_list_entry *devices, *dev_list_entry;
581 
582  /* Create a list of the devices in the 'usb' subsystem. */
583  enumerate = udev_enumerate_new(udev);
584  udev_enumerate_add_match_subsystem(enumerate, "usb");
585  udev_enumerate_scan_devices(enumerate);
586  devices = udev_enumerate_get_list_entry(enumerate);
587 
588  /* For each item enumerated */
589  udev_list_entry_foreach(dev_list_entry, devices)
590  {
591  struct udev_device *dev;
592  const char *devpath;
593 
594  /* Get the filename of the /sys entry for the device
595  and create a udev_device object (dev) representing it */
596  devpath = udev_list_entry_get_name(dev_list_entry);
597  dev = udev_device_new_from_syspath(udev, devpath);
598 
599 #ifdef DEBUG_HOTPLUG
600  Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
601 #endif
602  HPAddDevice(dev);
603 
604  /* free device */
605  udev_device_unref(dev);
606  }
607 
608  /* Free the enumerator object */
609  udev_enumerate_unref(enumerate);
610 }
611 
612 
613 static void * HPEstablishUSBNotifications(void *arg)
614 {
615  struct udev_monitor *udev_monitor = arg;
616  int r;
617  int fd;
618  struct pollfd pfd;
619 
620  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
621  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
622 
623  /* udev monitor file descriptor */
624  fd = udev_monitor_get_fd(udev_monitor);
625  if (fd < 0)
626  {
627  Log2(PCSC_LOG_ERROR, "udev_monitor_get_fd() error: %d", fd);
628  pthread_exit(NULL);
629  }
630 
631  pfd.fd = fd;
632  pfd.events = POLLIN;
633 
634  for (;;)
635  {
636  struct udev_device *dev;
637 
638 #ifdef DEBUG_HOTPLUG
639  Log0(PCSC_LOG_INFO);
640 #endif
641  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
642 
643  /* wait for a udev event */
644  r = TEMP_FAILURE_RETRY(poll(&pfd, 1, -1));
645  if (r < 0)
646  {
647  Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
648  pthread_exit(NULL);
649  }
650 
651  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
652 
653  dev = udev_monitor_receive_device(udev_monitor);
654  if (dev)
655  {
656  const char *action = udev_device_get_action(dev);
657 
658  if (action)
659  {
660  if (!strcmp("remove", action))
661  {
662  Log1(PCSC_LOG_INFO, "USB Device removed");
663  HPRemoveDevice(dev);
664  }
665  else
666  if (!strcmp("add", action))
667  {
668  Log1(PCSC_LOG_INFO, "USB Device add");
669  HPAddDevice(dev);
670  }
671  }
672 
673  /* free device */
674  udev_device_unref(dev);
675  }
676  }
677 
678  pthread_exit(NULL);
679 } /* HPEstablishUSBNotifications */
680 
681 
682 /***
683  * Start a thread waiting for hotplug events
684  */
685 LONG HPSearchHotPluggables(const char * hpDirPath)
686 {
687  readerTrackerNbEntries = 2;
688  readerTracker = calloc(readerTrackerNbEntries, sizeof(*readerTracker));
689 
690  return HPReadBundleValues(hpDirPath);
691 } /* HPSearchHotPluggables */
692 
693 
697 LONG HPStopHotPluggables(void)
698 {
699  int i;
700 
701  if (driverSize <= 0)
702  return 0;
703 
704  if (!Udev)
705  return 0;
706 
707  pthread_cancel(usbNotifyThread);
708  pthread_join(usbNotifyThread, NULL);
709 
710  for (i=0; i<driverSize; i++)
711  {
712  /* free strings allocated by strdup() */
713  free(driverTracker[i].bundleName);
714  free(driverTracker[i].libraryPath);
715  free(driverTracker[i].readerName);
716  free(driverTracker[i].CFBundleName);
717  }
718  free(driverTracker);
719 
720  udev_unref(Udev);
721  udev_monitor_unref(Udev_monitor);
722 
723  Udev = NULL;
724  driverSize = -1;
725 
726  Log1(PCSC_LOG_INFO, "Hotplug stopped");
727  return 0;
728 } /* HPStopHotPluggables */
729 
730 
734 ULONG HPRegisterForHotplugEvents(const char * hpDirPath)
735 {
736  int r;
737 
738  if (driverSize <= 0)
739  {
740  (void)hpDirPath;
741  Log2(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: %s",
742  hpDirPath);
743  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
744  return 0;
745  }
746 
747  /* Create the udev object */
748  Udev = udev_new();
749  if (!Udev)
750  {
751  Log1(PCSC_LOG_ERROR, "udev_new() failed");
752  return SCARD_F_INTERNAL_ERROR;
753  }
754 
755  Udev_monitor = udev_monitor_new_from_netlink(Udev, "udev");
756  if (NULL == Udev_monitor)
757  {
758  Log1(PCSC_LOG_ERROR, "udev_monitor_new_from_netlink() error");
759  pthread_exit(NULL);
760  }
761 
762  /* filter only the interfaces */
763  r = udev_monitor_filter_add_match_subsystem_devtype(Udev_monitor, "usb",
764  "usb_interface");
765  if (r)
766  {
767  Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
768  pthread_exit(NULL);
769  }
770 
771  r = udev_monitor_enable_receiving(Udev_monitor);
772  if (r)
773  {
774  Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
775  pthread_exit(NULL);
776  }
777 
778  /* scan the USB bus at least once before accepting client connections */
779  HPScanUSB(Udev);
780 
781  if (ThreadCreate(&usbNotifyThread, 0,
782  (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, Udev_monitor))
783  {
784  Log1(PCSC_LOG_ERROR, "ThreadCreate() failed");
785  return SCARD_F_INTERNAL_ERROR;
786  }
787 
788  return 0;
789 } /* HPRegisterForHotplugEvents */
790 
791 
792 void HPReCheckSerialReaders(void)
793 {
794  /* nothing to do here */
795 #ifdef DEBUG_HOTPLUG
796  Log0(PCSC_LOG_ERROR);
797 #endif
798 
799  /* re-scan the USB bus */
800  HPScanUSB(Udev);
801 
802 } /* HPReCheckSerialReaders */
803 
804 #endif
805 
list object
Definition: simclist.h:181
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
This handles abstract system level calls.
Reads lexical config files and updates database.
This keeps track of a list of currently available reader structures.
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
This provides a search API for hot pluggble devices.
This handles debugging.