pcsc-lite
1.8.2
|
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 6105 2011-11-14 10:19:44Z 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 00330 { 00331 if (rv == 1) 00332 { 00333 SocketActivated = TRUE; 00334 Log1(PCSC_LOG_INFO, "Started by systemd"); 00335 } 00336 else 00337 SocketActivated = FALSE; 00338 } 00339 00340 /* 00341 * test the presence of /var/run/pcscd/pcscd.comm 00342 */ 00343 00344 rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf); 00345 00346 if (rv == 0) 00347 { 00348 pid_t pid; 00349 00350 /* read the pid file to get the old pid and test if the old pcscd is 00351 * still running 00352 */ 00353 pid = GetDaemonPid(); 00354 00355 if (pid != -1) 00356 { 00357 if (HotPlug) 00358 return SendHotplugSignal(); 00359 00360 rv = kill(pid, 0); 00361 if (0 == rv) 00362 { 00363 Log1(PCSC_LOG_CRITICAL, 00364 "file " PCSCLITE_CSOCK_NAME " already exists."); 00365 Log2(PCSC_LOG_CRITICAL, 00366 "Another pcscd (pid: %d) seems to be running.", pid); 00367 return EXIT_FAILURE; 00368 } 00369 else 00370 if (ESRCH == errno) 00371 { 00372 /* the old pcscd is dead. make some cleanup */ 00373 clean_temp_files(); 00374 } 00375 else 00376 { 00377 /* permission denied or other error */ 00378 Log2(PCSC_LOG_CRITICAL, "kill failed: %s", strerror(errno)); 00379 return EXIT_FAILURE; 00380 } 00381 } 00382 else 00383 { 00384 if (HotPlug) 00385 { 00386 Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist"); 00387 Log1(PCSC_LOG_CRITICAL, "Hotplug failed"); 00388 return EXIT_FAILURE; 00389 } 00390 } 00391 } 00392 else 00393 if (HotPlug) 00394 { 00395 Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running"); 00396 return EXIT_FAILURE; 00397 } 00398 00399 /* like in daemon(3): changes the current working directory to the 00400 * root ("/") */ 00401 (void)chdir("/"); 00402 00403 /* 00404 * If this is set to one the user has asked it not to fork 00405 */ 00406 if (!setToForeground) 00407 { 00408 int pid; 00409 00410 if (pipe(pipefd) == -1) 00411 { 00412 Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno)); 00413 return EXIT_FAILURE; 00414 } 00415 00416 pid = fork(); 00417 if (-1 == pid) 00418 { 00419 Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno)); 00420 return EXIT_FAILURE; 00421 } 00422 00423 /* like in daemon(3): redirect standard input, standard output 00424 * and standard error to /dev/null */ 00425 (void)close(0); 00426 (void)close(1); 00427 (void)close(2); 00428 00429 if (pid) 00430 /* in the father */ 00431 { 00432 char buf; 00433 int ret; 00434 00435 /* close write side */ 00436 close(pipefd[1]); 00437 00438 /* wait for the son to write the return code */ 00439 ret = read(pipefd[0], &buf, 1); 00440 if (ret <= 0) 00441 return 2; 00442 00443 close(pipefd[0]); 00444 00445 /* exit code */ 00446 return buf; 00447 } 00448 else 00449 /* in the son */ 00450 { 00451 /* close read side */ 00452 close(pipefd[0]); 00453 } 00454 } 00455 00456 /* 00457 * cleanly remove /var/run/pcscd/files when exiting 00458 * signal_trap() does just set a global variable used by the main loop 00459 */ 00460 (void)signal(SIGQUIT, signal_trap); 00461 (void)signal(SIGTERM, signal_trap); /* default kill signal & init round 1 */ 00462 (void)signal(SIGINT, signal_trap); /* sent by Ctrl-C */ 00463 00464 /* exits on SIGALARM to allow pcscd to suicide if not used */ 00465 (void)signal(SIGALRM, signal_trap); 00466 00467 /* 00468 * If PCSCLITE_IPC_DIR does not exist then create it 00469 */ 00470 rv = stat(PCSCLITE_IPC_DIR, &fStatBuf); 00471 if (rv < 0) 00472 { 00473 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU; 00474 00475 rv = mkdir(PCSCLITE_IPC_DIR, mode); 00476 if (rv != 0) 00477 { 00478 Log2(PCSC_LOG_CRITICAL, 00479 "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno)); 00480 return EXIT_FAILURE; 00481 } 00482 00483 /* set mode so that the directory is world readable and 00484 * executable even is umask is restrictive 00485 * The directory containes files used by libpcsclite */ 00486 (void)chmod(PCSCLITE_IPC_DIR, mode); 00487 } 00488 00489 /* 00490 * Allocate memory for reader structures 00491 */ 00492 rv = RFAllocateReaderSpace(customMaxReaderHandles); 00493 if (SCARD_S_SUCCESS != rv) 00494 at_exit(); 00495 00496 #ifdef USE_SERIAL 00497 /* 00498 * Grab the information from the reader.conf 00499 */ 00500 if (newReaderConfig) 00501 { 00502 rv = RFStartSerialReaders(newReaderConfig); 00503 if (rv != 0) 00504 { 00505 Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig, 00506 strerror(errno)); 00507 at_exit(); 00508 } 00509 } 00510 else 00511 { 00512 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR); 00513 if (rv == -1) 00514 at_exit(); 00515 } 00516 #endif 00517 00518 Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready."); 00519 00520 /* 00521 * Record our pid to make it easier 00522 * to kill the correct pcscd 00523 * 00524 * Do not fork after this point or the stored pid will be wrong 00525 */ 00526 { 00527 int f; 00528 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 00529 00530 f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode); 00531 if (f != -1) 00532 { 00533 char pid[PID_ASCII_SIZE]; 00534 00535 (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid()); 00536 (void)write(f, pid, strlen(pid)); 00537 (void)close(f); 00538 00539 /* set mode so that the file is world readable even is umask is 00540 * restrictive 00541 * The file is used by libpcsclite */ 00542 (void)chmod(PCSCLITE_RUN_PID, mode); 00543 } 00544 else 00545 Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s", 00546 strerror(errno)); 00547 } 00548 00549 /* 00550 * post initialistion 00551 */ 00552 Init = FALSE; 00553 00554 /* 00555 * Hotplug rescan 00556 */ 00557 (void)signal(SIGUSR1, signal_reload); 00558 00559 /* 00560 * Initialize the comm structure 00561 */ 00562 if (SocketActivated) 00563 rv = ListenExistingSocket(SD_LISTEN_FDS_START + 0); 00564 else 00565 rv = InitializeSocket(); 00566 00567 if (rv) 00568 { 00569 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd."); 00570 at_exit(); 00571 } 00572 00573 /* 00574 * Initialize the contexts structure 00575 */ 00576 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles); 00577 00578 if (rv == -1) 00579 { 00580 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd."); 00581 at_exit(); 00582 } 00583 00584 (void)signal(SIGPIPE, SIG_IGN); 00585 (void)signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent 00586 * when the shell is existed */ 00587 00588 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB) 00589 /* 00590 * Set up the search for USB/PCMCIA devices 00591 */ 00592 rv = HPSearchHotPluggables(); 00593 if (rv) 00594 at_exit(); 00595 00596 rv = HPRegisterForHotplugEvents(); 00597 if (rv) 00598 { 00599 Log1(PCSC_LOG_ERROR, "HPRegisterForHotplugEvents failed"); 00600 at_exit(); 00601 } 00602 00603 RFWaitForReaderInit(); 00604 #endif 00605 00606 /* 00607 * Set up the power management callback routine 00608 */ 00609 (void)PMRegisterForPowerEvents(); 00610 00611 /* initialisation succeeded */ 00612 if (pipefd[1] >= 0) 00613 { 00614 char buf = 0; 00615 00616 /* write a 0 (success) to father process */ 00617 write(pipefd[1], &buf, 1); 00618 close(pipefd[1]); 00619 } 00620 00621 SVCServiceRunLoop(); 00622 00623 Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned"); 00624 return EXIT_FAILURE; 00625 } 00626 00627 static void at_exit(void) 00628 { 00629 Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR); 00630 00631 clean_temp_files(); 00632 00633 if (pipefd[1] >= 0) 00634 { 00635 char buf; 00636 00637 /* write the error code to father process */ 00638 buf = ExitValue; 00639 write(pipefd[1], &buf, 1); 00640 close(pipefd[1]); 00641 } 00642 00643 exit(ExitValue); 00644 } 00645 00646 static void clean_temp_files(void) 00647 { 00648 int rv; 00649 00650 if (!SocketActivated) 00651 { 00652 rv = remove(PCSCLITE_CSOCK_NAME); 00653 if (rv != 0) 00654 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s", 00655 strerror(errno)); 00656 } 00657 00658 rv = remove(PCSCLITE_RUN_PID); 00659 if (rv != 0) 00660 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s", 00661 strerror(errno)); 00662 } 00663 00664 static void signal_reload(/*@unused@*/ int sig) 00665 { 00666 (void)signal(SIGUSR1, signal_reload); 00667 00668 (void)sig; 00669 00670 if (AraKiri) 00671 return; 00672 00673 #ifdef USE_USB 00674 HPReCheckSerialReaders(); 00675 #endif 00676 } /* signal_reload */ 00677 00678 static void signal_trap(int sig) 00679 { 00680 Log2(PCSC_LOG_INFO, "Received signal: %d", sig); 00681 00682 /* do not wait if asked to terminate 00683 * avoids waiting after the reader(s) in shutdown for example */ 00684 if (SIGTERM == sig) 00685 { 00686 Log1(PCSC_LOG_INFO, "Direct suicide"); 00687 at_exit(); 00688 } 00689 00690 if (SIGALRM == sig) 00691 { 00692 /* normal exit without error */ 00693 ExitValue = EXIT_SUCCESS; 00694 } 00695 00696 /* the signal handler is called several times for the same Ctrl-C */ 00697 if (AraKiri == FALSE) 00698 { 00699 Log1(PCSC_LOG_INFO, "Preparing for suicide"); 00700 AraKiri = TRUE; 00701 00702 /* if still in the init/loading phase the AraKiri will not be 00703 * seen by the main event loop 00704 */ 00705 if (Init) 00706 { 00707 Log1(PCSC_LOG_INFO, "Suicide during init"); 00708 at_exit(); 00709 } 00710 } 00711 else 00712 { 00713 /* if pcscd do not want to die */ 00714 static int lives = 2; 00715 00716 lives--; 00717 /* no live left. Something is blocking the normal death. */ 00718 if (0 == lives) 00719 { 00720 Log1(PCSC_LOG_INFO, "Forced suicide"); 00721 at_exit(); 00722 } 00723 } 00724 } 00725 00726 static void print_version (void) 00727 { 00728 printf("%s version %s.\n", PACKAGE, VERSION); 00729 printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n"); 00730 printf("Copyright (C) 2001-2011 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n"); 00731 printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n"); 00732 printf("Report bugs to <muscle@lists.musclecard.com>.\n"); 00733 00734 printf ("Enabled features:%s\n", PCSCLITE_FEATURES); 00735 } 00736 00737 static void print_usage (char const * const progname) 00738 { 00739 printf("Usage: %s options\n", progname); 00740 printf("Options:\n"); 00741 #ifdef HAVE_GETOPT_LONG 00742 printf(" -a, --apdu log APDU commands and results\n"); 00743 printf(" -c, --config path to reader.conf\n"); 00744 printf(" -f, --foreground run in foreground (no daemon),\n"); 00745 printf(" send logs to stdout instead of syslog\n"); 00746 printf(" -T, --color force use of colored logs\n"); 00747 printf(" -h, --help display usage information\n"); 00748 printf(" -H, --hotplug ask the daemon to rescan the available readers\n"); 00749 printf(" -v, --version display the program version number\n"); 00750 printf(" -d, --debug display lower level debug messages\n"); 00751 printf(" --info display info level debug messages\n"); 00752 printf(" -e --error display error level debug messages (default level)\n"); 00753 printf(" -C --critical display critical only level debug messages\n"); 00754 printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n"); 00755 printf(" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS); 00756 printf(" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES); 00757 printf(" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES); 00758 printf(" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE); 00759 #else 00760 printf(" -a log APDU commands and results\n"); 00761 printf(" -c path to reader.conf\n"); 00762 printf(" -f run in foreground (no daemon), send logs to stdout instead of syslog\n"); 00763 printf(" -T force use of colored logs\n"); 00764 printf(" -d display debug messages.\n"); 00765 printf(" -e display error messages (default level).\n"); 00766 printf(" -C display critical messages.\n"); 00767 printf(" -h display usage information\n"); 00768 printf(" -H ask the daemon to rescan the available readers\n"); 00769 printf(" -v display the program version number\n"); 00770 printf(" -t maximum number of threads\n"); 00771 printf(" -s maximum number of card handle per thread\n"); 00772 printf(" -r maximum number of card handle per reader\n"); 00773 printf(" -x pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE); 00774 #endif 00775 } 00776