2005-04-15 Marcus Brinkmann <marcus@g10code.de>
[gnupg.git] / scd / pcsc-wrapper.c
blob93e78fdfebc1dee3724b01185e26643a3d27795b
1 /* pcsc-wrapper.c - Wrapper for ccessing the PC/SC service
2 * Copyright (C) 2003, 2004 Free Software Foundation, Inc.
4 * This file is part of GnuPG.
6 * GnuPG is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * GnuPG is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
22 This wrapper is required to handle problems with the libpscslite
23 library. That library assumes that pthreads are used and fails
24 badly if one tries to use it with a procerss using Pth.
26 The operation model is pretty simple: It reads requests from stdin
27 and returns the answer on stdout. There is no direct mapping to the
28 pcsc interface but to a higher level one which resembles the code
29 used in scdaemon (apdu.c) when not using Pth or while running under
30 Windows.
32 The interface is binary consisting of a command tag and the length
33 of the parameter list. The calling process needs to pass the
34 version number of the interface on the command line to make sure
35 that both agree on the same interface. For each port a separate
36 instance of this process needs to be started.
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stddef.h>
46 #include <string.h>
47 #include <errno.h>
48 #include <stdarg.h>
49 #include <assert.h>
50 #include <dlfcn.h>
53 #define PGM "pcsc-wrapper"
55 /* Allow for a standalone build. */
56 #ifdef VERSION
57 #define MYVERSION_LINE PGM " (GnuPG) " VERSION
58 #define BUGREPORT_LINE "\nReport bugs to <bug-gnupg@gnu.org>.\n"
59 #else
60 #define MYVERSION_LINE PGM
61 #define BUGREPORT_LINE ""
62 #endif
64 #define DEFAULT_PCSC_DRIVER "libpcsclite.so"
67 static int verbose;
70 /* PC/SC constants and function pointer. */
71 #define PCSC_SCOPE_USER 0
72 #define PCSC_SCOPE_TERMINAL 1
73 #define PCSC_SCOPE_SYSTEM 2
74 #define PCSC_SCOPE_GLOBAL 3
76 #define PCSC_PROTOCOL_T0 1
77 #define PCSC_PROTOCOL_T1 2
78 #define PCSC_PROTOCOL_RAW 4
80 #define PCSC_SHARE_EXCLUSIVE 1
81 #define PCSC_SHARE_SHARED 2
82 #define PCSC_SHARE_DIRECT 3
84 #define PCSC_LEAVE_CARD 0
85 #define PCSC_RESET_CARD 1
86 #define PCSC_UNPOWER_CARD 2
87 #define PCSC_EJECT_CARD 3
89 #define PCSC_UNKNOWN 0x0001
90 #define PCSC_ABSENT 0x0002 /* Card is absent. */
91 #define PCSC_PRESENT 0x0004 /* Card is present. */
92 #define PCSC_SWALLOWED 0x0008 /* Card is present and electrical connected. */
93 #define PCSC_POWERED 0x0010 /* Card is powered. */
94 #define PCSC_NEGOTIABLE 0x0020 /* Card is awaiting PTS. */
95 #define PCSC_SPECIFIC 0x0040 /* Card is ready for use. */
97 #define PCSC_STATE_UNAWARE 0x0000 /* Want status. */
98 #define PCSC_STATE_IGNORE 0x0001 /* Ignore this reader. */
99 #define PCSC_STATE_CHANGED 0x0002 /* State has changed. */
100 #define PCSC_STATE_UNKNOWN 0x0004 /* Reader unknown. */
101 #define PCSC_STATE_UNAVAILABLE 0x0008 /* Status unavailable. */
102 #define PCSC_STATE_EMPTY 0x0010 /* Card removed. */
103 #define PCSC_STATE_PRESENT 0x0020 /* Card inserted. */
104 #define PCSC_STATE_ATRMATCH 0x0040 /* ATR matches card. */
105 #define PCSC_STATE_EXCLUSIVE 0x0080 /* Exclusive Mode. */
106 #define PCSC_STATE_INUSE 0x0100 /* Shared mode. */
107 #define PCSC_STATE_MUTE 0x0200 /* Unresponsive card. */
109 struct pcsc_io_request_s {
110 unsigned long protocol;
111 unsigned long pci_len;
114 typedef struct pcsc_io_request_s *pcsc_io_request_t;
116 struct pcsc_readerstate_s
118 const char *reader;
119 void *user_data;
120 unsigned long current_state;
121 unsigned long event_state;
122 unsigned long atrlen;
123 unsigned char atr[33];
126 typedef struct pcsc_readerstate_s *pcsc_readerstate_t;
129 static int driver_is_open; /* True if the PC/SC driver has been
130 initialzied and is ready for
131 operations. The following variables
132 are then valid. */
133 static unsigned long pcsc_context; /* The current PC/CS context. */
134 static char *current_rdrname;
135 static unsigned long pcsc_card;
136 static unsigned long pcsc_protocol;
137 static unsigned char current_atr[33];
138 static size_t current_atrlen;
140 long (* pcsc_establish_context) (unsigned long scope,
141 const void *reserved1,
142 const void *reserved2,
143 unsigned long *r_context);
144 long (* pcsc_release_context) (unsigned long context);
145 long (* pcsc_list_readers) (unsigned long context,
146 const char *groups,
147 char *readers, unsigned long*readerslen);
148 long (* pcsc_get_status_change) (unsigned long context,
149 unsigned long timeout,
150 pcsc_readerstate_t readerstates,
151 unsigned long nreaderstates);
152 long (* pcsc_connect) (unsigned long context,
153 const char *reader,
154 unsigned long share_mode,
155 unsigned long preferred_protocols,
156 unsigned long *r_card,
157 unsigned long *r_active_protocol);
158 long (* pcsc_reconnect) (unsigned long card,
159 unsigned long share_mode,
160 unsigned long preferred_protocols,
161 unsigned long initialization,
162 unsigned long *r_active_protocol);
163 long (* pcsc_disconnect) (unsigned long card,
164 unsigned long disposition);
165 long (* pcsc_status) (unsigned long card,
166 char *reader, unsigned long *readerlen,
167 unsigned long *r_state,
168 unsigned long *r_protocol,
169 unsigned char *atr, unsigned long *atrlen);
170 long (* pcsc_begin_transaction) (unsigned long card);
171 long (* pcsc_end_transaction) (unsigned long card);
172 long (* pcsc_transmit) (unsigned long card,
173 const pcsc_io_request_t send_pci,
174 const unsigned char *send_buffer,
175 unsigned long send_len,
176 pcsc_io_request_t recv_pci,
177 unsigned char *recv_buffer,
178 unsigned long *recv_len);
179 long (* pcsc_set_timeout) (unsigned long context,
180 unsigned long timeout);
184 static void
185 bad_request (const char *type)
187 fprintf (stderr, PGM ": bad `%s' request\n", type);
188 exit (1);
191 static void
192 request_failed (int err)
194 if (!err)
195 err = -1;
197 putchar (0x81); /* Simple error/success response. */
199 putchar (0);
200 putchar (0);
201 putchar (0);
202 putchar (4);
204 putchar ((err >> 24) & 0xff);
205 putchar ((err >> 16) & 0xff);
206 putchar ((err >> 8) & 0xff);
207 putchar ((err ) & 0xff);
209 fflush (stdout);
213 static void
214 request_succeeded (const void *buffer, size_t buflen)
216 size_t len;
218 putchar (0x81); /* Simple error/success response. */
220 len = 4 + buflen;
221 putchar ((len >> 24) & 0xff);
222 putchar ((len >> 16) & 0xff);
223 putchar ((len >> 8) & 0xff);
224 putchar ((len ) & 0xff);
226 /* Error code. */
227 putchar (0);
228 putchar (0);
229 putchar (0);
230 putchar (0);
232 /* Optional reponse string. */
233 if (buffer)
234 fwrite (buffer, buflen, 1, stdout);
236 fflush (stdout);
241 static unsigned long
242 read_32 (FILE *fp)
244 int c1, c2, c3, c4;
246 c1 = getc (stdin);
247 c2 = getc (stdin);
248 c3 = getc (stdin);
249 c4 = getc (stdin);
250 if (c1 == EOF || c2 == EOF || c3 == EOF || c4 == EOF)
252 fprintf (stderr, PGM ": premature EOF while parsing request\n");
253 exit (1);
255 return (c1 << 24) | (c2 << 16) | (c3 << 8) | c4;
260 static const char *
261 pcsc_error_string (long err)
263 const char *s;
265 if (!err)
266 return "okay";
267 if ((err & 0x80100000) != 0x80100000)
268 return "invalid PC/SC error code";
269 err &= 0xffff;
270 switch (err)
272 case 0x0002: s = "cancelled"; break;
273 case 0x000e: s = "can't dispose"; break;
274 case 0x0008: s = "insufficient buffer"; break;
275 case 0x0015: s = "invalid ATR"; break;
276 case 0x0003: s = "invalid handle"; break;
277 case 0x0004: s = "invalid parameter"; break;
278 case 0x0005: s = "invalid target"; break;
279 case 0x0011: s = "invalid value"; break;
280 case 0x0006: s = "no memory"; break;
281 case 0x0013: s = "comm error"; break;
282 case 0x0001: s = "internal error"; break;
283 case 0x0014: s = "unknown error"; break;
284 case 0x0007: s = "waited too long"; break;
285 case 0x0009: s = "unknown reader"; break;
286 case 0x000a: s = "timeout"; break;
287 case 0x000b: s = "sharing violation"; break;
288 case 0x000c: s = "no smartcard"; break;
289 case 0x000d: s = "unknown card"; break;
290 case 0x000f: s = "proto mismatch"; break;
291 case 0x0010: s = "not ready"; break;
292 case 0x0012: s = "system cancelled"; break;
293 case 0x0016: s = "not transacted"; break;
294 case 0x0017: s = "reader unavailable"; break;
295 case 0x0065: s = "unsupported card"; break;
296 case 0x0066: s = "unresponsive card"; break;
297 case 0x0067: s = "unpowered card"; break;
298 case 0x0068: s = "reset card"; break;
299 case 0x0069: s = "removed card"; break;
300 case 0x006a: s = "inserted card"; break;
301 case 0x001f: s = "unsupported feature"; break;
302 case 0x0019: s = "PCI too small"; break;
303 case 0x001a: s = "reader unsupported"; break;
304 case 0x001b: s = "duplicate reader"; break;
305 case 0x001c: s = "card unsupported"; break;
306 case 0x001d: s = "no service"; break;
307 case 0x001e: s = "service stopped"; break;
308 default: s = "unknown PC/SC error code"; break;
310 return s;
313 static void
314 load_pcsc_driver (const char *libname)
316 void *handle;
318 handle = dlopen (libname, RTLD_LAZY);
319 if (!handle)
321 fprintf (stderr, PGM ": failed to open driver `%s': %s",
322 libname, dlerror ());
323 exit (1);
326 pcsc_establish_context = dlsym (handle, "SCardEstablishContext");
327 pcsc_release_context = dlsym (handle, "SCardReleaseContext");
328 pcsc_list_readers = dlsym (handle, "SCardListReaders");
329 pcsc_get_status_change = dlsym (handle, "SCardGetStatusChange");
330 pcsc_connect = dlsym (handle, "SCardConnect");
331 pcsc_reconnect = dlsym (handle, "SCardReconnect");
332 pcsc_disconnect = dlsym (handle, "SCardDisconnect");
333 pcsc_status = dlsym (handle, "SCardStatus");
334 pcsc_begin_transaction = dlsym (handle, "SCardBeginTransaction");
335 pcsc_end_transaction = dlsym (handle, "SCardEndTransaction");
336 pcsc_transmit = dlsym (handle, "SCardTransmit");
337 pcsc_set_timeout = dlsym (handle, "SCardSetTimeout");
339 if (!pcsc_establish_context
340 || !pcsc_release_context
341 || !pcsc_list_readers
342 || !pcsc_get_status_change
343 || !pcsc_connect
344 || !pcsc_reconnect
345 || !pcsc_disconnect
346 || !pcsc_status
347 || !pcsc_begin_transaction
348 || !pcsc_end_transaction
349 || !pcsc_transmit
350 /* || !pcsc_set_timeout */)
352 /* Note that set_timeout is currently not used and also not
353 available under Windows. */
354 fprintf (stderr,
355 "apdu_open_reader: invalid PC/SC driver "
356 "(%d%d%d%d%d%d%d%d%d%d%d%d)\n",
357 !!pcsc_establish_context,
358 !!pcsc_release_context,
359 !!pcsc_list_readers,
360 !!pcsc_get_status_change,
361 !!pcsc_connect,
362 !!pcsc_reconnect,
363 !!pcsc_disconnect,
364 !!pcsc_status,
365 !!pcsc_begin_transaction,
366 !!pcsc_end_transaction,
367 !!pcsc_transmit,
368 !!pcsc_set_timeout );
369 dlclose (handle);
370 exit (1);
377 /* Handle a open request. The argument is expected to be a string
378 with the port identification. ARGBUF is always guaranteed to be
379 terminted by a 0 which is not counted in ARGLEN. We may modifiy
380 ARGBUF. */
381 static void
382 handle_open (unsigned char *argbuf, size_t arglen)
384 long err;
385 const char * portstr;
386 char *list = NULL;
387 unsigned long nreader, listlen, atrlen;
388 char *p;
389 unsigned long card_state, card_protocol;
390 unsigned char atr[33];
392 /* Make sure there is only the port string */
393 if (arglen != strlen (argbuf))
394 bad_request ("OPEN");
395 portstr = argbuf;
397 if (driver_is_open)
399 fprintf (stderr, PGM ": PC/SC has already been opened\n");
400 request_failed (-1);
401 return;
404 err = pcsc_establish_context (PCSC_SCOPE_SYSTEM, NULL, NULL, &pcsc_context);
405 if (err)
407 fprintf (stderr, PGM": pcsc_establish_context failed: %s (0x%lx)\n",
408 pcsc_error_string (err), err);
409 request_failed (err);
410 return;
413 err = pcsc_list_readers (pcsc_context, NULL, NULL, &nreader);
414 if (!err)
416 list = malloc (nreader+1); /* Better add 1 for safety reasons. */
417 if (!list)
419 fprintf (stderr, PGM": error allocating memory for reader list\n");
420 exit (1);
422 err = pcsc_list_readers (pcsc_context, NULL, list, &nreader);
424 if (err)
426 fprintf (stderr, PGM": pcsc_list_readers failed: %s (0x%lx)\n",
427 pcsc_error_string (err), err);
428 pcsc_release_context (pcsc_context);
429 free (list);
430 request_failed (err);
431 return;
434 listlen = nreader;
435 p = list;
436 while (nreader)
438 if (!*p && !p[1])
439 break;
440 fprintf (stderr, PGM": detected reader `%s'\n", p);
441 if (nreader < (strlen (p)+1))
443 fprintf (stderr, PGM": invalid response from pcsc_list_readers\n");
444 break;
446 nreader -= strlen (p)+1;
447 p += strlen (p) + 1;
450 current_rdrname = malloc (strlen (portstr && *portstr? portstr:list)+1);
451 if (!current_rdrname)
453 fprintf (stderr, PGM": error allocating memory for reader name\n");
454 exit (1);
456 strcpy (current_rdrname, portstr && *portstr? portstr:list);
457 free (list);
459 err = pcsc_connect (pcsc_context,
460 current_rdrname,
461 PCSC_SHARE_EXCLUSIVE,
462 PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
463 &pcsc_card,
464 &pcsc_protocol);
465 if (err == 0x8010000c) /* No smartcard. */
467 pcsc_card = 0;
469 else if (err)
471 fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
472 pcsc_error_string (err), err);
473 pcsc_release_context (pcsc_context);
474 free (current_rdrname);
475 current_rdrname = NULL;
476 request_failed (err);
477 return;
480 current_atrlen = 0;
481 if (!err)
483 char reader[250];
484 unsigned long readerlen;
486 atrlen = 33;
487 readerlen = sizeof reader -1;
488 err = pcsc_status (pcsc_card,
489 reader, &readerlen,
490 &card_state, &card_protocol,
491 atr, &atrlen);
492 if (err)
493 fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
494 pcsc_error_string (err), err);
495 else
497 if (atrlen >= sizeof atr || atrlen >= sizeof current_atr)
499 fprintf (stderr, PGM": ATR returned by pcsc_status"
500 " is too large\n");
501 exit (4);
503 memcpy (current_atr, atr, atrlen);
504 current_atrlen = atrlen;
508 driver_is_open = 1;
509 request_succeeded (current_atr, current_atrlen);
514 /* Handle a close request. We expect no arguments. We may modifiy
515 ARGBUF. */
516 static void
517 handle_close (unsigned char *argbuf, size_t arglen)
519 if (!driver_is_open)
521 fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
522 request_failed (-1);
523 return;
526 free (current_rdrname);
527 current_rdrname = NULL;
528 pcsc_release_context (pcsc_context);
530 request_succeeded (NULL, 0);
535 /* Handle a status request. We expect no arguments. We may modifiy
536 ARGBUF. */
537 static void
538 handle_status (unsigned char *argbuf, size_t arglen)
540 long err;
541 struct pcsc_readerstate_s rdrstates[1];
542 int status;
543 unsigned char buf[20];
545 if (!driver_is_open)
547 fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
548 request_failed (-1);
549 return;
552 memset (rdrstates, 0, sizeof *rdrstates);
553 rdrstates[0].reader = current_rdrname;
554 rdrstates[0].current_state = PCSC_STATE_UNAWARE;
555 err = pcsc_get_status_change (pcsc_context,
557 rdrstates, 1);
558 if (err == 0x8010000a) /* Timeout. */
559 err = 0;
560 if (err)
562 fprintf (stderr, PGM": pcsc_get_status_change failed: %s (0x%lx)\n",
563 pcsc_error_string (err), err);
564 request_failed (err);
565 return;
568 status = 0;
569 if ( (rdrstates[0].event_state & PCSC_STATE_PRESENT) )
570 status |= 2;
571 if ( !(rdrstates[0].event_state & PCSC_STATE_MUTE) )
572 status |= 4;
573 /* We indicate a useful card if it is not in use by another
574 application. This is because we only use exclusive access
575 mode. */
576 if ( (status & 6) == 6
577 && !(rdrstates[0].event_state & PCSC_STATE_INUSE) )
578 status |= 1;
580 /* First word is identical to the one used by apdu.c. */
581 buf[0] = 0;
582 buf[1] = 0;
583 buf[2] = 0;
584 buf[3] = status;
585 /* The second word is the native PCSC state. */
586 buf[4] = (rdrstates[0].event_state >> 24);
587 buf[5] = (rdrstates[0].event_state >> 16);
588 buf[6] = (rdrstates[0].event_state >> 8);
589 buf[7] = (rdrstates[0].event_state >> 0);
591 request_succeeded (buf, 8);
595 /* Handle a reset request. We expect no arguments. We may modifiy
596 ARGBUF. */
597 static void
598 handle_reset (unsigned char *argbuf, size_t arglen)
600 long err;
601 char reader[250];
602 unsigned long nreader, atrlen;
603 unsigned long card_state, card_protocol;
605 if (!driver_is_open)
607 fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
608 request_failed (-1);
609 return;
612 if (pcsc_card)
614 err = pcsc_disconnect (pcsc_card, PCSC_LEAVE_CARD);
615 if (err)
617 fprintf (stderr, PGM": pcsc_disconnect failed: %s (0x%lx)\n",
618 pcsc_error_string (err), err);
619 request_failed (err);
620 return;
622 pcsc_card = 0;
625 err = pcsc_connect (pcsc_context,
626 current_rdrname,
627 PCSC_SHARE_EXCLUSIVE,
628 PCSC_PROTOCOL_T0|PCSC_PROTOCOL_T1,
629 &pcsc_card,
630 &pcsc_protocol);
631 if (err)
633 fprintf (stderr, PGM": pcsc_connect failed: %s (0x%lx)\n",
634 pcsc_error_string (err), err);
635 pcsc_card = 0;
636 request_failed (err);
637 return;
641 atrlen = 33;
642 nreader = sizeof reader - 1;
643 err = pcsc_status (pcsc_card,
644 reader, &nreader,
645 &card_state, &card_protocol,
646 current_atr, &atrlen);
647 if (err)
649 fprintf (stderr, PGM": pcsc_status failed: %s (0x%lx)\n",
650 pcsc_error_string (err), err);
651 current_atrlen = 0;
652 request_failed (err);
653 return;
656 request_succeeded (current_atr, current_atrlen);
661 /* Handle a transmit request. The argument is expected to be a buffer
662 with the APDU. We may modifiy ARGBUF. */
663 static void
664 handle_transmit (unsigned char *argbuf, size_t arglen)
666 long err;
667 struct pcsc_io_request_s send_pci;
668 unsigned long recv_len;
669 unsigned char buffer[1024];
671 /* The apdu should at least be one byte. */
672 if (!arglen)
673 bad_request ("TRANSMIT");
675 if (!driver_is_open)
677 fprintf (stderr, PGM ": PC/SC has not yet been opened\n");
678 request_failed (-1);
679 return;
681 if ((pcsc_protocol & PCSC_PROTOCOL_T1))
682 send_pci.protocol = PCSC_PROTOCOL_T1;
683 else
684 send_pci.protocol = PCSC_PROTOCOL_T0;
685 send_pci.pci_len = sizeof send_pci;
686 recv_len = sizeof (buffer);
687 err = pcsc_transmit (pcsc_card, &send_pci, argbuf, arglen,
688 NULL, buffer, &recv_len);
689 if (err)
691 if (verbose)
692 fprintf (stderr, PGM": pcsc_transmit failed: %s (0x%lx)\n",
693 pcsc_error_string (err), err);
694 request_failed (err);
695 return;
697 request_succeeded (buffer, recv_len);
702 static void
703 print_version (int with_help)
705 fputs (MYVERSION_LINE "\n"
706 "Copyright (C) 2004 Free Software Foundation, Inc.\n"
707 "This program comes with ABSOLUTELY NO WARRANTY.\n"
708 "This is free software, and you are welcome to redistribute it\n"
709 "under certain conditions. See the file COPYING for details.\n",
710 stdout);
712 if (with_help)
713 fputs ("\n"
714 "Usage: " PGM " [OPTIONS] API-NUMBER [LIBNAME]\n"
715 "Helper to connect scdaemon to the PC/SC library\n"
716 "\n"
717 " --verbose enable extra informational output\n"
718 " --version print version of the program and exit\n"
719 " --help display this help and exit\n"
720 BUGREPORT_LINE, stdout );
722 exit (0);
727 main (int argc, char **argv)
729 int last_argc = -1;
730 int api_number = 0;
731 int c;
733 if (argc)
735 argc--; argv++;
737 while (argc && last_argc != argc )
739 last_argc = argc;
740 if (!strcmp (*argv, "--"))
742 argc--; argv++;
743 break;
745 else if (!strcmp (*argv, "--version"))
746 print_version (0);
747 else if (!strcmp (*argv, "--help"))
748 print_version (1);
749 else if (!strcmp (*argv, "--verbose"))
751 verbose = 1;
752 argc--; argv++;
755 if (argc != 1 && argc != 2)
757 fprintf (stderr, "usage: " PGM " API-NUMBER [LIBNAME]\n");
758 exit (1);
761 api_number = atoi (*argv);
762 argv++; argc--;
763 if (api_number != 1)
765 fprintf (stderr, PGM ": api-number %d is not valid\n", api_number);
766 exit (1);
769 load_pcsc_driver (argc? *argv : DEFAULT_PCSC_DRIVER);
771 while ((c = getc (stdin)) != EOF)
773 size_t arglen;
774 unsigned char argbuffer[2048];
776 arglen = read_32 (stdin);
777 if (arglen >= sizeof argbuffer - 1)
779 fprintf (stderr, PGM ": request too long\n");
780 exit (1);
782 if (arglen && fread (argbuffer, arglen, 1, stdin) != 1)
784 fprintf (stderr, PGM ": error reading request: %s\n",
785 strerror (errno));
786 exit (1);
788 argbuffer[arglen] = 0;
789 switch (c)
791 case 1:
792 handle_open (argbuffer, arglen);
793 break;
795 case 2:
796 handle_close (argbuffer, arglen);
797 exit (0);
798 break;
800 case 3:
801 handle_transmit (argbuffer, arglen);
802 break;
804 case 4:
805 handle_status (argbuffer, arglen);
806 break;
808 case 5:
809 handle_reset (argbuffer, arglen);
810 break;
812 default:
813 fprintf (stderr, PGM ": invalid request 0x%02X\n", c);
814 exit (1);
816 free (argbuffer);
818 return 0;
824 Local Variables:
825 compile-command: "gcc -Wall -g -o pcsc-wrapper pcsc-wrapper.c -ldl"
826 End: