pcsc-lite 1.9.7
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-2022
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
78_Atomic char 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 = 0; /* 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#ifdef USE_SERIAL
264 char *newReaderConfig = NULL;
265#endif
266 struct stat fStatBuf;
267 int customMaxThreadCounter = 0;
268 int customMaxReaderHandles = 0;
269 int customMaxThreadCardHandles = 0;
270 int opt;
271 int r;
272#ifdef HAVE_GETOPT_LONG
273 int option_index = 0;
274 static struct option long_options[] = {
275 {"config", 1, NULL, 'c'},
276 {"foreground", 0, NULL, 'f'},
277 {"color", 0, NULL, 'T'},
278 {"help", 0, NULL, 'h'},
279 {"version", 0, NULL, 'v'},
280 {"apdu", 0, NULL, 'a'},
281 {"debug", 0, NULL, 'd'},
282 {"info", 0, NULL, 'i'},
283 {"error", 0, NULL, 'e'},
284 {"critical", 0, NULL, 'C'},
285 {"hotplug", 0, NULL, 'H'},
286 {"force-reader-polling", optional_argument, NULL, 0},
287 {"max-thread", 1, NULL, 't'},
288 {"max-card-handle-per-thread", 1, NULL, 's'},
289 {"max-card-handle-per-reader", 1, NULL, 'r'},
290 {"auto-exit", 0, NULL, 'x'},
291 {"reader-name-no-serial", 0, NULL, 'S'},
292 {"reader-name-no-interface", 0, NULL, 'I'},
293 {NULL, 0, NULL, 0}
294 };
295#endif
296#define OPT_STRING "c:fTdhvaieCHt:r:s:xSI"
297
298 setToForeground = FALSE;
299 HotPlug = FALSE;
300
301 /*
302 * test the version
303 */
304 if (strcmp(PCSCLITE_VERSION_NUMBER, VERSION) != 0)
305 {
306 printf("BUILD ERROR: The release version number PCSCLITE_VERSION_NUMBER\n");
307 printf(" in pcsclite.h (%s) does not match the release version number\n",
309 printf(" generated in config.h (%s) (see configure.in).\n", VERSION);
310
311 return EXIT_FAILURE;
312 }
313
314 /* Init the PRNG */
316
317 /*
318 * By default we create a daemon (not connected to any output)
319 * so log to syslog to have error messages.
320 */
321 DebugLogSetLogType(DEBUGLOG_SYSLOG_DEBUG);
322
323 /*
324 * Handle any command line arguments
325 */
326#ifdef HAVE_GETOPT_LONG
327 while ((opt = getopt_long (argc, argv, OPT_STRING, long_options, &option_index)) != -1) {
328#else
329 while ((opt = getopt (argc, argv, OPT_STRING)) != -1) {
330#endif
331 switch (opt) {
332#ifdef HAVE_GETOPT_LONG
333 case 0:
334 if (strcmp(long_options[option_index].name,
335 "force-reader-polling") == 0)
336 HPForceReaderPolling = optarg ? abs(atoi(optarg)) : 1;
337 break;
338#endif
339#ifdef USE_SERIAL
340 case 'c':
341 Log2(PCSC_LOG_INFO, "using new config directory: %s", optarg);
342 newReaderConfig = optarg;
343 break;
344#endif
345
346 case 'f':
347 setToForeground = TRUE;
348 /* debug to stdout instead of default syslog */
349 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
350 Log1(PCSC_LOG_INFO,
351 "pcscd set to foreground with debug send to stdout");
352 break;
353
354 case 'T':
355 DebugLogSetLogType(DEBUGLOG_STDOUT_COLOR_DEBUG);
356 Log1(PCSC_LOG_INFO, "Force colored logs");
357 break;
358
359 case 'd':
360 DebugLogSetLevel(PCSC_LOG_DEBUG);
361 break;
362
363 case 'i':
364 DebugLogSetLevel(PCSC_LOG_INFO);
365 break;
366
367 case 'e':
368 DebugLogSetLevel(PCSC_LOG_ERROR);
369 break;
370
371 case 'C':
372 DebugLogSetLevel(PCSC_LOG_CRITICAL);
373 break;
374
375 case 'h':
376 print_usage (argv[0]);
377 return EXIT_SUCCESS;
378
379 case 'v':
380 print_version ();
381 return EXIT_SUCCESS;
382
383 case 'a':
384 DebugLogSetCategory(DEBUG_CATEGORY_APDU);
385 break;
386
387 case 'H':
388 /* debug to stdout instead of default syslog */
389 DebugLogSetLogType(DEBUGLOG_STDOUT_DEBUG);
390 HotPlug = TRUE;
391 break;
392
393 case 't':
394 customMaxThreadCounter = optarg ? atoi(optarg) : 0;
395 Log2(PCSC_LOG_INFO, "setting customMaxThreadCounter to: %d",
396 customMaxThreadCounter);
397 break;
398
399 case 'r':
400 customMaxReaderHandles = optarg ? atoi(optarg) : 0;
401 Log2(PCSC_LOG_INFO, "setting customMaxReaderHandles to: %d",
402 customMaxReaderHandles);
403 break;
404
405 case 's':
406 customMaxThreadCardHandles = optarg ? atoi(optarg) : 0;
407 Log2(PCSC_LOG_INFO, "setting customMaxThreadCardHandles to: %d",
408 customMaxThreadCardHandles);
409 break;
410
411 case 'x':
412 AutoExit = TRUE;
413 Log2(PCSC_LOG_INFO, "Auto exit after %d seconds of inactivity",
414 TIME_BEFORE_SUICIDE);
415 break;
416
417 case 'S':
418 Add_Serial_In_Name = FALSE;
419 break;
420
421 case 'I':
422 Add_Interface_In_Name = FALSE;
423 break;
424
425 default:
426 print_usage (argv[0]);
427 return EXIT_FAILURE;
428 }
429
430 }
431
432 if (argv[optind])
433 {
434 printf("Unknown option: %s\n", argv[optind]);
435 print_usage(argv[0]);
436 return EXIT_FAILURE;
437 }
438
439#ifdef USE_LIBSYSTEMD
440 /*
441 * Check if systemd passed us any file descriptors
442 */
443 rv = sd_listen_fds(0);
444 if (rv > 1)
445 {
446 Log1(PCSC_LOG_CRITICAL, "Too many file descriptors received");
447 return EXIT_FAILURE;
448 }
449 else
450 {
451 if (rv == 1)
452 {
453 SocketActivated = TRUE;
454 Log1(PCSC_LOG_INFO, "Started by systemd");
455 }
456 else
457 SocketActivated = FALSE;
458 }
459#endif
460
461 /*
462 * test the presence of /var/run/pcscd/pcscd.comm
463 */
464
465 rv = stat(PCSCLITE_CSOCK_NAME, &fStatBuf);
466
467 /* if the file exist and pcscd was _not_ started by systemd */
468 if (rv == 0 && !SocketActivated)
469 {
470 pid_t pid;
471
472 /* read the pid file to get the old pid and test if the old pcscd is
473 * still running
474 */
475 pid = GetDaemonPid();
476
477 if (pid != -1)
478 {
479 if (HotPlug)
480 return SendHotplugSignal();
481
482 rv = kill(pid, 0);
483 if (0 == rv)
484 {
485 Log1(PCSC_LOG_CRITICAL,
486 "file " PCSCLITE_CSOCK_NAME " already exists.");
487 Log2(PCSC_LOG_CRITICAL,
488 "Another pcscd (pid: %ld) seems to be running.", (long)pid);
489 return EXIT_FAILURE;
490 }
491 else
492 if (ESRCH == errno)
493 {
494 /* the old pcscd is dead. make some cleanup */
495 clean_temp_files();
496 }
497 else
498 {
499 /* permission denied or other error */
500 Log2(PCSC_LOG_CRITICAL, "kill failed: %s", strerror(errno));
501 return EXIT_FAILURE;
502 }
503 }
504 else
505 {
506 if (HotPlug)
507 {
508 Log1(PCSC_LOG_CRITICAL, "file " PCSCLITE_RUN_PID " do not exist");
509 Log1(PCSC_LOG_CRITICAL, "Hotplug failed");
510 return EXIT_FAILURE;
511 }
512 }
513 }
514 else
515 if (HotPlug)
516 {
517 Log1(PCSC_LOG_CRITICAL, "Hotplug failed: pcscd is not running");
518 return EXIT_FAILURE;
519 }
520
521 /* like in daemon(3): changes the current working directory to the
522 * root ("/") */
523 r = chdir("/");
524 if (r < 0)
525 {
526 Log2(PCSC_LOG_CRITICAL, "chdir() failed: %s", strerror(errno));
527 return EXIT_FAILURE;
528 }
529
530 /*
531 * If this is set to one the user has asked it not to fork
532 */
533 if (!setToForeground)
534 {
535 int pid;
536 int fd;
537
538 if (pipe(pipefd) == -1)
539 {
540 Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
541 return EXIT_FAILURE;
542 }
543
544 pid = fork();
545 if (-1 == pid)
546 {
547 Log2(PCSC_LOG_CRITICAL, "fork() failed: %s", strerror(errno));
548 return EXIT_FAILURE;
549 }
550
551 /* like in daemon(3): redirect standard input, standard output
552 * and standard error to /dev/null */
553 fd = open("/dev/null", O_RDWR);
554 if (fd != -1)
555 {
556 dup2(fd, STDIN_FILENO);
557 dup2(fd, STDOUT_FILENO);
558 dup2(fd, STDERR_FILENO);
559
560 /* do not close stdin, stdout or stderr */
561 if (fd > 2)
562 close(fd);
563 }
564
565 if (pid)
566 /* in the father */
567 {
568 char buf;
569 int ret;
570
571 /* close write side */
572 close(pipefd[1]);
573
574 /* wait for the son to write the return code */
575 ret = read(pipefd[0], &buf, 1);
576 if (ret <= 0)
577 return 2;
578
579 close(pipefd[0]);
580
581 /* exit code */
582 return buf;
583 }
584 else
585 /* in the son */
586 {
587 /* close read side */
588 close(pipefd[0]);
589 }
590 }
591
592 /*
593 * cleanly remove /var/run/pcscd/files when exiting
594 * signal_trap() does just set a global variable used by the main loop
595 */
596 (void)signal(SIGQUIT, signal_trap);
597 (void)signal(SIGTERM, signal_trap); /* default kill signal & init round 1 */
598 (void)signal(SIGINT, signal_trap); /* sent by Ctrl-C */
599
600 /* exits on SIGALARM to allow pcscd to suicide if not used */
601 (void)signal(SIGALRM, signal_trap);
602
603 if (pipe(signal_handler_fd) == -1)
604 {
605 Log2(PCSC_LOG_CRITICAL, "pipe() failed: %s", strerror(errno));
606 return EXIT_FAILURE;
607 }
608
609 pthread_t signal_handler_thread;
610 rv = pthread_create(&signal_handler_thread, NULL, signal_thread, NULL);
611 if (rv)
612 {
613 Log2(PCSC_LOG_CRITICAL, "pthread_create failed: %s", strerror(rv));
614 return EXIT_FAILURE;
615 }
616
617 /*
618 * If PCSCLITE_IPC_DIR does not exist then create it
619 */
620 {
621 int mode = S_IROTH | S_IXOTH | S_IRGRP | S_IXGRP | S_IRWXU;
622
623 rv = mkdir(PCSCLITE_IPC_DIR, mode);
624 if ((rv != 0) && (errno != EEXIST))
625 {
626 Log2(PCSC_LOG_CRITICAL,
627 "cannot create " PCSCLITE_IPC_DIR ": %s", strerror(errno));
628 return EXIT_FAILURE;
629 }
630
631 /* set mode so that the directory is world readable and
632 * executable even is umask is restrictive
633 * The directory containes files used by libpcsclite */
634 (void)chmod(PCSCLITE_IPC_DIR, mode);
635 }
636
637 /*
638 * Allocate memory for reader structures
639 */
640 rv = RFAllocateReaderSpace(customMaxReaderHandles);
641 if (SCARD_S_SUCCESS != rv)
642 at_exit();
643
644#ifdef USE_SERIAL
645 /*
646 * Grab the information from the reader.conf files
647 */
648 if (newReaderConfig)
649 {
650 rv = RFStartSerialReaders(newReaderConfig);
651 if (rv != 0)
652 {
653 Log3(PCSC_LOG_CRITICAL, "invalid directory %s: %s", newReaderConfig,
654 strerror(errno));
655 at_exit();
656 }
657 }
658 else
659 {
660 rv = RFStartSerialReaders(PCSCLITE_CONFIG_DIR);
661 if (rv == -1)
662 at_exit();
663 }
664#endif
665
666 Log1(PCSC_LOG_INFO, "pcsc-lite " VERSION " daemon ready.");
667
668 /*
669 * Record our pid to make it easier
670 * to kill the correct pcscd
671 *
672 * Do not fork after this point or the stored pid will be wrong
673 */
674 {
675 int f;
676 int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
677
678 f = open(PCSCLITE_RUN_PID, O_RDWR | O_CREAT, mode);
679 if (f != -1)
680 {
681 char pid[PID_ASCII_SIZE];
682 ssize_t rr;
683
684 (void)snprintf(pid, sizeof(pid), "%u\n", (unsigned) getpid());
685 rr = write(f, pid, strlen(pid) + 1);
686 if (rr < 0)
687 {
688 Log2(PCSC_LOG_CRITICAL,
689 "writing " PCSCLITE_RUN_PID " failed: %s",
690 strerror(errno));
691 }
692
693 /* set mode so that the file is world readable even is umask is
694 * restrictive
695 * The file is used by libpcsclite */
696 (void)fchmod(f, mode);
697
698 (void)close(f);
699 }
700 else
701 Log2(PCSC_LOG_CRITICAL, "cannot create " PCSCLITE_RUN_PID ": %s",
702 strerror(errno));
703 }
704
705 /*
706 * post initialization
707 */
708 Init = FALSE;
709
710 /*
711 * Hotplug rescan
712 */
713 (void)signal(SIGUSR1, signal_trap);
714
715 /*
716 * Initialize the comm structure
717 */
718#ifdef USE_LIBSYSTEMD
719 if (SocketActivated)
720 rv = ListenExistingSocket(SD_LISTEN_FDS_START + 0);
721 else
722#endif
723 rv = InitializeSocket();
724
725 if (rv)
726 {
727 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
728 at_exit();
729 }
730
731 /*
732 * Initialize the contexts structure
733 */
734 rv = ContextsInitialize(customMaxThreadCounter, customMaxThreadCardHandles);
735
736 if (rv == -1)
737 {
738 Log1(PCSC_LOG_CRITICAL, "Error initializing pcscd.");
739 at_exit();
740 }
741
742 (void)signal(SIGPIPE, SIG_IGN);
743 (void)signal(SIGHUP, SIG_IGN); /* needed for Solaris. The signal is sent
744 * when the shell is exited */
745
746#if !defined(PCSCLITE_STATIC_DRIVER) && defined(USE_USB)
747 /*
748 * Set up the search for USB/PCMCIA devices
749 */
750 rv = HPSearchHotPluggables();
751#ifndef USE_SERIAL
752 if (rv)
753 at_exit();
754#else
755 (void)rv;
756#endif
757
758 rv = HPRegisterForHotplugEvents();
759 if (rv)
760 {
761 Log1(PCSC_LOG_ERROR, "HPRegisterForHotplugEvents failed");
762 at_exit();
763 }
764
765 RFWaitForReaderInit();
766#endif
767
768 /* initialization succeeded */
769 if (pipefd[1] >= 0)
770 {
771 char buf = 0;
772 ssize_t rr;
773
774 /* write a 0 (success) to father process */
775 rr = write(pipefd[1], &buf, 1);
776 if (rr < 0)
777 {
778 Log2(PCSC_LOG_ERROR, "write() failed: %s", strerror(errno));
779 }
780 close(pipefd[1]);
781 pipefd[1] = -1;
782 }
783
784 if (AutoExit)
785 {
786 Log2(PCSC_LOG_DEBUG, "Starting suicide alarm in %d seconds",
787 TIME_BEFORE_SUICIDE);
788 alarm(TIME_BEFORE_SUICIDE);
789 }
790
792
793 Log1(PCSC_LOG_ERROR, "SVCServiceRunLoop returned");
794 return EXIT_FAILURE;
795}
796
797static void at_exit(void)
798{
799 Log1(PCSC_LOG_INFO, "cleaning " PCSCLITE_IPC_DIR);
800
801 clean_temp_files();
802
803 if (pipefd[1] >= 0)
804 {
805 char buf;
806 ssize_t r;
807
808 /* write the error code to father process */
809 buf = ExitValue;
810 r = write(pipefd[1], &buf, 1);
811 if (r < 0)
812 {
813 Log2(PCSC_LOG_ERROR, "write() failed: %s", strerror(errno));
814 }
815 close(pipefd[1]);
816 }
817
818 exit(ExitValue);
819}
820
821static void clean_temp_files(void)
822{
823 int rv;
824
825 if (!SocketActivated)
826 {
827 rv = remove(PCSCLITE_CSOCK_NAME);
828 if (rv != 0)
829 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_CSOCK_NAME ": %s",
830 strerror(errno));
831 }
832
833 rv = remove(PCSCLITE_RUN_PID);
834 if (rv != 0)
835 Log2(PCSC_LOG_ERROR, "Cannot remove " PCSCLITE_RUN_PID ": %s",
836 strerror(errno));
837}
838
839static void signal_trap(int sig)
840{
841 int r;
842
843 r = write(signal_handler_fd[1], &sig, sizeof sig);
844 if (r < 0)
845 Log2(PCSC_LOG_ERROR, "write failed: %s", strerror(errno));
846}
847
848static void print_version(void)
849{
850 printf("%s version %s.\n", PACKAGE, VERSION);
851 printf("Copyright (C) 1999-2002 by David Corcoran <corcoran@musclecard.com>.\n");
852 printf("Copyright (C) 2001-2022 by Ludovic Rousseau <ludovic.rousseau@free.fr>.\n");
853 printf("Copyright (C) 2003-2004 by Damien Sauveron <sauveron@labri.fr>.\n");
854 printf("Report bugs to <pcsclite-muscle@lists.infradead.org>.\n");
855
856 printf("Enabled features:%s\n", PCSCLITE_FEATURES);
857 printf("MAX_READERNAME: %d, PCSCLITE_MAX_READERS_CONTEXTS: %d\n",
858 MAX_READERNAME, PCSCLITE_MAX_READERS_CONTEXTS);
859}
860
861static void print_usage(char const * const progname)
862{
863 printf("Usage: %s options\n", progname);
864 printf("Options:\n");
865#ifdef HAVE_GETOPT_LONG
866 printf(" -a, --apdu log APDU commands and results\n");
867#ifdef USE_SERIAL
868 printf(" -c, --config new reader.conf.d path\n");
869#endif
870 printf(" -f, --foreground run in foreground (no daemon),\n");
871 printf(" send logs to stdout instead of syslog\n");
872 printf(" -T, --color force use of colored logs\n");
873 printf(" -h, --help display usage information\n");
874 printf(" -H, --hotplug ask the daemon to rescan the available readers\n");
875 printf(" -v, --version display the program version number\n");
876 printf(" -d, --debug display lower level debug messages\n");
877 printf(" -i, --info display info level debug messages\n");
878 printf(" -e --error display error level debug messages (default level)\n");
879 printf(" -C --critical display critical only level debug messages\n");
880 printf(" --force-reader-polling ignore the IFD_GENERATE_HOTPLUG reader capability\n");
881 printf(" -t, --max-thread maximum number of threads (default %d)\n", PCSC_MAX_CONTEXT_THREADS);
882 printf(" -s, --max-card-handle-per-thread maximum number of card handle per thread (default: %d)\n", PCSC_MAX_CONTEXT_CARD_HANDLES);
883 printf(" -r, --max-card-handle-per-reader maximum number of card handle per reader (default: %d)\n", PCSC_MAX_READER_HANDLES);
884 printf(" -x, --auto-exit pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
885 printf(" -S, --reader-name-no-serial do not include the USB serial number in the name\n");
886 printf(" -I, --reader-name-no-interface do not include the USB interface name in the name\n");
887#else
888 printf(" -a log APDU commands and results\n");
889#ifdef USE_SERIAL
890 printf(" -c new reader.conf.d path\n");
891#endif
892 printf(" -f run in foreground (no daemon), send logs to stdout instead of syslog\n");
893 printf(" -T force use of colored logs\n");
894 printf(" -d display debug messages.\n");
895 printf(" -i display info messages.\n");
896 printf(" -e display error messages (default level).\n");
897 printf(" -C display critical messages.\n");
898 printf(" -h display usage information\n");
899 printf(" -H ask the daemon to rescan the available readers\n");
900 printf(" -v display the program version number\n");
901 printf(" -t maximum number of threads\n");
902 printf(" -s maximum number of card handle per thread\n");
903 printf(" -r maximum number of card handle per reader\n");
904 printf(" -x pcscd will quit after %d seconds of inactivity\n", TIME_BEFORE_SUICIDE);
905#endif
906}
907
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
#define PCSCLITE_MAX_READERS_CONTEXTS
Maximum readers context (a slot is count as a reader)
Definition: pcsclite.h:284
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.