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