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