pcsc-lite
1.7.4
|
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