pcsc-lite  1.8.8
hotplug_linux.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
3  *
4  * Copyright (C) 2001-2003
5  * David Corcoran <corcoran@linuxnet.com>
6  * Copyright (C) 2002-2011
7  * Ludovic Rousseau <ludovic.rousseau@free.fr>
8  *
9  * The USB code was based partly on Johannes Erdfelt
10  * libusb code found at libusb.sourceforge.net
11  *
12  * $Id: hotplug_linux.c 5993 2011-10-04 07:51:33Z rousseau $
13  */
14 
20 #include "config.h"
21 #include <string.h>
22 
23 #if defined(__linux__) && !defined(HAVE_LIBUSB) && !defined(HAVE_LIBUDEV)
24 #include <sys/types.h>
25 #include <stdio.h>
26 #include <dirent.h>
27 #include <fcntl.h>
28 #include <time.h>
29 #include <stdlib.h>
30 #include <unistd.h>
31 #include <pthread.h>
32 
33 #include "misc.h"
34 #include "pcsclite.h"
35 #include "pcscd.h"
36 #include "debuglog.h"
37 #include "parser.h"
38 #include "readerfactory.h"
39 #include "winscard_msg.h"
40 #include "sys_generic.h"
41 #include "hotplug.h"
42 #include "utils.h"
43 
44 #undef DEBUG_HOTPLUG
45 #define PCSCLITE_USB_PATH "/proc/bus/usb"
46 
47 #define FALSE 0
48 #define TRUE 1
49 
50 pthread_mutex_t usbNotifierMutex;
51 
52 struct usb_device_descriptor
53 {
54  u_int8_t bLength;
55  u_int8_t bDescriptorType;
56  u_int16_t bcdUSB;
57  u_int8_t bDeviceClass;
58  u_int8_t bDeviceSubClass;
59  u_int8_t bDeviceProtocol;
60  u_int8_t bMaxPacketSize0;
61  u_int16_t idVendor;
62  u_int16_t idProduct;
63  u_int16_t bcdDevice;
64  u_int8_t iManufacturer;
65  u_int8_t iProduct;
66  u_int8_t iSerialNumber;
67  u_int8_t bNumConfigurations;
68 }
69 __attribute__ ((packed));
70 
71 static LONG HPAddHotPluggable(int, unsigned long);
72 static LONG HPRemoveHotPluggable(int, unsigned long);
73 static LONG HPReadBundleValues(void);
74 static void HPEstablishUSBNotifications(void);
75 
76 static pthread_t usbNotifyThread;
77 static int AraKiriHotPlug = FALSE;
78 static int bundleSize = 0;
79 
83 static struct _bundleTracker
84 {
85  long manuID;
86  long productID;
87 
88  struct _deviceNumber {
89  int id;
90  char status;
91  } deviceNumber[PCSCLITE_MAX_READERS_CONTEXTS];
92 
93  char *bundleName;
94  char *libraryPath;
95  char *readerName;
96 }
97 bundleTracker[PCSCLITE_MAX_READERS_CONTEXTS];
98 
99 static LONG HPReadBundleValues(void)
100 {
101  LONG rv;
102  DIR *hpDir;
103  struct dirent *currFP = 0;
104  char fullPath[FILENAME_MAX];
105  char fullLibPath[FILENAME_MAX];
106  unsigned int listCount = 0;
107 
108  hpDir = opendir(PCSCLITE_HP_DROPDIR);
109 
110  if (hpDir == NULL)
111  {
112  Log1(PCSC_LOG_INFO,
113  "Cannot open PC/SC drivers directory: " PCSCLITE_HP_DROPDIR);
114  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd.");
115  return -1;
116  }
117 
118 #define GET_KEY(key, values) \
119  rv = LTPBundleFindValueWithKey(&plist, key, values); \
120  if (rv) \
121  { \
122  Log2(PCSC_LOG_ERROR, "Value/Key not defined for " key " in %s", \
123  fullPath); \
124  continue; \
125  }
126 
127  while ((currFP = readdir(hpDir)) != 0)
128  {
129  if (strstr(currFP->d_name, ".bundle") != 0)
130  {
131  unsigned int alias;
132  list_t plist, *values;
133  list_t *manuIDs, *productIDs, *readerNames;
134  char *libraryPath;
135 
136  /*
137  * The bundle exists - let's form a full path name and get the
138  * vendor and product ID's for this particular bundle
139  */
140  snprintf(fullPath, FILENAME_MAX, "%s/%s/Contents/Info.plist",
141  PCSCLITE_HP_DROPDIR, currFP->d_name);
142  fullPath[FILENAME_MAX - 1] = '\0';
143 
144  rv = bundleParse(fullPath, &plist);
145  if (rv)
146  continue;
147 
148  /* get CFBundleExecutable */
149  GET_KEY(PCSCLITE_HP_LIBRKEY_NAME, &values)
150  libraryPath = list_get_at(values, 0);
151  (void)snprintf(fullLibPath, sizeof(fullLibPath),
152  "%s/%s/Contents/%s/%s",
153  PCSCLITE_HP_DROPDIR, currFP->d_name, PCSC_ARCH,
154  libraryPath);
155  fullLibPath[sizeof(fullLibPath) - 1] = '\0';
156 
157  GET_KEY(PCSCLITE_HP_CPCTKEY_NAME, &values)
158  GET_KEY(PCSCLITE_HP_MANUKEY_NAME, &manuIDs)
159  GET_KEY(PCSCLITE_HP_PRODKEY_NAME, &productIDs)
160  GET_KEY(PCSCLITE_HP_NAMEKEY_NAME, &readerNames)
161 
162  /* while we find a nth ifdVendorID in Info.plist */
163  for (alias=0; alias<list_size(manuIDs); alias++)
164  {
165  char *value;
166 
167  /* variables entries */
168  value = list_get_at(manuIDs, alias);
169  bundleTracker[listCount].manuID = strtol(value, NULL, 16);
170 
171  value = list_get_at(productIDs, alias);
172  bundleTracker[listCount].productID = strtol(value, NULL, 16);
173 
174  bundleTracker[listCount].readerName = strdup(list_get_at(readerNames, alias));
175 
176  /* constant entries for a same driver */
177  bundleTracker[listCount].bundleName = strdup(currFP->d_name);
178  bundleTracker[listCount].libraryPath = strdup(fullLibPath);
179 
180 #ifdef DEBUG_HOTPLUG
181  Log2(PCSC_LOG_INFO, "Found driver for: %s",
182  bundleTracker[listCount].readerName);
183 #endif
184  listCount++;
185 
186  if (listCount >= sizeof(bundleTracker)/sizeof(bundleTracker[0]))
187  {
188  Log2(PCSC_LOG_CRITICAL, "Too many readers declared. Maximum is %zd", sizeof(bundleTracker)/sizeof(bundleTracker[0]));
189  goto end;
190  }
191  }
192  bundleRelease(&plist);
193  }
194  }
195 
196 end:
197  bundleSize = listCount;
198 
199  if (bundleSize == 0)
200  {
201  Log1(PCSC_LOG_INFO,
202  "No bundle files in pcsc drivers directory: " PCSCLITE_HP_DROPDIR);
203  Log1(PCSC_LOG_INFO, "Disabling USB support for pcscd");
204  }
205 
206  closedir(hpDir);
207  return 0;
208 }
209 
210 static void HPEstablishUSBNotifications(void)
211 {
212 
213  int i, j, usbDeviceStatus;
214  DIR *dir, *dirB;
215  struct dirent *entry, *entryB;
216  int deviceNumber;
217  int suspectDeviceNumber;
218  char dirpath[FILENAME_MAX];
219  char filename[FILENAME_MAX];
220  int fd, ret;
221  struct usb_device_descriptor usbDescriptor;
222 
223  usbDeviceStatus = 0;
224  suspectDeviceNumber = 0;
225 
226  while (1)
227  {
228  for (i = 0; i < bundleSize; i++)
229  {
230  usbDeviceStatus = 0;
231  suspectDeviceNumber = 0;
232 
233  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
234  /* clear rollcall */
235  bundleTracker[i].deviceNumber[j].status = 0;
236 
237  dir = NULL;
238  dir = opendir(PCSCLITE_USB_PATH);
239  if (dir == NULL)
240  {
241  Log1(PCSC_LOG_ERROR,
242  "Cannot open USB path directory: " PCSCLITE_USB_PATH);
243  return;
244  }
245 
246  entry = NULL;
247  while ((entry = readdir(dir)) != 0)
248  {
249 
250  /*
251  * Skip anything starting with a
252  */
253  if (entry->d_name[0] == '.')
254  continue;
255  if (!strchr("0123456789",
256  entry->d_name[strlen(entry->d_name) - 1]))
257  {
258  continue;
259  }
260 
261  snprintf(dirpath, sizeof dirpath, "%s/%s",
262  PCSCLITE_USB_PATH, entry->d_name);
263 
264  dirB = opendir(dirpath);
265 
266  if (dirB == NULL)
267  {
268  Log2(PCSC_LOG_ERROR,
269  "USB path seems to have disappeared %s", dirpath);
270  closedir(dir);
271  return;
272  }
273 
274  while ((entryB = readdir(dirB)) != NULL)
275  {
276  /*
277  * Skip anything starting with a
278  */
279  if (entryB->d_name[0] == '.')
280  continue;
281 
282  /* Get the device number so we can distinguish
283  multiple readers */
284  snprintf(filename, sizeof filename, "%s/%s",
285  dirpath, entryB->d_name);
286  deviceNumber = atoi(entryB->d_name);
287 
288  fd = open(filename, O_RDONLY);
289  if (fd < 0)
290  continue;
291 
292  ret = read(fd, (void *) &usbDescriptor,
293  sizeof(usbDescriptor));
294 
295  close(fd);
296 
297  if (ret < 0)
298  continue;
299 
300  /*
301  * Device is found and we don't know about it
302  */
303 
304  if (usbDescriptor.idVendor == bundleTracker[i].manuID &&
305  usbDescriptor.idProduct == bundleTracker[i].productID &&
306  usbDescriptor.idVendor !=0 &&
307  usbDescriptor.idProduct != 0)
308  {
309  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
310  {
311  if (bundleTracker[i].deviceNumber[j].id == deviceNumber &&
312  bundleTracker[i].deviceNumber[j].id != 0)
313  {
314  bundleTracker[i].deviceNumber[j].status = 1; /* i'm here */
315  break;
316  }
317  }
318 
319  if (j == PCSCLITE_MAX_READERS_CONTEXTS)
320  {
321  usbDeviceStatus = 1;
322  suspectDeviceNumber = deviceNumber;
323  }
324  }
325 
326  } /* End of while */
327 
328  closedir(dirB);
329 
330  } /* End of while */
331 
332 
333  if (usbDeviceStatus == 1)
334  {
335  pthread_mutex_lock(&usbNotifierMutex);
336 
337  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
338  {
339  if (bundleTracker[i].deviceNumber[j].id == 0)
340  break;
341  }
342 
343  if (j == PCSCLITE_MAX_READERS_CONTEXTS)
344  Log1(PCSC_LOG_ERROR,
345  "Too many identical readers plugged in");
346  else
347  {
348  HPAddHotPluggable(i, j+1);
349  bundleTracker[i].deviceNumber[j].id = suspectDeviceNumber;
350  }
351 
352  pthread_mutex_unlock(&usbNotifierMutex);
353  }
354  else
355  if (usbDeviceStatus == 0)
356  {
357 
358  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
359  {
360  if (bundleTracker[i].deviceNumber[j].id != 0 &&
361  bundleTracker[i].deviceNumber[j].status == 0)
362  {
363  pthread_mutex_lock(&usbNotifierMutex);
364  HPRemoveHotPluggable(i, j+1);
365  bundleTracker[i].deviceNumber[j].id = 0;
366  pthread_mutex_unlock(&usbNotifierMutex);
367  }
368  }
369  }
370  else
371  {
372  /*
373  * Do nothing - no USB devices found
374  */
375  }
376 
377  if (dir)
378  closedir(dir);
379 
380  } /* End of for..loop */
381 
382  SYS_Sleep(1);
383  if (AraKiriHotPlug)
384  {
385  int retval;
386 
387  Log1(PCSC_LOG_INFO, "Hotplug stopped");
388  pthread_exit(&retval);
389  }
390 
391  } /* End of while loop */
392 }
393 
394 LONG HPSearchHotPluggables(void)
395 {
396  int i, j;
397 
398  for (i = 0; i < PCSCLITE_MAX_READERS_CONTEXTS; i++)
399  {
400  bundleTracker[i].productID = 0;
401  bundleTracker[i].manuID = 0;
402 
403  for (j=0; j < PCSCLITE_MAX_READERS_CONTEXTS; j++)
404  bundleTracker[i].deviceNumber[j].id = 0;
405  }
406 
407  HPReadBundleValues();
408 
409  ThreadCreate(&usbNotifyThread, THREAD_ATTR_DETACHED,
410  (PCSCLITE_THREAD_FUNCTION( )) HPEstablishUSBNotifications, 0);
411 
412  return 0;
413 }
414 
415 LONG HPStopHotPluggables(void)
416 {
417  AraKiriHotPlug = TRUE;
418 
419  return 0;
420 }
421 
422 static LONG HPAddHotPluggable(int i, unsigned long usbAddr)
423 {
424  /* NOTE: The deviceName is an empty string "" until someone implements
425  * the code to get it */
426  RFAddReader(bundleTracker[i].readerName, PCSCLITE_HP_BASE_PORT + usbAddr,
427  bundleTracker[i].libraryPath, "");
428 
429  return 1;
430 } /* End of function */
431 
432 static LONG HPRemoveHotPluggable(int i, unsigned long usbAddr)
433 {
434  RFRemoveReader(bundleTracker[i].readerName, PCSCLITE_HP_BASE_PORT + usbAddr);
435 
436  return 1;
437 } /* End of function */
438 
442 ULONG HPRegisterForHotplugEvents(void)
443 {
444  (void)pthread_mutex_init(&usbNotifierMutex, NULL);
445  return 0;
446 }
447 
448 void HPReCheckSerialReaders(void)
449 {
450 }
451 
452 #endif /* __linux__ && !HAVE_LIBUSB */
list object
Definition: simclist.h:181
This handles abstract system level calls.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:44
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:195
This defines some structures and #defines to be used over the transport layer.
This keeps a list of defines for pcsc-lite.
This keeps a list of defines for pcsc-lite.
This keeps track of a list of currently available reader structures.
This provides a search API for hot pluggble devices.
int bundleParse(const char *fileName, list_t *l)
Parse a Info.plist file and file a list.
Definition: tokenparser.c:1936
void bundleRelease(list_t *l)
Free the list created by bundleParse()
Definition: tokenparser.c:1993
This handles debugging.