pcsc-lite  1.7.4
pcscdaemon.c
Go to the documentation of this file.
00001 /*
00002  * MUSCLE SmartCard Development ( http://www.linuxnet.com )
00003  *
00004  * Copyright (C) 1999-2002
00005  *  David Corcoran <corcoran@linuxnet.com>
00006  * Copyright (C) 2002-2011
00007  *  Ludovic Rousseau <ludovic.rousseau@free.fr>
00008  *
00009  * $Id: pcscdaemon.c 5764 2011-05-18 11:57:51Z rousseau $
00010  */
00011 
00021 #include "config.h"
00022 #include <time.h>
00023 #include <signal.h>
00024 #include <sys/types.h>
00025 #include <sys/stat.h>
00026 #include <fcntl.h>
00027 #include <errno.h>
00028 #include <stdio.h>
00029 #include <unistd.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 #ifdef HAVE_GETOPT_H
00033 #include <getopt.h>
00034 #endif
00035 
00036 #include "misc.h"
00037 #include "pcsclite.h"
00038 #include "pcscd.h"
00039 #include "debuglog.h"
00040 #include "sd-daemon.h"
00041 #include "winscard_msg.h"
00042 #include "winscard_svc.h"
00043 #include "sys_generic.h"
00044 #include "hotplug.h"
00045 #include "readerfactory.h"
00046 #include "configfile.h"
00047 #include "powermgt_generic.h"
00048 #include "utils.h"
00049 
00050 #ifndef TRUE
00051 #define TRUE 1
00052 #define FALSE 0
00053 #endif
00054 
00055 char AraKiri = FALSE;
00056 static char Init = TRUE;
00057 char AutoExit = FALSE;
00058 char SocketActivated = FALSE;
00059 static int ExitValue = EXIT_FAILURE;
00060 int HPForceReaderPolling = 0;
00061 static int pipefd[] = {-1, -1};
00062 
00063 /*
00064  * Some internal functions
00065  */
00066 static void at_exit(void);
00067 static void clean_temp_files(void);
00068 static void signal_reload(int sig);
00069 static void signal_trap(int);
00070 static void print_version (void);
00071 static void print_usage (char const * const);
00072 
00081 static void SVCServiceRunLoop(void)
00082 {
00083     int rsp;
00084     LONG rv;
00085     uint32_t dwClientID;    /* Connection ID used to reference the Client */
00086 
00087     while (TRUE)
00088     {
00089         switch (rsp = ProcessEventsServer(&dwClientID))
00090         {
00091 
00092         case 0:
00093             Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
00094             rv = CreateContextThread(&dwClientID);
00095 
00096             if (rv != SCARD_S_SUCCESS)
00097                 Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
00098             break;
00099 
00100         case 2:
00101             /*
00102              * timeout in ProcessEventsServer(): do nothing
00103              * this is used to catch the Ctrl-C signal at some time when
00104              * nothing else happens
00105              */
00106             break;
00107 
00108         case -1:
00109             Log1(PCSC_LOG_ERROR, "Error in ProcessEventsServer");
00110             break;
00111 
00112         case -2:
00113             /* Nothing to do in case of a syscall interrupted
00114              * It happens when SIGUSR1 (reload) or SIGINT (Ctrl-C) is received
00115              * We just try again */
00116             break;
00117 
00118         default:
00119             Log2(PCSC_LOG_ERROR, "ProcessEventsServer unknown retval: %d",
00120                 rsp);
00121             break;
00122         }
00123 
00124         if (AraKiri)
00125         {
00126             /* stop the hotpug thread and waits its exit */
00127 #ifdef USE_USB
00128             (void)HPStopHotPluggables();
00129 #endif
00130             (void)SYS_Sleep(1);
00131 
00132             /* now stop all the drivers */
00133             RFCleanupReaders();
00134             ContextsDeinitialize();
00135             at_exit();
00136         }
00137     }
00138 }
00139 
00140 int main(int argc, char **argv)
00141 {
00142     int rv;
00143     char setToForeground;
00144     char HotPlug;
00145     char *newReaderConfig;
00146     struct stat fStatBuf;
00147     int customMaxThreadCounter = 0;
00148     int customMaxReaderHandles = 0;
00149     int customMaxThreadCardHandles = 0;
00150     int opt;
00151     int limited_rights = FALSE;
00152 #ifdef HAVE_GETOPT_LONG
00153     int option_index = 0;
00154     static struct option long_options[] = {
00155         {"config", 1, NULL, 'c'},
00156         {"foreground", 0, NULL, 'f'},
00157         {"color", 0, NULL, 'T'},
00158         {"help", 0, NULL, 'h'},
00159         {"version", 0, NULL, 'v'},
00160         {"apdu", 0, NULL, 'a'},
00161         {"debug", 0, NULL, 'd'},
00162         {"info", 0, NULL, 0},
00163         {"error", 0, NULL, 'e'},
00164         {"critical", 0, NULL, 'C'},
00165         {"hotplug", 0, NULL, 'H'},
00166         {"force-reader-polling", optional_argument, NULL, 0},
00167         {"max-thread", 1, NULL, 't'},
00168         {"max-card-handle-per-thread", 1, NULL, 's'},
00169         {"max-card-handle-per-reader", 1, NULL, 'r'},
00170         {"auto-exit", 0, NULL, 'x'},
00171         {NULL, 0, NULL, 0}
00172     };
00173 #endif
00174 #define OPT_STRING "c:fTdhvaeCHt:r:s:x"
00175 
00176     newReaderConfig = NULL;
00177     setToForeground = FALSE;
00178     HotPlug = FALSE;
00179 
00180     /*
00181      * test the version
00182      */
00183     if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
00184     {
00185         printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
00186         printf("  in pcsclite.h (%s) does not match the release version number\n",
00187             PCSCLITE_VERSION_NUMBER);
00188         printf("  generated in config.h (%s) (see configure.in).\n", VERSION);
00189 
00190         return EXIT_FAILURE;
00191     }
00192 
00193     /*
00194      * By default we create a daemon (not connected to any output)
00195      * so log to syslog to have error messages.
00196      */
00197     DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
00198 
00199     /* if the process is setuid or setgid it may have some restrictions */
00200     limited_rights = (getgid() != getegid()) && (getuid() != 0);
00201 
00202     /*
00203      * Handle any command line arguments
00204      */
00205 #ifdef  HAVE_GETOPT_LONG
00206     while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
00207 #else
00208     while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
00209 #endif
00210         switch (opt) {
00211 #ifdef  HAVE_GETOPT_LONG
00212             case 0:
00213                 if (strcmp(long_options[option_index].name,
00214                     "force-reader-polling") == 0)
00215                     HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
00216                 break;
00217 #endif
00218             case 'c':
00219                 if (limited_rights)
00220                 {
00221                     Log1(PCSC_LOG_CRITICAL, "Can't use a user specified config file");
00222                     return EXIT_FAILURE;
00223                 }
00224                 Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
00225                 newReaderConfig = optarg;
00226                 break;
00227 
00228             case 'f':
00229                 setToForeground = TRUE;
00230                 /* debug to stdout instead of default syslog */
00231                 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
00232                 Log1(PCSC_LOG_INFO,
00233                     "pcscd set to foreground with debug send to stdout");
00234                 break;
00235 
00236             case 'T':
00237                 DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
00238                 Log1(PCSC_LOG_INFO, "Force colored logs");
00239                 break;
00240 
00241             case 'd':
00242                 DebugLogSetLevel(PCSC_LOG_DEBUG);
00243                 break;
00244 
00245             case 'e':
00246                 DebugLogSetLevel(PCSC_LOG_ERROR);
00247                 break;
00248 
00249             case 'C':
00250                 DebugLogSetLevel(PCSC_LOG_CRITICAL);
00251                 break;
00252 
00253             case 'h':
00254                 print_usage (argv[0]);
00255                 return EXIT_SUCCESS;
00256 
00257             case 'v':
00258                 print_version ();
00259                 return EXIT_SUCCESS;
00260 
00261             case 'a':
00262                 if (limited_rights)
00263                 {
00264                     Log1(PCSC_LOG_CRITICAL, "Can't log APDU (restricted)");
00265                     return EXIT_FAILURE;
00266                 }
00267                 (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
00268                 break;
00269 
00270             case 'H':
00271                 /* debug to stdout instead of default syslog */
00272                 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
00273                 HotPlug = TRUE;
00274                 break;
00275 
00276             case 't':
00277                 customMaxThreadCounter = optarg ? atoi(optarg) : 0;
00278                 if (limited_rights && (customMaxThreadCounter < PCSC_MAX_CONTEXT_THREADS))
00279                     customMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
00280                 Log2(PCSC_LOG_INFO, "setting customMaxThreadCounter to: %d",
00281                     customMaxThreadCounter);
00282                 break;
00283 
00284             case 'r':
00285                 customMaxReaderHandles = optarg ? atoi(optarg) : 0;
00286                 if (limited_rights && (customMaxReaderHandles < PCSC_MAX_READER_HANDLES))
00287                     customMaxReaderHandles = PCSC_MAX_READER_HANDLES;
00288                 Log2(PCSC_LOG_INFO, "setting customMaxReaderHandles to: %d",
00289                     customMaxReaderHandles);
00290                 break;
00291 
00292             case 's':
00293                 customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
00294                 if (limited_rights && (customMaxThreadCardHandles < PCSC_MAX_CONTEXT_CARD_HANDLES))
00295                     customMaxThreadCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
00296                 Log2(PCSC_LOG_INFO, "setting customMaxThreadCardHandles to: %d",
00297                     customMaxThreadCardHandles);
00298                 break;
00299 
00300             case 'x':
00301                 AutoExit = TRUE;
00302                 Log2(PCSC_LOG_INFO, "Auto exit after %d seconds of inactivity",
00303                     TIME_BEFORE_SUICIDE);
00304                 break;
00305 
00306             default:
00307                 print_usage (argv[0]);
00308                 return EXIT_FAILURE;
00309         }
00310 
00311     }
00312 
00313     if (argv[optind])
00314     {
00315         printf("Unknown option: %s\n", argv[optind]);
00316         print_usage(argv[0]);
00317         return EXIT_FAILURE;
00318     }
00319 
00320     /*
00321      * Check if systemd passed us any file descriptors
00322      */
00323     rv = sd_listen_fds(0);
00324     if (rv > 1)
00325     {
00326         Log1(PCSC_LOG_CRITICAL, "Too many file descriptors received");
00327         return EXIT_FAILURE;
00328     }
00329     else if (rv == 1)
00330         SocketActivated = TRUE;
00331     else
00332         SocketActivated = FALSE;
00333 
00334     /*
00335      * test the presence of /var/run/pcscd/pcscd.comm
00336      */
00337 
00338     rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
00339 
00340     if (rv == 0)
00341     {
00342         pid_t pid;
00343 
00344         /* read the pid file to get the old pid and test if the old pcscd is
00345          * still running
00346          */
00347         pid = GetDaemonPid();
00348 
00349         if (pid != -1)
00350         {
00351             if (HotPlug)
00352                 return SendHotplugSignal();
00353 
00354             rv = kill(pid, 0);
00355             if (0 == rv)
00356             {
00357                 Log1(PCSC_LOG_CRITICAL,
00358                     "file " PCSCLITE_CSOCK_NAME " already exists.");
00359                 Log2(PCSC_LOG_CRITICAL,
00360                     "Another pcscd (pid: %d) seems to be running.", pid);
00361                 return EXIT_FAILURE;
00362             }
00363             else
00364                 if (ESRCH == errno)
00365                 {
00366                     /* the old pcscd is dead. make some cleanup */
00367                     clean_temp_files();
00368                 }
00369                 else
00370                 {
00371                     /* permission denied or other error */
00372                     Log2(PCSC_LOG_CRITICAL, "kill failed: %s", strerror(errno));
00373                     return EXIT_FAILURE;
00374                 }
00375         }
00376         else
00377         {
00378             if (HotPlug)
00379             {
00380                 Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist");
00381                 Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
00382                 return EXIT_FAILURE;
00383             }
00384 
00385             if (!SocketActivated)
00386             {
00387                 Log1(PCSC_LOG_CRITICAL,
00388                     "file " PCSCLITE_CSOCK_NAME " already exists.");
00389                 Log1(PCSC_LOG_CRITICAL,
00390                     "Maybe another pcscd is running?");
00391                 Log1(PCSC_LOG_CRITICAL,
00392                     "I can't read process pid from " PCSCLITE_RUN_PID);
00393                 Log1(PCSC_LOG_CRITICAL, "Remove " PCSCLITE_CSOCK_NAME);
00394                 Log1(PCSC_LOG_CRITICAL,
00395                     "if pcscd is not running to clear this message.");
00396                 return EXIT_FAILURE;
00397             }
00398         }
00399     }
00400     else
00401         if (HotPlug)
00402         {
00403             Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running");
00404             return EXIT_FAILURE;
00405         }
00406 
00407     /* like in daemon(3): changes the current working directory to the
00408      * root ("/") */
00409     (void)chdir("/");
00410 
00411     if (AutoExit)
00412     {
00413         int pid;
00414 
00415         /* create a new session so that Ctrl-C on the application will
00416          * not also quit pcscd */
00417         setsid();
00418 
00419         /* fork() so that pcscd always return in --auto-exit mode */
00420         pid = fork();
00421         if (-1 == pid )
00422             Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
00423 
00424         if (pid)
00425             /* father */
00426             return EXIT_SUCCESS;
00427     }
00428 
00429     /*
00430      * If this is set to one the user has asked it not to fork
00431      */
00432     if (!setToForeground)
00433     {
00434         int pid;
00435 
00436         if (pipe(pipefd) == -1)
00437         {
00438             Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
00439             return EXIT_FAILURE;
00440         }
00441 
00442         pid = fork();
00443         if (-1 == pid)
00444         {
00445             Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
00446             return EXIT_FAILURE;
00447         }
00448 
00449         /* like in daemon(3): redirect standard input, standard output
00450          * and standard error to /dev/null */
00451         (void)close(0);
00452         (void)close(1);
00453         (void)close(2);
00454 
00455         if (pid)
00456         /* in the father */
00457         {
00458             char buf;
00459             int ret;
00460 
00461             /* close write side */
00462             close(pipefd[1]);
00463 
00464             /* wait for the son to write the return code */
00465             ret = read(pipefd[0], &buf, 1);
00466             if (ret <= 0)
00467                 return 2;
00468 
00469             close(pipefd[0]);
00470 
00471             /* exit code */
00472             return buf;
00473         }
00474         else
00475         /* in the son */
00476         {
00477             /* close read side */
00478             close(pipefd[0]);
00479         }
00480     }
00481 
00482     /*
00483      * cleanly remove /var/run/pcscd/files when exiting
00484      * signal_trap() does just set a global variable used by the main loop
00485      */
00486     (void)signal(SIGQUIT, signal_trap);
00487     (void)signal(SIGTERM, signal_trap); /* default kill signal & init round 1 */
00488     (void)signal(SIGINT, signal_trap);  /* sent by Ctrl-C */
00489 
00490     /* exits on SIGALARM to allow pcscd to suicide if not used */
00491     (void)signal(SIGALRM, signal_trap);
00492 
00493     /*
00494      * If PCSCLITE_IPC_DIR does not exist then create it
00495      */
00496     rv = stat(PCSCLITE_IPC_DIR, &fStatBuf);
00497     if (rv < 0)
00498     {
00499         int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
00500 
00501         rv = mkdir(PCSCLITE_IPC_DIR, mode);
00502         if (rv != 0)
00503         {
00504             Log2(PCSC_LOG_CRITICAL,
00505                 "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
00506             return EXIT_FAILURE;
00507         }
00508 
00509         /* set mode so that the directory is world readable and
00510          * executable even is umask is restrictive
00511          * The directory containes files used by libpcsclite */
00512         (void)chmod(PCSCLITE_IPC_DIR, mode);
00513     }
00514 
00515     /*
00516      * Record our pid to make it easier
00517      * to kill the correct pcscd
00518      */
00519     {
00520         int f;
00521         int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
00522 
00523         f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
00524         if (f != -1)
00525         {
00526             char pid[PID_ASCII_SIZE];
00527 
00528             (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid());
00529             (void)write(f, pid, strlen(pid));
00530             (void)close(f);
00531 
00532             /* set mode so that the file is world readable even is umask is
00533              * restrictive
00534              * The file is used by libpcsclite */
00535             (void)chmod(PCSCLITE_RUN_PID, mode);
00536         }
00537         else
00538             Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s",
00539                 strerror(errno));
00540     }
00541 
00542     /* cleanly remove /var/run/pcscd/pcsc.* files when exiting */
00543     if (atexit(at_exit))
00544         Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno));
00545 
00546     /*
00547      * Allocate memory for reader structures
00548      */
00549     rv = RFAllocateReaderSpace(customMaxReaderHandles);
00550     if (SCARD_S_SUCCESS != rv)
00551         at_exit();
00552 
00553 #ifdef USE_SERIAL
00554     /*
00555      * Grab the information from the reader.conf
00556      */
00557     if (newReaderConfig)
00558     {
00559         rv = RFStartSerialReaders(newReaderConfig);
00560         if (rv != 0)
00561         {
00562             Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
00563                 strerror(errno));
00564             at_exit();
00565         }
00566     }
00567     else
00568     {
00569         rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
00570         if (rv == -1)
00571             at_exit();
00572     }
00573 #endif
00574 
00575     Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
00576 
00577     /*
00578      * post initialistion
00579      */
00580     Init = FALSE;
00581 
00582     /*
00583      * Hotplug rescan
00584      */
00585     (void)signal(SIGUSR1, signal_reload);
00586 
00587     /*
00588      * Initialize the comm structure
00589      */
00590     if (SocketActivated)
00591         rv = ListenExistingSocket(SD_LISTEN_FDS_START + 0);
00592     else
00593         rv = InitializeSocket();
00594 
00595     if (rv)
00596     {
00597         Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
00598         at_exit();
00599     }
00600 
00601     /*
00602      * Initialize the contexts structure
00603      */
00604     rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
00605 
00606     if (rv == -1)
00607     {
00608         Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
00609         at_exit();
00610     }
00611 
00612     (void)signal(SIGPIPE, SIG_IGN);
00613     (void)signal(SIGHUP, SIG_IGN);  /* needed for Solaris. The signal is sent
00614                  * when the shell is existed */
00615 
00616 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
00617     /*
00618      * Set up the search for USB/PCMCIA devices
00619      */
00620     rv = HPSearchHotPluggables();
00621     if (rv)
00622         at_exit();
00623 
00624     rv = HPRegisterForHotplugEvents();
00625     if (rv)
00626     {
00627         Log1(PCSC_LOG_ERROR, "HPRegisterForHotplugEvents failed");
00628         at_exit();
00629     }
00630 
00631     RFWaitForReaderInit();
00632 #endif
00633 
00634     /*
00635      * Set up the power management callback routine
00636      */
00637     (void)PMRegisterForPowerEvents();
00638 
00639     /* initialisation succeeded */
00640     if (pipefd[1] >= 0)
00641     {
00642         char buf = 0;
00643 
00644         /* write a 0 (success) to father process */
00645         write(pipefd[1], &buf, 1);
00646         close(pipefd[1]);
00647     }
00648 
00649     SVCServiceRunLoop();
00650 
00651     Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
00652     return EXIT_FAILURE;
00653 }
00654 
00655 static void at_exit(void)
00656 {
00657     Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
00658 
00659     clean_temp_files();
00660 
00661     if (pipefd[1] >= 0)
00662     {
00663         char buf;
00664 
00665         /* write the error code to father process */
00666         buf = ExitValue;
00667         write(pipefd[1], &buf, 1);
00668         close(pipefd[1]);
00669     }
00670 
00671     exit(ExitValue);
00672 }
00673 
00674 static void clean_temp_files(void)
00675 {
00676     int rv;
00677 
00678     if (!SocketActivated)
00679     {
00680         rv = remove(PCSCLITE_CSOCK_NAME);
00681         if (rv != 0)
00682             Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
00683                 strerror(errno));
00684     }
00685 
00686     rv = remove(PCSCLITE_RUN_PID);
00687     if (rv != 0)
00688         Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
00689             strerror(errno));
00690 }
00691 
00692 static void signal_reload(/*@unused@*/ int sig)
00693 {
00694     (void)signal(SIGUSR1, signal_reload);
00695 
00696     (void)sig;
00697 
00698     if (AraKiri)
00699         return;
00700 
00701 #ifdef USE_USB
00702     HPReCheckSerialReaders();
00703 #endif
00704 } /* signal_reload */
00705 
00706 static void signal_trap(int sig)
00707 {
00708     Log2(PCSC_LOG_INFO, "Received signal: %d", sig);
00709 
00710     /* do not wait if asked to terminate
00711      * avoids waiting after the reader(s) in shutdown for example */
00712     if (SIGTERM == sig)
00713     {
00714         Log1(PCSC_LOG_INFO, "Direct suicide");
00715         at_exit();
00716     }
00717 
00718     /* the signal handler is called several times for the same Ctrl-C */
00719     if (AraKiri == FALSE)
00720     {
00721         Log1(PCSC_LOG_INFO, "Preparing for suicide");
00722         AraKiri = TRUE;
00723 
00724         /* if still in the init/loading phase the AraKiri will not be
00725          * seen by the main event loop
00726          */
00727         if (Init)
00728         {
00729             Log1(PCSC_LOG_INFO, "Suicide during init");
00730             at_exit();
00731         }
00732     }
00733     else
00734     {
00735         /* if pcscd do not want to die */
00736         static int lives = 2;
00737 
00738         lives--;
00739         /* no live left. Something is blocking the normal death. */
00740         if (0 == lives)
00741         {
00742             Log1(PCSC_LOG_INFO, "Forced suicide");
00743             at_exit();
00744         }
00745     }
00746 }
00747 
00748 static void print_version (void)
00749 {
00750     printf("%s version %s.\n",  PACKAGE, VERSION);
00751     printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
00752     printf("Copyright (C) 2001-2011 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
00753     printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
00754     printf("Report bugs to <muscle@lists.musclecard.com>.\n");
00755 
00756     printf ("Enabled features:%s\n", PCSCLITE_FEATURES);
00757 }
00758 
00759 static void print_usage (char const * const progname)
00760 {
00761     printf("Usage: %s options\n", progname);
00762     printf("Options:\n");
00763 #ifdef HAVE_GETOPT_LONG
00764     printf("  -a, --apdu        log APDU commands and results\n");
00765     printf("  -c, --config      path to reader.conf\n");
00766     printf("  -f, --foreground  run in foreground (no daemon),\n");
00767     printf("            send logs to stdout instead of syslog\n");
00768     printf("  -T, --color       force use of colored logs\n");
00769     printf("  -h, --help        display usage information\n");
00770     printf("  -H, --hotplug     ask the daemon to rescan the available readers\n");
00771     printf("  -v, --version     display the program version number\n");
00772     printf("  -d, --debug       display lower level debug messages\n");
00773     printf("      --info        display info level debug messages (default level)\n");
00774     printf("  -e  --error       display error level debug messages\n");
00775     printf("  -C  --critical    display critical only level debug messages\n");
00776     printf("  --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
00777     printf("  -t, --max-thread  maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
00778     printf("  -s, --max-card-handle-per-thread  maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
00779     printf("  -r, --max-card-handle-per-reader  maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
00780     printf("  -x, --auto-exits  pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
00781 #else
00782     printf("  -a    log APDU commands and results\n");
00783     printf("  -c    path to reader.conf\n");
00784     printf("  -f    run in foreground (no daemon), send logs to stdout instead of syslog\n");
00785     printf("  -T    force use of colored logs\n");
00786     printf("  -d    display debug messages. Output may be:\n");
00787     printf("  -h    display usage information\n");
00788     printf("  -H    ask the daemon to rescan the available readers\n");
00789     printf("  -v    display the program version number\n");
00790     printf("  -t    maximum number of threads\n");
00791     printf("  -s    maximum number of card handle per thread\n");
00792     printf("  -r    maximum number of card handle per reader\n");
00793     printf("  -x    pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
00794 #endif
00795 }
00796