pcsc-lite  1.9.7
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-2022
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 _Atomic 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 = 0; /* 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 #ifdef USE_SERIAL
264  char *newReaderConfig = NULL;
265 #endif
266  struct stat fStatBuf;
267  int customMaxThreadCounter = 0;
268  int customMaxReaderHandles = 0;
269  int customMaxThreadCardHandles = 0;
270  int opt;
271  int r;
272 #ifdef HAVE_GETOPT_LONG
273  int option_index = 0;
274  static struct option long_options[] = {
275  {"config", 1, NULL, 'c'},
276  {"foreground", 0, NULL, 'f'},
277  {"color", 0, NULL, 'T'},
278  {"help", 0, NULL, 'h'},
279  {"version", 0, NULL, 'v'},
280  {"apdu", 0, NULL, 'a'},
281  {"debug", 0, NULL, 'd'},
282  {"info", 0, NULL, 'i'},
283  {"error", 0, NULL, 'e'},
284  {"critical", 0, NULL, 'C'},
285  {"hotplug", 0, NULL, 'H'},
286  {"force-reader-polling", optional_argument, NULL, 0},
287  {"max-thread", 1, NULL, 't'},
288  {"max-card-handle-per-thread", 1, NULL, 's'},
289  {"max-card-handle-per-reader", 1, NULL, 'r'},
290  {"auto-exit", 0, NULL, 'x'},
291  {"reader-name-no-serial", 0, NULL, 'S'},
292  {"reader-name-no-interface", 0, NULL, 'I'},
293  {NULL, 0, NULL, 0}
294  };
295 #endif
296 #define OPT_STRING "c:fTdhvaieCHt:r:s:xSI"
297 
298  setToForeground = FALSE;
299  HotPlug = FALSE;
300 
301  /*
302  * test the version
303  */
304  if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
305  {
306  printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
307  printf(" in pcsclite.h (%s) does not match the release version number\n",
309  printf(" generated in config.h (%s) (see configure.in).\n", VERSION);
310 
311  return EXIT_FAILURE;
312  }
313 
314  /* Init the PRNG */
315  SYS_InitRandom();
316 
317  /*
318  * By default we create a daemon (not connected to any output)
319  * so log to syslog to have error messages.
320  */
321  DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
322 
323  /*
324  * Handle any command line arguments
325  */
326 #ifdef HAVE_GETOPT_LONG
327  while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
328 #else
329  while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
330 #endif
331  switch (opt) {
332 #ifdef HAVE_GETOPT_LONG
333  case 0:
334  if (strcmp(long_options[option_index].name,
335  "force-reader-polling") == 0)
336  HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
337  break;
338 #endif
339 #ifdef USE_SERIAL
340  case 'c':
341  Log2(PCSC_LOG_INFO, "using new config directory: %s", optarg);
342  newReaderConfig = optarg;
343  break;
344 #endif
345 
346  case 'f':
347  setToForeground = TRUE;
348  /* debug to stdout instead of default syslog */
349  DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
350  Log1(PCSC_LOG_INFO,
351  "pcscd set to foreground with debug send to stdout");
352  break;
353 
354  case 'T':
355  DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
356  Log1(PCSC_LOG_INFO, "Force colored logs");
357  break;
358 
359  case 'd':
360  DebugLogSetLevel(PCSC_LOG_DEBUG);
361  break;
362 
363  case 'i':
364  DebugLogSetLevel(PCSC_LOG_INFO);
365  break;
366 
367  case 'e':
368  DebugLogSetLevel(PCSC_LOG_ERROR);
369  break;
370 
371  case 'C':
372  DebugLogSetLevel(PCSC_LOG_CRITICAL);
373  break;
374 
375  case 'h':
376  print_usage (argv[0]);
377  return EXIT_SUCCESS;
378 
379  case 'v':
380  print_version ();
381  return EXIT_SUCCESS;
382 
383  case 'a':
384  DebugLogSetCategory(DEBUG_CATEGORY_APDU);
385  break;
386 
387  case 'H':
388  /* debug to stdout instead of default syslog */
389  DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
390  HotPlug = TRUE;
391  break;
392 
393  case 't':
394  customMaxThreadCounter = optarg ? atoi(optarg) : 0;
395  Log2(PCSC_LOG_INFO, "setting customMaxThreadCounter to: %d",
396  customMaxThreadCounter);
397  break;
398 
399  case 'r':
400  customMaxReaderHandles = optarg ? atoi(optarg) : 0;
401  Log2(PCSC_LOG_INFO, "setting customMaxReaderHandles to: %d",
402  customMaxReaderHandles);
403  break;
404 
405  case 's':
406  customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
407  Log2(PCSC_LOG_INFO, "setting customMaxThreadCardHandles to: %d",
408  customMaxThreadCardHandles);
409  break;
410 
411  case 'x':
412  AutoExit = TRUE;
413  Log2(PCSC_LOG_INFO, "Auto exit after %d seconds of inactivity",
414  TIME_BEFORE_SUICIDE);
415  break;
416 
417  case 'S':
418  Add_Serial_In_Name = FALSE;
419  break;
420 
421  case 'I':
422  Add_Interface_In_Name = FALSE;
423  break;
424 
425  default:
426  print_usage (argv[0]);
427  return EXIT_FAILURE;
428  }
429 
430  }
431 
432  if (argv[optind])
433  {
434  printf("Unknown option: %s\n", argv[optind]);
435  print_usage(argv[0]);
436  return EXIT_FAILURE;
437  }
438 
439 #ifdef USE_LIBSYSTEMD
440  /*
441  * Check if systemd passed us any file descriptors
442  */
443  rv = sd_listen_fds(0);
444  if (rv > 1)
445  {
446  Log1(PCSC_LOG_CRITICAL, "Too many file descriptors received");
447  return EXIT_FAILURE;
448  }
449  else
450  {
451  if (rv == 1)
452  {
453  SocketActivated = TRUE;
454  Log1(PCSC_LOG_INFO, "Started by systemd");
455  }
456  else
457  SocketActivated = FALSE;
458  }
459 #endif
460 
461  /*
462  * test the presence of /var/run/pcscd/pcscd.comm
463  */
464 
465  rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
466 
467  /* if the file exist and pcscd was _not_ started by systemd */
468  if (rv == 0 && !SocketActivated)
469  {
470  pid_t pid;
471 
472  /* read the pid file to get the old pid and test if the old pcscd is
473  * still running
474  */
475  pid = GetDaemonPid();
476 
477  if (pid != -1)
478  {
479  if (HotPlug)
480  return SendHotplugSignal();
481 
482  rv = kill(pid, 0);
483  if (0 == rv)
484  {
485  Log1(PCSC_LOG_CRITICAL,
486  "file " PCSCLITE_CSOCK_NAME " already exists.");
487  Log2(PCSC_LOG_CRITICAL,
488  "Another pcscd (pid: %ld) seems to be running.", (long)pid);
489  return EXIT_FAILURE;
490  }
491  else
492  if (ESRCH == errno)
493  {
494  /* the old pcscd is dead. make some cleanup */
495  clean_temp_files();
496  }
497  else
498  {
499  /* permission denied or other error */
500  Log2(PCSC_LOG_CRITICAL, "kill failed: %s", strerror(errno));
501  return EXIT_FAILURE;
502  }
503  }
504  else
505  {
506  if (HotPlug)
507  {
508  Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist");
509  Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
510  return EXIT_FAILURE;
511  }
512  }
513  }
514  else
515  if (HotPlug)
516  {
517  Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running");
518  return EXIT_FAILURE;
519  }
520 
521  /* like in daemon(3): changes the current working directory to the
522  * root ("/") */
523  r = chdir("/");
524  if (r < 0)
525  {
526  Log2(PCSC_LOG_CRITICAL, "chdir() failed: %s", strerror(errno));
527  return EXIT_FAILURE;
528  }
529 
530  /*
531  * If this is set to one the user has asked it not to fork
532  */
533  if (!setToForeground)
534  {
535  int pid;
536  int fd;
537 
538  if (pipe(pipefd) == -1)
539  {
540  Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
541  return EXIT_FAILURE;
542  }
543 
544  pid = fork();
545  if (-1 == pid)
546  {
547  Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
548  return EXIT_FAILURE;
549  }
550 
551  /* like in daemon(3): redirect standard input, standard output
552  * and standard error to /dev/null */
553  fd = open("/dev/null", O_RDWR);
554  if (fd != -1)
555  {
556  dup2(fd, STDIN_FILENO);
557  dup2(fd, STDOUT_FILENO);
558  dup2(fd, STDERR_FILENO);
559 
560  /* do not close stdin, stdout or stderr */
561  if (fd > 2)
562  close(fd);
563  }
564 
565  if (pid)
566  /* in the father */
567  {
568  char buf;
569  int ret;
570 
571  /* close write side */
572  close(pipefd[1]);
573 
574  /* wait for the son to write the return code */
575  ret = read(pipefd[0], &buf, 1);
576  if (ret <= 0)
577  return 2;
578 
579  close(pipefd[0]);
580 
581  /* exit code */
582  return buf;
583  }
584  else
585  /* in the son */
586  {
587  /* close read side */
588  close(pipefd[0]);
589  }
590  }
591 
592  /*
593  * cleanly remove /var/run/pcscd/files when exiting
594  * signal_trap() does just set a global variable used by the main loop
595  */
596  (void)signal(SIGQUIT, signal_trap);
597  (void)signal(SIGTERM, signal_trap); /* default kill signal & init round 1 */
598  (void)signal(SIGINT, signal_trap); /* sent by Ctrl-C */
599 
600  /* exits on SIGALARM to allow pcscd to suicide if not used */
601  (void)signal(SIGALRM, signal_trap);
602 
603  if (pipe(signal_handler_fd) == -1)
604  {
605  Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
606  return EXIT_FAILURE;
607  }
608 
609  pthread_t signal_handler_thread;
610  rv = pthread_create(&signal_handler_thread, NULL, signal_thread, NULL);
611  if (rv)
612  {
613  Log2(PCSC_LOG_CRITICAL, "pthread_create failed: %s", strerror(rv));
614  return EXIT_FAILURE;
615  }
616 
617  /*
618  * If PCSCLITE_IPC_DIR does not exist then create it
619  */
620  {
621  int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
622 
623  rv = mkdir(PCSCLITE_IPC_DIR, mode);
624  if ((rv != 0) && (errno != EEXIST))
625  {
626  Log2(PCSC_LOG_CRITICAL,
627  "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
628  return EXIT_FAILURE;
629  }
630 
631  /* set mode so that the directory is world readable and
632  * executable even is umask is restrictive
633  * The directory containes files used by libpcsclite */
634  (void)chmod(PCSCLITE_IPC_DIR, mode);
635  }
636 
637  /*
638  * Allocate memory for reader structures
639  */
640  rv = RFAllocateReaderSpace(customMaxReaderHandles);
641  if (SCARD_S_SUCCESS != rv)
642  at_exit();
643 
644 #ifdef USE_SERIAL
645  /*
646  * Grab the information from the reader.conf files
647  */
648  if (newReaderConfig)
649  {
650  rv = RFStartSerialReaders(newReaderConfig);
651  if (rv != 0)
652  {
653  Log3(PCSC_LOG_CRITICAL, "invalid directory %s: %s", newReaderConfig,
654  strerror(errno));
655  at_exit();
656  }
657  }
658  else
659  {
660  rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
661  if (rv == -1)
662  at_exit();
663  }
664 #endif
665 
666  Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
667 
668  /*
669  * Record our pid to make it easier
670  * to kill the correct pcscd
671  *
672  * Do not fork after this point or the stored pid will be wrong
673  */
674  {
675  int f;
676  int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
677 
678  f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
679  if (f != -1)
680  {
681  char pid[PID_ASCII_SIZE];
682  ssize_t rr;
683 
684  (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid());
685  rr = write(f, pid, strlen(pid) + 1);
686  if (rr < 0)
687  {
688  Log2(PCSC_LOG_CRITICAL,
689  "writing " PCSCLITE_RUN_PID " failed: %s",
690  strerror(errno));
691  }
692 
693  /* set mode so that the file is world readable even is umask is
694  * restrictive
695  * The file is used by libpcsclite */
696  (void)fchmod(f, mode);
697 
698  (void)close(f);
699  }
700  else
701  Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s",
702  strerror(errno));
703  }
704 
705  /*
706  * post initialization
707  */
708  Init = FALSE;
709 
710  /*
711  * Hotplug rescan
712  */
713  (void)signal(SIGUSR1, signal_trap);
714 
715  /*
716  * Initialize the comm structure
717  */
718 #ifdef USE_LIBSYSTEMD
719  if (SocketActivated)
720  rv = ListenExistingSocket(SD_LISTEN_FDS_START + 0);
721  else
722 #endif
723  rv = InitializeSocket();
724 
725  if (rv)
726  {
727  Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
728  at_exit();
729  }
730 
731  /*
732  * Initialize the contexts structure
733  */
734  rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
735 
736  if (rv == -1)
737  {
738  Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
739  at_exit();
740  }
741 
742  (void)signal(SIGPIPE, SIG_IGN);
743  (void)signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent
744  * when the shell is exited */
745 
746 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
747  /*
748  * Set up the search for USB/PCMCIA devices
749  */
750  rv = HPSearchHotPluggables();
751 #ifndef USE_SERIAL
752  if (rv)
753  at_exit();
754 #else
755  (void)rv;
756 #endif
757 
758  rv = HPRegisterForHotplugEvents();
759  if (rv)
760  {
761  Log1(PCSC_LOG_ERROR, "HPRegisterForHotplugEvents failed");
762  at_exit();
763  }
764 
765  RFWaitForReaderInit();
766 #endif
767 
768  /* initialization succeeded */
769  if (pipefd[1] >= 0)
770  {
771  char buf = 0;
772  ssize_t rr;
773 
774  /* write a 0 (success) to father process */
775  rr = write(pipefd[1], &buf, 1);
776  if (rr < 0)
777  {
778  Log2(PCSC_LOG_ERROR, "write() failed: %s", strerror(errno));
779  }
780  close(pipefd[1]);
781  pipefd[1] = -1;
782  }
783 
784  if (AutoExit)
785  {
786  Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
787  TIME_BEFORE_SUICIDE);
788  alarm(TIME_BEFORE_SUICIDE);
789  }
790 
792 
793  Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
794  return EXIT_FAILURE;
795 }
796 
797 static void at_exit(void)
798 {
799  Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
800 
801  clean_temp_files();
802 
803  if (pipefd[1] >= 0)
804  {
805  char buf;
806  ssize_t r;
807 
808  /* write the error code to father process */
809  buf = ExitValue;
810  r = write(pipefd[1], &buf, 1);
811  if (r < 0)
812  {
813  Log2(PCSC_LOG_ERROR, "write() failed: %s", strerror(errno));
814  }
815  close(pipefd[1]);
816  }
817 
818  exit(ExitValue);
819 }
820 
821 static void clean_temp_files(void)
822 {
823  int rv;
824 
825  if (!SocketActivated)
826  {
827  rv = remove(PCSCLITE_CSOCK_NAME);
828  if (rv != 0)
829  Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
830  strerror(errno));
831  }
832 
833  rv = remove(PCSCLITE_RUN_PID);
834  if (rv != 0)
835  Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
836  strerror(errno));
837 }
838 
839 static void signal_trap(int sig)
840 {
841  int r;
842 
843  r = write(signal_handler_fd[1], &sig, sizeof sig);
844  if (r < 0)
845  Log2(PCSC_LOG_ERROR, "write failed: %s", strerror(errno));
846 }
847 
848 static void print_version(void)
849 {
850  printf("%s version %s.\n", PACKAGE, VERSION);
851  printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@musclecard.com>.\n");
852  printf("Copyright (C) 2001-2022 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
853  printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
854  printf("Report bugs to <pcsclite-muscle@lists.infradead.org>.\n");
855 
856  printf("Enabled features:%s\n", PCSCLITE_FEATURES);
857  printf("MAX_READERNAME: %d, PCSCLITE_MAX_READERS_CONTEXTS: %d\n",
858  MAX_READERNAME, PCSCLITE_MAX_READERS_CONTEXTS);
859 }
860 
861 static void print_usage(char const * const progname)
862 {
863  printf("Usage: %s options\n", progname);
864  printf("Options:\n");
865 #ifdef HAVE_GETOPT_LONG
866  printf(" -a, --apdu log APDU commands and results\n");
867 #ifdef USE_SERIAL
868  printf(" -c, --config new reader.conf.d path\n");
869 #endif
870  printf(" -f, --foreground run in foreground (no daemon),\n");
871  printf(" send logs to stdout instead of syslog\n");
872  printf(" -T, --color force use of colored logs\n");
873  printf(" -h, --help display usage information\n");
874  printf(" -H, --hotplug ask the daemon to rescan the available readers\n");
875  printf(" -v, --version display the program version number\n");
876  printf(" -d, --debug display lower level debug messages\n");
877  printf(" -i, --info display info level debug messages\n");
878  printf(" -e --error display error level debug messages (default level)\n");
879  printf(" -C --critical display critical only level debug messages\n");
880  printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
881  printf(" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
882  printf(" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
883  printf(" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
884  printf(" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
885  printf(" -S, --reader-name-no-serial do not include the USB serial number in the name\n");
886  printf(" -I, --reader-name-no-interface do not include the USB interface name in the name\n");
887 #else
888  printf(" -a log APDU commands and results\n");
889 #ifdef USE_SERIAL
890  printf(" -c new reader.conf.d path\n");
891 #endif
892  printf(" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
893  printf(" -T force use of colored logs\n");
894  printf(" -d display debug messages.\n");
895  printf(" -i display info messages.\n");
896  printf(" -e display error messages (default level).\n");
897  printf(" -C display critical messages.\n");
898  printf(" -h display usage information\n");
899  printf(" -H ask the daemon to rescan the available readers\n");
900  printf(" -v display the program version number\n");
901  printf(" -t maximum number of threads\n");
902  printf(" -s maximum number of card handle per thread\n");
903  printf(" -r maximum number of card handle per reader\n");
904  printf(" -x pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
905 #endif
906 }
907 
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
void SYS_InitRandom(void)
Initialize the random generator.
Definition: sys_unix.c:111
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
Definition: winscard_svc.c:171
This handles abstract system level calls.
char AutoExit
Represents an Application Context on the Server side.
Definition: pcscdaemon.c:80
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:53
This demarshalls functions over the message queue and keeps track of clients and their handles...
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:71
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:284
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.
This handles card insertion/removal events, updates ATR, protocol, and status information.
static void SVCServiceRunLoop(void)
The Server&#39;s Message Queue Listener function.
Definition: pcscdaemon.c:106
This keeps a list of defines for pcsc-lite.
static void * signal_thread(void *arg)
thread dedicated to handle signals
Definition: pcscdaemon.c:177
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:282
This handles debugging.