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