45 #include <sys/types.h> 61 #include "sd-daemon.h" 67 #include "configfile.h" 78 static char Init = TRUE;
80 char SocketActivated = FALSE;
81 static int ExitValue = EXIT_FAILURE;
82 int HPForceReaderPolling = 0;
83 static int pipefd[] = {-1, -1};
84 static int signal_handler_fd[] = {-1, -1};
85 char Add_Serial_In_Name = TRUE;
86 char Add_Interface_In_Name = TRUE;
91 static void at_exit(
void);
92 static void clean_temp_files(
void);
93 static void signal_trap(
int);
94 static void print_version (
void);
95 static void print_usage (
char const *
const);
117 (void)HPStopHotPluggables();
123 EHDeinitializeEventStructures();
124 ContextsDeinitialize();
132 Log2(PCSC_LOG_DEBUG,
"A new context thread creation is requested: %d", dwClientID);
136 Log1(PCSC_LOG_ERROR,
"Problem during the context thread creation");
148 Log1(PCSC_LOG_ERROR,
"Error in ProcessEventsServer");
162 Log2(PCSC_LOG_ERROR,
"ProcessEventsServer unknown retval: %d",
185 r = read(signal_handler_fd[0], &sig,
sizeof sig);
188 Log2(PCSC_LOG_ERROR,
"read failed: %s", strerror(errno));
192 Log2(PCSC_LOG_INFO,
"Received signal: %d", sig);
199 HPReCheckSerialReaders();
203 (void)signal(SIGUSR1, signal_trap);
212 Log1(PCSC_LOG_INFO,
"Direct suicide");
219 ExitValue = EXIT_SUCCESS;
223 if (AraKiri == FALSE)
225 Log1(PCSC_LOG_INFO,
"Preparing for suicide");
233 Log1(PCSC_LOG_INFO,
"Suicide during init");
240 static int lives = 2;
246 Log1(PCSC_LOG_INFO,
"Forced suicide");
256 int main(
int argc,
char **argv)
259 char setToForeground;
261 char *newReaderConfig;
262 struct stat fStatBuf;
263 int customMaxThreadCounter = 0;
264 int customMaxReaderHandles = 0;
265 int customMaxThreadCardHandles = 0;
268 #ifdef HAVE_GETOPT_LONG 269 int option_index = 0;
270 static struct option long_options[] = {
271 {
"config", 1, NULL,
'c'},
272 {
"foreground", 0, NULL,
'f'},
273 {
"color", 0, NULL,
'T'},
274 {
"help", 0, NULL,
'h'},
275 {
"version", 0, NULL,
'v'},
276 {
"apdu", 0, NULL,
'a'},
277 {
"debug", 0, NULL,
'd'},
278 {
"info", 0, NULL, 0},
279 {
"error", 0, NULL,
'e'},
280 {
"critical", 0, NULL,
'C'},
281 {
"hotplug", 0, NULL,
'H'},
282 {
"force-reader-polling", optional_argument, NULL, 0},
283 {
"max-thread", 1, NULL,
't'},
284 {
"max-card-handle-per-thread", 1, NULL,
's'},
285 {
"max-card-handle-per-reader", 1, NULL,
'r'},
286 {
"auto-exit", 0, NULL,
'x'},
287 {
"reader-name-no-serial", 0, NULL,
'S'},
288 {
"reader-name-no-interface", 0, NULL,
'I'},
292 #define OPT_STRING "c:fTdhvaeCHt:r:s:xSI" 294 newReaderConfig = NULL;
295 setToForeground = FALSE;
303 printf(
"BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
304 printf(
" in pcsclite.h (%s) does not match the release version number\n",
306 printf(
" generated in config.h (%s) (see configure.in).\n", VERSION);
318 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
323 #ifdef HAVE_GETOPT_LONG 324 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
326 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
329 #ifdef HAVE_GETOPT_LONG 331 if (strcmp(long_options[option_index].name,
332 "force-reader-polling") == 0)
333 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
337 Log2(PCSC_LOG_INFO,
"using new config file: %s", optarg);
338 newReaderConfig = optarg;
342 setToForeground = TRUE;
344 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
346 "pcscd set to foreground with debug send to stdout");
350 DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
351 Log1(PCSC_LOG_INFO,
"Force colored logs");
355 DebugLogSetLevel(PCSC_LOG_DEBUG);
359 DebugLogSetLevel(PCSC_LOG_ERROR);
363 DebugLogSetLevel(PCSC_LOG_CRITICAL);
367 print_usage (argv[0]);
375 (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
380 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
385 customMaxThreadCounter = optarg ? atoi(optarg) : 0;
386 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCounter to: %d",
387 customMaxThreadCounter);
391 customMaxReaderHandles = optarg ? atoi(optarg) : 0;
392 Log2(PCSC_LOG_INFO,
"setting customMaxReaderHandles to: %d",
393 customMaxReaderHandles);
397 customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
398 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCardHandles to: %d",
399 customMaxThreadCardHandles);
404 Log2(PCSC_LOG_INFO,
"Auto exit after %d seconds of inactivity",
405 TIME_BEFORE_SUICIDE);
409 Add_Serial_In_Name = FALSE;
413 Add_Interface_In_Name = FALSE;
417 print_usage (argv[0]);
425 printf(
"Unknown option: %s\n", argv[optind]);
426 print_usage(argv[0]);
433 rv = sd_listen_fds(0);
436 Log1(PCSC_LOG_CRITICAL,
"Too many file descriptors received");
443 SocketActivated = TRUE;
444 Log1(PCSC_LOG_INFO,
"Started by systemd");
447 SocketActivated = FALSE;
454 rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
457 if (rv == 0 && !SocketActivated)
464 pid = GetDaemonPid();
469 return SendHotplugSignal();
474 Log1(PCSC_LOG_CRITICAL,
475 "file " PCSCLITE_CSOCK_NAME
" already exists.");
476 Log2(PCSC_LOG_CRITICAL,
477 "Another pcscd (pid: %ld) seems to be running.", (
long)pid);
489 Log2(PCSC_LOG_CRITICAL,
"kill failed: %s", strerror(errno));
497 Log1(PCSC_LOG_CRITICAL,
"file " PCSCLITE_RUN_PID
" do not exist");
498 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed");
506 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed: pcscd is not running");
515 Log2(PCSC_LOG_CRITICAL,
"chdir() failed: %s", strerror(errno));
522 if (!setToForeground)
527 if (pipe(pipefd) == -1)
529 Log2(PCSC_LOG_CRITICAL,
"pipe() failed: %s", strerror(errno));
536 Log2(PCSC_LOG_CRITICAL,
"fork() failed: %s", strerror(errno));
542 fd = open(
"/dev/null", O_RDWR);
545 dup2(fd, STDIN_FILENO);
546 dup2(fd, STDOUT_FILENO);
547 dup2(fd, STDERR_FILENO);
564 ret = read(pipefd[0], &buf, 1);
585 (void)signal(SIGQUIT, signal_trap);
586 (void)signal(SIGTERM, signal_trap);
587 (void)signal(SIGINT, signal_trap);
590 (void)signal(SIGALRM, signal_trap);
592 if (pipe(signal_handler_fd) == -1)
594 Log2(PCSC_LOG_CRITICAL,
"pipe() failed: %s", strerror(errno));
598 pthread_t signal_handler_thread;
599 rv = pthread_create(&signal_handler_thread, NULL,
signal_thread, NULL);
602 Log2(PCSC_LOG_CRITICAL,
"pthread_create failed: %s", strerror(rv));
610 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
612 rv = mkdir(PCSCLITE_IPC_DIR, mode);
613 if ((rv != 0) && (errno != EEXIST))
615 Log2(PCSC_LOG_CRITICAL,
616 "cannot create " PCSCLITE_IPC_DIR
": %s", strerror(errno));
623 (void)chmod(PCSCLITE_IPC_DIR, mode);
629 rv = RFAllocateReaderSpace(customMaxReaderHandles);
639 rv = RFStartSerialReaders(newReaderConfig);
642 Log3(PCSC_LOG_CRITICAL,
"invalid file %s: %s", newReaderConfig,
649 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
655 Log1(PCSC_LOG_INFO,
"pcsc-lite " VERSION
" daemon ready.");
665 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
667 f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
670 char pid[PID_ASCII_SIZE];
673 (void)snprintf(pid,
sizeof(pid),
"%u\n", (unsigned) getpid());
674 rr = write(f, pid, strlen(pid) + 1);
677 Log2(PCSC_LOG_CRITICAL,
678 "writing " PCSCLITE_RUN_PID
" failed: %s",
686 (void)chmod(PCSCLITE_RUN_PID, mode);
689 Log2(PCSC_LOG_CRITICAL,
"cannot create " PCSCLITE_RUN_PID
": %s",
701 (void)signal(SIGUSR1, signal_trap);
713 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
720 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
724 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
728 (void)signal(SIGPIPE, SIG_IGN);
729 (void)signal(SIGHUP, SIG_IGN);
732 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB) 736 rv = HPSearchHotPluggables();
742 rv = HPRegisterForHotplugEvents();
745 Log1(PCSC_LOG_ERROR,
"HPRegisterForHotplugEvents failed");
749 RFWaitForReaderInit();
764 rr = write(pipefd[1], &buf, 1);
767 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
775 Log1(PCSC_LOG_ERROR,
"SVCServiceRunLoop returned");
779 static void at_exit(
void)
781 Log1(PCSC_LOG_INFO,
"cleaning " PCSCLITE_IPC_DIR);
792 r = write(pipefd[1], &buf, 1);
795 Log2(PCSC_LOG_ERROR,
"write() failed: %s", strerror(errno));
803 static void clean_temp_files(
void)
807 if (!SocketActivated)
809 rv =
remove(PCSCLITE_CSOCK_NAME);
811 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_CSOCK_NAME
": %s",
815 rv =
remove(PCSCLITE_RUN_PID);
817 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_RUN_PID
": %s",
821 static void signal_trap(
int sig)
825 r = write(signal_handler_fd[1], &sig,
sizeof sig);
827 Log2(PCSC_LOG_ERROR,
"write failed: %s", strerror(errno));
830 static void print_version (
void)
832 printf(
"%s version %s.\n", PACKAGE, VERSION);
833 printf(
"Copyright (C) 1999-2002 by David Corcoran <corcoran@musclecard.com>.\n");
834 printf(
"Copyright (C) 2001-2015 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
835 printf(
"Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
836 printf(
"Report bugs to <pcsclite-muscle@lists.alioth.debian.org>.\n");
838 printf (
"Enabled features:%s\n", PCSCLITE_FEATURES);
841 static void print_usage (
char const *
const progname)
843 printf(
"Usage: %s options\n", progname);
844 printf(
"Options:\n");
845 #ifdef HAVE_GETOPT_LONG 846 printf(
" -a, --apdu log APDU commands and results\n");
847 printf(
" -c, --config path to reader.conf\n");
848 printf(
" -f, --foreground run in foreground (no daemon),\n");
849 printf(
" send logs to stdout instead of syslog\n");
850 printf(
" -T, --color force use of colored logs\n");
851 printf(
" -h, --help display usage information\n");
852 printf(
" -H, --hotplug ask the daemon to rescan the available readers\n");
853 printf(
" -v, --version display the program version number\n");
854 printf(
" -d, --debug display lower level debug messages\n");
855 printf(
" --info display info level debug messages\n");
856 printf(
" -e --error display error level debug messages (default level)\n");
857 printf(
" -C --critical display critical only level debug messages\n");
858 printf(
" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
859 printf(
" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
860 printf(
" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
861 printf(
" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
862 printf(
" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
863 printf(
" -S, --reader-name-no-serial do not include the USB serial number in the name\n");
864 printf(
" -I, --reader-name-no-interface do not include the USB interface name in the name\n");
866 printf(
" -a log APDU commands and results\n");
867 printf(
" -c path to reader.conf\n");
868 printf(
" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
869 printf(
" -T force use of colored logs\n");
870 printf(
" -d display debug messages.\n");
871 printf(
" -e display error messages (default level).\n");
872 printf(
" -C display critical messages.\n");
873 printf(
" -h display usage information\n");
874 printf(
" -H ask the daemon to rescan the available readers\n");
875 printf(
" -v display the program version number\n");
876 printf(
" -t maximum number of threads\n");
877 printf(
" -s maximum number of card handle per thread\n");
878 printf(
" -r maximum number of card handle per reader\n");
879 printf(
" -x pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
#define SCARD_S_SUCCESS
No error was encountered.
void SYS_InitRandom(void)
Initialize the random generator.
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.
This handles power management routines.
This handles abstract system level calls.
char AutoExit
Represents an Application Context on the Server side.
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
This demarshalls functions over the message queue and keeps track of clients and their handles...
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
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's Message Queue Listener function.
This keeps a list of defines for pcsc-lite.
static void * signal_thread(void *arg)
thread dedicated to handle signals
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.