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