24 #include <sys/types.h>
40 #include "sd-daemon.h"
46 #include "configfile.h"
56 static char Init = TRUE;
58 char SocketActivated = FALSE;
59 static int ExitValue = EXIT_FAILURE;
60 int HPForceReaderPolling = 0;
61 static int pipefd[] = {-1, -1};
66 static void at_exit(
void);
67 static void clean_temp_files(
void);
68 static void signal_reload(
int sig);
69 static void signal_trap(
int);
70 static void print_version (
void);
71 static void print_usage (
char const *
const);
93 Log2(PCSC_LOG_DEBUG,
"A new context thread creation is requested: %d", dwClientID);
97 Log1(PCSC_LOG_ERROR,
"Problem during the context thread creation");
109 Log1(PCSC_LOG_ERROR,
"Error in ProcessEventsServer");
119 Log2(PCSC_LOG_ERROR,
"ProcessEventsServer unknown retval: %d",
128 (void)HPStopHotPluggables();
134 ContextsDeinitialize();
140 int main(
int argc,
char **argv)
143 char setToForeground;
145 char *newReaderConfig;
146 struct stat fStatBuf;
147 int customMaxThreadCounter = 0;
148 int customMaxReaderHandles = 0;
149 int customMaxThreadCardHandles = 0;
151 int limited_rights = FALSE;
152 #ifdef HAVE_GETOPT_LONG
153 int option_index = 0;
154 static struct option long_options[] = {
155 {
"config", 1, NULL,
'c'},
156 {
"foreground", 0, NULL,
'f'},
157 {
"color", 0, NULL,
'T'},
158 {
"help", 0, NULL,
'h'},
159 {
"version", 0, NULL,
'v'},
160 {
"apdu", 0, NULL,
'a'},
161 {
"debug", 0, NULL,
'd'},
162 {
"info", 0, NULL, 0},
163 {
"error", 0, NULL,
'e'},
164 {
"critical", 0, NULL,
'C'},
165 {
"hotplug", 0, NULL,
'H'},
166 {
"force-reader-polling", optional_argument, NULL, 0},
167 {
"max-thread", 1, NULL,
't'},
168 {
"max-card-handle-per-thread", 1, NULL,
's'},
169 {
"max-card-handle-per-reader", 1, NULL,
'r'},
170 {
"auto-exit", 0, NULL,
'x'},
174 #define OPT_STRING "c:fTdhvaeCHt:r:s:x"
176 newReaderConfig = NULL;
177 setToForeground = FALSE;
185 printf(
"BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
186 printf(
" in pcsclite.h (%s) does not match the release version number\n",
188 printf(
" generated in config.h (%s) (see configure.in).\n", VERSION);
197 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
200 limited_rights = (getgid() != getegid()) && (getuid() != 0);
205 #ifdef HAVE_GETOPT_LONG
206 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
208 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
211 #ifdef HAVE_GETOPT_LONG
213 if (strcmp(long_options[option_index].name,
214 "force-reader-polling") == 0)
215 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
221 Log1(PCSC_LOG_CRITICAL,
"Can't use a user specified config file");
224 Log2(PCSC_LOG_INFO,
"using new config file: %s", optarg);
225 newReaderConfig = optarg;
229 setToForeground = TRUE;
231 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
233 "pcscd set to foreground with debug send to stdout");
237 DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
238 Log1(PCSC_LOG_INFO,
"Force colored logs");
242 DebugLogSetLevel(PCSC_LOG_DEBUG);
246 DebugLogSetLevel(PCSC_LOG_ERROR);
250 DebugLogSetLevel(PCSC_LOG_CRITICAL);
254 print_usage (argv[0]);
264 Log1(PCSC_LOG_CRITICAL,
"Can't log APDU (restricted)");
267 (void)DebugLogSetCategory(DEBUG_CATEGORY_APDU);
272 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
277 customMaxThreadCounter = optarg ? atoi(optarg) : 0;
278 if (limited_rights && (customMaxThreadCounter < PCSC_MAX_CONTEXT_THREADS))
279 customMaxThreadCounter = PCSC_MAX_CONTEXT_THREADS;
280 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCounter to: %d",
281 customMaxThreadCounter);
285 customMaxReaderHandles = optarg ? atoi(optarg) : 0;
286 if (limited_rights && (customMaxReaderHandles < PCSC_MAX_READER_HANDLES))
287 customMaxReaderHandles = PCSC_MAX_READER_HANDLES;
288 Log2(PCSC_LOG_INFO,
"setting customMaxReaderHandles to: %d",
289 customMaxReaderHandles);
293 customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
294 if (limited_rights && (customMaxThreadCardHandles < PCSC_MAX_CONTEXT_CARD_HANDLES))
295 customMaxThreadCardHandles = PCSC_MAX_CONTEXT_CARD_HANDLES;
296 Log2(PCSC_LOG_INFO,
"setting customMaxThreadCardHandles to: %d",
297 customMaxThreadCardHandles);
302 Log2(PCSC_LOG_INFO,
"Auto exit after %d seconds of inactivity",
303 TIME_BEFORE_SUICIDE);
307 print_usage (argv[0]);
315 printf(
"Unknown option: %s\n", argv[optind]);
316 print_usage(argv[0]);
323 rv = sd_listen_fds(0);
326 Log1(PCSC_LOG_CRITICAL,
"Too many file descriptors received");
333 SocketActivated = TRUE;
334 Log1(PCSC_LOG_INFO,
"Started by systemd");
337 SocketActivated = FALSE;
344 rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
353 pid = GetDaemonPid();
358 return SendHotplugSignal();
363 Log1(PCSC_LOG_CRITICAL,
364 "file " PCSCLITE_CSOCK_NAME
" already exists.");
365 Log2(PCSC_LOG_CRITICAL,
366 "Another pcscd (pid: %d) seems to be running.", pid);
378 Log2(PCSC_LOG_CRITICAL,
"kill failed: %s", strerror(errno));
386 Log1(PCSC_LOG_CRITICAL,
"file " PCSCLITE_RUN_PID
" do not exist");
387 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed");
395 Log1(PCSC_LOG_CRITICAL,
"Hotplug failed: pcscd is not running");
406 if (!setToForeground)
411 if (pipe(pipefd) == -1)
413 Log2(PCSC_LOG_CRITICAL,
"pipe() failed: %s", strerror(errno));
420 Log2(PCSC_LOG_CRITICAL,
"fork() failed: %s", strerror(errno));
426 fd = open(
"/dev/null", O_RDWR);
429 dup2(fd, STDIN_FILENO);
430 dup2(fd, STDOUT_FILENO);
431 dup2(fd, STDERR_FILENO);
448 ret = read(pipefd[0], &buf, 1);
469 (void)signal(SIGQUIT, signal_trap);
470 (void)signal(SIGTERM, signal_trap);
471 (void)signal(SIGINT, signal_trap);
474 (void)signal(SIGALRM, signal_trap);
480 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
482 rv = mkdir(PCSCLITE_IPC_DIR, mode);
483 if ((rv != 0) && (errno != EEXIST))
485 Log2(PCSC_LOG_CRITICAL,
486 "cannot create " PCSCLITE_IPC_DIR
": %s", strerror(errno));
493 (void)chmod(PCSCLITE_IPC_DIR, mode);
499 rv = RFAllocateReaderSpace(customMaxReaderHandles);
509 rv = RFStartSerialReaders(newReaderConfig);
512 Log3(PCSC_LOG_CRITICAL,
"invalid file %s: %s", newReaderConfig,
519 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
525 Log1(PCSC_LOG_INFO,
"pcsc-lite " VERSION
" daemon ready.");
535 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
537 f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
540 char pid[PID_ASCII_SIZE];
542 (void)snprintf(pid,
sizeof(pid),
"%u\n", (unsigned) getpid());
543 (void)write(f, pid, strlen(pid));
549 (void)chmod(PCSCLITE_RUN_PID, mode);
552 Log2(PCSC_LOG_CRITICAL,
"cannot create " PCSCLITE_RUN_PID
": %s",
564 (void)signal(SIGUSR1, signal_reload);
576 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
583 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
587 Log1(PCSC_LOG_CRITICAL,
"Error initializing pcscd.");
591 (void)signal(SIGPIPE, SIG_IGN);
592 (void)signal(SIGHUP, SIG_IGN);
595 #if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
599 rv = HPSearchHotPluggables();
605 rv = HPRegisterForHotplugEvents();
608 Log1(PCSC_LOG_ERROR,
"HPRegisterForHotplugEvents failed");
612 RFWaitForReaderInit();
626 write(pipefd[1], &buf, 1);
632 Log1(PCSC_LOG_ERROR,
"SVCServiceRunLoop returned");
636 static void at_exit(
void)
638 Log1(PCSC_LOG_INFO,
"cleaning " PCSCLITE_IPC_DIR);
648 write(pipefd[1], &buf, 1);
655 static void clean_temp_files(
void)
659 if (!SocketActivated)
661 rv =
remove(PCSCLITE_CSOCK_NAME);
663 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_CSOCK_NAME
": %s",
667 rv =
remove(PCSCLITE_RUN_PID);
669 Log2(PCSC_LOG_ERROR,
"Cannot remove " PCSCLITE_RUN_PID
": %s",
673 static void signal_reload(
int sig)
675 (void)signal(SIGUSR1, signal_reload);
683 HPReCheckSerialReaders();
687 static void signal_trap(
int sig)
689 Log2(PCSC_LOG_INFO,
"Received signal: %d", sig);
695 Log1(PCSC_LOG_INFO,
"Direct suicide");
702 ExitValue = EXIT_SUCCESS;
706 if (AraKiri == FALSE)
708 Log1(PCSC_LOG_INFO,
"Preparing for suicide");
716 Log1(PCSC_LOG_INFO,
"Suicide during init");
723 static int lives = 2;
729 Log1(PCSC_LOG_INFO,
"Forced suicide");
735 static void print_version (
void)
737 printf(
"%s version %s.\n", PACKAGE, VERSION);
738 printf(
"Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
739 printf(
"Copyright (C) 2001-2011 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
740 printf(
"Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
741 printf(
"Report bugs to <muscle@lists.musclecard.com>.\n");
743 printf (
"Enabled features:%s\n", PCSCLITE_FEATURES);
746 static void print_usage (
char const *
const progname)
748 printf(
"Usage: %s options\n", progname);
749 printf(
"Options:\n");
750 #ifdef HAVE_GETOPT_LONG
751 printf(
" -a, --apdu log APDU commands and results\n");
752 printf(
" -c, --config path to reader.conf\n");
753 printf(
" -f, --foreground run in foreground (no daemon),\n");
754 printf(
" send logs to stdout instead of syslog\n");
755 printf(
" -T, --color force use of colored logs\n");
756 printf(
" -h, --help display usage information\n");
757 printf(
" -H, --hotplug ask the daemon to rescan the available readers\n");
758 printf(
" -v, --version display the program version number\n");
759 printf(
" -d, --debug display lower level debug messages\n");
760 printf(
" --info display info level debug messages\n");
761 printf(
" -e --error display error level debug messages (default level)\n");
762 printf(
" -C --critical display critical only level debug messages\n");
763 printf(
" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
764 printf(
" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
765 printf(
" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
766 printf(
" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
767 printf(
" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
769 printf(
" -a log APDU commands and results\n");
770 printf(
" -c path to reader.conf\n");
771 printf(
" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
772 printf(
" -T force use of colored logs\n");
773 printf(
" -d display debug messages.\n");
774 printf(
" -e display error messages (default level).\n");
775 printf(
" -C display critical messages.\n");
776 printf(
" -h display usage information\n");
777 printf(
" -H ask the daemon to rescan the available readers\n");
778 printf(
" -v display the program version number\n");
779 printf(
" -t maximum number of threads\n");
780 printf(
" -s maximum number of card handle per thread\n");
781 printf(
" -r maximum number of card handle per reader\n");
782 printf(
" -x pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
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...
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.
static void SVCServiceRunLoop(void)
The Server's Message Queue Listener function.
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.
#define SCARD_S_SUCCESS
error codes from http://msdn.microsoft.com/en-us/library/aa924526.aspx