pcsc-lite  1.8.26
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 
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 
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 *devpath;
334  struct udev_device *parent;
335  const char *sysname;
336 
337  /* The device pointed to by dev contains information about
338  the interface. In order to get information about the USB
339  device, get the parent device with the subsystem/devtype pair
340  of "usb"/"usb_device". This will be several levels up the
341  tree, but the function will find it.*/
342  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
343  "usb_device");
344  if (!parent)
345  return;
346 
347  devpath = udev_device_get_devnode(parent);
348  if (!devpath)
349  {
350  /* the device disapeared? */
351  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
352  return;
353  }
354 
355  sysname = udev_device_get_sysname(dev);
356  if (!sysname)
357  {
358  Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
359  return;
360  }
361 
362  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
363  {
364  if (readerTracker[i].fullName && !strcmp(sysname, readerTracker[i].sysname))
365  {
366  Log4(PCSC_LOG_INFO, "Removing USB device[%d]: %s at %s", i,
367  readerTracker[i].fullName, readerTracker[i].devpath);
368 
369  RFRemoveReader(readerTracker[i].fullName, PCSCLITE_HP_BASE_PORT + i);
370 
371  free(readerTracker[i].devpath);
372  readerTracker[i].devpath = NULL;
373  free(readerTracker[i].fullName);
374  readerTracker[i].fullName = NULL;
375  free(readerTracker[i].sysname);
376  readerTracker[i].sysname = NULL;
377  break;
378  }
379  }
380 }
381 
382 
383 static void HPAddDevice(struct udev_device *dev)
384 {
385  int index, a;
386  char *deviceName = NULL;
387  char *fullname = NULL;
388  struct _driverTracker *driver, *classdriver;
389  const char *sSerialNumber = NULL, *sInterfaceName = NULL;
390  const char *sInterfaceNumber;
391  LONG ret;
392  int bInterfaceNumber;
393  const char *devpath;
394  struct udev_device *parent;
395  const char *sysname;
396 
397  /* The device pointed to by dev contains information about
398  the interface. In order to get information about the USB
399  device, get the parent device with the subsystem/devtype pair
400  of "usb"/"usb_device". This will be several levels up the
401  tree, but the function will find it.*/
402  parent = udev_device_get_parent_with_subsystem_devtype(dev, "usb",
403  "usb_device");
404  if (!parent)
405  return;
406 
407  devpath = udev_device_get_devnode(parent);
408  if (!devpath)
409  {
410  /* the device disapeared? */
411  Log1(PCSC_LOG_ERROR, "udev_device_get_devnode() failed");
412  return;
413  }
414 
415  driver = get_driver(parent, devpath, &classdriver);
416  if (NULL == driver)
417  {
418  /* not a smart card reader */
419 #ifdef DEBUG_HOTPLUG
420  Log2(PCSC_LOG_DEBUG, "%s is not a supported smart card reader",
421  devpath);
422 #endif
423  return;
424  }
425 
426  sysname = udev_device_get_sysname(dev);
427  if (!sysname)
428  {
429  Log1(PCSC_LOG_ERROR, "udev_device_get_sysname() failed");
430  return;
431  }
432 
433  /* check for duplicated add */
434  for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
435  {
436  if (readerTracker[index].fullName && !strcmp(sysname, readerTracker[index].sysname))
437  return;
438  }
439 
440  Log2(PCSC_LOG_INFO, "Adding USB device: %s", driver->readerName);
441 
442  sInterfaceNumber = udev_device_get_sysattr_value(dev, "bInterfaceNumber");
443  if (sInterfaceNumber)
444  bInterfaceNumber = atoi(sInterfaceNumber);
445  else
446  bInterfaceNumber = 0;
447 
448  a = asprintf(&deviceName, "usb:%04x/%04x:libudev:%d:%s",
449  driver->manuID, driver->productID, bInterfaceNumber, devpath);
450  if (-1 == a)
451  {
452  Log1(PCSC_LOG_ERROR, "asprintf() failed");
453  return;
454  }
455 
456  /* find a free entry */
457  for (index=0; index<PCSCLITE_MAX_READERS_CONTEXTS; index++)
458  {
459  if (NULL == readerTracker[index].fullName)
460  break;
461  }
462 
463  if (PCSCLITE_MAX_READERS_CONTEXTS == index)
464  {
465  Log2(PCSC_LOG_ERROR,
466  "Not enough reader entries. Already found %d readers", index);
467  return;
468  }
469 
470  if (Add_Interface_In_Name)
471  sInterfaceName = udev_device_get_sysattr_value(dev, "interface");
472 
473  if (Add_Serial_In_Name)
474  sSerialNumber = udev_device_get_sysattr_value(parent, "serial");
475 
476  /* name from the Info.plist file */
477  fullname = strdup(driver->readerName);
478 
479  /* interface name from the device (if any) */
480  if (sInterfaceName)
481  {
482  char *result;
483 
484  /* create a new name */
485  a = asprintf(&result, "%s [%s]", fullname, sInterfaceName);
486  if (-1 == a)
487  {
488  Log1(PCSC_LOG_ERROR, "asprintf() failed");
489  goto exit;
490  }
491 
492  free(fullname);
493  fullname = result;
494  }
495 
496  /* serial number from the device (if any) */
497  if (sSerialNumber)
498  {
499  /* only add the serial number if it is not already present in the
500  * interface name */
501  if (!sInterfaceName || NULL == strstr(sInterfaceName, sSerialNumber))
502  {
503  char *result;
504 
505  /* create a new name */
506  a = asprintf(&result, "%s (%s)", fullname, sSerialNumber);
507  if (-1 == a)
508  {
509  Log1(PCSC_LOG_ERROR, "asprintf() failed");
510  goto exit;
511  }
512 
513  free(fullname);
514  fullname = result;
515  }
516  }
517 
518  readerTracker[index].fullName = strdup(fullname);
519  readerTracker[index].devpath = strdup(devpath);
520  readerTracker[index].sysname = strdup(sysname);
521 
522  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
523  driver->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 
529  if (classdriver && driver != classdriver)
530  {
531  /* the reader can also be used by the a class driver */
532  ret = RFAddReader(fullname, PCSCLITE_HP_BASE_PORT + index,
533  classdriver->libraryPath, deviceName);
534  if ((SCARD_S_SUCCESS != ret) && (SCARD_E_UNKNOWN_READER != ret))
535  {
536  Log2(PCSC_LOG_ERROR, "Failed adding USB device: %s",
537  driver->readerName);
538  (void)CheckForOpenCT();
539  }
540  }
541  else
542  {
543  (void)CheckForOpenCT();
544  }
545  }
546 
547  if (SCARD_S_SUCCESS != ret)
548  {
549  /* adding the reader failed */
550  free(readerTracker[index].devpath);
551  readerTracker[index].devpath = NULL;
552  free(readerTracker[index].fullName);
553  readerTracker[index].fullName = NULL;
554  free(readerTracker[index].sysname);
555  readerTracker[index].sysname = NULL;
556  }
557 
558 exit:
559  free(fullname);
560  free(deviceName);
561 } /* HPAddDevice */
562 
563 
564 static void HPScanUSB(struct udev *udev)
565 {
566  struct udev_enumerate *enumerate;
567  struct udev_list_entry *devices, *dev_list_entry;
568 
569  /* Create a list of the devices in the 'usb' subsystem. */
570  enumerate = udev_enumerate_new(udev);
571  udev_enumerate_add_match_subsystem(enumerate, "usb");
572  udev_enumerate_scan_devices(enumerate);
573  devices = udev_enumerate_get_list_entry(enumerate);
574 
575  /* For each item enumerated */
576  udev_list_entry_foreach(dev_list_entry, devices)
577  {
578  struct udev_device *dev;
579  const char *devpath;
580 
581  /* Get the filename of the /sys entry for the device
582  and create a udev_device object (dev) representing it */
583  devpath = udev_list_entry_get_name(dev_list_entry);
584  dev = udev_device_new_from_syspath(udev, devpath);
585 
586 #ifdef DEBUG_HOTPLUG
587  Log2(PCSC_LOG_DEBUG, "Found matching USB device: %s", devpath);
588 #endif
589  HPAddDevice(dev);
590 
591  /* free device */
592  udev_device_unref(dev);
593  }
594 
595  /* Free the enumerator object */
596  udev_enumerate_unref(enumerate);
597 }
598 
599 
600 static void * HPEstablishUSBNotifications(void *arg)
601 {
602  struct udev_monitor *udev_monitor = arg;
603  int r;
604  int fd;
605  struct pollfd pfd;
606 
607  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
608  pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
609 
610  /* udev monitor file descriptor */
611  fd = udev_monitor_get_fd(udev_monitor);
612  if (fd < 0)
613  {
614  Log2(PCSC_LOG_ERROR, "udev_monitor_get_fd() error: %d", fd);
615  pthread_exit(NULL);
616  }
617 
618  pfd.fd = fd;
619  pfd.events = POLLIN;
620 
621  for (;;)
622  {
623  struct udev_device *dev;
624 
625 #ifdef DEBUG_HOTPLUG
626  Log0(PCSC_LOG_INFO);
627 #endif
628  pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
629 
630  /* wait for a udev event */
631  r = TEMP_FAILURE_RETRY(poll(&pfd, 1, -1));
632  if (r < 0)
633  {
634  Log2(PCSC_LOG_ERROR, "select(): %s", strerror(errno));
635  pthread_exit(NULL);
636  }
637 
638  pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
639 
640  dev = udev_monitor_receive_device(udev_monitor);
641  if (dev)
642  {
643  const char *action = udev_device_get_action(dev);
644 
645  if (action)
646  {
647  if (!strcmp("remove", action))
648  {
649  Log1(PCSC_LOG_INFO, "USB Device removed");
650  HPRemoveDevice(dev);
651  }
652  else
653  if (!strcmp("add", action))
654  {
655  Log1(PCSC_LOG_INFO, "USB Device add");
656  HPAddDevice(dev);
657  }
658  }
659 
660  /* free device */
661  udev_device_unref(dev);
662  }
663  }
664 
665  pthread_exit(NULL);
666 } /* HPEstablishUSBNotifications */
667 
668 
669 /***
670  * Start a thread waiting for hotplug events
671  */
672 LONG HPSearchHotPluggables(void)
673 {
674  int i;
675 
676  for (i=0; i<PCSCLITE_MAX_READERS_CONTEXTS; i++)
677  {
678  readerTracker[i].devpath = NULL;
679  readerTracker[i].fullName = NULL;
680  readerTracker[i].sysname = NULL;
681  }
682 
683  return HPReadBundleValues();
684 } /* HPSearchHotPluggables */
685 
686 
690 LONG HPStopHotPluggables(void)
691 {
692  int i;
693 
694  if (driverSize <= 0)
695  return 0;
696 
697  if (!Udev)
698  return 0;
699 
700  pthread_cancel(usbNotifyThread);
701  pthread_join(usbNotifyThread, NULL);
702 
703  for (i=0; i<driverSize; i++)
704  {
705  /* free strings allocated by strdup() */
706  free(driverTracker[i].bundleName);
707  free(driverTracker[i].libraryPath);
708  free(driverTracker[i].readerName);
709  }
710  free(driverTracker);
711 
712  udev_unref(Udev);
713 
714  Udev = NULL;
715  driverSize = -1;
716 
717  Log1(PCSC_LOG_INFO, "Hotplug stopped");
718  return 0;
719 } /* HPStopHotPluggables */
720 
721 
725 ULONG HPRegisterForHotplugEvents(void)
726 {
727  struct udev_monitor *udev_monitor;
728  int r;
729 
730  if (driverSize <= 0)
731  {
732  Log1(PCSC_LOG_INFO, "No bundle files in pcsc drivers directory: "
733  PCSCLITE_HP_DROPDIR);
734  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
735  return 0;
736  }
737 
738  /* Create the udev object */
739  Udev = udev_new();
740  if (!Udev)
741  {
742  Log1(PCSC_LOG_ERROR, "udev_new() failed");
743  return SCARD_F_INTERNAL_ERROR;
744  }
745 
746  udev_monitor = udev_monitor_new_from_netlink(Udev, "udev");
747  if (NULL == udev_monitor)
748  {
749  Log1(PCSC_LOG_ERROR, "udev_monitor_new_from_netlink() error");
750  pthread_exit(NULL);
751  }
752 
753  /* filter only the interfaces */
754  r = udev_monitor_filter_add_match_subsystem_devtype(udev_monitor, "usb",
755  "usb_interface");
756  if (r)
757  {
758  Log2(PCSC_LOG_ERROR, "udev_monitor_filter_add_match_subsystem_devtype() error: %d\n", r);
759  pthread_exit(NULL);
760  }
761 
762  r = udev_monitor_enable_receiving(udev_monitor);
763  if (r)
764  {
765  Log2(PCSC_LOG_ERROR, "udev_monitor_enable_receiving() error: %d\n", r);
766  pthread_exit(NULL);
767  }
768 
769  /* scan the USB bus at least once before accepting client connections */
770  HPScanUSB(Udev);
771 
772  if (ThreadCreate(&usbNotifyThread, 0,
773  (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, udev_monitor))
774  {
775  Log1(PCSC_LOG_ERROR, "ThreadCreate() failed");
776  return SCARD_F_INTERNAL_ERROR;
777  }
778 
779  return 0;
780 } /* HPRegisterForHotplugEvents */
781 
782 
783 void HPReCheckSerialReaders(void)
784 {
785  /* nothing to do here */
786 #ifdef DEBUG_HOTPLUG
787  Log0(PCSC_LOG_ERROR);
788 #endif
789 } /* HPReCheckSerialReaders */
790 
791 #endif
792 
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:284
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.