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