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