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