1 /*
2 ** Copyright (C) 2005-2020 by Carnegie Mellon University.
3 **
4 ** @OPENSOURCE_LICENSE_START@
5 ** See license information in ../../LICENSE.txt
6 ** @OPENSOURCE_LICENSE_END@
7 */
8 
9 /*
10 **  Functions to print error message for skstream
11 **
12 */
13 
14 
15 #include <silk/silk.h>
16 
17 RCSIDENT("$SiLK: skstream-err.c ef14e54179be 2020-04-14 21:57:45Z mthomas $");
18 
19 #include "skstream_priv.h"
20 
21 
22 /*
23  *    Typedef for a printf-type function, except this function has a
24  *    context object as the first parameter.
25  */
26 typedef int (*msg_fn_with_context)(
27     void       *ctxobj,
28     const char *fmt,
29     ...)
30     SK_CHECK_TYPEDEF_PRINTF(2, 3);
31 
32 
33 /*
34  *    A structure to hold a buffer and the size of the buffer.  This
35  *    will be used at the context object for msg_fn_with_context.
36  */
37 typedef struct stream_err_msg_buf_st {
38     char       *buf;
39     size_t      len;
40 } stream_err_msg_buf_t;
41 
42 
43 /*
44  *    The function which looks up the current error code of the stream
45  *    and calls one of two possible functions to "print" the error
46  *    message.
47  *
48  *    This is a helper function for the two public functions,
49  *    skStreamPrintLastErr() and skStreamLastErrMessage().
50  *
51  *    The 'errfn1' callback is used if it is set.  Otherwise, the
52  *    'errfn2' function is called if it is set with 'errfn2_ctx' as
53  *    the first argument to that function.  If neither is set,
54  *    skAbort() is called.
55  */
56 static int
57 streamLastErrFunc(
58     const skstream_t       *stream,
59     ssize_t                 errcode,
60     sk_msg_fn_t             errfn1,
61     void                   *errfn2_ctx,
62     msg_fn_with_context     errfn2);
63 
64 
65 /* FUNCTION DEFINITIONS */
66 
67 SK_DIAGNOSTIC_FORMAT_NONLITERAL_PUSH
68 
69 /*
70  *    Callback to "print" the error message into a buffer.  The buffer
71  *    and its length are specified in the first argument.
72  */
73 static int
streamLastErrMsg(void * v_msg_buf,const char * fmt,...)74 streamLastErrMsg(
75     void               *v_msg_buf,
76     const char         *fmt,
77     ...)
78 {
79     stream_err_msg_buf_t *msg_buf = (stream_err_msg_buf_t*)v_msg_buf;
80     va_list args;
81     int rv;
82 
83     va_start(args, fmt);
84     rv = vsnprintf(msg_buf->buf, msg_buf->len, fmt, args);
85     va_end(args);
86 
87     return rv;
88 }
89 
90 SK_DIAGNOSTIC_FORMAT_NONLITERAL_POP
91 
92 
93 
94 /*
95  *    Fill 'buffer' with the message that corresponds to the stream
96  *    error code 'errcode'.  The stream object may provide addition
97  *    context for the message.
98  */
99 int
skStreamLastErrMessage(const skstream_t * stream,ssize_t errcode,char * buffer,size_t buffer_len)100 skStreamLastErrMessage(
101     const skstream_t   *stream,
102     ssize_t             errcode,
103     char               *buffer,
104     size_t              buffer_len)
105 {
106     stream_err_msg_buf_t msg_buf;
107 
108     msg_buf.buf = buffer;
109     msg_buf.len = buffer_len;
110 
111     return streamLastErrFunc(stream, errcode, NULL,
112                              &msg_buf, &streamLastErrMsg);
113 }
114 
115 
116 /*
117  *    Call 'errfn' to print the message that corresponds to the stream
118  *    error code 'errcode'.  The stream object may provide addition
119  *    context for the message.
120  */
121 void
skStreamPrintLastErr(const skstream_t * stream,ssize_t errcode,sk_msg_fn_t errfn)122 skStreamPrintLastErr(
123     const skstream_t   *stream,
124     ssize_t             errcode,
125     sk_msg_fn_t         errfn)
126 {
127     if (errfn == NULL) {
128         errfn = &skAppPrintErr;
129     }
130     streamLastErrFunc(stream, errcode, errfn, NULL, NULL);
131 }
132 
133 
134 /* This function is described above. */
135 static int
streamLastErrFunc(const skstream_t * stream,ssize_t errcode,sk_msg_fn_t errfn1,void * ef2_ctx,msg_fn_with_context errfn2)136 streamLastErrFunc(
137     const skstream_t       *stream,
138     ssize_t                 errcode,
139     sk_msg_fn_t             errfn1,
140     void                   *ef2_ctx,
141     msg_fn_with_context     errfn2)
142 {
143     const char *msg;
144     char t_stamp1[SKTIMESTAMP_STRLEN];
145     char t_stamp2[SKTIMESTAMP_STRLEN];
146     char format_name[SK_MAX_STRLEN_FILE_FORMAT+1];
147     int64_t limit = 0;
148 
149 #define ERR_FN(ef1_fmt_args, ef2_ctx_fmt_args)                  \
150     if (errfn1) { return errfn1 ef1_fmt_args ; }                \
151     else if (errfn2) { return errfn2 ef2_ctx_fmt_args ; }       \
152     else { skAbort() ; }
153 
154 #ifdef TEST_PRINTF_FORMATS
155 #undef ERR_FN
156 #define ERR_FN(ef1_fmt_args, ef2_ctx_fmt_args)  \
157     return printf ef1_fmt_args
158 #endif
159 
160     /* macros for common error messages */
161 #define FILENAME_MSG(m)                                         \
162     if (!stream) {                                              \
163         ERR_FN(("%s", m),                                       \
164                (ef2_ctx, "%s", m));                             \
165     } else {                                                    \
166         ERR_FN(("%s '%s'", m, stream->pathname),                \
167                (ef2_ctx, "%s '%s'", m, stream->pathname));      \
168     }
169 
170 #define STRERROR_MSG(m)                                                 \
171     if (!stream) {                                                      \
172         ERR_FN(("%s", m),                                               \
173                (ef2_ctx, "%s", m));                                     \
174     }                                                                   \
175     else if (stream->errnum == 0) {                                     \
176         ERR_FN(("%s '%s'", m, stream->pathname),                        \
177                (ef2_ctx, "%s '%s'", m, stream->pathname)); }            \
178     else {                                                              \
179         ERR_FN(("%s '%s': %s",                                          \
180                 m, stream->pathname, strerror(stream->errnum)),         \
181                (ef2_ctx, "%s '%s': %s",                                 \
182                 m, stream->pathname, strerror(stream->errnum)));        \
183     }
184 
185     switch (errcode) {
186       case SKSTREAM_OK:
187         FILENAME_MSG("Command completed successfully");
188         break;
189 
190       case SKSTREAM_ERR_UNSUPPORT_FORMAT:
191         msg = "Cannot process file given its format";
192         if (!stream) {
193             ERR_FN(("%s", msg),
194                    (ef2_ctx, "%s", msg));
195         } else {
196             skFileFormatGetName(format_name, sizeof(format_name),
197                                 skHeaderGetFileFormat(stream->silk_hdr));
198             ERR_FN(("%s: '%s' has format %s (0x%02x)", msg,
199                     stream->pathname, format_name,
200                     skHeaderGetFileFormat(stream->silk_hdr)),
201                    (ef2_ctx, "%s: '%s' has format %s (0x%02x)", msg,
202                     stream->pathname, format_name,
203                     skHeaderGetFileFormat(stream->silk_hdr)));
204         }
205         break;
206 
207       case SKSTREAM_ERR_REQUIRE_SILK_FLOW:
208         msg = "File does not contain SiLK Flow data";
209         if (!stream) {
210             ERR_FN(("%s", msg),
211                    (ef2_ctx, "%s", msg));
212         } else {
213             skFileFormatGetName(format_name, sizeof(format_name),
214                                 skHeaderGetFileFormat(stream->silk_hdr));
215             ERR_FN(("%s: '%s' has format %s (0x%02x)", msg,
216                     stream->pathname, format_name,
217                     skHeaderGetFileFormat(stream->silk_hdr)),
218                    (ef2_ctx, "%s: '%s' has format %s (0x%02x)", msg,
219                     stream->pathname, format_name,
220                     skHeaderGetFileFormat(stream->silk_hdr)));
221         }
222         break;
223 
224       case SKSTREAM_ERR_UNSUPPORT_VERSION:
225         msg = "This SiLK release does not support";
226         if (!stream) {
227             ERR_FN(("%s the format and version of the file", msg),
228                    (ef2_ctx, "%s the format and version of the file", msg));
229         } else {
230             sk_file_header_t *hdr = stream->silk_hdr;
231             skFileFormatGetName(format_name, sizeof(format_name),
232                                 skHeaderGetFileFormat(hdr));
233             ERR_FN(("%s %s(0x%02x) v%u records in the v%u file '%s'", msg,
234                     format_name, skHeaderGetFileFormat(hdr),
235                     skHeaderGetRecordVersion(hdr), skHeaderGetFileVersion(hdr),
236                     stream->pathname),
237                    (ef2_ctx,
238                     "%s %s(0x%02x) v%u records in the v%u file '%s'", msg,
239                     format_name, skHeaderGetFileFormat(hdr),
240                     skHeaderGetRecordVersion(hdr), skHeaderGetFileVersion(hdr),
241                     stream->pathname));
242         }
243         break;
244 
245       case SKSTREAM_ERR_READ_SHORT: /* RWIO_ERR_READ_SHORT */
246         msg = "Read incomplete record";
247         if (!stream) {
248             ERR_FN(("%s", msg),
249                    (ef2_ctx, "%s", msg));
250         } else {
251             ERR_FN(("%s (%lu of %lu bytes) from %s",
252                     msg, (unsigned long)(stream->errobj.num),
253                     (unsigned long)stream->recLen, stream->pathname),
254                    (ef2_ctx, "%s (%lu of %lu bytes) from %s",
255                     msg, (unsigned long)(stream->errobj.num),
256                     (unsigned long)stream->recLen, stream->pathname));
257         }
258         break;
259 
260       case SKSTREAM_ERR_STIME_UNDRFLO:
261         msg = "Record's start time less than that allowed in file";
262         if (!stream) {
263             ERR_FN(("%s", msg),
264                    (ef2_ctx, "%s", msg));
265         } else {
266             sktimestamp_r(t_stamp1, rwRecGetStartTime(stream->errobj.rec),
267                           SKTIMESTAMP_UTC);
268             skStreamGetLimit(stream, errcode, &limit);
269             sktimestamp_r(t_stamp2, limit, SKTIMESTAMP_UTC);
270             ERR_FN(("%s '%s': %sZ < %sZ", msg,
271                     stream->pathname, t_stamp1, t_stamp2),
272                    (ef2_ctx, "%s '%s': %sZ < %sZ", msg,
273                     stream->pathname, t_stamp1, t_stamp2));
274         }
275         break;
276 
277       case SKSTREAM_ERR_STIME_OVRFLO:
278         msg = "Record's start time greater than that allowed in file";
279         if (!stream) {
280             ERR_FN(("%s", msg),
281                    (ef2_ctx, "%s", msg));
282         } else {
283             sktimestamp_r(t_stamp1, rwRecGetStartTime(stream->errobj.rec),
284                           SKTIMESTAMP_UTC);
285             skStreamGetLimit(stream, errcode, &limit);
286             sktimestamp_r(t_stamp2, limit, SKTIMESTAMP_UTC);
287             ERR_FN(("%s '%s': %sZ > %sZ", msg,
288                     stream->pathname, t_stamp1, t_stamp2),
289                    (ef2_ctx, "%s '%s': %sZ > %sZ", msg,
290                     stream->pathname, t_stamp1, t_stamp2));
291         }
292         break;
293 
294       case SKSTREAM_ERR_ELPSD_OVRFLO:
295         msg = "Record's duration greater than that allowed in file";
296         if (!stream) {
297             ERR_FN(("%s", msg),
298                    (ef2_ctx, "%s", msg));
299         } else {
300             /* Returned limit is milliseconds; displayed is seconds */
301             skStreamGetLimit(stream, errcode, &limit);
302             limit /= 1000;
303             ERR_FN(("%s '%s': %u > %" PRId64, msg,
304                     stream->pathname,
305                     rwRecGetElapsedSeconds(stream->errobj.rec), limit),
306                    (ef2_ctx, "%s '%s': %u > %" PRId64, msg,
307                     stream->pathname,
308                     rwRecGetElapsedSeconds(stream->errobj.rec), limit));
309         }
310         break;
311 
312       case SKSTREAM_ERR_PKTS_OVRFLO:
313         msg = "Record's packet count greater than that allowed in file";
314         if (!stream) {
315             ERR_FN(("%s", msg),
316                    (ef2_ctx, "%s", msg));
317         } else {
318             skStreamGetLimit(stream, errcode, &limit);
319             ERR_FN(("%s '%s': %u > %" PRId64, msg,
320                     stream->pathname, rwRecGetPkts(stream->errobj.rec), limit),
321                    (ef2_ctx, "%s '%s': %u > %" PRId64, msg,
322                     stream->pathname, rwRecGetPkts(stream->errobj.rec),limit));
323         }
324         break;
325 
326       case SKSTREAM_ERR_PKTS_ZERO:
327         FILENAME_MSG("Record's packet count is zero while writing to file");
328         break;
329 
330       case SKSTREAM_ERR_BPP_OVRFLO:
331         msg = "Record's byte-per-pkt ratio greater than that allowed in file";
332         if (!stream) {
333             ERR_FN(("%s", msg),
334                    (ef2_ctx, "%s", msg));
335         } else {
336             skStreamGetLimit(stream, errcode, &limit);
337             ERR_FN(("%s '%s': %u > %" PRId64, msg,
338                     stream->pathname, (rwRecGetBytes(stream->errobj.rec)
339                                        / rwRecGetPkts(stream->errobj.rec)),
340                     limit),
341                    (ef2_ctx, "%s '%s': %u > %" PRId64, msg,
342                     stream->pathname, (rwRecGetBytes(stream->errobj.rec)
343                                        / rwRecGetPkts(stream->errobj.rec)),
344                     limit));
345         }
346         break;
347 
348       case SKSTREAM_ERR_SNMP_OVRFLO:
349         msg = "Record's SNMP index greater than that allowed in file";
350         if (!stream) {
351             ERR_FN(("%s", msg),
352                    (ef2_ctx, "%s", msg));
353         } else {
354             const char *snmp_str = "input";
355             unsigned int snmp_val = rwRecGetInput(stream->errobj.rec);
356             skStreamGetLimit(stream, errcode, &limit);
357             if (snmp_val <= limit) {
358                 snmp_str = "output";
359                 snmp_val = rwRecGetOutput(stream->errobj.rec);
360             }
361             ERR_FN(("%s '%s': %s %" PRIu16 " > %" PRId64, msg,
362                     stream->pathname, snmp_str, snmp_val, limit),
363                    (ef2_ctx, "%s '%s': %s %" PRIu16 " > %" PRId64, msg,
364                     stream->pathname, snmp_str, snmp_val, limit));
365         }
366         break;
367 
368       case SKSTREAM_ERR_SENSORID_OVRFLO:
369         msg = "Record's Sensor ID greater than that allowed in file";
370         if (!stream) {
371             ERR_FN(("%s", msg),
372                    (ef2_ctx, "%s", msg));
373         } else {
374             skStreamGetLimit(stream, errcode, &limit);
375             ERR_FN(("%s '%s': %" PRIu16 " > %" PRId64, msg,
376                     stream->pathname,
377                     rwRecGetSensor(stream->errobj.rec), limit),
378                    (ef2_ctx, "%s '%s': %" PRIu16 " > %" PRId64, msg,
379                     stream->pathname,
380                     rwRecGetSensor(stream->errobj.rec), limit));
381         }
382         break;
383 
384       case SKSTREAM_ERR_PROTO_MISMATCH:
385         msg = "Record's IP-protocol is not supported in file";
386         if (!stream) {
387             ERR_FN(("%s", msg),
388                    (ef2_ctx, "%s", msg));
389         } else {
390             ERR_FN(("%s '%s': %u", msg,
391                     stream->pathname,
392                     (unsigned int)rwRecGetProto(stream->errobj.rec)),
393                    (ef2_ctx, "%s '%s': %u", msg,
394                     stream->pathname,
395                     (unsigned int)rwRecGetProto(stream->errobj.rec)));
396         }
397         break;
398 
399       case SKSTREAM_ERR_PKTS_GT_BYTES:
400         msg = "Record's 'pkts' value is greater than its 'bytes' value";
401         if (!stream) {
402             ERR_FN(("%s", msg),
403                    (ef2_ctx, "%s", msg));
404         } else {
405             ERR_FN(("%s in file '%s': %u > %u", msg,
406                     stream->pathname,
407                     (unsigned int)rwRecGetPkts(stream->errobj.rec),
408                     (unsigned int)rwRecGetBytes(stream->errobj.rec)),
409                    (ef2_ctx, "%s in file '%s': %u > %u", msg,
410                     stream->pathname,
411                     (unsigned int)rwRecGetPkts(stream->errobj.rec),
412                     (unsigned int)rwRecGetBytes(stream->errobj.rec)));
413         }
414         break;
415 
416       case SKSTREAM_ERR_UNSUPPORT_IPV6:
417         FILENAME_MSG("Record has an unsupported IPv6 address");
418         break;
419 
420       case SKSTREAM_ERR_ALLOC:
421         ERR_FN(("Memory allocation failed"),
422                (ef2_ctx, "Memory allocation failed"));
423         break;
424 
425       case SKSTREAM_ERR_PREV_DATA:
426         FILENAME_MSG("Initial data has already been read or written");
427         break;
428 
429       case SKSTREAM_ERR_BAD_MAGIC:
430         FILENAME_MSG("File does not appear to be a SiLK data file");
431         break;
432 
433       case SKSTREAM_ERR_CLOSED:
434         FILENAME_MSG("Cannot modify a stream once it is closed");
435         break;
436 
437       case SKSTREAM_ERR_EOF:    /* RWIO_ERR_READ_EOF */
438         FILENAME_MSG("Reached end of file");
439         break;
440 
441       case SKSTREAM_ERR_FILE_EXISTS:
442         STRERROR_MSG("Will not create new file over existing file");
443         break;
444 
445       case SKSTREAM_ERR_INVALID_INPUT:
446         ERR_FN(("Argument's value is invalid"),
447                (ef2_ctx, "Argument's value is invalid"));
448         break;
449 
450       case SKSTREAM_ERR_IOBUF:
451         if (!stream) {
452             ERR_FN(("Error reading/writing iobuffer"),
453                    (ef2_ctx, "Error reading/writing iobuffer"));
454         } else {
455             ERR_FN(("Error %s iobuffer for '%s': %s",
456                     ((stream->io_mode == SK_IO_READ) ? "reading" : "writing"),
457                     stream->pathname, skIOBufStrError(stream->iobuf)),
458                    (ef2_ctx, "Error %s iobuffer for '%s': %s",
459                     ((stream->io_mode == SK_IO_READ) ? "reading" : "writing"),
460                     stream->pathname, skIOBufStrError(stream->iobuf)));
461         }
462         break;
463 
464       case SKSTREAM_ERR_ISTERMINAL:
465         if (!stream) {
466             ERR_FN(("Will not read/write binary data on a terminal"),
467                    (ef2_ctx, "Will not read/write binary data on a terminal"));
468         } else {
469             ERR_FN(("Will not %s binary data on a terminal '%s'",
470                     ((stream->io_mode == SK_IO_READ) ? "read" : "write"),
471                     stream->pathname),
472                    (ef2_ctx, "Will not %s binary data on a terminal '%s'",
473                     ((stream->io_mode == SK_IO_READ) ? "read" : "write"),
474                     stream->pathname));
475         }
476         break;
477 
478       case SKSTREAM_ERR_LONG_LINE:
479         ERR_FN(("Input string is too long"),
480                (ef2_ctx, "Input string is too long"));
481         break;
482 
483       case SKSTREAM_ERR_NOPAGER:
484         msg = "Unable to invoke pager";
485         if (!stream) {
486             ERR_FN(("%s", msg),
487                    (ef2_ctx, "%s", msg));
488         } else {
489             ERR_FN(("%s '%s'",
490                     msg, stream->pager),
491                    (ef2_ctx, "%s '%s'",
492                     msg, stream->pager));
493         }
494         break;
495 
496       case SKSTREAM_ERR_NOT_BOUND:
497         ERR_FN(("Stream is not bound to a file"),
498                (ef2_ctx, "Stream is not bound to a file"));
499         break;
500 
501       case SKSTREAM_ERR_NOT_OPEN:
502         FILENAME_MSG("Cannot read/write/close an unopened stream");
503         break;
504 
505       case SKSTREAM_ERR_NOT_SEEKABLE:
506         FILENAME_MSG("Unsupported operation---cannot seek on stream");
507         break;
508 
509       case SKSTREAM_ERR_NULL_ARGUMENT:
510         ERR_FN(("Unexpected NULL or empty argument"),
511                (ef2_ctx, "Unexpected NULL or empty argument"));
512         break;
513 
514       case SKSTREAM_ERR_PREV_BOUND:
515         ERR_FN(("Cannot bind stream because it is already bound"),
516                (ef2_ctx, "Cannot bind stream because it is already bound"));
517         break;
518 
519       case SKSTREAM_ERR_PREV_OPEN:
520         FILENAME_MSG("Stream is already open");
521         break;
522 
523       case SKSTREAM_ERR_PREV_COPYINPUT:
524         FILENAME_MSG("Only one copy stream is supported per input stream");
525         break;
526 
527       case SKSTREAM_ERR_READ:
528         STRERROR_MSG("Error reading from stream");
529         break;
530 
531       case SKSTREAM_ERR_RLOCK:
532         STRERROR_MSG("Cannot get read lock on file");
533         break;
534 
535       case SKSTREAM_ERR_SYS_FDOPEN:
536         STRERROR_MSG("Cannot convert file descriptor");
537         break;
538 
539       case SKSTREAM_ERR_SYS_FORK:
540         skAppPrintErr("Cannot fork");
541         break;
542 
543       case SKSTREAM_ERR_SYS_LSEEK:
544         STRERROR_MSG("Cannot seek on stream");
545         break;
546 
547       case SKSTREAM_ERR_SYS_MKSTEMP:
548         STRERROR_MSG("Cannot create temporary file");
549         break;
550 
551       case SKSTREAM_ERR_SYS_OPEN:
552         STRERROR_MSG("Error opening file");
553         break;
554 
555       case SKSTREAM_ERR_SYS_PIPE:
556         STRERROR_MSG("Cannot create pipe");
557         break;
558 
559       case SKSTREAM_ERR_SYS_MKDIR:
560         STRERROR_MSG("Cannot create directory component to file");
561         break;
562 
563       case SKSTREAM_ERR_SYS_FCNTL_GETFL:
564         STRERROR_MSG("Cannot get status flags for stream");
565         break;
566 
567       case SKSTREAM_ERR_SYS_FTRUNCATE:
568         STRERROR_MSG("Cannot set length of file");
569         break;
570 
571       case SKSTREAM_ERR_COMPRESS_INVALID:
572         msg = "Specified compression identifier is not recognized";
573         if (!stream) {
574             ERR_FN(("%s", msg),
575                    (ef2_ctx, "%s", msg));
576         } else {
577             ssize_t cm;
578             cm = (ssize_t)skHeaderGetCompressionMethod(stream->silk_hdr);
579             ERR_FN(("%s %" SK_PRIdZ " '%s'",
580                     msg, cm, stream->pathname),
581                    (ef2_ctx, "%s %" SK_PRIdZ " '%s'",
582                     msg, cm, stream->pathname));
583         }
584         break;
585 
586       case SKSTREAM_ERR_COMPRESS_UNAVAILABLE:
587         msg = "Specified compression method is not available";
588         if (!stream) {
589             ERR_FN(("%s", msg),
590                    (ef2_ctx, "%s", msg));
591         } else {
592             skCompMethodGetName(
593                 format_name, sizeof(format_name),
594                 skHeaderGetCompressionMethod(stream->silk_hdr));
595             ERR_FN(("%s '%s' uses %s",
596                     msg, stream->pathname, format_name),
597                    (ef2_ctx, "%s '%s' uses %s",
598                     msg, stream->pathname, format_name));
599         }
600         break;
601 
602       case SKSTREAM_ERR_UNSUPPORT_CONTENT:
603         msg = "Action not supported on stream's content type";
604         if (!stream) {
605             ERR_FN(("%s", msg),
606                    (ef2_ctx, "%s", msg));
607         } else {
608             const char *ct = "";
609             switch (stream->content_type) {
610               case SK_CONTENT_SILK:
611               case SK_CONTENT_SILK_FLOW:
612                 ct = " is SiLK";
613                 break;
614               case SK_CONTENT_TEXT:
615                 ct = " is text";
616                 break;
617               case SK_CONTENT_OTHERBINARY:
618                 ct = " is binary";
619                 break;
620             }
621             ERR_FN(("%s '%s'%s",
622                     msg, stream->pathname, ct),
623                    (ef2_ctx, "%s '%s'%s",
624                     msg, stream->pathname, ct));
625         }
626         break;
627 
628       case SKSTREAM_ERR_UNSUPPORT_IOMODE:
629         msg = "Action not permitted on stream";
630         if (!stream) {
631             ERR_FN(("%s", msg),
632                    (ef2_ctx, "%s", msg));
633         } else {
634             const char *io = "";
635             switch (stream->io_mode) {
636               case SK_IO_READ:
637                 io = ": read from";
638                 break;
639               case SK_IO_WRITE:
640                 io = ": write to";
641                 break;
642               case SK_IO_APPEND:
643                 io = ": append to";
644                 break;
645             }
646             ERR_FN(("%s%s '%s'",
647                     msg, io, stream->pathname),
648                    (ef2_ctx, "%s%s '%s'",
649                     msg, io, stream->pathname));
650         }
651         break;
652 
653       case SKSTREAM_ERR_WLOCK:
654         STRERROR_MSG("Cannot get write lock on file");
655         break;
656 
657       case SKSTREAM_ERR_WRITE:
658         STRERROR_MSG("Error writing to stream");
659         break;
660 
661       case SKSTREAM_ERR_ZLIB:
662         msg = "Error in zlib library";
663         if (!stream) {
664             ERR_FN(("%s", msg),
665                    (ef2_ctx, "%s", msg));
666         } else {
667             int zerr = 0;
668             const char *zerr_msg = NULL;
669 #if SK_ENABLE_ZLIB
670             if (stream->gz) {
671                 zerr_msg = gzerror(stream->gz, &zerr);
672             } else
673 #endif  /* SK_ENABLE_ZLIB */
674             {
675                 zerr = stream->errnum;
676             }
677             if (zerr_msg) {
678                 ERR_FN(("%s for '%s': %s",
679                         msg, stream->pathname, zerr_msg),
680                        (ef2_ctx, "%s for '%s': %s",
681                         msg, stream->pathname, zerr_msg));
682             } else {
683                 ERR_FN(("%s for '%s': [%d]",
684                         msg, stream->pathname, zerr),
685                        (ef2_ctx, "%s for '%s': [%d]",
686                         msg, stream->pathname, zerr));
687             }
688         }
689         break;
690 
691       case SKSTREAM_ERR_IO:     /* -1 */
692         if (!stream) {
693             ERR_FN(("Bad read/write"),
694                    (ef2_ctx, "Bad read/write"));
695         } else if (stream->err_info == SKSTREAM_ERR_IO) {
696             /* avoid infinite loop */
697             FILENAME_MSG("Bad read/write");
698         } else {
699             /* call ourself with the real error code */
700             return streamLastErrFunc(stream, stream->err_info,
701                                      errfn1, ef2_ctx, errfn2);
702         }
703         break;
704     }
705 
706     if (errcode > 0) {
707         /* Pass it off to skheaders */
708         msg = "Error processing headers";
709         if (!stream) {
710             ERR_FN(("%s: %s", msg, skHeaderStrerror(errcode)),
711                    (ef2_ctx, "%s: %s", msg, skHeaderStrerror(errcode)));
712         } else {
713             ERR_FN(("%s on file '%s': %s",
714                     msg, stream->pathname, skHeaderStrerror(errcode)),
715                    (ef2_ctx, "%s on file '%s': %s",
716                     msg, stream->pathname, skHeaderStrerror(errcode)));
717         }
718     }
719 
720     ERR_FN(("Unrecognized error code %" SK_PRIdZ, errcode),
721            (ef2_ctx, "Unrecognized error code %" SK_PRIdZ, errcode));
722 }
723 
724 
725 /*
726 ** Local Variables:
727 ** mode:c
728 ** indent-tabs-mode:nil
729 ** c-basic-offset:4
730 ** End:
731 */
732