pcsc-lite  2.0.3
hotplug_libudev.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3  *
4  * Copyright (C) 2011
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 
77 
81 static struct _driverTracker
82 {
83  unsigned int manuID;
84  unsigned int productID;
85 
86  char *bundleName;
87  char *libraryPath;
88  char *readerName;
89  char *CFBundleName;
90 } *driverTracker = NULL;
91 #define DRIVER_TRACKER_SIZE_STEP 10
92 
93 /* The CCID driver already supports 176 readers.
94  * We start with a big array size to avoid reallocation. */
95 #define DRIVER_TRACKER_INITIAL_SIZE 200
96 
100 static struct _readerTracker
101 {
102  char *devpath;
103  char *fullName;
104  char *sysname;
105 } readerTracker[PCSCLITE_MAX_READERS_CONTEXTS];
106 
107 
108 static LONG HPReadBundleValues(const char * hpDirPath)
109 {
110  LONG rv;
111  DIR *hpDir;
112  struct dirent *currFP = NULL;
113  char fullPath[FILENAME_MAX];
114  char fullLibPath[FILENAME_MAX];
115  int listCount = 0;
116 
117  hpDir = opendir(hpDirPath);
118 
119  if (NULL == hpDir)
120  {
121  Log2(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: %s", hpDirPath);
122  Log1(PCSC_LOG_ERROR, "Disabling USB support for pcscd.");
123  return -1;
124  }
125 
126  /* allocate a first array */
127  driverSize = DRIVER_TRACKER_INITIAL_SIZE;
128  driverTracker = calloc(driverSize, sizeof(*driverTracker));
129  if (NULL == driverTracker)
130  {
131  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
132  (void)closedir(hpDir);
133  return -1;
134  }
135 
136 #define GET_KEY(key, values) \
137  rv = LTPBundleFindValueWithKey(&plist, key, values); \
138  if (rv) \
139  { \
140  Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
141  fullPath); \
142  continue; \
143  }
144 
145  while ((currFP = readdir(hpDir)) != 0)
146  {
147  if (strstr(currFP->d_name, ".bundle") != 0)
148  {
149  unsigned int alias;
150  list_t plist, *values;
151  list_t *manuIDs, *productIDs, *readerNames;
152  char *CFBundleName;
153  char *libraryPath;
154 
155  /*
156  * The bundle exists - let's form a full path name and get the
157  * vendor and product ID's for this particular bundle
158  */
159  (void)snprintf(fullPath, sizeof(fullPath), "%s/%s/Contents/Info.plist",
160  hpDirPath, currFP->d_name);
161  fullPath[sizeof(fullPath) - 1] = '\0';
162 
163  rv = bundleParse(fullPath, &plist);
164  if (rv)
165  continue;
166 
167  /* get CFBundleExecutable */
168  GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
169  libraryPath = list_get_at(values, 0);
170  (void)snprintf(fullLibPath, sizeof(fullLibPath),
171  "%s/%s/Contents/%s/%s",
172  hpDirPath, currFP->d_name, PCSC_ARCH,
173  libraryPath);
174  fullLibPath[sizeof(fullLibPath) - 1] = '\0';
175 
176  GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
177  GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
178  GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
179 
180  if ((list_size(manuIDs) != list_size(productIDs))
181  || (list_size(manuIDs) != list_size(readerNames)))
182  {
183  Log2(PCSC_LOG_CRITICAL, "Error parsing %s", fullPath);
184  (void)closedir(hpDir);
185  return -1;
186  }
187 
188  /* Get CFBundleName */
189  rv = LTPBundleFindValueWithKey(&plist, PCSCLITE_HP_CFBUNDLE_NAME,
190  &values);
191  if (rv)
192  CFBundleName = NULL;
193  else
194  CFBundleName = strdup(list_get_at(values, 0));
195 
196  /* while we find a nth ifdVendorID in Info.plist */
197  for (alias=0; alias<list_size(manuIDs); alias++)
198  {
199  char *value;
200 
201  /* variables entries */
202  value = list_get_at(manuIDs, alias);
203  driverTracker[listCount].manuID = strtol(value, NULL, 16);
204 
205  value = list_get_at(productIDs, alias);
206  driverTracker[listCount].productID = strtol(value, NULL, 16);
207 
208  driverTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
209 
210  /* constant entries for a same driver */
211  driverTracker[listCount].bundleName = strdup(currFP->d_name);
212  driverTracker[listCount].libraryPath = strdup(fullLibPath);
213  driverTracker[listCount].CFBundleName = CFBundleName;
214 
215 #ifdef DEBUG_HOTPLUG
216  Log2(PCSC_LOG_INFO, "Found driver for: %s",
217  driverTracker[listCount].readerName);
218 #endif
219  listCount++;
220  if (listCount >= driverSize)
221  {
222  int i;
223 
224  /* increase the array size */
225  driverSize += DRIVER_TRACKER_SIZE_STEP;
226 #ifdef DEBUG_HOTPLUG
227  Log2(PCSC_LOG_INFO,
228  "Increase driverTracker to %d entries", driverSize);
229 #endif
230 
231  void* tmp = realloc(driverTracker,
232  driverSize * sizeof(*driverTracker));
233 
234  if (NULL == tmp)
235  {
236  free(driverTracker);
237  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
238  driverSize = -1;
239  (void)closedir(hpDir);
240  return -1;
241  }
242  driverTracker = tmp;
243 
244  /* clean the newly allocated entries */
245  for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
246  {
247  driverTracker[i].manuID = 0;
248  driverTracker[i].productID = 0;
249  driverTracker[i].bundleName = NULL;
250  driverTracker[i].libraryPath = NULL;
251  driverTracker[i].readerName = NULL;
252  driverTracker[i].CFBundleName = NULL;
253  }
254  }
255  }
256  bundleRelease(&plist);
257  }
258  }
259 
260  driverSize = listCount;
261  (void)closedir(hpDir);
262 
263 #ifdef DEBUG_HOTPLUG
264  Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
265 #endif
266 
267  return 0;
268 } /* HPReadBundleValues */
269 
270 
271 /*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
272  const char *devpath, struct _driverTracker **classdriver)
273 {
274  int i;
275  unsigned int idVendor, idProduct;
276  static struct _driverTracker *driver;
277  const char *str;
278 
279  str = udev_device_get_sysattr_value(dev, "idVendor");
280  if (!str)
281  {
282  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
283  return NULL;
284  }
285  idVendor = strtol(str, NULL, 16);
286 
287  str = udev_device_get_sysattr_value(dev, "idProduct");
288  if (!str)
289  {
290  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
291  return NULL;
292  }
293  idProduct = strtol(str, NULL, 16);
294 
295 #ifdef NO_LOG
296  (void)devpath;
297 #endif
298  Log4(PCSC_LOG_DEBUG,
299  "Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
300  idVendor, idProduct, devpath);
301 
302  *classdriver = NULL;
303  driver = NULL;
304  /* check if the device is supported by one driver */
305  for (i=0; i<driverSize; i++)
306  {
307  if (driverTracker[i].libraryPath != NULL &&
308  idVendor == driverTracker[i].manuID &&
309  idProduct == driverTracker[i].productID)
310  {
311  if ((driverTracker[i].CFBundleName != NULL)
312  && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
313  *classdriver = &driverTracker[i];
314  else
315  /* it is not a CCID Class driver */
316  driver = &driverTracker[i];
317  }
318  }
319 
320  /* if we found a specific driver */
321  if (driver)
322  return driver;
323 
324  /* else return the Class driver (if any) */
325  return *classdriver;
326 }
327 
328 
329 static void HPRemoveDevice(struct udev_device *dev)
330 {
331  int i;
332  const char *sysname;
333 
334  sysname = udev_device_get_sysname(dev);
335  if (!sysname)
336  {
337  Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
338  return;
339  }
340 
341  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
342  {
343  if (readerTracker[i].fullName && !strcmp(sysname, readerTracker[i].sysname))
344  {
345  Log4(PCSC_LOG_INFO, "Removing USB device[%d]: %s at %s", i,
346  readerTracker[i].fullName, readerTracker[i].devpath);
347 
348  RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i, REMOVE_READER_FLAG_REMOVED);
349 
350  free(readerTracker[i].devpath);
351  readerTracker[i].devpath = NULL;
352  free(readerTracker[i].fullName);
353  readerTracker[i].fullName = NULL;
354  free(readerTracker[i].sysname);
355  readerTracker[i].sysname = NULL;
356  break;
357  }
358  }
359 }
360 
361 
362 static void HPAddDevice(struct udev_device *dev)
363 {
364  int index, a;
365  char *deviceName = NULL;
366  char *fullname = NULL;
367  struct _driverTracker *driver, *classdriver;
368  const char *sSerialNumber = NULL, *sInterfaceName = NULL;
369  const char *sInterfaceNumber;
370  LONG ret;
371  int bInterfaceNumber;
372  const char *devpath;
373  struct udev_device *parent;
374  const char *sysname;
375 
376  /* The device pointed to by dev contains information about
377  the interface. In order to get information about the USB
378  device, get the parent device with the subsystem/devtype pair
379  of "usb"/"usb_device". This will be several levels up the
380  tree, but the function will find it.*/
381  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
382  "usb_device");
383  if (!parent)
384  return;
385 
386  devpath = udev_device_get_devnode(parent);
387  if (!devpath)
388  {
389  /* the device disappeared? */
390  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
391  return;
392  }
393 
394  driver = get_driver(parent, devpath, &classdriver);
395  if (NULL == driver)
396  {
397  /* not a smart card reader */
398 #ifdef DEBUG_HOTPLUG
399  Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
400  devpath);
401 #endif
402  return;
403  }
404 
405  sysname = udev_device_get_sysname(dev);
406  if (!sysname)
407  {
408  Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
409  return;
410  }
411 
412  /* check for duplicated add */
413  for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
414  {
415  if (readerTracker[index].fullName && !strcmp(sysname, readerTracker[index].sysname))
416  return;
417  }
418 
419  Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
420 
421  sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
422  if (sInterfaceNumber)
423  bInterfaceNumber = atoi(sInterfaceNumber);
424  else
425  bInterfaceNumber = 0;
426 
427  a = asprintf(&deviceName, "usb:%04x/%04x:libudev:%d:%s",
428  driver->manuID, driver->productID, bInterfaceNumber, devpath);
429  if (-1 == a)
430  {
431  Log1(PCSC_LOG_ERROR, "asprintf() failed");
432  return;
433  }
434 
435  /* find a free entry */
436  for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
437  {
438  if (NULL == readerTracker[index].fullName)
439  break;
440  }
441 
442  if (PCSCLITE_MAX_READERS_CONTEXTS == index)
443  {
444  Log2(PCSC_LOG_ERROR,
445  "Not enough reader entries. Already found %d readers", index);
446  goto exit;
447  }
448 
449  if (Add_Interface_In_Name)
450  sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
451 
452  if (Add_Serial_In_Name)
453  sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
454 
455  /* name from the Info.plist file */
456  fullname = strdup(driver->readerName);
457 
458  /* interface name from the device (if any) */
459  if (sInterfaceName)
460  {
461  char *result;
462 
463  char *tmpInterfaceName = strdup(sInterfaceName);
464 
465  /* check the interface name contains only valid ASCII codes */
466  for (size_t i=0; i<strlen(tmpInterfaceName); i++)
467  {
468  if (! isascii(tmpInterfaceName[i]))
469  tmpInterfaceName[i] = '.';
470  }
471 
472  /* create a new name */
473  a = asprintf(&result, "%s [%s]", fullname, tmpInterfaceName);
474  if (-1 == a)
475  {
476  Log1(PCSC_LOG_ERROR, "asprintf() failed");
477  free(tmpInterfaceName);
478  goto exit;
479  }
480 
481  free(fullname);
482  free(tmpInterfaceName);
483  fullname = result;
484  }
485 
486  /* serial number from the device (if any) */
487  if (sSerialNumber)
488  {
489  /* only add the serial number if it is not already present in the
490  * interface name */
491  if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
492  {
493  char *result;
494 
495  /* create a new name */
496  a = asprintf(&result, "%s (%s)", fullname, sSerialNumber);
497  if (-1 == a)
498  {
499  Log1(PCSC_LOG_ERROR, "asprintf() failed");
500  goto exit;
501  }
502 
503  free(fullname);
504  fullname = result;
505  }
506  }
507 
508  readerTracker[index].fullName = strdup(fullname);
509  readerTracker[index].devpath = strdup(devpath);
510  readerTracker[index].sysname = strdup(sysname);
511 
512  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
513  driver->libraryPath, deviceName);
514  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
515  {
516  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
517  driver->readerName);
518 
519  if (classdriver && driver != classdriver)
520  {
521  /* the reader can also be used by the a class driver */
522  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
523  classdriver->libraryPath, deviceName);
524  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
525  {
526  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
527  driver->readerName);
528  (void)CheckForOpenCT();
529  }
530  }
531  else
532  {
533  (void)CheckForOpenCT();
534  }
535  }
536 
537  if (SCARD_S_SUCCESS != ret)
538  {
539  /* adding the reader failed */
540  free(readerTracker[index].devpath);
541  readerTracker[index].devpath = NULL;
542  free(readerTracker[index].fullName);
543  readerTracker[index].fullName = NULL;
544  free(readerTracker[index].sysname);
545  readerTracker[index].sysname = NULL;
546  }
547 
548 exit:
549  free(fullname);
550  free(deviceName);
551 } /* HPAddDevice */
552 
553 
554 static void HPScanUSB(struct udev *udev)
555 {
556  struct udev_enumerate *enumerate;
557  struct udev_list_entry *devices, *dev_list_entry;
558 
559  /* Create a list of the devices in the 'usb' subsystem. */
560  enumerate = udev_enumerate_new(udev);
561  udev_enumerate_add_match_subsystem(enumerate, "usb");
562  udev_enumerate_scan_devices(enumerate);
563  devices = udev_enumerate_get_list_entry(enumerate);
564 
565  /* For each item enumerated */
566  udev_list_entry_foreach(dev_list_entry, devices)
567  {
568  struct udev_device *dev;
569  const char *devpath;
570 
571  /* Get the filename of the /sys entry for the device
572  and create a udev_device object (dev) representing it */
573  devpath = udev_list_entry_get_name(dev_list_entry);
574  dev = udev_device_new_from_syspath(udev, devpath);
575 
576 #ifdef DEBUG_HOTPLUG
577  Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
578 #endif
579  HPAddDevice(dev);
580 
581  /* free device */
582  udev_device_unref(dev);
583  }
584 
585  /* Free the enumerator object */
586  udev_enumerate_unref(enumerate);
587 }
588 
589 
590 static void * HPEstablishUSBNotifications(void *arg)
591 {
592  struct udev_monitor *udev_monitor = arg;
593  int r;
594  int fd;
595  struct pollfd pfd;
596 
597  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
598  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
599 
600  /* udev monitor file descriptor */
601  fd = udev_monitor_get_fd(udev_monitor);
602  if (fd < 0)
603  {
604  Log2(PCSC_LOG_ERROR, "udev_monitor_get_fd() error: %d", fd);
605  pthread_exit(NULL);
606  }
607 
608  pfd.fd = fd;
609  pfd.events = POLLIN;
610 
611  for (;;)
612  {
613  struct udev_device *dev;
614 
615 #ifdef DEBUG_HOTPLUG
616  Log0(PCSC_LOG_INFO);
617 #endif
618  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
619 
620  /* wait for a udev event */
621  r = TEMP_FAILURE_RETRY(poll(&pfd, 1, -1));
622  if (r < 0)
623  {
624  Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
625  pthread_exit(NULL);
626  }
627 
628  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
629 
630  dev = udev_monitor_receive_device(udev_monitor);
631  if (dev)
632  {
633  const char *action = udev_device_get_action(dev);
634 
635  if (action)
636  {
637  if (!strcmp("remove", action))
638  {
639  Log1(PCSC_LOG_INFO, "USB Device removed");
640  HPRemoveDevice(dev);
641  }
642  else
643  if (!strcmp("add", action))
644  {
645  Log1(PCSC_LOG_INFO, "USB Device add");
646  HPAddDevice(dev);
647  }
648  }
649 
650  /* free device */
651  udev_device_unref(dev);
652  }
653  }
654 
655  pthread_exit(NULL);
656 } /* HPEstablishUSBNotifications */
657 
658 
659 /***
660  * Start a thread waiting for hotplug events
661  */
662 LONG HPSearchHotPluggables(const char * hpDirPath)
663 {
664  int i;
665 
666  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
667  {
668  readerTracker[i].devpath = NULL;
669  readerTracker[i].fullName = NULL;
670  readerTracker[i].sysname = NULL;
671  }
672 
673  return HPReadBundleValues(hpDirPath);
674 } /* HPSearchHotPluggables */
675 
676 
680 LONG HPStopHotPluggables(void)
681 {
682  int i;
683 
684  if (driverSize <= 0)
685  return 0;
686 
687  if (!Udev)
688  return 0;
689 
690  pthread_cancel(usbNotifyThread);
691  pthread_join(usbNotifyThread, NULL);
692 
693  for (i=0; i<driverSize; i++)
694  {
695  /* free strings allocated by strdup() */
696  free(driverTracker[i].bundleName);
697  free(driverTracker[i].libraryPath);
698  free(driverTracker[i].readerName);
699  }
700  free(driverTracker);
701 
702  udev_unref(Udev);
703 
704  Udev = NULL;
705  driverSize = -1;
706 
707  Log1(PCSC_LOG_INFO, "Hotplug stopped");
708  return 0;
709 } /* HPStopHotPluggables */
710 
711 
715 ULONG HPRegisterForHotplugEvents(const char * hpDirPath)
716 {
717  struct udev_monitor *udev_monitor;
718  int r;
719 
720  if (driverSize <= 0)
721  {
722  (void)hpDirPath;
723  Log2(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: %s",
724  hpDirPath);
725  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
726  return 0;
727  }
728 
729  /* Create the udev object */
730  Udev = udev_new();
731  if (!Udev)
732  {
733  Log1(PCSC_LOG_ERROR, "udev_new() failed");
734  return SCARD_F_INTERNAL_ERROR;
735  }
736 
737  udev_monitor = udev_monitor_new_from_netlink(Udev, "udev");
738  if (NULL == udev_monitor)
739  {
740  Log1(PCSC_LOG_ERROR, "udev_monitor_new_from_netlink() error");
741  pthread_exit(NULL);
742  }
743 
744  /* filter only the interfaces */
745  r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb",
746  "usb_interface");
747  if (r)
748  {
749  Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
750  pthread_exit(NULL);
751  }
752 
753  r = udev_monitor_enable_receiving(udev_monitor);
754  if (r)
755  {
756  Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
757  pthread_exit(NULL);
758  }
759 
760  /* scan the USB bus at least once before accepting client connections */
761  HPScanUSB(Udev);
762 
763  if (ThreadCreate(&usbNotifyThread, 0,
764  (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev_monitor))
765  {
766  Log1(PCSC_LOG_ERROR, "ThreadCreate() failed");
767  return SCARD_F_INTERNAL_ERROR;
768  }
769 
770  return 0;
771 } /* HPRegisterForHotplugEvents */
772 
773 
774 void HPReCheckSerialReaders(void)
775 {
776  /* nothing to do here */
777 #ifdef DEBUG_HOTPLUG
778  Log0(PCSC_LOG_ERROR);
779 #endif
780 } /* HPReCheckSerialReaders */
781 
782 #endif
783 
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.
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:285
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.