Fix usage of dlerror to conform to POSIX.
[gnupg.git] / tools / gpgsplit.c
1 /* gpgsplit.c - An OpenPGP packet splitting tool
2  * Copyright (C) 2001, 2002, 2003 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 <http://www.gnu.org/licenses/>.
18  */
19
20 /* 
21  * TODO: Add an option to uncompress packets.  This should come quite handy.
22  */
23
24 #include <config.h>
25 #include <errno.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <unistd.h>
31 #include <assert.h>
32 #ifdef HAVE_DOSISH_SYSTEM
33 # include <fcntl.h> /* for setmode() */
34 #endif
35 #include <zlib.h>
36 #ifdef HAVE_BZIP2
37 #include <bzlib.h>
38 #endif /* HAVE_BZIP2 */
39 #if defined(__riscos__) && defined(USE_ZLIBRISCOS)
40 # include "zlib-riscos.h"
41 #endif
42
43 #define INCLUDED_BY_MAIN_MODULE 1
44 #include "../g10/packet.h"
45 #include "util.h"
46
47 static int opt_verbose;
48 static const char *opt_prefix = "";
49 static int opt_uncompress;
50 static int opt_secret_to_public;
51 static int opt_no_split;
52
53 static void g10_exit( int rc );
54 static void split_packets (const char *fname);
55
56
57 enum cmd_and_opt_values {
58   aNull = 0,
59   oVerbose        = 'v',
60   oPrefix       = 'p',                          
61   oUncompress   = 500,                      
62   oSecretToPublic,                      
63   oNoSplit,
64
65   aTest
66 };
67
68
69 static ARGPARSE_OPTS opts[] = {
70
71     { 301, NULL, 0, "@Options:\n " },
72
73     { oVerbose, "verbose",   0, "verbose" },
74     { oPrefix,  "prefix",    2, "|STRING|Prepend filenames with STRING" },
75     { oUncompress, "uncompress", 0, "uncompress a packet"},
76     { oSecretToPublic, "secret-to-public", 0, "convert secret keys to public keys"},
77     { oNoSplit, "no-split", 0, "write to stdout and don't actually split"},
78 {0} };
79
80
81 const char *
82 strusage( int level )
83 {
84   const char *p;
85   switch (level)
86     {
87     case 11: p = "gpgsplit (GnuPG)";
88       break;
89     case 13: p = VERSION; break;
90     case 17: p = PRINTABLE_OS_NAME; break;
91     case 19: p =
92                "Please report bugs to <bug-gnupg@gnu.org>.\n";
93     break;
94     case 1:
95     case 40:    p =
96                   "Usage: gpgsplit [options] [files] (-h for help)";
97     break;
98     case 41:    p =
99                   "Syntax: gpgsplit [options] [files]\n"
100                   "Split an OpenPGP message into packets\n";
101     break;
102     
103     default:    p = default_strusage(level);
104     }
105   return p;
106 }
107
108
109
110 int
111 main( int argc, char **argv )
112 {
113   ARGPARSE_ARGS pargs;
114
115 #ifdef HAVE_DOSISH_SYSTEM
116   setmode( fileno(stdin), O_BINARY );
117   setmode( fileno(stdout), O_BINARY );
118 #endif
119   log_set_name("gpgsplit");
120   
121   pargs.argc = &argc;
122   pargs.argv = &argv;
123   pargs.flags=  1;  /* do not remove the args */
124   while (optfile_parse( NULL, NULL, NULL, &pargs, opts))
125     {
126       switch (pargs.r_opt)
127         {
128         case oVerbose: opt_verbose = 1; break;
129         case oPrefix: opt_prefix = pargs.r.ret_str; break;
130         case oUncompress: opt_uncompress = 1; break;
131         case oSecretToPublic: opt_secret_to_public = 1; break;
132         case oNoSplit: opt_no_split = 1; break;
133         default : pargs.err = 2; break;
134         }
135     }
136   
137   if (log_get_errorcount(0))
138     g10_exit (2);
139
140   if (!argc)
141     split_packets (NULL);
142   else
143     {
144       for ( ;argc; argc--, argv++) 
145         split_packets (*argv);
146     }
147   
148   g10_exit (0);
149   return 0; 
150 }
151
152
153 static void
154 g10_exit (int rc)
155 {
156   rc = rc? rc : log_get_errorcount(0)? 2 : 0;
157   exit(rc );
158 }
159
160 static const char *
161 pkttype_to_string (int pkttype)
162 {
163   const char *s;
164
165   switch (pkttype)
166     {
167     case PKT_PUBKEY_ENC    : s = "pk_enc"; break;
168     case PKT_SIGNATURE     : s = "sig"; break;
169     case PKT_SYMKEY_ENC    : s = "sym_enc"; break;
170     case PKT_ONEPASS_SIG   : s = "onepass_sig"; break;
171     case PKT_SECRET_KEY    : s = "secret_key"; break;
172     case PKT_PUBLIC_KEY    : s = "public_key"; break;
173     case PKT_SECRET_SUBKEY : s = "secret_subkey"; break;
174     case PKT_COMPRESSED    : 
175       s = opt_uncompress? "uncompressed":"compressed";
176       break;
177     case PKT_ENCRYPTED     : s = "encrypted"; break;
178     case PKT_MARKER            : s = "marker"; break;
179     case PKT_PLAINTEXT     : s = "plaintext"; break;
180     case PKT_RING_TRUST    : s = "ring_trust"; break;
181     case PKT_USER_ID       : s = "user_id"; break;
182     case PKT_PUBLIC_SUBKEY : s = "public_subkey"; break;
183     case PKT_OLD_COMMENT   : s = "old_comment"; break;
184     case PKT_ATTRIBUTE     : s = "attribute"; break;
185     case PKT_ENCRYPTED_MDC : s = "encrypted_mdc"; break;
186     case PKT_MDC               : s = "mdc"; break;
187     case PKT_COMMENT       : s = "comment"; break;
188     case PKT_GPG_CONTROL   : s = "gpg_control"; break;
189     default: s = "unknown"; break;
190     }
191   return s;
192 }
193
194
195 /*
196  * Create a new filename and a return a pointer to a statically
197  * allocated buffer 
198  */
199 static char *
200 create_filename (int pkttype)
201 {
202   static unsigned int partno = 0;
203   static char *name;
204   
205   if (!name) 
206     name = xmalloc (strlen (opt_prefix) + 100 );
207   
208   assert (pkttype < 1000 && pkttype >= 0 );
209   partno++;
210   sprintf (name, "%s%06u-%03d" EXTSEP_S "%.40s",
211            opt_prefix, partno, pkttype, pkttype_to_string (pkttype));
212   return name;
213 }
214
215 static int
216 read_u16 (FILE *fp, size_t *rn)
217 {
218   int c;
219
220   if ( (c = getc (fp)) == EOF )
221     return -1;
222   *rn = c << 8;
223   if ( (c = getc (fp)) == EOF )
224     return -1;
225   *rn |= c;
226   return 0;
227 }
228
229 static int
230 read_u32 (FILE *fp, unsigned long *rn)
231 {
232   size_t tmp;
233   
234   if (read_u16 (fp, &tmp))
235     return -1;
236   *rn = tmp << 16;
237   if (read_u16 (fp, &tmp))
238     return -1;
239   *rn |= tmp;
240   return 0;
241 }
242
243 static int
244 write_old_header (FILE *fp, int pkttype, unsigned int len)
245 {     
246   int ctb = (0x80 | ((pkttype & 15)<<2));
247   
248   if (len < 256)
249     ;
250   else if (len < 65536)
251     ctb |= 1;
252   else
253     ctb |= 2;
254
255   if ( putc ( ctb, fp) == EOF )
256     return -1;
257
258   if ( (ctb & 2) )
259     {
260       if (putc ((len>>24), fp) == EOF)
261         return -1;
262       if (putc ((len>>16), fp) == EOF)
263         return -1;
264     }
265   if ( (ctb & 3) )
266     {
267       if (putc ((len>>8), fp) == EOF)
268         return -1;
269     }
270   if (putc ((len&0xff), fp) == EOF)
271     return -1;
272   return 0;
273 }
274
275 static int
276 write_new_header (FILE *fp, int pkttype, unsigned int len)
277 {     
278   if ( putc ((0xc0 | (pkttype & 0x3f)), fp) == EOF )
279     return -1;
280
281   if (len < 192)
282     {
283       if (putc (len, fp) == EOF)
284         return -1;
285     }
286   else if (len < 8384)
287     {
288       len -= 192;
289       if (putc ((len/256)+192, fp) == EOF)
290         return -1;
291       if (putc ((len%256), fp) == EOF)
292         return -1;
293     }
294   else
295     {
296       if (putc ( 0xff, fp) == EOF)
297         return -1;
298       if (putc ( (len >> 24), fp) == EOF)
299         return -1;
300       if (putc ( (len >> 16), fp) == EOF)
301         return -1;
302       if (putc ( (len >> 8), fp) == EOF)
303         return -1;
304       if (putc ( (len & 0xff), fp) == EOF)
305         return -1;
306     }
307   return 0;
308 }
309
310 /* Return the length of the public key given BUF of BUFLEN with a
311    secret key. */
312 static int
313 public_key_length (const unsigned char *buf, size_t buflen)
314 {
315   const unsigned char *s;
316   int nmpis;
317
318   /*   byte version number (3 or 4)
319        u32  creation time 
320        [u16  valid days (version 3 only)]
321        byte algorithm 
322        n    MPIs (n and e) */
323   if (!buflen)
324     return 0;
325   if (buf[0] < 2 || buf[0] > 4)
326     return 0; /* wrong version number */
327   if (buflen < (buf[0] == 4? 6:8))
328     return 0;
329   s = buf + (buf[0] == 4? 6:8);
330   buflen -= (buf[0] == 4? 6:8);
331   switch (s[-1])
332     {
333     case 1:
334     case 2:
335     case 3:
336       nmpis = 2;
337       break;
338     case 16:
339     case 20:
340       nmpis = 3;
341       break;
342     case 17:
343       nmpis = 4;
344       break;
345     default:
346       return 0;
347     }
348
349   for (; nmpis; nmpis--)
350     {
351       unsigned int nbits, nbytes;
352
353       if (buflen < 2)
354         return 0;
355       nbits = (s[0] << 8) | s[1];
356       s += 2; buflen -= 2;
357       nbytes = (nbits+7) / 8;
358       if (buflen < nbytes)
359         return 0;
360       s += nbytes; buflen -= nbytes;
361     }
362
363   return s - buf;
364 }
365
366 static int
367 handle_zlib(int algo,FILE *fpin,FILE *fpout)
368 {
369   z_stream zs;
370   byte *inbuf, *outbuf;
371   unsigned int inbufsize, outbufsize;
372   int c,zinit_done, zrc, nread, count;
373   size_t n;
374               
375   memset (&zs, 0, sizeof zs);
376   inbufsize = 2048;
377   inbuf = xmalloc (inbufsize);
378   outbufsize = 8192;
379   outbuf = xmalloc (outbufsize);
380   zs.avail_in = 0;
381   zinit_done = 0;
382               
383   do
384     {
385       if (zs.avail_in < inbufsize)
386         {
387           n = zs.avail_in;
388           if (!n)
389             zs.next_in = (Bytef *) inbuf;
390           count = inbufsize - n;
391           for (nread=0;
392                nread < count && (c=getc (fpin)) != EOF;
393                nread++) 
394             inbuf[n+nread] = c;
395                       
396           n += nread;
397           if (nread < count && algo == 1) 
398             {
399               inbuf[n] = 0xFF; /* chew dummy byte */
400               n++;
401             }
402           zs.avail_in = n;
403         }
404       zs.next_out = (Bytef *) outbuf;
405       zs.avail_out = outbufsize;
406                     
407       if (!zinit_done) 
408         {
409           zrc = (algo == 1? inflateInit2 ( &zs, -13)
410                  : inflateInit ( &zs ));
411           if (zrc != Z_OK) 
412             {
413               log_fatal ("zlib problem: %s\n", zs.msg? zs.msg :
414                          zrc == Z_MEM_ERROR ? "out of core" :
415                          zrc == Z_VERSION_ERROR ?
416                          "invalid lib version" :
417                          "unknown error" );
418             }
419           zinit_done = 1;
420         }
421       else
422         {
423 #ifdef Z_SYNC_FLUSH
424           zrc = inflate (&zs, Z_SYNC_FLUSH);
425 #else
426           zrc = inflate (&zs, Z_PARTIAL_FLUSH);
427 #endif
428           if (zrc == Z_STREAM_END)
429             ; /* eof */
430           else if (zrc != Z_OK && zrc != Z_BUF_ERROR)
431             {
432               if (zs.msg)
433                 log_fatal ("zlib inflate problem: %s\n", zs.msg );
434               else
435                 log_fatal ("zlib inflate problem: rc=%d\n", zrc );
436             }
437           for (n=0; n < outbufsize - zs.avail_out; n++) 
438             {
439               if (putc (outbuf[n], fpout) == EOF )
440                 return 1;
441             }
442         }
443     } 
444   while (zrc != Z_STREAM_END && zrc != Z_BUF_ERROR);
445   inflateEnd (&zs);
446
447   return 0;
448 }
449
450 #ifdef HAVE_BZIP2
451 static int
452 handle_bzip2(int algo,FILE *fpin,FILE *fpout)
453 {
454   bz_stream bzs;
455   byte *inbuf, *outbuf;
456   unsigned int inbufsize, outbufsize;
457   int c,zinit_done, zrc, nread, count;
458   size_t n;
459               
460   memset (&bzs, 0, sizeof bzs);
461   inbufsize = 2048;
462   inbuf = xmalloc (inbufsize);
463   outbufsize = 8192;
464   outbuf = xmalloc (outbufsize);
465   bzs.avail_in = 0;
466   zinit_done = 0;
467               
468   do
469     {
470       if (bzs.avail_in < inbufsize)
471         {
472           n = bzs.avail_in;
473           if (!n)
474             bzs.next_in = inbuf;
475           count = inbufsize - n;
476           for (nread=0;
477                nread < count && (c=getc (fpin)) != EOF;
478                nread++) 
479             inbuf[n+nread] = c;
480                       
481           n += nread;
482           if (nread < count && algo == 1) 
483             {
484               inbuf[n] = 0xFF; /* chew dummy byte */
485               n++;
486             }
487           bzs.avail_in = n;
488         }
489       bzs.next_out = outbuf;
490       bzs.avail_out = outbufsize;
491                     
492       if (!zinit_done) 
493         {
494           zrc = BZ2_bzDecompressInit(&bzs,0,0);
495           if (zrc != BZ_OK) 
496             log_fatal ("bz2lib problem: %d\n",zrc);
497           zinit_done = 1;
498         }
499       else
500         {
501           zrc = BZ2_bzDecompress(&bzs);
502           if (zrc == BZ_STREAM_END)
503             ; /* eof */
504           else if (zrc != BZ_OK && zrc != BZ_PARAM_ERROR)
505             log_fatal ("bz2lib inflate problem: %d\n", zrc );
506           for (n=0; n < outbufsize - bzs.avail_out; n++) 
507             {
508               if (putc (outbuf[n], fpout) == EOF )
509                 return 1;
510             }
511         }
512     } 
513   while (zrc != BZ_STREAM_END && zrc != BZ_PARAM_ERROR);
514   BZ2_bzDecompressEnd(&bzs);
515
516   return 0;
517 }
518 #endif /* HAVE_BZIP2 */
519
520 /* hdr must point to a buffer large enough to hold all header bytes */
521 static int
522 write_part ( const char *fname, FILE *fpin, unsigned long pktlen,
523              int pkttype, int partial, unsigned char *hdr, size_t hdrlen)
524 {
525   FILE *fpout;
526   int c, first;
527   unsigned char *p;
528   const char *outname = create_filename (pkttype);
529   
530 #if defined(__riscos__) && defined(USE_ZLIBRISCOS)
531   static int initialized = 0;
532
533   if (!initialized)
534       initialized = riscos_load_module("ZLib", zlib_path, 1);
535 #endif
536   if (opt_no_split)
537     fpout = stdout;
538   else
539     {
540       if (opt_verbose)
541         log_info ("writing `%s'\n", outname);
542       fpout = fopen (outname, "wb");
543       if (!fpout) 
544         {
545           log_error ("error creating `%s': %s\n", outname, strerror(errno));
546           /* stop right now, otherwise we would mess up the sequence
547              of the part numbers */
548           g10_exit (1);
549         }
550     }
551
552   if (opt_secret_to_public
553       && (pkttype == PKT_SECRET_KEY || pkttype == PKT_SECRET_SUBKEY))
554     {
555       unsigned char *blob = xmalloc (pktlen);
556       int i, len;
557
558       pkttype = pkttype == PKT_SECRET_KEY? PKT_PUBLIC_KEY:PKT_PUBLIC_SUBKEY;
559
560       for (i=0; i < pktlen; i++) 
561         {
562           c = getc (fpin);
563           if (c == EOF) 
564             goto read_error;
565           blob[i] = c;
566         }
567       len = public_key_length (blob, pktlen);
568       if (!len)
569         {
570           log_error ("error calcualting public key length\n");
571           g10_exit (1);
572         }
573       if ( (hdr[0] & 0x40) )
574         { 
575           if (write_new_header (fpout, pkttype, len))
576             goto write_error;
577         }
578       else
579         { 
580           if (write_old_header (fpout, pkttype, len))
581             goto write_error;
582         }
583
584       for (i=0; i < len; i++) 
585         {
586           if ( putc (blob[i], fpout) == EOF )
587             goto write_error;
588         }
589
590       goto ready;
591     }
592
593
594   if (!opt_uncompress)
595     {
596       for (p=hdr; hdrlen; p++, hdrlen--)
597         {
598           if ( putc (*p, fpout) == EOF )
599             goto write_error;
600         }
601     }
602   
603   first = 1;
604   while (partial)
605     {
606       size_t partlen;
607       
608       if (partial == 1)
609         { /* openpgp */
610           if (first )
611             {
612               c = pktlen;
613               assert( c >= 224 && c < 255 );
614               first = 0;
615             }
616           else if ((c = getc (fpin)) == EOF ) 
617             goto read_error;
618           else
619             hdr[hdrlen++] = c;
620             
621           if (c < 192)
622             {
623               pktlen = c;
624               partial = 0; /* (last segment may follow) */
625             }
626           else if (c < 224 )
627             {
628               pktlen = (c - 192) * 256;
629               if ((c = getc (fpin)) == EOF) 
630                 goto read_error;
631               hdr[hdrlen++] = c;
632               pktlen += c + 192;
633               partial = 0;
634             }
635           else if (c == 255)
636             {
637               if (read_u32 (fpin, &pktlen))
638                 goto read_error;
639               hdr[hdrlen++] = pktlen >> 24;
640               hdr[hdrlen++] = pktlen >> 16;
641               hdr[hdrlen++] = pktlen >> 8;
642               hdr[hdrlen++] = pktlen;
643               partial = 0;
644             }
645           else
646             { /* next partial body length */
647               for (p=hdr; hdrlen; p++, hdrlen--)
648                 {
649                   if ( putc (*p, fpout) == EOF )
650                     goto write_error;
651                 }
652               partlen = 1 << (c & 0x1f);
653               for (; partlen; partlen--) 
654                 {
655                   if ((c = getc (fpin)) == EOF) 
656                     goto read_error;
657                   if ( putc (c, fpout) == EOF )
658                     goto write_error;
659                 }
660             }
661         }
662       else if (partial == 2)
663         { /* old gnupg */
664           assert (!pktlen);
665           if ( read_u16 (fpin, &partlen) )
666             goto read_error;
667           hdr[hdrlen++] = partlen >> 8;
668           hdr[hdrlen++] = partlen;
669           for (p=hdr; hdrlen; p++, hdrlen--) 
670             {
671               if ( putc (*p, fpout) == EOF )
672                 goto write_error;
673             }
674           if (!partlen)
675             partial = 0; /* end of packet */
676           for (; partlen; partlen--) 
677             {
678               c = getc (fpin);
679               if (c == EOF) 
680                 goto read_error;
681               if ( putc (c, fpout) == EOF )
682                 goto write_error;
683             }
684         }
685       else
686         { /* compressed: read to end */
687           pktlen = 0;
688           partial = 0;
689           hdrlen = 0;
690           if (opt_uncompress) 
691             {
692               if ((c = getc (fpin)) == EOF)
693                 goto read_error;
694
695               if(c==1 || c==2)
696                 {
697                   if(handle_zlib(c,fpin,fpout))
698                     goto write_error;
699                 }
700 #ifdef HAVE_BZIP2
701               else if(c==3)
702                 {
703                   if(handle_bzip2(c,fpin,fpout))
704                     goto write_error;
705                 }
706 #endif /* HAVE_BZIP2 */
707               else
708                 {
709                   log_error("invalid compression algorithm (%d)\n",c);
710                   goto read_error;
711                 }
712             }
713           else
714             {
715               while ( (c=getc (fpin)) != EOF ) 
716                 {
717                   if ( putc (c, fpout) == EOF )
718                     goto write_error;
719                 }
720             }
721           if (!feof (fpin))
722             goto read_error;
723         }
724     }
725
726   for (p=hdr; hdrlen; p++, hdrlen--) 
727     {
728       if ( putc (*p, fpout) == EOF )
729         goto write_error;
730     }
731   
732   /* standard packet or last segment of partial length encoded packet */
733   for (; pktlen; pktlen--) 
734     {
735       c = getc (fpin);
736       if (c == EOF) 
737         goto read_error;
738       if ( putc (c, fpout) == EOF )
739         goto write_error;
740     }
741   
742  ready:
743   if ( !opt_no_split && fclose (fpout) )
744     log_error ("error closing `%s': %s\n", outname, strerror (errno));
745   return 0;
746   
747  write_error:    
748   log_error ("error writing `%s': %s\n", outname, strerror (errno));
749   if (!opt_no_split)
750     fclose (fpout);
751   return 2;
752   
753  read_error:
754   if (!opt_no_split)
755     {
756       int save = errno;
757       fclose (fpout);
758       errno = save;
759     }
760   return -1;
761 }
762
763
764
765 static int
766 do_split (const char *fname, FILE *fp)
767 {
768   int c, ctb, pkttype;
769   unsigned long pktlen = 0;
770   int partial = 0;
771   unsigned char header[20];
772   int header_idx = 0;
773   
774   ctb = getc (fp);
775   if (ctb == EOF)
776     return 3; /* ready */
777   header[header_idx++] = ctb;
778   
779   if (!(ctb & 0x80))
780     {
781       log_error("invalid CTB %02x\n", ctb );
782       return 1;
783     }
784   if ( (ctb & 0x40) )
785     { /* new CTB */
786       pkttype =  (ctb & 0x3f);
787       if( (c = getc (fp)) == EOF )
788         return -1;
789       header[header_idx++] = c;
790
791       if ( c < 192 )
792         pktlen = c;
793       else if ( c < 224 )
794         {
795           pktlen = (c - 192) * 256;
796           if( (c = getc (fp)) == EOF ) 
797             return -1;
798           header[header_idx++] = c;
799           pktlen += c + 192;
800         }
801       else if ( c == 255 ) 
802         {
803           if (read_u32 (fp, &pktlen))
804             return -1;
805           header[header_idx++] = pktlen >> 24;
806           header[header_idx++] = pktlen >> 16;
807           header[header_idx++] = pktlen >> 8;
808           header[header_idx++] = pktlen; 
809         }
810       else
811         { /* partial body length */
812           pktlen = c;
813           partial = 1;
814         }
815     }
816   else
817     {
818       int lenbytes;
819       
820       pkttype = (ctb>>2)&0xf;
821       lenbytes = ((ctb&3)==3)? 0 : (1<<(ctb & 3));
822       if (!lenbytes )
823         {
824           pktlen = 0; /* don't know the value */
825           if( pkttype == PKT_COMPRESSED )
826             partial = 3;
827           else
828             partial = 2; /* the old GnuPG partial length encoding */
829         }
830       else
831         {
832           for ( ; lenbytes; lenbytes-- ) 
833             {
834               pktlen <<= 8;
835               if( (c = getc (fp)) == EOF ) 
836                 return -1;
837               header[header_idx++] = c;
838               
839               pktlen |= c;
840             }
841         }
842     }
843
844   return write_part (fname, fp, pktlen, pkttype, partial,
845                      header, header_idx);
846 }
847
848
849 static void
850 split_packets (const char *fname)
851 {
852   FILE *fp;
853   int rc;
854   
855   if (!fname || !strcmp (fname, "-"))
856     {
857       fp = stdin;
858       fname = "-";
859     }
860   else if ( !(fp = fopen (fname,"rb")) ) 
861     {
862       log_error ("can't open `%s': %s\n", fname, strerror (errno));
863       return;
864     }
865   
866   while ( !(rc = do_split (fname, fp)) )
867     ;
868   if ( rc > 0 )
869     ; /* error already handled */
870   else if ( ferror (fp) )
871     log_error ("error reading `%s': %s\n", fname, strerror (errno));
872   else
873     log_error ("premature EOF while reading `%s'\n", fname );
874   
875   if ( fp != stdin )
876     fclose (fp);
877 }