chiark / gitweb /
gnupg2 (2.1.17-3) unstable; urgency=medium
[gnupg2.git] / tools / ccidmon.c
1 /* ccidmon.c - CCID monitor for use with the Linux usbmon facility.
2  *      Copyright (C) 2009 Free Software Foundation, Inc.
3  *
4  * This file is part of GnuPG.
5  *
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 3 of the License, or
9  * (at your option) any later version.
10  *
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.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, see <https://www.gnu.org/licenses/>.
18  */
19
20
21 /* This utility takes the output of usbmon, filters out the bulk data
22    and prints the CCID messages in a human friendly way.
23
24 */
25
26 #ifdef HAVE_CONFIG_H
27 #include <config.h>
28 #endif
29
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <stddef.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <assert.h>
37 #include <unistd.h>
38 #include <signal.h>
39
40
41 #ifndef PACKAGE_VERSION
42 # define PACKAGE_VERSION "[build on " __DATE__ " " __TIME__ "]"
43 #endif
44 #ifndef PACKAGE_BUGREPORT
45 # define PACKAGE_BUGREPORT "devnull@example.org"
46 #endif
47 #define PGM "ccidmon"
48 #ifndef GNUPG_NAME
49 # define GNUPG_NAME "GnuPG"
50 #endif
51
52 /* Option flags. */
53 static int verbose;
54 static int debug;
55 static int skip_escape;
56 static int usb_bus, usb_dev;
57 static int sniffusb;
58
59
60 /* Error counter.  */
61 static int any_error;
62
63 /* Data storage.  */
64 struct
65 {
66   int is_bi;
67   char address[50];
68   int count;
69   char data[2000];
70 } databuffer;
71
72
73 enum {
74   RDR_to_PC_NotifySlotChange= 0x50,
75   RDR_to_PC_HardwareError   = 0x51,
76
77   PC_to_RDR_SetParameters   = 0x61,
78   PC_to_RDR_IccPowerOn      = 0x62,
79   PC_to_RDR_IccPowerOff     = 0x63,
80   PC_to_RDR_GetSlotStatus   = 0x65,
81   PC_to_RDR_Secure          = 0x69,
82   PC_to_RDR_T0APDU          = 0x6a,
83   PC_to_RDR_Escape          = 0x6b,
84   PC_to_RDR_GetParameters   = 0x6c,
85   PC_to_RDR_ResetParameters = 0x6d,
86   PC_to_RDR_IccClock        = 0x6e,
87   PC_to_RDR_XfrBlock        = 0x6f,
88   PC_to_RDR_Mechanical      = 0x71,
89   PC_to_RDR_Abort           = 0x72,
90   PC_to_RDR_SetDataRate     = 0x73,
91
92   RDR_to_PC_DataBlock       = 0x80,
93   RDR_to_PC_SlotStatus      = 0x81,
94   RDR_to_PC_Parameters      = 0x82,
95   RDR_to_PC_Escape          = 0x83,
96   RDR_to_PC_DataRate        = 0x84
97 };
98
99
100 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
101 #define hexdigitp(a) (digitp (a)                     \
102                       || (*(a) >= 'A' && *(a) <= 'F')  \
103                       || (*(a) >= 'a' && *(a) <= 'f'))
104 #define ascii_isspace(a) ((a)==' ' || (a)=='\n' || (a)=='\r' || (a)=='\t')
105 #define xtoi_1(p)   ((p) <= '9'? ((p)- '0'): \
106                      (p) <= 'F'? ((p)-'A'+10):((p)-'a'+10))
107
108
109
110 /* Print diagnostic message and exit with failure. */
111 static void
112 die (const char *format, ...)
113 {
114   va_list arg_ptr;
115
116   fflush (stdout);
117   fprintf (stderr, "%s: ", PGM);
118
119   va_start (arg_ptr, format);
120   vfprintf (stderr, format, arg_ptr);
121   va_end (arg_ptr);
122   putc ('\n', stderr);
123
124   exit (1);
125 }
126
127
128 /* Print diagnostic message. */
129 static void
130 err (const char *format, ...)
131 {
132   va_list arg_ptr;
133
134   any_error = 1;
135
136   fflush (stdout);
137   fprintf (stderr, "%s: ", PGM);
138
139   va_start (arg_ptr, format);
140   vfprintf (stderr, format, arg_ptr);
141   va_end (arg_ptr);
142   putc ('\n', stderr);
143 }
144
145
146 /* Convert a little endian stored 4 byte value into an unsigned
147    integer. */
148 static unsigned int
149 convert_le_u32 (const unsigned char *buf)
150 {
151   return buf[0] | (buf[1] << 8) | (buf[2] << 16) | ((unsigned int)buf[3] << 24);
152 }
153
154
155 /* Convert a little endian stored 2 byte value into an unsigned
156    integer. */
157 static unsigned int
158 convert_le_u16 (const unsigned char *buf)
159 {
160   return buf[0] | (buf[1] << 8);
161 }
162
163
164
165
166 static void
167 print_pr_data (const unsigned char *data, size_t datalen, size_t off)
168 {
169   int needlf = 0;
170   int first = 1;
171
172   for (; off < datalen; off++)
173     {
174       if (!(off % 16) || first)
175         {
176           if (needlf)
177             putchar ('\n');
178           printf ("  [%04lu] ", (unsigned long)off);
179         }
180       printf (" %02X", data[off]);
181       needlf = 1;
182       first = 0;
183     }
184   if (needlf)
185     putchar ('\n');
186 }
187
188
189 static void
190 print_p2r_header (const char *name, const unsigned char *msg, size_t msglen)
191 {
192   printf ("%s:\n", name);
193   if (msglen < 7)
194     return;
195   printf ("  dwLength ..........: %u\n", convert_le_u32 (msg+1));
196   printf ("  bSlot .............: %u\n", msg[5]);
197   printf ("  bSeq ..............: %u\n", msg[6]);
198 }
199
200
201 static void
202 print_p2r_iccpoweron (const unsigned char *msg, size_t msglen)
203 {
204   print_p2r_header ("PC_to_RDR_IccPowerOn", msg, msglen);
205   if (msglen < 10)
206     return;
207   printf ("  bPowerSelect ......: 0x%02x (%s)\n", msg[7],
208           msg[7] == 0? "auto":
209           msg[7] == 1? "5.0 V":
210           msg[7] == 2? "3.0 V":
211           msg[7] == 3? "1.8 V":"");
212   print_pr_data (msg, msglen, 8);
213 }
214
215
216 static void
217 print_p2r_iccpoweroff (const unsigned char *msg, size_t msglen)
218 {
219   print_p2r_header ("PC_to_RDR_IccPowerOff", msg, msglen);
220   print_pr_data (msg, msglen, 7);
221 }
222
223
224 static void
225 print_p2r_getslotstatus (const unsigned char *msg, size_t msglen)
226 {
227   print_p2r_header ("PC_to_RDR_GetSlotStatus", msg, msglen);
228   print_pr_data (msg, msglen, 7);
229 }
230
231
232 static void
233 print_p2r_xfrblock (const unsigned char *msg, size_t msglen)
234 {
235   unsigned int val;
236
237   print_p2r_header ("PC_to_RDR_XfrBlock", msg, msglen);
238   if (msglen < 10)
239     return;
240   printf ("  bBWI ..............: 0x%02x\n", msg[7]);
241   val = convert_le_u16 (msg+8);
242   printf ("  wLevelParameter ...: 0x%04x%s\n", val,
243           val == 1? " (continued)":
244           val == 2? " (continues+ends)":
245           val == 3? " (continues+continued)":
246           val == 16? " (DataBlock-expected)":"");
247   print_pr_data (msg, msglen, 10);
248 }
249
250
251 static void
252 print_p2r_getparameters (const unsigned char *msg, size_t msglen)
253 {
254   print_p2r_header ("PC_to_RDR_GetParameters", msg, msglen);
255   print_pr_data (msg, msglen, 7);
256 }
257
258
259 static void
260 print_p2r_resetparameters (const unsigned char *msg, size_t msglen)
261 {
262   print_p2r_header ("PC_to_RDR_ResetParameters", msg, msglen);
263   print_pr_data (msg, msglen, 7);
264 }
265
266
267 static void
268 print_p2r_setparameters (const unsigned char *msg, size_t msglen)
269 {
270   print_p2r_header ("PC_to_RDR_SetParameters", msg, msglen);
271   if (msglen < 10)
272     return;
273   printf ("  bProtocolNum ......: 0x%02x\n", msg[7]);
274   print_pr_data (msg, msglen, 8);
275 }
276
277
278 static void
279 print_p2r_escape (const unsigned char *msg, size_t msglen)
280 {
281   if (skip_escape)
282     return;
283   print_p2r_header ("PC_to_RDR_Escape", msg, msglen);
284   print_pr_data (msg, msglen, 7);
285 }
286
287
288 static void
289 print_p2r_iccclock (const unsigned char *msg, size_t msglen)
290 {
291   print_p2r_header ("PC_to_RDR_IccClock", msg, msglen);
292   if (msglen < 10)
293     return;
294   printf ("  bClockCommand .....: 0x%02x\n", msg[7]);
295   print_pr_data (msg, msglen, 8);
296 }
297
298
299 static void
300 print_p2r_to0apdu (const unsigned char *msg, size_t msglen)
301 {
302   print_p2r_header ("PC_to_RDR_T0APDU", msg, msglen);
303   if (msglen < 10)
304     return;
305   printf ("  bmChanges .........: 0x%02x\n", msg[7]);
306   printf ("  bClassGetResponse .: 0x%02x\n", msg[8]);
307   printf ("  bClassEnvelope ....: 0x%02x\n", msg[9]);
308   print_pr_data (msg, msglen, 10);
309 }
310
311
312 static void
313 print_p2r_secure (const unsigned char *msg, size_t msglen)
314 {
315   unsigned int val;
316
317   print_p2r_header ("PC_to_RDR_Secure", msg, msglen);
318   if (msglen < 10)
319     return;
320   printf ("  bBMI ..............: 0x%02x\n", msg[7]);
321   val = convert_le_u16 (msg+8);
322   printf ("  wLevelParameter ...: 0x%04x%s\n", val,
323           val == 1? " (continued)":
324           val == 2? " (continues+ends)":
325           val == 3? " (continues+continued)":
326           val == 16? " (DataBlock-expected)":"");
327   print_pr_data (msg, msglen, 10);
328 }
329
330
331 static void
332 print_p2r_mechanical (const unsigned char *msg, size_t msglen)
333 {
334   print_p2r_header ("PC_to_RDR_Mechanical", msg, msglen);
335   if (msglen < 10)
336     return;
337   printf ("  bFunction .........: 0x%02x\n", msg[7]);
338   print_pr_data (msg, msglen, 8);
339 }
340
341
342 static void
343 print_p2r_abort (const unsigned char *msg, size_t msglen)
344 {
345   print_p2r_header ("PC_to_RDR_Abort", msg, msglen);
346   print_pr_data (msg, msglen, 7);
347 }
348
349
350 static void
351 print_p2r_setdatarate (const unsigned char *msg, size_t msglen)
352 {
353   print_p2r_header ("PC_to_RDR_SetDataRate", msg, msglen);
354   if (msglen < 10)
355     return;
356   print_pr_data (msg, msglen, 7);
357 }
358
359
360 static void
361 print_p2r_unknown (const unsigned char *msg, size_t msglen)
362 {
363   char buf[100];
364
365   snprintf (buf, sizeof buf, "Unknown PC_to_RDR command 0x%02X",
366             msglen? msg[0]:0);
367   print_p2r_header (buf, msg, msglen);
368   if (msglen < 10)
369     return;
370   print_pr_data (msg, msglen, 0);
371 }
372
373
374 static void
375 print_p2r (const unsigned char *msg, size_t msglen)
376 {
377   switch (msglen? msg[0]:0)
378     {
379     case PC_to_RDR_IccPowerOn:
380       print_p2r_iccpoweron (msg, msglen);
381       break;
382     case PC_to_RDR_IccPowerOff:
383       print_p2r_iccpoweroff (msg, msglen);
384       break;
385     case PC_to_RDR_GetSlotStatus:
386       print_p2r_getslotstatus (msg, msglen);
387       break;
388     case PC_to_RDR_XfrBlock:
389       print_p2r_xfrblock (msg, msglen);
390       break;
391     case PC_to_RDR_GetParameters:
392       print_p2r_getparameters (msg, msglen);
393       break;
394     case PC_to_RDR_ResetParameters:
395       print_p2r_resetparameters (msg, msglen);
396       break;
397     case PC_to_RDR_SetParameters:
398       print_p2r_setparameters (msg, msglen);
399       break;
400     case PC_to_RDR_Escape:
401       print_p2r_escape (msg, msglen);
402       break;
403     case PC_to_RDR_IccClock:
404       print_p2r_iccclock (msg, msglen);
405       break;
406     case PC_to_RDR_T0APDU:
407       print_p2r_to0apdu (msg, msglen);
408       break;
409     case PC_to_RDR_Secure:
410       print_p2r_secure (msg, msglen);
411       break;
412     case PC_to_RDR_Mechanical:
413       print_p2r_mechanical (msg, msglen);
414       break;
415     case PC_to_RDR_Abort:
416       print_p2r_abort (msg, msglen);
417       break;
418     case PC_to_RDR_SetDataRate:
419       print_p2r_setdatarate (msg, msglen);
420       break;
421     default:
422       print_p2r_unknown (msg, msglen);
423       break;
424     }
425 }
426
427
428 static void
429 print_r2p_header (const char *name, const unsigned char *msg, size_t msglen)
430 {
431   printf ("%s:\n", name);
432   if (msglen < 9)
433     return;
434   printf ("  dwLength ..........: %u\n", convert_le_u32 (msg+1));
435   printf ("  bSlot .............: %u\n", msg[5]);
436   printf ("  bSeq ..............: %u\n", msg[6]);
437   printf ("  bStatus ...........: %u\n", msg[7]);
438   if (msg[8])
439     printf ("  bError ............: %u\n", msg[8]);
440 }
441
442
443 static void
444 print_r2p_datablock (const unsigned char *msg, size_t msglen)
445 {
446   print_r2p_header ("RDR_to_PC_DataBlock", msg, msglen);
447   if (msglen < 10)
448     return;
449   if (msg[9])
450     printf ("  bChainParameter ...: 0x%02x%s\n", msg[9],
451             msg[9] == 1? " (continued)":
452             msg[9] == 2? " (continues+ends)":
453             msg[9] == 3? " (continues+continued)":
454             msg[9] == 16? " (XferBlock-expected)":"");
455   print_pr_data (msg, msglen, 10);
456 }
457
458
459 static void
460 print_r2p_slotstatus (const unsigned char *msg, size_t msglen)
461 {
462   print_r2p_header ("RDR_to_PC_SlotStatus", msg, msglen);
463   if (msglen < 10)
464     return;
465   printf ("  bClockStatus ......: 0x%02x%s\n", msg[9],
466           msg[9] == 0? " (running)":
467           msg[9] == 1? " (stopped-L)":
468           msg[9] == 2? " (stopped-H)":
469           msg[9] == 3? " (stopped)":"");
470   print_pr_data (msg, msglen, 10);
471 }
472
473
474 static void
475 print_r2p_parameters (const unsigned char *msg, size_t msglen)
476 {
477   print_r2p_header ("RDR_to_PC_Parameters", msg, msglen);
478   if (msglen < 10)
479     return;
480
481   printf ("  protocol ..........: T=%d\n", msg[9]);
482   if (msglen == 17 && msg[9] == 1)
483     {
484       /* Protocol T=1.  */
485       printf ("  bmFindexDindex ....: %02X\n", msg[10]);
486       printf ("  bmTCCKST1 .........: %02X\n", msg[11]);
487       printf ("  bGuardTimeT1 ......: %02X\n", msg[12]);
488       printf ("  bmWaitingIntegersT1: %02X\n", msg[13]);
489       printf ("  bClockStop ........: %02X\n", msg[14]);
490       printf ("  bIFSC .............: %d\n", msg[15]);
491       printf ("  bNadValue .........: %d\n", msg[16]);
492     }
493   else
494     print_pr_data (msg, msglen, 10);
495 }
496
497
498 static void
499 print_r2p_escape (const unsigned char *msg, size_t msglen)
500 {
501   if (skip_escape)
502     return;
503   print_r2p_header ("RDR_to_PC_Escape", msg, msglen);
504   if (msglen < 10)
505     return;
506   printf ("  buffer[9] .........: %02X\n", msg[9]);
507   print_pr_data (msg, msglen, 10);
508 }
509
510
511 static void
512 print_r2p_datarate (const unsigned char *msg, size_t msglen)
513 {
514   print_r2p_header ("RDR_to_PC_DataRate", msg, msglen);
515   if (msglen < 10)
516     return;
517   if (msglen >= 18)
518     {
519       printf ("  dwClockFrequency ..: %u\n", convert_le_u32 (msg+10));
520       printf ("  dwDataRate ..... ..: %u\n", convert_le_u32 (msg+14));
521       print_pr_data (msg, msglen, 18);
522     }
523   else
524     print_pr_data (msg, msglen, 10);
525 }
526
527
528 static void
529 print_r2p_unknown (const unsigned char *msg, size_t msglen)
530 {
531   char buf[100];
532
533   snprintf (buf, sizeof buf, "Unknown RDR_to_PC command 0x%02X",
534             msglen? msg[0]:0);
535   print_r2p_header (buf, msg, msglen);
536   if (msglen < 10)
537     return;
538   printf ("  bMessageType ......: %02X\n", msg[0]);
539   printf ("  buffer[9] .........: %02X\n", msg[9]);
540   print_pr_data (msg, msglen, 10);
541 }
542
543
544 static void
545 print_r2p (const unsigned char *msg, size_t msglen)
546 {
547   switch (msglen? msg[0]:0)
548     {
549     case RDR_to_PC_DataBlock:
550       print_r2p_datablock (msg, msglen);
551       break;
552     case RDR_to_PC_SlotStatus:
553       print_r2p_slotstatus (msg, msglen);
554       break;
555     case RDR_to_PC_Parameters:
556       print_r2p_parameters (msg, msglen);
557       break;
558     case RDR_to_PC_Escape:
559       print_r2p_escape (msg, msglen);
560       break;
561     case RDR_to_PC_DataRate:
562       print_r2p_datarate (msg, msglen);
563       break;
564     default:
565       print_r2p_unknown (msg, msglen);
566       break;
567     }
568
569 }
570
571
572 static void
573 flush_data (void)
574 {
575   if (!databuffer.count)
576     return;
577
578   if (verbose)
579     printf ("Address: %s\n", databuffer.address);
580   if (databuffer.is_bi)
581     {
582       print_r2p (databuffer.data, databuffer.count);
583       if (verbose)
584         putchar ('\n');
585     }
586   else
587     print_p2r (databuffer.data, databuffer.count);
588
589   databuffer.count = 0;
590 }
591
592 static void
593 collect_data (char *hexdata, const char *address, unsigned int lineno)
594 {
595   size_t length;
596   int is_bi;
597   char *s;
598   unsigned int value;
599
600   is_bi = (*address && address[1] == 'i');
601
602   if (databuffer.is_bi != is_bi || strcmp (databuffer.address, address))
603     flush_data ();
604   databuffer.is_bi = is_bi;
605   if (strlen (address) >= sizeof databuffer.address)
606     die ("address field too long");
607   strcpy (databuffer.address, address);
608
609   length = databuffer.count;
610   for (s=hexdata; *s; s++ )
611     {
612       if (ascii_isspace (*s))
613         continue;
614       if (!hexdigitp (s))
615         {
616           err ("invalid hex digit in line %u - line skipped", lineno);
617           break;
618         }
619       value = xtoi_1 (*s) * 16;
620       s++;
621       if (!hexdigitp (s))
622         {
623           err ("invalid hex digit in line %u - line skipped", lineno);
624           break;
625         }
626       value += xtoi_1 (*s);
627
628       if (length >= sizeof (databuffer.data))
629         {
630           err ("too much data at line %u - can handle only up to % bytes",
631                lineno, sizeof (databuffer.data));
632           break;
633         }
634       databuffer.data[length++] = value;
635     }
636   databuffer.count = length;
637 }
638
639
640 static void
641 parse_line (char *line, unsigned int lineno)
642 {
643   char *p;
644   char *event_type, *address, *data, *status, *datatag;
645
646   if (debug)
647     printf ("line[%u] ='%s'\n", lineno, line);
648
649   p = strtok (line, " ");
650   if (!p)
651     die ("invalid line %d (no URB)");
652   p = strtok (NULL, " ");
653   if (!p)
654     die ("invalid line %d (no timestamp)");
655   event_type = strtok (NULL, " ");
656   if (!event_type)
657     die ("invalid line %d (no event type)");
658   address = strtok (NULL, " ");
659   if (!address)
660     die ("invalid line %d (no address");
661   if (usb_bus || usb_dev)
662     {
663       int bus, dev;
664
665       p = strchr (address, ':');
666       if (!p)
667         die ("invalid line %d (invalid address");
668       p++;
669       bus = atoi (p);
670       p = strchr (p, ':');
671       if (!p)
672         die ("invalid line %d (invalid address");
673       p++;
674       dev = atoi (p);
675
676       if ((usb_bus && usb_bus != bus) || (usb_dev && usb_dev != dev))
677         return;  /* We don't want that one.  */
678     }
679   if (*address != 'B' || (address[1] != 'o' && address[1] != 'i'))
680     return; /* We only want block in and block out.  */
681   status = strtok (NULL, " ");
682   if (!status)
683     return;
684   if (!strchr ("-0123456789", *status))
685     return; /* Setup packet.  */
686   /* We don't support "Z[io]" types thus we don't need to check here.  */
687   p = strtok (NULL, " ");
688   if (!p)
689     return; /* No data length.  */
690
691   datatag = strtok (NULL, " ");
692   if (datatag && *datatag == '=')
693     {
694       data = strtok (NULL, "");
695       collect_data (data?data:"", address, lineno);
696     }
697 }
698
699
700 static void
701 parse_line_sniffusb (char *line, unsigned int lineno)
702 {
703   char *p;
704
705   if (debug)
706     printf ("line[%u] ='%s'\n", lineno, line);
707
708   p = strtok (line, " \t");
709   if (!p)
710     return;
711   p = strtok (NULL, " \t");
712   if (!p)
713     return;
714   p = strtok (NULL, " \t");
715   if (!p)
716     return;
717
718   if (hexdigitp (p+0) && hexdigitp (p+1)
719       && hexdigitp (p+2) && hexdigitp (p+3)
720       && p[4] == ':' && !p[5])
721     {
722       size_t length;
723       unsigned int value;
724
725       length = databuffer.count;
726       while ((p=strtok (NULL, " \t")))
727         {
728           if (!hexdigitp (p+0) || !hexdigitp (p+1))
729             {
730               err ("invalid hex digit in line %u (%s)", lineno,p);
731               break;
732             }
733           value = xtoi_1 (p[0]) * 16 + xtoi_1 (p[1]);
734
735           if (length >= sizeof (databuffer.data))
736             {
737               err ("too much data at line %u - can handle only up to % bytes",
738                    lineno, sizeof (databuffer.data));
739               break;
740             }
741           databuffer.data[length++] = value;
742         }
743       databuffer.count = length;
744
745     }
746   else if (!strcmp (p, "TransferFlags"))
747     {
748       flush_data ();
749
750       *databuffer.address = 0;
751       while ((p=strtok (NULL, " \t(,)")))
752         {
753           if (!strcmp (p, "USBD_TRANSFER_DIRECTION_IN"))
754             {
755               databuffer.is_bi = 1;
756               break;
757             }
758           else if (!strcmp (p, "USBD_TRANSFER_DIRECTION_OUT"))
759             {
760               databuffer.is_bi = 0;
761               break;
762             }
763         }
764     }
765
766 }
767
768
769 static void
770 parse_input (FILE *fp)
771 {
772   char line[2000];
773   size_t length;
774   unsigned int lineno = 0;
775
776   while (fgets (line, sizeof (line), fp))
777     {
778       lineno++;
779       length = strlen (line);
780       if (length && line[length - 1] == '\n')
781         line[--length] = 0;
782       else
783         err ("line number %u too long or last line not terminated", lineno);
784       if (length && line[length - 1] == '\r')
785         line[--length] = 0;
786       if (sniffusb)
787         parse_line_sniffusb (line, lineno);
788       else
789         parse_line (line, lineno);
790     }
791   flush_data ();
792   if (ferror (fp))
793     err ("error reading input at line %u: %s", lineno, strerror (errno));
794 }
795
796
797 int
798 main (int argc, char **argv)
799 {
800   int last_argc = -1;
801
802   if (argc)
803     {
804       argc--; argv++;
805     }
806   while (argc && last_argc != argc )
807     {
808       last_argc = argc;
809       if (!strcmp (*argv, "--"))
810         {
811           argc--; argv++;
812           break;
813         }
814       else if (!strcmp (*argv, "--version"))
815         {
816           fputs (PGM " (" GNUPG_NAME ") " PACKAGE_VERSION "\n", stdout);
817           exit (0);
818         }
819       else if (!strcmp (*argv, "--help"))
820         {
821           puts ("Usage: " PGM " [BUS:DEV]\n"
822                 "Parse the output of usbmod assuming it is CCID compliant.\n\n"
823                 "  --skip-escape  do not show escape packets\n"
824                 "  --sniffusb     Assume output from Sniffusb.exe\n"
825                 "  --verbose      enable extra informational output\n"
826                 "  --debug        enable additional debug output\n"
827                 "  --help         display this help and exit\n\n"
828                 "Report bugs to " PACKAGE_BUGREPORT ".");
829           exit (0);
830         }
831       else if (!strcmp (*argv, "--verbose"))
832         {
833           verbose = 1;
834           argc--; argv++;
835         }
836       else if (!strcmp (*argv, "--debug"))
837         {
838           verbose = debug = 1;
839           argc--; argv++;
840         }
841       else if (!strcmp (*argv, "--skip-escape"))
842         {
843           skip_escape = 1;
844           argc--; argv++;
845         }
846       else if (!strcmp (*argv, "--sniffusb"))
847         {
848           sniffusb = 1;
849           argc--; argv++;
850         }
851     }
852
853   if (argc && sniffusb)
854     die ("no arguments expected when using --sniffusb\n");
855   else if (argc > 1)
856     die ("usage: " PGM " [BUS:DEV]  (try --help for more information)\n");
857
858   if (argc == 1)
859     {
860       const char *s = strchr (argv[0], ':');
861
862       usb_bus = atoi (argv[0]);
863       if (s)
864         usb_dev =  atoi (s+1);
865       if (usb_bus < 1 || usb_bus > 999 || usb_dev < 1 || usb_dev > 999)
866         die ("invalid bus:dev specified");
867     }
868
869
870   signal (SIGPIPE, SIG_IGN);
871
872   parse_input (stdin);
873
874   return any_error? 1:0;
875 }
876
877
878 /*
879 Local Variables:
880 compile-command: "gcc -Wall -Wno-pointer-sign -g -o ccidmon ccidmon.c"
881 End:
882 */