1 /***************************************
2 WWWOFFLE - World Wide Web Offline Explorer - Version 2.9j.
3
4 Generate error messages in a standard format optionally to syslog and stderr.
5 ******************/ /******************
6 Written by Andrew M. Bishop
7
8 This file Copyright 1996-2016 Andrew M. Bishop
9 It may be distributed under the GNU Public License, version 2, or
10 any higher version. See section COPYING of the GNU Public license
11 for conditions under which this file may be redistributed.
12 ***************************************/
13
14
15 #include "autoconfig.h"
16
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 #if TIME_WITH_SYS_TIME
25 # include <sys/time.h>
26 # include <time.h>
27 #else
28 # if HAVE_SYS_TIME_H
29 # include <sys/time.h>
30 # else
31 # include <time.h>
32 # endif
33 #endif
34
35 #include <fcntl.h>
36
37 #ifdef __STDC__
38 #include <stdarg.h>
39 #else
40 #include <varargs.h>
41 #endif
42
43 #ifdef __CYGWIN__
44 #include "config.h"
45 #endif
46
47
48 #ifndef O_BINARY
49 /*+ A work-around for needing O_BINARY with Win32 to use binary mode. +*/
50 #define O_BINARY 0
51 #endif
52
53
54 /* syslog definitions */
55
56 #if !defined(__CYGWIN__)
57 #include <syslog.h>
58
59 #if defined (hpux)
60 /* HP/UX does not declare these in <syslog.h> */
61 extern int syslog (int pri, const char *message, ...);
62 extern int openlog (const char *ident, int logopt, int facility);
63 extern int closelog (void);
64 #endif
65
66 #else
67 /* I prefer not to use the Cygwin syslog functions here. */
68 static void openlog(char *facility);
69 static void closelog(void);
70 static void syslog(int level,const char* format,char* string);
71 #endif /* __CYGWIN__ */
72
73
74 /* errno and str_error() definitions */
75
76 #include <errno.h>
77
78 #if defined(__sun__) && !defined(__svr4__)
79 /* SunOS 4.x does not have strerror(). */
80 char* strerror(int err);
81
82 extern int sys_nerr;
83 extern char *sys_errlist[];
84
strerror(int err)85 char* strerror(int err)
86 {
87 if(err>0 && err<sys_nerr)
88 return(sys_errlist[err]);
89 else
90 return("Unknown error");
91 }
92 #endif /* defined(__sun__) && !defined(__svr4__) */
93
94
95 /* h_errno and h_strerror() definitions */
96
97 #include <netdb.h>
98
99 #if defined (hpux)
100 /* HP/UX has h_errno but does not declare it in any header file */
101 extern int h_errno;
102 #endif
103
104 /* A function to get an error message for h_errno. */
105
106 static /*@observer@*/ char* h_strerror(int err);
107
h_strerror(int err)108 static char* h_strerror(int err)
109 {
110 #ifdef NETDB_INTERNAL
111 if(err==NETDB_INTERNAL)
112 return("Name Lookup Internal error");
113 else
114 #endif
115 #ifdef NETDB_SUCCESS
116 if(err==NETDB_SUCCESS)
117 return("Name Lookup Success");
118 else
119 #endif
120 #ifdef HOST_NOT_FOUND
121 if(err==HOST_NOT_FOUND)
122 return("Name Lookup Authoritative Answer Host not found");
123 else
124 #endif
125 #ifdef TRY_AGAIN
126 if(err==TRY_AGAIN)
127 return("Name Lookup Non-Authoritative Answer Host not found");
128 else
129 #endif
130 #ifdef NO_RECOVERY
131 if(err==NO_RECOVERY)
132 return("Name Lookup Non recoverable error");
133 else
134 #endif
135 #ifdef NO_DATA
136 if(err==NO_DATA)
137 return("Name Lookup Valid name, no data record of requested type");
138 else
139 #endif
140 #ifdef NO_ADDRESS
141 if(err==NO_ADDRESS)
142 return("Name Lookup Valid name, no data record of requested type");
143 else
144 #endif
145 return("Unknown error");
146 }
147
148
149 #include "io.h"
150 #include "errors.h"
151
152 /* io_errno and io_errstr definitions */
153
154 /*+ The chunked encoding/compression error number. +*/
155 extern int io_errno;
156
157 /*+ The chunked encoding/compression error message string. +*/
158 extern char *io_strerror;
159
160
161 /* gai_errno and gai_strerror() definitions */
162
163 #if USE_IPV6
164 /*+ The IPv6 functions error number. +*/
165 extern int gai_errno;
166 #endif
167
168
169 /* The function that does the work. */
170
171 static char /*@observer@*/ *print_message(ErrorLevel errlev,const char* fmt,va_list ap);
172
173 /*+ The name of the program. +*/
174 static char *program="?";
175
176 /*+ The process id of the program. +*/
177 static pid_t pid;
178
179 /*+ The last time that a message was printed. +*/
180 static time_t last_time=0;
181
182 /*+ The error messages. +*/
183 static const char *ErrorString[]={"ExtraDebug","Debug" ,"Information","Important","Warning" ,"Fatal"};
184
185 /*+ The priority to apply to syslog messages. +*/
186 #if defined(__CYGWIN__)
187 static const int ErrorPriority[]={-1 ,Debug ,Inform ,Important ,Warning ,Fatal};
188 #else
189 static const int ErrorPriority[]={-1 ,LOG_DEBUG,LOG_INFO ,LOG_NOTICE ,LOG_WARNING,LOG_ERR};
190 #endif
191
192 /*+ The error facility to use, +*/
193 static int use_syslog=0, /*+ use syslog. +*/
194 use_stderr=1; /*+ use stderr. +*/
195
196 /*+ The level of error logging +*/
197 ErrorLevel SyslogLevel=Important, /*+ in the config file for syslog. +*/
198 StderrLevel=NoLogging; /*+ on the command line for stderr. +*/
199
200
201 /*++++++++++++++++++++++++++++++++++++++
202 Initialise the error handler, get the program name and pid.
203
204 char *name The name of the program.
205
206 int syslogable Set to true if the errors are allowed to go to syslog (or -1 to remain unchanged).
207
208 int stderrable Set to true if the errors are allowed to go to stderr (or -1 to remain unchanged).
209 ++++++++++++++++++++++++++++++++++++++*/
210
InitErrorHandler(char * name,int syslogable,int stderrable)211 void InitErrorHandler(char *name,int syslogable,int stderrable)
212 {
213 if(use_syslog && *program!='?')
214 closelog();
215
216 program=name;
217 if(syslogable!=-1)
218 use_syslog=syslogable;
219 if(stderrable!=-1)
220 use_stderr=stderrable;
221
222 if(use_syslog)
223 {
224 #if defined(__CYGWIN__)
225 openlog(program);
226 #elif defined(__ultrix__)
227 openlog(program,LOG_PID);
228 #else
229 openlog(program,LOG_CONS|LOG_PID,LOG_DAEMON);
230 #endif
231 atexit(closelog);
232 }
233
234 pid=getpid();
235
236 last_time=time(NULL)-3590;
237 }
238
239
240 /*++++++++++++++++++++++++++++++++++++++
241 Open the log file.
242
243 char *name The name of the log file.
244 ++++++++++++++++++++++++++++++++++++++*/
245
OpenErrorLog(char * name)246 void OpenErrorLog(char *name)
247 {
248 int log;
249
250 close(STDERR_FILENO);
251
252 log=open(name,O_WRONLY|O_CREAT|O_BINARY,0600);
253
254 use_stderr=1;
255
256 if(log==-1)
257 {
258 use_stderr=0;
259 PrintMessage(Warning,"Cannot open log file '%s' [%!s].",name);
260 }
261 else
262 {
263 lseek(log,(off_t)0,SEEK_END);
264
265 if(log!=STDERR_FILENO)
266 {
267 if(dup2(log,STDERR_FILENO)==-1)
268 {
269 use_stderr=0;
270 PrintMessage(Warning,"Cannot put log file on stderr [%!s].");
271 }
272
273 close(log);
274 }
275 }
276
277 last_time=1;
278 }
279
280
281 /*++++++++++++++++++++++++++++++++++++++
282 Print an error message.
283
284 ErrorLevel errlev Which error level.
285
286 const char* fmt The format of the message.
287
288 ... The rest of the arguments (printf style).
289 ++++++++++++++++++++++++++++++++++++++*/
290
PrintMessage(ErrorLevel errlev,const char * fmt,...)291 void PrintMessage(ErrorLevel errlev,const char* fmt, ...)
292 {
293 va_list ap;
294
295 /* Shortcut (bypass if debug) */
296
297 if(errlev<=Debug && (errlev<SyslogLevel && errlev<StderrLevel))
298 return;
299
300 /* Print the message */
301
302 #ifdef __STDC__
303 va_start(ap,fmt);
304 #else
305 va_start(ap);
306 #endif
307
308 print_message(errlev,fmt,ap);
309
310 va_end(ap);
311 }
312
313
314 /*++++++++++++++++++++++++++++++++++++++
315 Print an error message and return the string.
316
317 char *GetPrintMessage Return the error message (except the pid etc.).
318
319 ErrorLevel errlev Which error level.
320
321 const char* fmt The format of the message.
322
323 ... The rest of the arguments (printf style).
324 ++++++++++++++++++++++++++++++++++++++*/
325
GetPrintMessage(ErrorLevel errlev,const char * fmt,...)326 char *GetPrintMessage(ErrorLevel errlev,const char* fmt, ...)
327 {
328 va_list ap;
329 char *string,*malloced;
330
331 /* Shortcut (bypass if debug) */
332
333 if(errlev<=Debug && (errlev<SyslogLevel && errlev<StderrLevel))
334 return(NULL);
335
336 /* Print the message */
337
338 #ifdef __STDC__
339 va_start(ap,fmt);
340 #else
341 va_start(ap);
342 #endif
343
344 string=print_message(errlev,fmt,ap);
345
346 va_end(ap);
347
348 /* Copy the message and return it */
349
350 malloced=(char*)malloc(strlen(string)+1);
351 strcpy(malloced,string);
352
353 return(malloced);
354 }
355
356
357 /*++++++++++++++++++++++++++++++++++++++
358 Print an error message and return the string.
359
360 char *print_message Return the error message (except the pid etc.).
361
362 ErrorLevel errlev Which error level.
363
364 const char* fmt The format of the message.
365
366 va_list ap The rest of the arguments (printf style).
367 ++++++++++++++++++++++++++++++++++++++*/
368
print_message(ErrorLevel errlev,const char * fmt,va_list ap)369 static char *print_message(ErrorLevel errlev,const char* fmt,va_list ap)
370 {
371 size_t str_len=1+strlen(fmt);
372 static /*@only@*/ char* string=NULL;
373 int i,j;
374 time_t this_time=time(NULL);
375
376 /* Periodic timestamp */
377
378 if(last_time && (this_time-last_time)>3600)
379 {
380 last_time=this_time;
381 if(use_stderr)
382 fprintf(stderr,"%s[%ld] Timestamp: %s",program,(long)pid,ctime(&this_time)); /* Used in audit-usage.pl */
383 }
384
385 /* Prepare a string. */
386
387 if(string)
388 free(string);
389
390 string=(char*)malloc(str_len);
391
392 /* Parsing of printf style arguments. */
393
394 for(i=0,j=0;fmt[i];i++)
395 if(fmt[i]!='%')
396 string[j++]=fmt[i];
397 else
398 {
399 char str[20+16],*strp=NULL; /* 20 characters for 64-bit unsigned (%llu) value ~0. */
400
401 switch(fmt[++i])
402 {
403 case '!':
404 if(fmt[++i]=='s')
405 {
406 if(errno==ERRNO_USE_H_ERRNO)
407 strp=h_strerror(h_errno);
408 else if(errno==ERRNO_USE_IO_ERRNO)
409 strp=io_strerror;
410 #if USE_IPV6
411 else if(errno==ERRNO_USE_GAI_ERRNO)
412 strp=(char*)gai_strerror(gai_errno);
413 #endif
414 else
415 strp=strerror(errno);
416 }
417 else
418 {
419 if(errno==ERRNO_USE_H_ERRNO)
420 sprintf(strp=str,"%d (h_errno)",h_errno);
421 else if(errno==ERRNO_USE_IO_ERRNO)
422 sprintf(strp=str,"%d (io_errno)",io_errno);
423 #if USE_IPV6
424 else if(errno==ERRNO_USE_GAI_ERRNO)
425 sprintf(strp=str,"%d (gai_errno)",gai_errno);
426 #endif
427 else
428 sprintf(strp=str,"%d",errno);
429 }
430 break;
431
432 case 'c':
433 str[0]=(char)va_arg(ap,int); /* beware of type promotion */
434 str[1]=0;
435 strp=str;
436 break;
437
438 case 'd':
439 sprintf(strp=str,"%d",va_arg(ap,int));
440 break;
441
442 case 's':
443 strp=va_arg(ap,char*);
444 if(!strp) strp="(null)";
445 break;
446
447 default:
448 str[0]='%';
449 str[1]=fmt[i];
450 str[2]=0;
451 strp=str;
452 (void)va_arg(ap,void*);
453 }
454
455 str_len+=strlen(strp);
456 string=realloc(string,str_len);
457 strcpy(&string[j],strp);
458 j+=strlen(strp);
459 }
460
461 string[j--]=0;
462
463 while(j>=0 && (string[j]=='\r' || string[j]=='\n'))
464 string[j--]=0;
465
466 /* Output the result. */
467
468 if(use_syslog && errlev>=SyslogLevel && ErrorPriority[errlev]!=-1)
469 syslog(ErrorPriority[errlev],"%s",string);
470
471 if(use_stderr && ((StderrLevel==NoLogging && errlev>=SyslogLevel) || (StderrLevel!=NoLogging && errlev>=StderrLevel)))
472 {
473 if(SyslogLevel==ExtraDebug || StderrLevel==ExtraDebug)
474 fprintf(stderr,"%s[%ld] %10ld: %s: %s\n",program,(long)pid,(long)this_time,ErrorString[errlev],string);
475 else
476 fprintf(stderr,"%s[%ld] %s: %s\n",program,(long)pid,ErrorString[errlev],string);
477 }
478
479 if(errlev==Fatal)
480 exit(2);
481
482 return(string);
483 }
484
485
486 #if defined(__CYGWIN__)
487
488 static int syslog_file=-1;
489 static char *syslog_facility=NULL;
490
491 /*++++++++++++++++++++++++++++++++++++++
492 Open the syslog file.
493 ++++++++++++++++++++++++++++++++++++++*/
494
openlog(char * facility)495 static void openlog(char *facility)
496 {
497 char *config_file=ConfigurationFileName();
498 char *syslogfile=(char*)malloc(strlen(config_file)+16),*p;
499
500 strcpy(syslogfile,config_file);
501 p=syslogfile+strlen(syslogfile)-1;
502 while(p>=syslogfile && *p!='/')
503 *p--=0;
504 strcat(syslogfile,"wwwoffle.syslog");
505
506 syslog_file=open(syslogfile,O_WRONLY|O_CREAT|O_APPEND,0600);
507
508 if(syslog_file!=-1)
509 init_io(syslog_file);
510
511 syslog_facility=facility;
512 }
513
514
515 /*++++++++++++++++++++++++++++++++++++++
516 Close the syslog file.
517 ++++++++++++++++++++++++++++++++++++++*/
518
closelog(void)519 static void closelog(void)
520 {
521 if(syslog_file!=-1)
522 {
523 finish_io(syslog_file);
524 close(syslog_file);
525 }
526
527 syslog_file=-1;
528 syslog_facility=NULL;
529 }
530
531
532 /*++++++++++++++++++++++++++++++++++++++
533 Write to the syslog file.
534 ++++++++++++++++++++++++++++++++++++++*/
535
syslog(int level,const char * format,char * string)536 static void syslog(int level,const char* format,char* string)
537 {
538 if(syslog_file!=-1 && syslog_facility)
539 write_formatted(syslog_file,"%s[%ld](%s): %s\r\n",syslog_facility,(long)pid,ErrorString[level],string);
540 }
541
542 #endif /* __CYGWIN__ */
543