pcsc-lite  2.2.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-2023
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 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(const char * hpDirPath)
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(hpDirPath);
119 
120  if (NULL == hpDir)
121  {
122  Log2(PCSC_LOG_ERROR, "Cannot open PC/SC drivers directory: %s", hpDirPath);
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  hpDirPath, 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  hpDirPath, 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 = 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 ? strdup(CFBundleName) : NULL;
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 
232  void* tmp = realloc(driverTracker,
233  driverSize * sizeof(*driverTracker));
234 
235  if (NULL == tmp)
236  {
237  free(driverTracker);
238  Log1(PCSC_LOG_CRITICAL, "Not enough memory");
239  driverSize = -1;
240  (void)closedir(hpDir);
241  return -1;
242  }
243  driverTracker = tmp;
244 
245  /* clean the newly allocated entries */
246  for (i=driverSize-DRIVER_TRACKER_SIZE_STEP; i<driverSize; i++)
247  {
248  driverTracker[i].manuID = 0;
249  driverTracker[i].productID = 0;
250  driverTracker[i].bundleName = NULL;
251  driverTracker[i].libraryPath = NULL;
252  driverTracker[i].readerName = NULL;
253  driverTracker[i].CFBundleName = NULL;
254  }
255  }
256  }
257  bundleRelease(&plist);
258  }
259  }
260 
261  driverSize = listCount;
262  (void)closedir(hpDir);
263 
264 #ifdef DEBUG_HOTPLUG
265  Log2(PCSC_LOG_INFO, "Found drivers for %d readers", listCount);
266 #endif
267 
268  return 0;
269 } /* HPReadBundleValues */
270 
271 
272 /*@null@*/ static struct _driverTracker *get_driver(struct udev_device *dev,
273  const char *devpath, struct _driverTracker **classdriver)
274 {
275  int i;
276  unsigned int idVendor, idProduct;
277  static struct _driverTracker *driver;
278  const char *str;
279 
280  str = udev_device_get_sysattr_value(dev, "idVendor");
281  if (!str)
282  {
283  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
284  return NULL;
285  }
286  idVendor = strtol(str, NULL, 16);
287 
288  str = udev_device_get_sysattr_value(dev, "idProduct");
289  if (!str)
290  {
291  Log1(PCSC_LOG_ERROR, "udev_device_get_sysattr_value() failed");
292  return NULL;
293  }
294  idProduct = strtol(str, NULL, 16);
295 
296 #ifdef NO_LOG
297  (void)devpath;
298 #endif
299  Log4(PCSC_LOG_DEBUG,
300  "Looking for a driver for VID: 0x%04X, PID: 0x%04X, path: %s",
301  idVendor, idProduct, devpath);
302 
303  *classdriver = NULL;
304  driver = NULL;
305  /* check if the device is supported by one driver */
306  for (i=0; i<driverSize; i++)
307  {
308  if (driverTracker[i].libraryPath != NULL &&
309  idVendor == driverTracker[i].manuID &&
310  idProduct == driverTracker[i].productID)
311  {
312  if ((driverTracker[i].CFBundleName != NULL)
313  && (0 == strcmp(driverTracker[i].CFBundleName, "CCIDCLASSDRIVER")))
314  *classdriver = &driverTracker[i];
315  else
316  /* it is not a CCID Class driver */
317  driver = &driverTracker[i];
318  }
319  }
320 
321  /* if we found a specific driver */
322  if (driver)
323  return driver;
324 
325  /* else return the Class driver (if any) */
326  return *classdriver;
327 }
328 
329 
330 static void HPRemoveDevice(struct udev_device *dev)
331 {
332  int i;
333  const char *sysname;
334 
335  sysname = udev_device_get_sysname(dev);
336  if (!sysname)
337  {
338  Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
339  return;
340  }
341 
342  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
343  {
344  if (readerTracker[i].fullName && !strcmp(sysname, readerTracker[i].sysname))
345  {
346  Log4(PCSC_LOG_INFO, "Removing USB device[%d]: %s at %s", i,
347  readerTracker[i].fullName, readerTracker[i].devpath);
348 
349  RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i, REMOVE_READER_FLAG_REMOVED);
350 
351  free(readerTracker[i].devpath);
352  readerTracker[i].devpath = NULL;
353  free(readerTracker[i].fullName);
354  readerTracker[i].fullName = NULL;
355  free(readerTracker[i].sysname);
356  readerTracker[i].sysname = NULL;
357  break;
358  }
359  }
360 }
361 
362 
363 static void HPAddDevice(struct udev_device *dev)
364 {
365  int index, a;
366  char *deviceName = NULL;
367  char *fullname = NULL;
368  struct _driverTracker *driver, *classdriver;
369  const char *sSerialNumber = NULL, *sInterfaceName = NULL;
370  const char *sInterfaceNumber;
371  LONG ret;
372  int bInterfaceNumber;
373  const char *devpath;
374  struct udev_device *parent;
375  const char *sysname;
376 
377  /* The device pointed to by dev contains information about
378  the interface. In order to get information about the USB
379  device, get the parent device with the subsystem/devtype pair
380  of "usb"/"usb_device". This will be several levels up the
381  tree, but the function will find it.*/
382  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
383  "usb_device");
384  if (!parent)
385  return;
386 
387  devpath = udev_device_get_devnode(parent);
388  if (!devpath)
389  {
390  /* the device disappeared? */
391  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
392  return;
393  }
394 
395  driver = get_driver(parent, devpath, &classdriver);
396  if (NULL == driver)
397  {
398  /* not a smart card reader */
399 #ifdef DEBUG_HOTPLUG
400  Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
401  devpath);
402 #endif
403  return;
404  }
405 
406  sysname = udev_device_get_sysname(dev);
407  if (!sysname)
408  {
409  Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
410  return;
411  }
412 
413  /* check for duplicated add */
414  for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
415  {
416  if (readerTracker[index].fullName && !strcmp(sysname, readerTracker[index].sysname))
417  return;
418  }
419 
420  Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
421 
422  sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
423  if (sInterfaceNumber)
424  bInterfaceNumber = atoi(sInterfaceNumber);
425  else
426  bInterfaceNumber = 0;
427 
428  a = asprintf(&deviceName, "usb:%04x/%04x:libudev:%d:%s",
429  driver->manuID, driver->productID, bInterfaceNumber, devpath);
430  if (-1 == a)
431  {
432  Log1(PCSC_LOG_ERROR, "asprintf() failed");
433  return;
434  }
435 
436  /* find a free entry */
437  for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
438  {
439  if (NULL == readerTracker[index].fullName)
440  break;
441  }
442 
443  if (PCSCLITE_MAX_READERS_CONTEXTS == index)
444  {
445  Log2(PCSC_LOG_ERROR,
446  "Not enough reader entries. Already found %d readers", index);
447  goto exit;
448  }
449 
450  if (Add_Interface_In_Name)
451  sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
452 
453  if (Add_Serial_In_Name)
454  sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
455 
456  /* name from the Info.plist file */
457  fullname = strdup(driver->readerName);
458 
459  /* interface name from the device (if any) */
460  if (sInterfaceName)
461  {
462  char *result;
463 
464  char *tmpInterfaceName = strdup(sInterfaceName);
465 
466  /* check the interface name contains only valid ASCII codes */
467  for (size_t i=0; i<strlen(tmpInterfaceName); i++)
468  {
469  if (! isascii(tmpInterfaceName[i]))
470  tmpInterfaceName[i] = '.';
471  }
472 
473  /* create a new name */
474  a = asprintf(&result, "%s [%s]", fullname, tmpInterfaceName);
475  if (-1 == a)
476  {
477  Log1(PCSC_LOG_ERROR, "asprintf() failed");
478  free(tmpInterfaceName);
479  goto exit;
480  }
481 
482  free(fullname);
483  free(tmpInterfaceName);
484  fullname = result;
485  }
486 
487  /* serial number from the device (if any) */
488  if (sSerialNumber)
489  {
490  /* only add the serial number if it is not already present in the
491  * interface name */
492  if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
493  {
494  char *result;
495 
496  /* create a new name */
497  a = asprintf(&result, "%s (%s)", fullname, sSerialNumber);
498  if (-1 == a)
499  {
500  Log1(PCSC_LOG_ERROR, "asprintf() failed");
501  goto exit;
502  }
503 
504  free(fullname);
505  fullname = result;
506  }
507  }
508 
509  readerTracker[index].fullName = strdup(fullname);
510  readerTracker[index].devpath = strdup(devpath);
511  readerTracker[index].sysname = strdup(sysname);
512 
513  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
514  driver->libraryPath, deviceName);
515  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
516  {
517  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
518  driver->readerName);
519 
520  if (classdriver && driver != classdriver)
521  {
522  /* the reader can also be used by the a class driver */
523  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
524  classdriver->libraryPath, deviceName);
525  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
526  {
527  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
528  driver->readerName);
529  (void)CheckForOpenCT();
530  }
531  }
532  else
533  {
534  (void)CheckForOpenCT();
535  }
536  }
537 
538  if (SCARD_S_SUCCESS != ret)
539  {
540  /* adding the reader failed */
541  free(readerTracker[index].devpath);
542  readerTracker[index].devpath = NULL;
543  free(readerTracker[index].fullName);
544  readerTracker[index].fullName = NULL;
545  free(readerTracker[index].sysname);
546  readerTracker[index].sysname = NULL;
547  }
548 
549 exit:
550  free(fullname);
551  free(deviceName);
552 } /* HPAddDevice */
553 
554 
555 static void HPScanUSB(struct udev *udev)
556 {
557  struct udev_enumerate *enumerate;
558  struct udev_list_entry *devices, *dev_list_entry;
559 
560  /* Create a list of the devices in the 'usb' subsystem. */
561  enumerate = udev_enumerate_new(udev);
562  udev_enumerate_add_match_subsystem(enumerate, "usb");
563  udev_enumerate_scan_devices(enumerate);
564  devices = udev_enumerate_get_list_entry(enumerate);
565 
566  /* For each item enumerated */
567  udev_list_entry_foreach(dev_list_entry, devices)
568  {
569  struct udev_device *dev;
570  const char *devpath;
571 
572  /* Get the filename of the /sys entry for the device
573  and create a udev_device object (dev) representing it */
574  devpath = udev_list_entry_get_name(dev_list_entry);
575  dev = udev_device_new_from_syspath(udev, devpath);
576 
577 #ifdef DEBUG_HOTPLUG
578  Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
579 #endif
580  HPAddDevice(dev);
581 
582  /* free device */
583  udev_device_unref(dev);
584  }
585 
586  /* Free the enumerator object */
587  udev_enumerate_unref(enumerate);
588 }
589 
590 
591 static void * HPEstablishUSBNotifications(void *arg)
592 {
593  struct udev_monitor *udev_monitor = arg;
594  int r;
595  int fd;
596  struct pollfd pfd;
597 
598  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
599  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
600 
601  /* udev monitor file descriptor */
602  fd = udev_monitor_get_fd(udev_monitor);
603  if (fd < 0)
604  {
605  Log2(PCSC_LOG_ERROR, "udev_monitor_get_fd() error: %d", fd);
606  pthread_exit(NULL);
607  }
608 
609  pfd.fd = fd;
610  pfd.events = POLLIN;
611 
612  for (;;)
613  {
614  struct udev_device *dev;
615 
616 #ifdef DEBUG_HOTPLUG
617  Log0(PCSC_LOG_INFO);
618 #endif
619  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
620 
621  /* wait for a udev event */
622  r = TEMP_FAILURE_RETRY(poll(&pfd, 1, -1));
623  if (r < 0)
624  {
625  Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
626  pthread_exit(NULL);
627  }
628 
629  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
630 
631  dev = udev_monitor_receive_device(udev_monitor);
632  if (dev)
633  {
634  const char *action = udev_device_get_action(dev);
635 
636  if (action)
637  {
638  if (!strcmp("remove", action))
639  {
640  Log1(PCSC_LOG_INFO, "USB Device removed");
641  HPRemoveDevice(dev);
642  }
643  else
644  if (!strcmp("add", action))
645  {
646  Log1(PCSC_LOG_INFO, "USB Device add");
647  HPAddDevice(dev);
648  }
649  }
650 
651  /* free device */
652  udev_device_unref(dev);
653  }
654  }
655 
656  pthread_exit(NULL);
657 } /* HPEstablishUSBNotifications */
658 
659 
660 /***
661  * Start a thread waiting for hotplug events
662  */
663 LONG HPSearchHotPluggables(const char * hpDirPath)
664 {
665  int i;
666 
667  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
668  {
669  readerTracker[i].devpath = NULL;
670  readerTracker[i].fullName = NULL;
671  readerTracker[i].sysname = NULL;
672  }
673 
674  return HPReadBundleValues(hpDirPath);
675 } /* HPSearchHotPluggables */
676 
677 
681 LONG HPStopHotPluggables(void)
682 {
683  int i;
684 
685  if (driverSize <= 0)
686  return 0;
687 
688  if (!Udev)
689  return 0;
690 
691  pthread_cancel(usbNotifyThread);
692  pthread_join(usbNotifyThread, NULL);
693 
694  for (i=0; i<driverSize; i++)
695  {
696  /* free strings allocated by strdup() */
697  free(driverTracker[i].bundleName);
698  free(driverTracker[i].libraryPath);
699  free(driverTracker[i].readerName);
700  free(driverTracker[i].CFBundleName);
701  }
702  free(driverTracker);
703 
704  udev_unref(Udev);
705  udev_monitor_unref(Udev_monitor);
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(const char * hpDirPath)
719 {
720  int r;
721 
722  if (driverSize <= 0)
723  {
724  (void)hpDirPath;
725  Log2(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: %s",
726  hpDirPath);
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 
debuglog.h
This handles debugging.
SCARD_S_SUCCESS
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
sys_generic.h
This handles abstract system level calls.
readerfactory.h
This keeps track of a list of currently available reader structures.
list_t
list object
Definition: simclist.h:181
PCSCLITE_MAX_READERS_CONTEXTS
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:285
parser.h
Reads lexical config files and updates database.
SCARD_F_INTERNAL_ERROR
#define SCARD_F_INTERNAL_ERROR
An internal consistency check failed.
Definition: pcsclite.h:109
SCARD_E_UNKNOWN_READER
#define SCARD_E_UNKNOWN_READER
The specified reader name is not recognized.
Definition: pcsclite.h:125
hotplug.h
This provides a search API for hot pluggble devices.