pcsc-lite 1.9.5
pcscdaemon.c
Go to the documentation of this file.
1/*
2 * MUSCLE SmartCard Development ( https://pcsclite.apdu.fr/ )
3 *
4 * Copyright (C) 1999-2002
5 * David Corcoran <corcoran@musclecard.com>
6 * Copyright (C) 2002-2018
7 * Ludovic Rousseau <ludovic.rousseau@free.fr>
8 *
9Redistribution and use in source and binary forms, with or without
10modification, are permitted provided that the following conditions
11are met:
12
131. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
152. Redistributions in binary form must reproduce the above copyright
16 notice, this list of conditions and the following disclaimer in the
17 documentation and/or other materials provided with the distribution.
183. The name of the author may not be used to endorse or promote products
19 derived from this software without specific prior written permission.
20
21THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
42#include "config.h"
43#include <time.h>
44#include <signal.h>
45#include <sys/types.h>
46#include <sys/stat.h>
47#include <fcntl.h>
48#include <errno.h>
49#include <stdio.h>
50#include <unistd.h>
51#include <stdlib.h>
52#include <string.h>
53#ifdef HAVE_GETOPT_H
54#include <getopt.h>
55#endif
56#ifdef USE_LIBSYSTEMD
57#include <systemd/sd-daemon.h>
58#endif
59
60#include "misc.h"
61#include "pcsclite.h"
62#include "pcscd.h"
63#include "debuglog.h"
64#include "winscard_msg.h"
65#include "winscard_svc.h"
66#include "sys_generic.h"
67#include "hotplug.h"
68#include "readerfactory.h"
69#include "configfile.h"
70#include "utils.h"
71#include "eventhandler.h"
72
73#ifndef TRUE
74#define TRUE 1
75#define FALSE 0
76#endif
77
78char AraKiri = FALSE;
79static char Init = TRUE;
80char AutoExit = FALSE;
81char SocketActivated = FALSE;
82static int ExitValue = EXIT_FAILURE;
83int HPForceReaderPolling = 0;
84static int pipefd[] = {-1, -1};
85static int signal_handler_fd[] = {-1, -1};
86char Add_Serial_In_Name = TRUE;
87char Add_Interface_In_Name = TRUE;
88
89/*
90 * Some internal functions
91 */
92static void at_exit(void);
93static void clean_temp_files(void);
94static void signal_trap(int);
95static void print_version(void);
96static void print_usage(char const * const);
97
106static void SVCServiceRunLoop(void)
107{
108 int rsp;
109 LONG rv;
110 uint32_t dwClientID; /* Connection ID used to reference the Client */
111
112 while (TRUE)
113 {
114 if (AraKiri)
115 {
116 /* stop the hotpug thread and waits its exit */
117#ifdef USE_USB
118 (void)HPStopHotPluggables();
119#endif
120 (void)SYS_Sleep(1);
121
122 /* now stop all the drivers */
123 RFCleanupReaders();
124 EHDeinitializeEventStructures();
125 ContextsDeinitialize();
126 at_exit();
127 }
128
129 switch (rsp = ProcessEventsServer(&dwClientID))
130 {
131
132 case 0:
133 Log2(PCSC_LOG_DEBUG, "A new context thread creation is requested: %d", dwClientID);
134 rv = CreateContextThread(&dwClientID);
135
136 if (rv != SCARD_S_SUCCESS)
137 Log1(PCSC_LOG_ERROR, "Problem during the context thread creation");
138 break;
139
140 case 2:
141 /*
142 * timeout in ProcessEventsServer(): do nothing
143 * this is used to catch the Ctrl-C signal at some time when
144 * nothing else happens
145 */
146 break;
147
148 case -1:
149 Log1(PCSC_LOG_ERROR, "Error in ProcessEventsServer");
150 break;
151
152 case -2:
153 /* Nothing to do in case of a syscall interrupted
154 * It happens when SIGUSR1 (reload) or SIGINT (Ctrl-C) is received
155 * We just try again */
156
157 /* we wait a bit so that the signal handler thread can do
158 * its job and set AraKiri if needed */
159 SYS_USleep(1000);
160 break;
161
162 default:
163 Log2(PCSC_LOG_ERROR, "ProcessEventsServer unknown retval: %d",
164 rsp);
165 break;
166 }
167 }
168}
169
177static void *signal_thread(void *arg)
178{
179 (void)arg;
180
181 while (TRUE)
182 {
183 int r;
184 int sig;
185
186 r = read(signal_handler_fd[0], &sig, sizeof sig);
187 if (r < 0)
188 {
189 Log2(PCSC_LOG_ERROR, "read failed: %s", strerror(errno));
190 return NULL;
191 }
192
193 Log2(PCSC_LOG_INFO, "Received signal: %d", sig);
194
195 /* signal for hotplug */
196 if (SIGUSR1 == sig)
197 {
198#ifdef USE_USB
199 if (! AraKiri)
200 HPReCheckSerialReaders();
201#endif
202 /* Reenable the signal handler.
203 * This is needed on Solaris and HPUX. */
204 (void)signal(SIGUSR1, signal_trap);
205
206 continue;
207 }
208
209 /* do not wait if asked to terminate
210 * avoids waiting after the reader(s) in shutdown for example */
211 if (SIGTERM == sig)
212 {
213 Log1(PCSC_LOG_INFO, "Direct suicide");
214 ExitValue = EXIT_SUCCESS;
215 at_exit();
216 }
217
218 if (SIGALRM == sig)
219 {
220 /* normal exit without error */
221 ExitValue = EXIT_SUCCESS;
222 }
223
224 /* the signal handler is called several times for the same Ctrl-C */
225 if (AraKiri == FALSE)
226 {
227 Log1(PCSC_LOG_INFO, "Preparing for suicide");
228 AraKiri = TRUE;
229
230 /* if still in the init/loading phase the AraKiri will not be
231 * seen by the main event loop
232 */
233 if (Init)
234 {
235 Log1(PCSC_LOG_INFO, "Suicide during init");
236 at_exit();
237 }
238 }
239 else
240 {
241 /* if pcscd do not want to die */
242 static int lives = 2;
243
244 lives--;
245 /* no live left. Something is blocking the normal death. */
246 if (0 == lives)
247 {
248 Log1(PCSC_LOG_INFO, "Forced suicide");
249 at_exit();
250 }
251 }
252 }
253
254 return NULL;
255}
256
257
258int main(int argc, char **argv)
259{
260 int rv;
261 char setToForeground;
262 char HotPlug;
263 char *newReaderConfig;
264 struct stat fStatBuf;
265 int customMaxThreadCounter = 0;
266 int customMaxReaderHandles = 0;
267 int customMaxThreadCardHandles = 0;
268 int opt;
269 int r;
270#ifdef HAVE_GETOPT_LONG
271 int option_index = 0;
272 static struct option long_options[] = {
273 {"config", 1, NULL, 'c'},
274 {"foreground", 0, NULL, 'f'},
275 {"color", 0, NULL, 'T'},
276 {"help", 0, NULL, 'h'},
277 {"version", 0, NULL, 'v'},
278 {"apdu", 0, NULL, 'a'},
279 {"debug", 0, NULL, 'd'},
280 {"info", 0, NULL, 'i'},
281 {"error", 0, NULL, 'e'},
282 {"critical", 0, NULL, 'C'},
283 {"hotplug", 0, NULL, 'H'},
284 {"force-reader-polling", optional_argument, NULL, 0},
285 {"max-thread", 1, NULL, 't'},
286 {"max-card-handle-per-thread", 1, NULL, 's'},
287 {"max-card-handle-per-reader", 1, NULL, 'r'},
288 {"auto-exit", 0, NULL, 'x'},
289 {"reader-name-no-serial", 0, NULL, 'S'},
290 {"reader-name-no-interface", 0, NULL, 'I'},
291 {NULL, 0, NULL, 0}
292 };
293#endif
294#define OPT_STRING "c:fTdhvaieCHt:r:s:xSI"
295
296 newReaderConfig = NULL;
297 setToForeground = FALSE;
298 HotPlug = FALSE;
299
300 /*
301 * test the version
302 */
303 if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
304 {
305 printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
306 printf(" in pcsclite.h (%s) does not match the release version number\n",
308 printf(" generated in config.h (%s) (see configure.in).\n", VERSION);
309
310 return EXIT_FAILURE;
311 }
312
313 /* Init the PRNG */
315
316 /*
317 * By default we create a daemon (not connected to any output)
318 * so log to syslog to have error messages.
319 */
320 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
321
322 /*
323 * Handle any command line arguments
324 */
325#ifdef HAVE_GETOPT_LONG
326 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
327#else
328 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
329#endif
330 switch (opt) {
331#ifdef HAVE_GETOPT_LONG
332 case 0:
333 if (strcmp(long_options[option_index].name,
334 "force-reader-polling") == 0)
335 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
336 break;
337#endif
338 case 'c':
339 Log2(PCSC_LOG_INFO, "using new config file: %s", optarg);
340 newReaderConfig = optarg;
341 break;
342
343 case 'f':
344 setToForeground = TRUE;
345 /* debug to stdout instead of default syslog */
346 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
347 Log1(PCSC_LOG_INFO,
348 "pcscd set to foreground with debug send to stdout");
349 break;
350
351 case 'T':
352 DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
353 Log1(PCSC_LOG_INFO, "Force colored logs");
354 break;
355
356 case 'd':
357 DebugLogSetLevel(PCSC_LOG_DEBUG);
358 break;
359
360 case 'i':
361 DebugLogSetLevel(PCSC_LOG_INFO);
362 break;
363
364 case 'e':
365 DebugLogSetLevel(PCSC_LOG_ERROR);
366 break;
367
368 case 'C':
369 DebugLogSetLevel(PCSC_LOG_CRITICAL);
370 break;
371
372 case 'h':
373 print_usage (argv[0]);
374 return EXIT_SUCCESS;
375
376 case 'v':
377 print_version ();
378 return EXIT_SUCCESS;
379
380 case 'a':
381 DebugLogSetCategory(DEBUG_CATEGORY_APDU);
382 break;
383
384 case 'H':
385 /* debug to stdout instead of default syslog */
386 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
387 HotPlug = TRUE;
388 break;
389
390 case 't':
391 customMaxThreadCounter = optarg ? atoi(optarg) : 0;
392 Log2(PCSC_LOG_INFO, "setting customMaxThreadCounter to: %d",
393 customMaxThreadCounter);
394 break;
395
396 case 'r':
397 customMaxReaderHandles = optarg ? atoi(optarg) : 0;
398 Log2(PCSC_LOG_INFO, "setting customMaxReaderHandles to: %d",
399 customMaxReaderHandles);
400 break;
401
402 case 's':
403 customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
404 Log2(PCSC_LOG_INFO, "setting customMaxThreadCardHandles to: %d",
405 customMaxThreadCardHandles);
406 break;
407
408 case 'x':
409 AutoExit = TRUE;
410 Log2(PCSC_LOG_INFO, "Auto exit after %d seconds of inactivity",
411 TIME_BEFORE_SUICIDE);
412 break;
413
414 case 'S':
415 Add_Serial_In_Name = FALSE;
416 break;
417
418 case 'I':
419 Add_Interface_In_Name = FALSE;
420 break;
421
422 default:
423 print_usage (argv[0]);
424 return EXIT_FAILURE;
425 }
426
427 }
428
429 if (argv[optind])
430 {
431 printf("Unknown option: %s\n", argv[optind]);
432 print_usage(argv[0]);
433 return EXIT_FAILURE;
434 }
435
436#ifdef USE_LIBSYSTEMD
437 /*
438 * Check if systemd passed us any file descriptors
439 */
440 rv = sd_listen_fds(0);
441 if (rv > 1)
442 {
443 Log1(PCSC_LOG_CRITICAL, "Too many file descriptors received");
444 return EXIT_FAILURE;
445 }
446 else
447 {
448 if (rv == 1)
449 {
450 SocketActivated = TRUE;
451 Log1(PCSC_LOG_INFO, "Started by systemd");
452 }
453 else
454 SocketActivated = FALSE;
455 }
456#endif
457
458 /*
459 * test the presence of /var/run/pcscd/pcscd.comm
460 */
461
462 rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
463
464 /* if the file exist and pcscd was _not_ started by systemd */
465 if (rv == 0 && !SocketActivated)
466 {
467 pid_t pid;
468
469 /* read the pid file to get the old pid and test if the old pcscd is
470 * still running
471 */
472 pid = GetDaemonPid();
473
474 if (pid != -1)
475 {
476 if (HotPlug)
477 return SendHotplugSignal();
478
479 rv = kill(pid, 0);
480 if (0 == rv)
481 {
482 Log1(PCSC_LOG_CRITICAL,
483 "file " PCSCLITE_CSOCK_NAME " already exists.");
484 Log2(PCSC_LOG_CRITICAL,
485 "Another pcscd (pid: %ld) seems to be running.", (long)pid);
486 return EXIT_FAILURE;
487 }
488 else
489 if (ESRCH == errno)
490 {
491 /* the old pcscd is dead. make some cleanup */
492 clean_temp_files();
493 }
494 else
495 {
496 /* permission denied or other error */
497 Log2(PCSC_LOG_CRITICAL, "kill failed: %s", strerror(errno));
498 return EXIT_FAILURE;
499 }
500 }
501 else
502 {
503 if (HotPlug)
504 {
505 Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist");
506 Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
507 return EXIT_FAILURE;
508 }
509 }
510 }
511 else
512 if (HotPlug)
513 {
514 Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running");
515 return EXIT_FAILURE;
516 }
517
518 /* like in daemon(3): changes the current working directory to the
519 * root ("/") */
520 r = chdir("/");
521 if (r < 0)
522 {
523 Log2(PCSC_LOG_CRITICAL, "chdir() failed: %s", strerror(errno));
524 return EXIT_FAILURE;
525 }
526
527 /*
528 * If this is set to one the user has asked it not to fork
529 */
530 if (!setToForeground)
531 {
532 int pid;
533 int fd;
534
535 if (pipe(pipefd) == -1)
536 {
537 Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
538 return EXIT_FAILURE;
539 }
540
541 pid = fork();
542 if (-1 == pid)
543 {
544 Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
545 return EXIT_FAILURE;
546 }
547
548 /* like in daemon(3): redirect standard input, standard output
549 * and standard error to /dev/null */
550 fd = open("/dev/null", O_RDWR);
551 if (fd != -1)
552 {
553 dup2(fd, STDIN_FILENO);
554 dup2(fd, STDOUT_FILENO);
555 dup2(fd, STDERR_FILENO);
556
557 /* do not close stdin, stdout or stderr */
558 if (fd > 2)
559 close(fd);
560 }
561
562 if (pid)
563 /* in the father */
564 {
565 char buf;
566 int ret;
567
568 /* close write side */
569 close(pipefd[1]);
570
571 /* wait for the son to write the return code */
572 ret = read(pipefd[0], &buf, 1);
573 if (ret <= 0)
574 return 2;
575
576 close(pipefd[0]);
577
578 /* exit code */
579 return buf;
580 }
581 else
582 /* in the son */
583 {
584 /* close read side */
585 close(pipefd[0]);
586 }
587 }
588
589 /*
590 * cleanly remove /var/run/pcscd/files when exiting
591 * signal_trap() does just set a global variable used by the main loop
592 */
593 (void)signal(SIGQUIT, signal_trap);
594 (void)signal(SIGTERM, signal_trap); /* default kill signal & init round 1 */
595 (void)signal(SIGINT, signal_trap); /* sent by Ctrl-C */
596
597 /* exits on SIGALARM to allow pcscd to suicide if not used */
598 (void)signal(SIGALRM, signal_trap);
599
600 if (pipe(signal_handler_fd) == -1)
601 {
602 Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
603 return EXIT_FAILURE;
604 }
605
606 pthread_t signal_handler_thread;
607 rv = pthread_create(&signal_handler_thread, NULL, signal_thread, NULL);
608 if (rv)
609 {
610 Log2(PCSC_LOG_CRITICAL, "pthread_create failed: %s", strerror(rv));
611 return EXIT_FAILURE;
612 }
613
614 /*
615 * If PCSCLITE_IPC_DIR does not exist then create it
616 */
617 {
618 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
619
620 rv = mkdir(PCSCLITE_IPC_DIR, mode);
621 if ((rv != 0) && (errno != EEXIST))
622 {
623 Log2(PCSC_LOG_CRITICAL,
624 "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
625 return EXIT_FAILURE;
626 }
627
628 /* set mode so that the directory is world readable and
629 * executable even is umask is restrictive
630 * The directory containes files used by libpcsclite */
631 (void)chmod(PCSCLITE_IPC_DIR, mode);
632 }
633
634 /*
635 * Allocate memory for reader structures
636 */
637 rv = RFAllocateReaderSpace(customMaxReaderHandles);
638 if (SCARD_S_SUCCESS != rv)
639 at_exit();
640
641#ifdef USE_SERIAL
642 /*
643 * Grab the information from the reader.conf
644 */
645 if (newReaderConfig)
646 {
647 rv = RFStartSerialReaders(newReaderConfig);
648 if (rv != 0)
649 {
650 Log3(PCSC_LOG_CRITICAL, "invalid file %s: %s", newReaderConfig,
651 strerror(errno));
652 at_exit();
653 }
654 }
655 else
656 {
657 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
658 if (rv == -1)
659 at_exit();
660 }
661#endif
662
663 Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
664
665 /*
666 * Record our pid to make it easier
667 * to kill the correct pcscd
668 *
669 * Do not fork after this point or the stored pid will be wrong
670 */
671 {
672 int f;
673 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
674
675 f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
676 if (f != -1)
677 {
678 char pid[PID_ASCII_SIZE];
679 ssize_t rr;
680
681 (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid());
682 rr = write(f, pid, strlen(pid) + 1);
683 if (rr < 0)
684 {
685 Log2(PCSC_LOG_CRITICAL,
686 "writing " PCSCLITE_RUN_PID " failed: %s",
687 strerror(errno));
688 }
689
690 /* set mode so that the file is world readable even is umask is
691 * restrictive
692 * The file is used by libpcsclite */
693 (void)fchmod(f, mode);
694
695 (void)close(f);
696 }
697 else
698 Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s",
699 strerror(errno));
700 }
701
702 /*
703 * post initialization
704 */
705 Init = FALSE;
706
707 /*
708 * Hotplug rescan
709 */
710 (void)signal(SIGUSR1, signal_trap);
711
712 /*
713 * Initialize the comm structure
714 */
715#ifdef USE_LIBSYSTEMD
716 if (SocketActivated)
717 rv = ListenExistingSocket(SD_LISTEN_FDS_START + 0);
718 else
719#endif
720 rv = InitializeSocket();
721
722 if (rv)
723 {
724 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
725 at_exit();
726 }
727
728 /*
729 * Initialize the contexts structure
730 */
731 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
732
733 if (rv == -1)
734 {
735 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
736 at_exit();
737 }
738
739 (void)signal(SIGPIPE, SIG_IGN);
740 (void)signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent
741 * when the shell is exited */
742
743#if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
744 /*
745 * Set up the search for USB/PCMCIA devices
746 */
747 rv = HPSearchHotPluggables();
748#ifndef USE_SERIAL
749 if (rv)
750 at_exit();
751#endif
752
753 rv = HPRegisterForHotplugEvents();
754 if (rv)
755 {
756 Log1(PCSC_LOG_ERROR, "HPRegisterForHotplugEvents failed");
757 at_exit();
758 }
759
760 RFWaitForReaderInit();
761#endif
762
763 /* initialization succeeded */
764 if (pipefd[1] >= 0)
765 {
766 char buf = 0;
767 ssize_t rr;
768
769 /* write a 0 (success) to father process */
770 rr = write(pipefd[1], &buf, 1);
771 if (rr < 0)
772 {
773 Log2(PCSC_LOG_ERROR, "write() failed: %s", strerror(errno));
774 }
775 close(pipefd[1]);
776 pipefd[1] = -1;
777 }
778
779 if (AutoExit)
780 {
781 Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
782 TIME_BEFORE_SUICIDE);
783 alarm(TIME_BEFORE_SUICIDE);
784 }
785
787
788 Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
789 return EXIT_FAILURE;
790}
791
792static void at_exit(void)
793{
794 Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
795
796 clean_temp_files();
797
798 if (pipefd[1] >= 0)
799 {
800 char buf;
801 ssize_t r;
802
803 /* write the error code to father process */
804 buf = ExitValue;
805 r = write(pipefd[1], &buf, 1);
806 if (r < 0)
807 {
808 Log2(PCSC_LOG_ERROR, "write() failed: %s", strerror(errno));
809 }
810 close(pipefd[1]);
811 }
812
813 exit(ExitValue);
814}
815
816static void clean_temp_files(void)
817{
818 int rv;
819
820 if (!SocketActivated)
821 {
822 rv = remove(PCSCLITE_CSOCK_NAME);
823 if (rv != 0)
824 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
825 strerror(errno));
826 }
827
828 rv = remove(PCSCLITE_RUN_PID);
829 if (rv != 0)
830 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
831 strerror(errno));
832}
833
834static void signal_trap(int sig)
835{
836 int r;
837
838 r = write(signal_handler_fd[1], &sig, sizeof sig);
839 if (r < 0)
840 Log2(PCSC_LOG_ERROR, "write failed: %s", strerror(errno));
841}
842
843static void print_version(void)
844{
845 printf("%s version %s.\n", PACKAGE, VERSION);
846 printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@musclecard.com>.\n");
847 printf("Copyright (C) 2001-2018 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
848 printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
849 printf("Report bugs to <pcsclite-muscle@lists.infradead.org>.\n");
850
851 printf ("Enabled features:%s\n", PCSCLITE_FEATURES);
852}
853
854static void print_usage(char const * const progname)
855{
856 printf("Usage: %s options\n", progname);
857 printf("Options:\n");
858#ifdef HAVE_GETOPT_LONG
859 printf(" -a, --apdu log APDU commands and results\n");
860 printf(" -c, --config path to reader.conf\n");
861 printf(" -f, --foreground run in foreground (no daemon),\n");
862 printf(" send logs to stdout instead of syslog\n");
863 printf(" -T, --color force use of colored logs\n");
864 printf(" -h, --help display usage information\n");
865 printf(" -H, --hotplug ask the daemon to rescan the available readers\n");
866 printf(" -v, --version display the program version number\n");
867 printf(" -d, --debug display lower level debug messages\n");
868 printf(" -i, --info display info level debug messages\n");
869 printf(" -e --error display error level debug messages (default level)\n");
870 printf(" -C --critical display critical only level debug messages\n");
871 printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
872 printf(" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
873 printf(" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
874 printf(" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
875 printf(" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
876 printf(" -S, --reader-name-no-serial do not include the USB serial number in the name\n");
877 printf(" -I, --reader-name-no-interface do not include the USB interface name in the name\n");
878#else
879 printf(" -a log APDU commands and results\n");
880 printf(" -c path to reader.conf\n");
881 printf(" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
882 printf(" -T force use of colored logs\n");
883 printf(" -d display debug messages.\n");
884 printf(" -i display info messages.\n");
885 printf(" -e display error messages (default level).\n");
886 printf(" -C display critical messages.\n");
887 printf(" -h display usage information\n");
888 printf(" -H ask the daemon to rescan the available readers\n");
889 printf(" -v display the program version number\n");
890 printf(" -t maximum number of threads\n");
891 printf(" -s maximum number of card handle per thread\n");
892 printf(" -r maximum number of card handle per reader\n");
893 printf(" -x pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
894#endif
895}
896
This handles debugging.
This handles card insertion/removal events, updates ATR, protocol, and status information.
#define SCARD_S_SUCCESS
No error was encountered.
Definition: pcsclite.h:107
This provides a search API for hot pluggble devices.
This keeps a list of defines for pcsc-lite.
static void * signal_thread(void *arg)
thread dedicated to handle signals
Definition: pcscdaemon.c:177
static void SVCServiceRunLoop(void)
The Server's Message Queue Listener function.
Definition: pcscdaemon.c:106
char AutoExit
Represents an Application Context on the Server side.
Definition: pcscdaemon.c:80
This keeps a list of defines for pcsc-lite.
#define PCSCLITE_VERSION_NUMBER
Current version.
Definition: pcsclite.h:282
This keeps track of a list of currently available reader structures.
This handles abstract system level calls.
int SYS_USleep(int)
Makes the current process sleep for some microseconds.
Definition: sys_unix.c:71
void SYS_InitRandom(void)
Initialize the random generator.
Definition: sys_unix.c:111
int SYS_Sleep(int)
Makes the current process sleep for some seconds.
Definition: sys_unix.c:53
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.
INTERNAL int32_t ProcessEventsServer(uint32_t *pdwClientID)
Looks for messages sent by clients.
LONG CreateContextThread(uint32_t *pdwClientID)
Creates threads to handle messages received from Clients.
Definition: winscard_svc.c:171
This demarshalls functions over the message queue and keeps track of clients and their handles.