2
* MUSCLE SmartCard Development ( http://www.linuxnet.com )
4
* Copyright (C) 1999-2005
5
* David Corcoran <corcoran@linuxnet.com>
6
* Ludovic Rousseau <ludovic.rousseau@free.fr>
8
* $Id: pcscdaemon.c 1565 2005-06-27 08:42:33Z rousseau $
13
* @brief This is the main pcscd daemon.
15
* The function \c main() starts up the communication environment.\n
16
* Then an endless loop is calld to look for Client connections. For each
17
* Client connection a call to \c CreateContextThread() is done.
24
#include <sys/types.h>
37
#include "winscard_msg.h"
38
#include "winscard_svc.h"
39
#include "sys_generic.h"
40
#include "thread_generic.h"
42
#include "readerfactory.h"
43
#include "configfile.h"
44
#include "powermgt_generic.h"
52
static char Init = TRUE;
53
extern char ReCheckSerialReaders;
56
* Some internal functions
58
void SVCServiceRunLoop(void);
59
void SVCClientCleanup(psharedSegmentMsg);
61
void clean_temp_files(void);
62
void signal_reload(int sig);
63
void signal_trap(int);
64
void print_version (void);
65
void print_usage (char const * const);
67
PCSCLITE_MUTEX usbNotifierMutex;
70
* Cleans up messages still on the queue when a client dies
72
void SVCClientCleanup(psharedSegmentMsg msgStruct)
75
* May be implemented in future releases
80
* @brief The Server's Message Queue Listener function.
82
* An endless loop calls the function \c SHMProcessEventsServer() to check for
83
* messages sent by clients.
84
* If the message is valid, \c CreateContextThread() is called to serve this
87
void SVCServiceRunLoop(void)
91
DWORD dwClientID; /* Connection ID used to reference the Client */
97
* Initialize the comm structure
99
rsp = SHMInitializeCommonSegment();
103
Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
108
* Initialize the contexts structure
110
rv = ContextsInitialize();
114
Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
119
* Solaris sends a SIGALRM and it is annoying
122
signal(SIGALRM, SIG_IGN);
123
signal(SIGPIPE, SIG_IGN);
124
signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent
125
* when the shell is existed */
128
* This function always returns zero
130
rsp = SYS_MutexInit(&usbNotifierMutex);
133
* Set up the search for USB/PCMCIA devices
135
HPSearchHotPluggables();
136
HPRegisterForHotplugEvents();
139
* Set up the power management callback routine
141
PMRegisterForPowerEvents();
146
switch (rsp = SHMProcessEventsServer(&dwClientID, 0))
150
Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
151
rv = CreateContextThread(&dwClientID);
153
if (rv != SCARD_S_SUCCESS)
155
Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
163
* timeout in SHMProcessEventsServer(): do nothing
164
* this is used to catch the Ctrl-C signal at some time when
165
* nothing else happens
170
/* do not display if we are exiting or re-reading the config */
171
if ((!AraKiri) && (!ReCheckSerialReaders))
172
Log1(PCSC_LOG_ERROR, "Error in SHMProcessEventsServer");
176
Log2(PCSC_LOG_ERROR, "SHMProcessEventsServer unknown retval: %d",
183
/* stop the hotpug thread and waits its exit */
184
HPStopHotPluggables();
187
/* now stop all the drivers */
193
int main(int argc, char **argv)
196
char setToForeground;
197
char *newReaderConfig;
198
struct stat fStatBuf;
200
#ifdef HAVE_GETOPT_LONG
201
int option_index = 0;
202
static struct option long_options[] = {
203
{"config", 1, 0, 'c'},
204
{"foreground", 0, 0, 'f'},
206
{"version", 0, 0, 'v'},
208
{"debug", 0, 0, 'd'},
210
{"error", 0, 0, 'e'},
211
{"critical", 0, 0, 'C'},
218
setToForeground = FALSE;
223
if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
225
printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
226
printf(" in pcsclite.h (%s) does not match the release version number\n",
227
PCSCLITE_VERSION_NUMBER);
228
printf(" generated in config.h (%s) (see configure.in).\n", VERSION);
234
* By default we create a daemon (not connected to any output)
235
* so log to syslog to have error messages.
237
DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
240
* Handle any command line arguments
242
#ifdef HAVE_GETOPT_LONG
243
while ((opt = getopt_long (argc, argv, "c:fdhvaeC", long_options, &option_index)) != -1) {
245
while ((opt = getopt (argc, argv, "c:fdhvaeC")) != -1) {
249
Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
250
newReaderConfig = optarg;
254
setToForeground = TRUE;
255
/* debug to stderr instead of default syslog */
256
DebugLogSetLogType(DEBUGLOG_STDERR_DEBUG);
258
"pcscd set to foreground with debug send to stderr");
262
DebugLogSetLevel(PCSC_LOG_DEBUG);
266
DebugLogSetLevel(PCSC_LOG_ERROR);
270
DebugLogSetLevel(PCSC_LOG_CRITICAL);
274
print_usage (argv[0]);
282
DebugLogSetCategory(DEBUG_CATEGORY_APDU);
286
print_usage (argv[0]);
294
printf("Unknown option: %s\n\n", argv[optind]);
295
print_usage(argv[0]);
300
* test the presence of /var/run/pcsc.pub
303
rv = SYS_Stat(PCSCLITE_PUBSHM_FILE, &fStatBuf);
309
/* read the pid file to get the old pid and test if the old pcscd is
313
/* pids are only 15 bits but 4294967296
314
* (32 bits in case of a new system use it) is on 10 bytes
316
#define PID_ASCII_SIZE 11
317
char pid_ascii[PID_ASCII_SIZE];
320
if ((f = fopen(USE_RUN_PID, "rb")) != NULL)
322
fgets(pid_ascii, PID_ASCII_SIZE, f);
325
pid = atoi(pid_ascii);
327
if (kill(pid, 0) == 0)
329
Log1(PCSC_LOG_CRITICAL,
330
"file " PCSCLITE_PUBSHM_FILE " already exists.");
331
Log2(PCSC_LOG_CRITICAL,
332
"Another pcscd (pid: %d) seems to be running.", pid);
336
/* the old pcscd is dead. make some cleanup */
341
Log1(PCSC_LOG_CRITICAL,
342
"file " PCSCLITE_PUBSHM_FILE " already exists.");
343
Log1(PCSC_LOG_CRITICAL,
344
"Maybe another pcscd is running?");
345
Log1(PCSC_LOG_CRITICAL,
346
"I can't read process pid from " USE_RUN_PID);
347
Log1(PCSC_LOG_CRITICAL,
348
"Remove " PCSCLITE_PUBSHM_FILE " and " PCSCLITE_CSOCK_NAME);
349
Log1(PCSC_LOG_CRITICAL,
350
"if pcscd is not running to clear this message.");
354
Log1(PCSC_LOG_CRITICAL,
355
"file " PCSCLITE_PUBSHM_FILE " already exists.");
356
Log1(PCSC_LOG_CRITICAL,
357
"Maybe another pcscd is running?");
358
Log1(PCSC_LOG_CRITICAL,
359
"Remove " PCSCLITE_PUBSHM_FILE " and " PCSCLITE_CSOCK_NAME);
360
Log1(PCSC_LOG_CRITICAL,
361
"if pcscd is not running to clear this message.");
367
* If this is set to one the user has asked it not to fork
369
if (!setToForeground)
371
if (SYS_Daemon(0, 0))
372
Log2(PCSC_LOG_CRITICAL, "SYS_Daemon() failed: %s",
377
* cleanly remove /tmp/pcsc when exiting
379
signal(SIGQUIT, signal_trap);
380
signal(SIGTERM, signal_trap);
381
signal(SIGINT, signal_trap);
382
signal(SIGHUP, signal_trap);
386
* Record our pid to make it easier
387
* to kill the correct pcscd
392
if ((f = fopen(USE_RUN_PID, "wb")) != NULL)
394
fprintf(f, "%u\n", (unsigned) getpid());
401
* If PCSCLITE_IPC_DIR does not exist then create it
403
rv = SYS_Stat(PCSCLITE_IPC_DIR, &fStatBuf);
406
rv = SYS_Mkdir(PCSCLITE_IPC_DIR, S_ISVTX | S_IRWXO | S_IRWXG | S_IRWXU);
409
Log2(PCSC_LOG_CRITICAL,
410
"cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
415
/* cleanly remove /var/run/pcsc.* files when exiting */
417
Log2(PCSC_LOG_CRITICAL, "atexit() failed: %s", strerror(errno));
420
* Allocate memory for reader structures
422
RFAllocateReaderSpace();
425
* Grab the information from the reader.conf
429
rv = RFStartSerialReaders(newReaderConfig);
432
Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
439
rv = RFStartSerialReaders(PCSCLITE_READER_CONFIG);
445
"warning: no " PCSCLITE_READER_CONFIG " found");
447
* Token error in file
457
* Set the default globals
459
g_rgSCardT0Pci.dwProtocol = SCARD_PROTOCOL_T0;
460
g_rgSCardT1Pci.dwProtocol = SCARD_PROTOCOL_T1;
461
g_rgSCardRawPci.dwProtocol = SCARD_PROTOCOL_RAW;
463
Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
471
* signal_trap() does just set a global variable used by the main loop
473
signal(SIGQUIT, signal_trap);
474
signal(SIGTERM, signal_trap);
475
signal(SIGINT, signal_trap);
476
signal(SIGHUP, signal_trap);
478
signal(SIGUSR1, signal_reload);
482
Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
488
Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
492
SYS_Exit(EXIT_SUCCESS);
495
void clean_temp_files(void)
499
rv = SYS_Unlink(PCSCLITE_PUBSHM_FILE);
501
Log2(PCSC_LOG_ERROR, "Cannot unlink " PCSCLITE_PUBSHM_FILE ": %s",
504
rv = SYS_Unlink(PCSCLITE_CSOCK_NAME);
506
Log2(PCSC_LOG_ERROR, "Cannot unlink " PCSCLITE_CSOCK_NAME ": %s",
510
rv = SYS_Unlink(USE_RUN_PID);
512
Log2(PCSC_LOG_ERROR, "Cannot unlink " USE_RUN_PID ": %s",
517
void signal_reload(int sig)
519
Log1(PCSC_LOG_INFO, "Reload serial configuration");
520
HPReCheckSerialReaders();
521
} /* signal_reload */
523
void signal_trap(int sig)
525
/* the signal handler is called several times for the same Ctrl-C */
526
if (AraKiri == FALSE)
528
Log1(PCSC_LOG_INFO, "Preparing for suicide");
531
/* if still in the init/loading phase the AraKiri will not be
532
* seen by the main event loop
536
Log1(PCSC_LOG_INFO, "Suicide during init");
542
void print_version (void)
544
printf("%s version %s.\n", PACKAGE, VERSION);
545
printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@linuxnet.com>.\n");
546
printf("Copyright (C) 2001-2005 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
547
printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
548
printf("Report bugs to <sclinux@linuxnet.com>.\n");
551
void print_usage (char const * const progname)
553
printf("Usage: %s options\n", progname);
554
printf("Options:\n");
555
#ifdef HAVE_GETOPT_LONG
556
printf(" -a, --apdu log APDU commands and results\n");
557
printf(" -c, --config path to reader.conf\n");
558
printf(" -f, --foreground run in foreground (no daemon),\n");
559
printf(" send logs to stderr instead of syslog\n");
560
printf(" -h, --help display usage information\n");
561
printf(" -v, --version display the program version number\n");
562
printf(" -d, --debug display lower level debug messages\n");
563
printf(" --info display info level debug messages (default level)\n");
564
printf(" -e --error display error level debug messages\n");
565
printf(" -C --critical display critical only level debug messages\n");
567
printf(" -a log APDU commands and results\n");
568
printf(" -c path to reader.conf\n");
569
printf(" -f run in foreground (no daemon), send logs to stderr instead of syslog\n");
570
printf(" -d display debug messages. Output may be:\n");
571
printf(" -h display usage information\n");
572
printf(" -v display the program version number\n");