pcsc-lite  1.8.8
pcscdaemon.c
Go to the documentation of this file.
1 /*
2  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
3  *
4  * Copyright (C) 1999-2002
5  * David Corcoran <corcoran@linuxnet.com>
6  * Copyright (C) 2002-2011
7  * Ludovic Rousseau <ludovic.rousseau@free.fr>
8  *
9  * $Id: pcscdaemon.c 6446 2012-08-24 09:07:18Z rousseau $
10  */
11 
21 #include "config.h"
22 #include <time.h>
23 #include <signal.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26 #include <fcntl.h>
27 #include <errno.h>
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #ifdef HAVE_GETOPT_H
33 #include <getopt.h>
34 #endif
35 
36 #include "misc.h"
37 #include "pcsclite.h"
38 #include "pcscd.h"
39 #include "debuglog.h"
40 #include "sd-daemon.h"
41 #include "winscard_msg.h"
42 #include "winscard_svc.h"
43 #include "sys_generic.h"
44 #include "hotplug.h"
45 #include "readerfactory.h"
46 #include "configfile.h"
47 #include "powermgt_generic.h"
48 #include "utils.h"
49 
50 #ifndef TRUE
51 #define TRUE 1
52 #define FALSE 0
53 #endif
54 
55 char AraKiri = FALSE;
56 static char Init = TRUE;
57 char AutoExit = FALSE;
58 char SocketActivated = FALSE;
59 static int ExitValue = EXIT_FAILURE;
60 int HPForceReaderPolling = 0;
61 static int pipefd[] = {-1, -1};
62 
63 /*
64  * Some internal functions
65  */
66 static void at_exit(void);
67 static void clean_temp_files(void);
68 static void signal_reload(int sig);
69 static void signal_trap(int);
70 static void print_version (void);
71 static void print_usage (char const * const);
72 
81 static void SVCServiceRunLoop(void)
82 {
83  int rsp;
84  LONG rv;
85  uint32_t dwClientID; /* Connection ID used to reference the Client */
86 
87  while (TRUE)
88  {
89  switch (rsp = ProcessEventsServer(&dwClientID))
90  {
91 
92  case 0:
93  Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
94  rv = CreateContextThread(&dwClientID);
95 
96  if (rv != SCARD_S_SUCCESS)
97  Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
98  break;
99 
100  case 2:
101  /*
102  * timeout in ProcessEventsServer(): do nothing
103  * this is used to catch the Ctrl-C signal at some time when
104  * nothing else happens
105  */
106  break;
107 
108  case -1:
109  Log1(PCSC_LOG_ERROR, "Error in ProcessEventsServer");
110  break;
111 
112  case -2:
113  /* Nothing to do in case of a syscall interrupted
114  * It happens when SIGUSR1 (reload) or SIGINT (Ctrl-C) is received
115  * We just try again */
116  break;
117 
118  default:
119  Log2(PCSC_LOG_ERROR, "ProcessEventsServer unknown retval: %d",
120  rsp);
121  break;
122  }
123 
124  if (AraKiri)
125  {
126  /* stop the hotpug thread and waits its exit */
127 #ifdef USE_USB
128  (void)HPStopHotPluggables();
129 #endif
130  (void)SYS_Sleep(1);
131 
132  /* now stop all the drivers */
133  RFCleanupReaders();
134  ContextsDeinitialize();
135  at_exit();
136  }
137  }
138 }
139 
140 int main(int argc, char **argv)
141 {
142  int rv;
143  char setToForeground;
144  char HotPlug;
145  char *newReaderConfig;
146  struct stat fStatBuf;
147  int customMaxThreadCounter = 0;
148  int customMaxReaderHandles = 0;
149  int customMaxThreadCardHandles = 0;
150  int opt;
151  int limited_rights = FALSE;
152 #ifdef HAVE_GETOPT_LONG
153  int option_index = 0;
154  static struct option long_options[] = {
155  {"config", 1, NULL, 'c'},
156  {"foreground", 0, NULL, 'f'},
157  {"color", 0, NULL, 'T'},
158  {"help", 0, NULL, 'h'},
159  {"version", 0, NULL, 'v'},
160  {"apdu", 0, NULL, 'a'},
161  {"debug", 0, NULL, 'd'},
162  {"info", 0, NULL, 0},
163  {"error", 0, NULL, 'e'},
164  {"critical", 0, NULL, 'C'},
165  {"hotplug", 0, NULL, 'H'},
166  {"force-reader-polling", optional_argument, NULL, 0},
167  {"max-thread", 1, NULL, 't'},
168  {"max-card-handle-per-thread", 1, NULL, 's'},
169  {"max-card-handle-per-reader", 1, NULL, 'r'},
170  {"auto-exit", 0, NULL, 'x'},
171  {NULL, 0, NULL, 0}
172  };
173 #endif
174 #define OPT_STRING "c:fTdhvaeCHt:r:s:x"
175 
176  newReaderConfig = NULL;
177  setToForeground = FALSE;
178  HotPlug = FALSE;
179 
180  /*
181  * test the version
182  */
183  if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
184  {
185  printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
186  printf(" in pcsclite.h (%s) does not match the release version number\n",
188  printf(" generated in config.h (%s) (see configure.in).\n", VERSION);
189 
190  return EXIT_FAILURE;
191  }
192 
193  /*
194  * By default we create a daemon (not connected to any output)
195  * so log to syslog to have error messages.
196  */
197  DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
198 
199  /* if the process is setuid or setgid it may have some restrictions */
200  limited_rights = (getgid() != getegid()) && (getuid() != 0);
201 
202  /*
203  * Handle any command line arguments
204  */
205 #ifdef HAVE_GETOPT_LONG
206  while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
207 #else
208  while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
209 #endif
210  switch (opt) {
211 #ifdef HAVE_GETOPT_LONG
212  case 0:
213  if (strcmp(long_options[option_index].name,
214  "force-reader-polling") == 0)
215  HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
216  break;
217 #endif
218  case 'c':
219  if (limited_rights)
220  {
221  Log1(PCSC_LOG_CRITICAL, "Can't use a user specified config file");
222  return EXIT_FAILURE;
223  }
224  Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
225  newReaderConfig = optarg;
226  break;
227 
228  case 'f':
229  setToForeground = TRUE;
230  /* debug to stdout instead of default syslog */
231  DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
232  Log1(PCSC_LOG_INFO,
233  "pcscd set to foreground with debug send to stdout");
234  break;
235 
236  case 'T':
237  DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
238  Log1(PCSC_LOG_INFO, "Force colored logs");
239  break;
240 
241  case 'd':
242  DebugLogSetLevel(PCSC_LOG_DEBUG);
243  break;
244 
245  case 'e':
246  DebugLogSetLevel(PCSC_LOG_ERROR);
247  break;
248 
249  case 'C':
250  DebugLogSetLevel(PCSC_LOG_CRITICAL);
251  break;
252 
253  case 'h':
254  print_usage (argv[0]);
255  return EXIT_SUCCESS;
256 
257  case 'v':
258  print_version ();
259  return EXIT_SUCCESS;
260 
261  case 'a':
262  if (limited_rights)
263  {
264  Log1(PCSC_LOG_CRITICAL, "Can't log APDU (restricted)");
265  return EXIT_FAILURE;
266  }
267  (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
268  break;
269 
270  case 'H':
271  /* debug to stdout instead of default syslog */
272  DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
273  HotPlug = TRUE;
274  break;
275 
276  case 't':
277  customMaxThreadCounter = optarg ? atoi(optarg) : 0;
278  if (limited_rights && (customMaxThreadCounter < PCSC_MAX_CONTEXT_THREADS))
279  customMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
280  Log2(PCSC_LOG_INFO, "setting customMaxThreadCounter to: %d",
281  customMaxThreadCounter);
282  break;
283 
284  case 'r':
285  customMaxReaderHandles = optarg ? atoi(optarg) : 0;
286  if (limited_rights && (customMaxReaderHandles < PCSC_MAX_READER_HANDLES))
287  customMaxReaderHandles = PCSC_MAX_READER_HANDLES;
288  Log2(PCSC_LOG_INFO, "setting customMaxReaderHandles to: %d",
289  customMaxReaderHandles);
290  break;
291 
292  case 's':
293  customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
294  if (limited_rights && (customMaxThreadCardHandles < PCSC_MAX_CONTEXT_CARD_HANDLES))
295  customMaxThreadCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
296  Log2(PCSC_LOG_INFO, "setting customMaxThreadCardHandles to: %d",
297  customMaxThreadCardHandles);
298  break;
299 
300  case 'x':
301  AutoExit = TRUE;
302  Log2(PCSC_LOG_INFO, "Auto exit after %d seconds of inactivity",
303  TIME_BEFORE_SUICIDE);
304  break;
305 
306  default:
307  print_usage (argv[0]);
308  return EXIT_FAILURE;
309  }
310 
311  }
312 
313  if (argv[optind])
314  {
315  printf("Unknown option: %s\n", argv[optind]);
316  print_usage(argv[0]);
317  return EXIT_FAILURE;
318  }
319 
320  /*
321  * Check if systemd passed us any file descriptors
322  */
323  rv = sd_listen_fds(0);
324  if (rv > 1)
325  {
326  Log1(PCSC_LOG_CRITICAL, "Too many file descriptors received");
327  return EXIT_FAILURE;
328  }
329  else
330  {
331  if (rv == 1)
332  {
333  SocketActivated = TRUE;
334  Log1(PCSC_LOG_INFO, "Started by systemd");
335  }
336  else
337  SocketActivated = FALSE;
338  }
339 
340  /*
341  * test the presence of /var/run/pcscd/pcscd.comm
342  */
343 
344  rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
345 
346  if (rv == 0)
347  {
348  pid_t pid;
349 
350  /* read the pid file to get the old pid and test if the old pcscd is
351  * still running
352  */
353  pid = GetDaemonPid();
354 
355  if (pid != -1)
356  {
357  if (HotPlug)
358  return SendHotplugSignal();
359 
360  rv = kill(pid, 0);
361  if (0 == rv)
362  {
363  Log1(PCSC_LOG_CRITICAL,
364  "file " PCSCLITE_CSOCK_NAME " already exists.");
365  Log2(PCSC_LOG_CRITICAL,
366  "Another pcscd (pid: %d) seems to be running.", pid);
367  return EXIT_FAILURE;
368  }
369  else
370  if (ESRCH == errno)
371  {
372  /* the old pcscd is dead. make some cleanup */
373  clean_temp_files();
374  }
375  else
376  {
377  /* permission denied or other error */
378  Log2(PCSC_LOG_CRITICAL, "kill failed: %s", strerror(errno));
379  return EXIT_FAILURE;
380  }
381  }
382  else
383  {
384  if (HotPlug)
385  {
386  Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist");
387  Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
388  return EXIT_FAILURE;
389  }
390  }
391  }
392  else
393  if (HotPlug)
394  {
395  Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running");
396  return EXIT_FAILURE;
397  }
398 
399  /* like in daemon(3): changes the current working directory to the
400  * root ("/") */
401  (void)chdir("/");
402 
403  /*
404  * If this is set to one the user has asked it not to fork
405  */
406  if (!setToForeground)
407  {
408  int pid;
409  int fd;
410 
411  if (pipe(pipefd) == -1)
412  {
413  Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
414  return EXIT_FAILURE;
415  }
416 
417  pid = fork();
418  if (-1 == pid)
419  {
420  Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
421  return EXIT_FAILURE;
422  }
423 
424  /* like in daemon(3): redirect standard input, standard output
425  * and standard error to /dev/null */
426  fd = open("/dev/null", O_RDWR);
427  if (fd != -1)
428  {
429  dup2(fd, STDIN_FILENO);
430  dup2(fd, STDOUT_FILENO);
431  dup2(fd, STDERR_FILENO);
432 
433  /* do not close stdin, stdout or stderr */
434  if (fd > 2)
435  close(fd);
436  }
437 
438  if (pid)
439  /* in the father */
440  {
441  char buf;
442  int ret;
443 
444  /* close write side */
445  close(pipefd[1]);
446 
447  /* wait for the son to write the return code */
448  ret = read(pipefd[0], &buf, 1);
449  if (ret <= 0)
450  return 2;
451 
452  close(pipefd[0]);
453 
454  /* exit code */
455  return buf;
456  }
457  else
458  /* in the son */
459  {
460  /* close read side */
461  close(pipefd[0]);
462  }
463  }
464 
465  /*
466  * cleanly remove /var/run/pcscd/files when exiting
467  * signal_trap() does just set a global variable used by the main loop
468  */
469  (void)signal(SIGQUIT, signal_trap);
470  (void)signal(SIGTERM, signal_trap); /* default kill signal & init round 1 */
471  (void)signal(SIGINT, signal_trap); /* sent by Ctrl-C */
472 
473  /* exits on SIGALARM to allow pcscd to suicide if not used */
474  (void)signal(SIGALRM, signal_trap);
475 
476  /*
477  * If PCSCLITE_IPC_DIR does not exist then create it
478  */
479  {
480  int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
481 
482  rv = mkdir(PCSCLITE_IPC_DIR, mode);
483  if ((rv != 0) && (errno != EEXIST))
484  {
485  Log2(PCSC_LOG_CRITICAL,
486  "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
487  return EXIT_FAILURE;
488  }
489 
490  /* set mode so that the directory is world readable and
491  * executable even is umask is restrictive
492  * The directory containes files used by libpcsclite */
493  (void)chmod(PCSCLITE_IPC_DIR, mode);
494  }
495 
496  /*
497  * Allocate memory for reader structures
498  */
499  rv = RFAllocateReaderSpace(customMaxReaderHandles);
500  if (SCARD_S_SUCCESS != rv)
501  at_exit();
502 
503 #ifdef USE_SERIAL
504  /*
505  * Grab the information from the reader.conf
506  */
507  if (newReaderConfig)
508  {
509  rv = RFStartSerialReaders(newReaderConfig);
510  if (rv != 0)
511  {
512  Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
513  strerror(errno));
514  at_exit();
515  }
516  }
517  else
518  {
519  rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
520  if (rv == -1)
521  at_exit();
522  }
523 #endif
524 
525  Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
526 
527  /*
528  * Record our pid to make it easier
529  * to kill the correct pcscd
530  *
531  * Do not fork after this point or the stored pid will be wrong
532  */
533  {
534  int f;
535  int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
536 
537  f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
538  if (f != -1)
539  {
540  char pid[PID_ASCII_SIZE];
541 
542  (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid());
543  (void)write(f, pid, strlen(pid));
544  (void)close(f);
545 
546  /* set mode so that the file is world readable even is umask is
547  * restrictive
548  * The file is used by libpcsclite */
549  (void)chmod(PCSCLITE_RUN_PID, mode);
550  }
551  else
552  Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s",
553  strerror(errno));
554  }
555 
556  /*
557  * post initialistion
558  */
559  Init = FALSE;
560 
561  /*
562  * Hotplug rescan
563  */
564  (void)signal(SIGUSR1, signal_reload);
565 
566  /*
567  * Initialize the comm structure
568  */
569  if (SocketActivated)
570  rv = ListenExistingSocket(SD_LISTEN_FDS_START + 0);
571  else
572  rv = InitializeSocket();
573 
574  if (rv)
575  {
576  Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
577  at_exit();
578  }
579 
580  /*
581  * Initialize the contexts structure
582  */
583  rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
584 
585  if (rv == -1)
586  {
587  Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
588  at_exit();
589  }
590 
591  (void)signal(SIGPIPE, SIG_IGN);
592  (void)signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent
593  * when the shell is existed */
594 
595 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
596  /*
597  * Set up the search for USB/PCMCIA devices
598  */
599  rv = HPSearchHotPluggables();
600 #ifndef USE_SERIAL
601  if (rv)
602  at_exit();
603 #endif
604 
605  rv = HPRegisterForHotplugEvents();
606  if (rv)
607  {
608  Log1(PCSC_LOG_ERROR, "HPRegisterForHotplugEvents failed");
609  at_exit();
610  }
611 
612  RFWaitForReaderInit();
613 #endif
614 
615  /*
616  * Set up the power management callback routine
617  */
618  (void)PMRegisterForPowerEvents();
619 
620  /* initialisation succeeded */
621  if (pipefd[1] >= 0)
622  {
623  char buf = 0;
624 
625  /* write a 0 (success) to father process */
626  write(pipefd[1], &buf, 1);
627  close(pipefd[1]);
628  }
629 
631 
632  Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
633  return EXIT_FAILURE;
634 }
635 
636 static void at_exit(void)
637 {
638  Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
639 
640  clean_temp_files();
641 
642  if (pipefd[1] >= 0)
643  {
644  char buf;
645 
646  /* write the error code to father process */
647  buf = ExitValue;
648  write(pipefd[1], &buf, 1);
649  close(pipefd[1]);
650  }
651 
652  exit(ExitValue);
653 }
654 
655 static void clean_temp_files(void)
656 {
657  int rv;
658 
659  if (!SocketActivated)
660  {
661  rv = remove(PCSCLITE_CSOCK_NAME);
662  if (rv != 0)
663  Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
664  strerror(errno));
665  }
666 
667  rv = remove(PCSCLITE_RUN_PID);
668  if (rv != 0)
669  Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
670  strerror(errno));
671 }
672 
673 static void signal_reload(/*@unused@*/ int sig)
674 {
675  (void)signal(SIGUSR1, signal_reload);
676 
677  (void)sig;
678 
679  if (AraKiri)
680  return;
681 
682 #ifdef USE_USB
683  HPReCheckSerialReaders();
684 #endif
685 } /* signal_reload */
686 
687 static void signal_trap(int sig)
688 {
689  Log2(PCSC_LOG_INFO, "Received signal: %d", sig);
690 
691  /* do not wait if asked to terminate
692  * avoids waiting after the reader(s) in shutdown for example */
693  if (SIGTERM == sig)
694  {
695  Log1(PCSC_LOG_INFO, "Direct suicide");
696  at_exit();
697  }
698 
699  if (SIGALRM == sig)
700  {
701  /* normal exit without error */
702  ExitValue = EXIT_SUCCESS;
703  }
704 
705  /* the signal handler is called several times for the same Ctrl-C */
706  if (AraKiri == FALSE)
707  {
708  Log1(PCSC_LOG_INFO, "Preparing for suicide");
709  AraKiri = TRUE;
710 
711  /* if still in the init/loading phase the AraKiri will not be
712  * seen by the main event loop
713  */
714  if (Init)
715  {
716  Log1(PCSC_LOG_INFO, "Suicide during init");
717  at_exit();
718  }
719  }
720  else
721  {
722  /* if pcscd do not want to die */
723  static int lives = 2;
724 
725  lives--;
726  /* no live left. Something is blocking the normal death. */
727  if (0 == lives)
728  {
729  Log1(PCSC_LOG_INFO, "Forced suicide");
730  at_exit();
731  }
732  }
733 }
734 
735 static void print_version (void)
736 {
737  printf("%s version %s.\n", PACKAGE, VERSION);
738  printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
739  printf("Copyright (C) 2001-2011 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
740  printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
741  printf("Report bugs to <muscle@lists.musclecard.com>.\n");
742 
743  printf ("Enabled features:%s\n", PCSCLITE_FEATURES);
744 }
745 
746 static void print_usage (char const * const progname)
747 {
748  printf("Usage: %s options\n", progname);
749  printf("Options:\n");
750 #ifdef HAVE_GETOPT_LONG
751  printf(" -a, --apdu log APDU commands and results\n");
752  printf(" -c, --config path to reader.conf\n");
753  printf(" -f, --foreground run in foreground (no daemon),\n");
754  printf(" send logs to stdout instead of syslog\n");
755  printf(" -T, --color force use of colored logs\n");
756  printf(" -h, --help display usage information\n");
757  printf(" -H, --hotplug ask the daemon to rescan the available readers\n");
758  printf(" -v, --version display the program version number\n");
759  printf(" -d, --debug display lower level debug messages\n");
760  printf(" --info display info level debug messages\n");
761  printf(" -e --error display error level debug messages (default level)\n");
762  printf(" -C --critical display critical only level debug messages\n");
763  printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
764  printf(" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
765  printf(" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
766  printf(" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
767  printf(" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
768 #else
769  printf(" -a log APDU commands and results\n");
770  printf(" -c path to reader.conf\n");
771  printf(" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
772  printf(" -T force use of colored logs\n");
773  printf(" -d display debug messages.\n");
774  printf(" -e display error messages (default level).\n");
775  printf(" -C display critical messages.\n");
776  printf(" -h display usage information\n");
777  printf(" -H ask the daemon to rescan the available readers\n");
778  printf(" -v display the program version number\n");
779  printf(" -t maximum number of threads\n");
780  printf(" -s maximum number of card handle per thread\n");
781  printf(" -r maximum number of card handle per reader\n");
782  printf(" -x pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
783 #endif
784 }
785 
INTERNAL int32_t ListenExistingSocket(int fd)
Acquires a socket passed in from systemd.
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
Definition: winscard_svc.c:144
This handles power management routines.
This handles abstract system level calls.
char AutoExit
Represents an Application Context on the Server side.
Definition: pcscdaemon.c:57
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:44
This demarshalls functions over the message queue and keeps track of clients and their handles...
This defines some structures and #defines to be used over the transport layer.
INTERNAL int32_t InitializeSocket(void)
Prepares the communication channel used by the server to talk to the clients.
ULONG PMRegisterForPowerEvents(void)
Registers for Power Management callbacks.
static void SVCServiceRunLoop(void)
The Server&#39;s Message Queue Listener function.
Definition: pcscdaemon.c:81
This keeps a list of defines for pcsc-lite.
This keeps a list of defines for pcsc-lite.
INTERNAL int32_t ProcessEventsServer(uint32_t *pdwClientID)
Looks for messages sent by clients.
This keeps track of a list of currently available reader structures.
This provides a search API for hot pluggble devices.
#define PCSCLITE_VERSION_NUMBER
Current version.
Definition: pcsclite.h:193
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx
Definition: pcsclite.h:80
This handles debugging.