]> sjero.net Git - wget/blob - src/log.c
[svn] Don't #define __STDC__ against the compiler's will.
[wget] / src / log.c
1 /* Messages logging.
2    Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
3
4 This file is part of GNU Wget.
5
6 GNU Wget 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 2 of the License, or
9 (at your option) any later version.
10
11 GNU Wget 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 Wget; if not, write to the Free Software
18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20 In addition, as a special exception, the Free Software Foundation
21 gives permission to link the code of its release of Wget with the
22 OpenSSL project's "OpenSSL" library (or with modified versions of it
23 that use the same license as the "OpenSSL" library), and distribute
24 the linked executables.  You must obey the GNU General Public License
25 in all respects for all of the code used other than "OpenSSL".  If you
26 modify this file, you may extend this exception to your version of the
27 file, but you are not obligated to do so.  If you do not wish to do
28 so, delete this exception statement from your version.  */
29
30 #include <config.h>
31
32 /* This allows the architecture-specific .h files to specify the use
33    of stdargs regardless of __STDC__.  */
34 #ifndef WGET_USE_STDARG
35 /* Use stdarg only if the compiler supports ANSI C and stdarg.h is
36    present.  We check for both because there are configurations where
37    stdarg.h exists, but doesn't work. */
38 # ifdef __STDC__
39 #  ifdef HAVE_STDARG_H
40 #   define WGET_USE_STDARG
41 #  endif
42 # endif
43 #endif /* not WGET_USE_STDARG */
44
45 #include <stdio.h>
46 #ifdef HAVE_STRING_H
47 # include <string.h>
48 #else
49 # include <strings.h>
50 #endif
51 #include <stdlib.h>
52 #ifdef WGET_USE_STDARG
53 # include <stdarg.h>
54 #else
55 # include <varargs.h>
56 #endif
57 #ifdef HAVE_UNISTD_H
58 # include <unistd.h>
59 #endif
60 #include <assert.h>
61 #include <errno.h>
62
63 #include "wget.h"
64 #include "utils.h"
65
66 #ifndef errno
67 extern int errno;
68 #endif
69
70 /* This file impplement support for "logging".  Logging means printing
71    output, plus several additional features:
72
73    - Cataloguing output by importance.  You can specify that a log
74    message is "verbose" or "debug", and it will not be printed unless
75    in verbose or debug mode, respectively.
76
77    - Redirecting the log to the file.  When Wget's output goes to the
78    terminal, and Wget receives SIGHUP, all further output is
79    redirected to a log file.  When this is the case, Wget can also
80    print the last several lines of "context" to the log file so that
81    it does not begin in the middle of a line.  For this to work, the
82    logging code stores the last several lines of context.  Callers may
83    request for certain output not to be stored.
84
85    - Inhibiting output.  When Wget receives SIGHUP, but redirecting
86    the output fails, logging is inhibited.  */
87
88 \f
89 /* The file descriptor used for logging.  This is NULL before log_init
90    is called; logging functions log to stderr then.  log_init sets it
91    either to stderr or to a file pointer obtained from fopen().  If
92    logging is inhibited, logfp is set back to NULL. */
93 static FILE *logfp;
94
95 /* If non-zero, it means logging is inhibited, i.e. nothing is printed
96    or stored.  */
97 static int inhibit_logging;
98
99 /* Whether the last output lines are stored for use as context.  */
100 static int save_context_p;
101
102 /* Whether the log is flushed after each command. */
103 static int flush_log_p = 1;
104
105 /* Whether any output has been received while flush_log_p was 0. */
106 static int needs_flushing;
107
108 /* In the event of a hang-up, and if its output was on a TTY, Wget
109    redirects its output to `wget-log'.
110
111    For the convenience of reading this newly-created log, we store the
112    last several lines ("screenful", hence the choice of 24) of Wget
113    output, and dump them as context when the time comes.  */
114 #define SAVED_LOG_LINES 24
115
116 /* log_lines is a circular buffer that stores SAVED_LOG_LINES lines of
117    output.  log_line_current always points to the position in the
118    buffer that will be written to next.  When log_line_current reaches
119    SAVED_LOG_LINES, it is reset to zero.
120
121    The problem here is that we'd have to either (re)allocate and free
122    strings all the time, or limit the lines to an arbitrary number of
123    characters.  Instead of settling for either of these, we do both:
124    if the line is smaller than a certain "usual" line length (128
125    chars by default), a preallocated memory is used.  The rare lines
126    that are longer than 128 characters are malloc'ed and freed
127    separately.  This gives good performance with minimum memory
128    consumption and fragmentation.  */
129
130 #define STATIC_LENGTH 128
131
132 static struct log_ln {
133   char static_line[STATIC_LENGTH + 1]; /* statically allocated
134                                           line. */
135   char *malloced_line;          /* malloc'ed line, for lines of output
136                                    larger than 80 characters. */
137   char *content;                /* this points either to malloced_line
138                                    or to the appropriate static_line.
139                                    If this is NULL, it means the line
140                                    has not yet been used. */
141 } log_lines[SAVED_LOG_LINES];
142
143 /* The current position in the ring. */
144 static int log_line_current = -1;
145
146 /* Whether the most recently written line was "trailing", i.e. did not
147    finish with \n.  This is an important piece of information because
148    the code is always careful to append data to trailing lines, rather
149    than create new ones.  */
150 static int trailing_line;
151
152 static void check_redirect_output PARAMS ((void));
153 \f
154 #define ROT_ADVANCE(num) do {                   \
155   if (++num >= SAVED_LOG_LINES)                 \
156     num = 0;                                    \
157 } while (0)
158
159 /* Free the log line index with NUM.  This calls free on
160    ln->malloced_line if it's non-NULL, and it also resets
161    ln->malloced_line and ln->content to NULL.  */
162
163 static void
164 free_log_line (int num)
165 {
166   struct log_ln *ln = log_lines + num;
167   if (ln->malloced_line)
168     {
169       xfree (ln->malloced_line);
170       ln->malloced_line = NULL;
171     }
172   ln->content = NULL;
173 }
174
175 /* Append bytes in the range [start, end) to one line in the log.  The
176    region is not supposed to contain newlines, except for the last
177    character (at end[-1]).  */
178
179 static void
180 saved_append_1 (const char *start, const char *end)
181 {
182   int len = end - start;
183   if (!len)
184     return;
185
186   /* First, check whether we need to append to an existing line or to
187      create a new one.  */
188   if (!trailing_line)
189     {
190       /* Create a new line. */
191       struct log_ln *ln;
192
193       if (log_line_current == -1)
194         log_line_current = 0;
195       else
196         free_log_line (log_line_current);
197       ln = log_lines + log_line_current;
198       if (len > STATIC_LENGTH)
199         {
200           ln->malloced_line = strdupdelim (start, end);
201           ln->content = ln->malloced_line;
202         }
203       else
204         {
205           memcpy (ln->static_line, start, len);
206           ln->static_line[len] = '\0';
207           ln->content = ln->static_line;
208         }
209     }
210   else
211     {
212       /* Append to the last line.  If the line is malloc'ed, we just
213          call realloc and append the new string.  If the line is
214          static, we have to check whether appending the new string
215          would make it exceed STATIC_LENGTH characters, and if so,
216          convert it to malloc(). */
217       struct log_ln *ln = log_lines + log_line_current;
218       if (ln->malloced_line)
219         {
220           /* Resize malloc'ed line and append. */
221           int old_len = strlen (ln->malloced_line);
222           ln->malloced_line = xrealloc (ln->malloced_line, old_len + len + 1);
223           memcpy (ln->malloced_line + old_len, start, len);
224           ln->malloced_line[old_len + len] = '\0';
225           /* might have changed due to realloc */
226           ln->content = ln->malloced_line;
227         }
228       else
229         {
230           int old_len = strlen (ln->static_line);
231           if (old_len + len > STATIC_LENGTH)
232             {
233               /* Allocate memory and concatenate the old and the new
234                  contents. */
235               ln->malloced_line = xmalloc (old_len + len + 1);
236               memcpy (ln->malloced_line, ln->static_line,
237                       old_len);
238               memcpy (ln->malloced_line + old_len, start, len);
239               ln->malloced_line[old_len + len] = '\0';
240               ln->content = ln->malloced_line;
241             }
242           else
243             {
244               /* Just append to the old, statically allocated
245                  contents.  */
246               memcpy (ln->static_line + old_len, start, len);
247               ln->static_line[old_len + len] = '\0';
248               ln->content = ln->static_line;
249             }
250         }
251     }
252   trailing_line = !(end[-1] == '\n');
253   if (!trailing_line)
254     ROT_ADVANCE (log_line_current);
255 }
256
257 /* Log the contents of S, as explained above.  If S consists of
258    multiple lines, they are logged separately.  If S does not end with
259    a newline, it will form a "trailing" line, to which things will get
260    appended the next time this function is called.  */
261
262 static void
263 saved_append (const char *s)
264 {
265   while (*s)
266     {
267       const char *end = strchr (s, '\n');
268       if (!end)
269         end = s + strlen (s);
270       else
271         ++end;
272       saved_append_1 (s, end);
273       s = end;
274     }
275 }
276 \f
277 /* Check X against opt.verbose and opt.quiet.  The semantics is as
278    follows:
279
280    * LOG_ALWAYS - print the message unconditionally;
281
282    * LOG_NOTQUIET - print the message if opt.quiet is non-zero;
283
284    * LOG_NONVERBOSE - print the message if opt.verbose is zero;
285
286    * LOG_VERBOSE - print the message if opt.verbose is non-zero.  */
287 #define CHECK_VERBOSE(x)                        \
288   switch (x)                                    \
289     {                                           \
290     case LOG_ALWAYS:                            \
291       break;                                    \
292     case LOG_NOTQUIET:                          \
293       if (opt.quiet)                            \
294         return;                                 \
295       break;                                    \
296     case LOG_NONVERBOSE:                        \
297       if (opt.verbose || opt.quiet)             \
298         return;                                 \
299       break;                                    \
300     case LOG_VERBOSE:                           \
301       if (!opt.verbose)                         \
302         return;                                 \
303     }
304
305 /* Returns the file descriptor for logging.  This is LOGFP, except if
306    called before log_init, in which case it returns stderr.  This is
307    useful in case someone calls a logging function before log_init.
308
309    If logging is inhibited, return NULL.  */
310
311 static FILE *
312 get_log_fp (void)
313 {
314   if (inhibit_logging)
315     return NULL;
316   if (logfp)
317     return logfp;
318   return stderr;
319 }
320 \f
321 /* Log a literal string S.  The string is logged as-is, without a
322    newline appended.  */
323
324 void
325 logputs (enum log_options o, const char *s)
326 {
327   FILE *fp;
328
329   check_redirect_output ();
330   if (!(fp = get_log_fp ()))
331     return;
332   CHECK_VERBOSE (o);
333
334   fputs (s, fp);
335   if (save_context_p)
336     saved_append (s);
337   if (flush_log_p)
338     logflush ();
339   else
340     needs_flushing = 1;
341 }
342
343 struct logvprintf_state {
344   char *bigmsg;
345   int expected_size;
346   int allocated;
347 };
348
349 /* Print a message to the log.  A copy of message will be saved to
350    saved_log, for later reusal by log_dump_context().
351
352    It is not possible to code this function in a "natural" way, using
353    a loop, because of the braindeadness of the varargs API.
354    Specifically, each call to vsnprintf() must be preceded by va_start
355    and followed by va_end.  And this is possible only in the function
356    that contains the `...' declaration.  The alternative would be to
357    use va_copy, but that's not portable.  */
358
359 static int
360 logvprintf (struct logvprintf_state *state, const char *fmt, va_list args)
361 {
362   char smallmsg[128];
363   char *write_ptr = smallmsg;
364   int available_size = sizeof (smallmsg);
365   int numwritten;
366   FILE *fp = get_log_fp ();
367
368   if (!save_context_p)
369     {
370       /* In the simple case just call vfprintf(), to avoid needless
371          allocation and games with vsnprintf(). */
372       vfprintf (fp, fmt, args);
373       goto flush;
374     }
375
376   if (state->allocated != 0)
377     {
378       write_ptr = state->bigmsg;
379       available_size = state->allocated;
380     }
381
382   /* The GNU coding standards advise not to rely on the return value
383      of sprintf().  However, vsnprintf() is a relatively new function
384      missing from legacy systems.  Therefore I consider it safe to
385      assume that its return value is meaningful.  On the systems where
386      vsnprintf() is not available, we use the implementation from
387      snprintf.c which does return the correct value.  */
388   numwritten = vsnprintf (write_ptr, available_size, fmt, args);
389
390   /* vsnprintf() will not step over the limit given by available_size.
391      If it fails, it will return either -1 (POSIX?) or the number of
392      characters that *would have* been written, if there had been
393      enough room.  In the former case, we double the available_size
394      and malloc() to get a larger buffer, and try again.  In the
395      latter case, we use the returned information to build a buffer of
396      the correct size.  */
397
398   if (numwritten == -1)
399     {
400       /* Writing failed, and we don't know the needed size.  Try
401          again with doubled size. */
402       int newsize = available_size << 1;
403       state->bigmsg = xrealloc (state->bigmsg, newsize);
404       state->allocated = newsize;
405       return 0;
406     }
407   else if (numwritten >= available_size)
408     {
409       /* Writing failed, but we know exactly how much space we
410          need. */
411       int newsize = numwritten + 1;
412       state->bigmsg = xrealloc (state->bigmsg, newsize);
413       state->allocated = newsize;
414       return 0;
415     }
416
417   /* Writing succeeded. */
418   saved_append (write_ptr);
419   fputs (write_ptr, fp);
420   if (state->bigmsg)
421     xfree (state->bigmsg);
422
423  flush:
424   if (flush_log_p)
425     logflush ();
426   else
427     needs_flushing = 1;
428
429   return 1;
430 }
431
432 /* Flush LOGFP.  Useful while flushing is disabled.  */
433 void
434 logflush (void)
435 {
436   FILE *fp = get_log_fp ();
437   if (fp)
438     fflush (fp);
439   needs_flushing = 0;
440 }
441
442 /* Enable or disable log flushing. */
443 void
444 log_set_flush (int flush)
445 {
446   if (flush == flush_log_p)
447     return;
448
449   if (flush == 0)
450     {
451       /* Disable flushing by setting flush_log_p to 0. */
452       flush_log_p = 0;
453     }
454   else
455     {
456       /* Reenable flushing.  If anything was printed in no-flush mode,
457          flush the log now.  */
458       if (needs_flushing)
459         logflush ();
460       flush_log_p = 1;
461     }
462 }
463
464 /* (Temporarily) disable storing log to memory.  Returns the old
465    status of storing, with which this function can be called again to
466    reestablish storing. */
467
468 int
469 log_set_save_context (int savep)
470 {
471   int old = save_context_p;
472   save_context_p = savep;
473   return old;
474 }
475
476 #ifdef WGET_USE_STDARG
477 # define VA_START_1(arg1_type, arg1, args) va_start(args, arg1)
478 # define VA_START_2(arg1_type, arg1, arg2_type, arg2, args) va_start(args, arg2)
479 #else  /* not WGET_USE_STDARG */
480 # define VA_START_1(arg1_type, arg1, args) do { \
481   va_start (args);                                                      \
482   arg1 = va_arg (args, arg1_type);                                      \
483 } while (0)
484 # define VA_START_2(arg1_type, arg1, arg2_type, arg2, args) do {        \
485   va_start (args);                                                      \
486   arg1 = va_arg (args, arg1_type);                                      \
487   arg2 = va_arg (args, arg2_type);                                      \
488 } while (0)
489 #endif /* not WGET_USE_STDARG */
490
491 /* Portability with pre-ANSI compilers makes these two functions look
492    like @#%#@$@#$.  */
493
494 #ifdef WGET_USE_STDARG
495 void
496 logprintf (enum log_options o, const char *fmt, ...)
497 #else  /* not WGET_USE_STDARG */
498 void
499 logprintf (va_alist)
500      va_dcl
501 #endif /* not WGET_USE_STDARG */
502 {
503   va_list args;
504   struct logvprintf_state lpstate;
505   int done;
506
507 #ifndef WGET_USE_STDARG
508   enum log_options o;
509   const char *fmt;
510
511   /* Perform a "dry run" of VA_START_2 to get the value of O. */
512   VA_START_2 (enum log_options, o, char *, fmt, args);
513   va_end (args);
514 #endif
515
516   check_redirect_output ();
517   if (inhibit_logging)
518     return;
519   CHECK_VERBOSE (o);
520
521   memset (&lpstate, '\0', sizeof (lpstate));
522   do
523     {
524       VA_START_2 (enum log_options, o, char *, fmt, args);
525       done = logvprintf (&lpstate, fmt, args);
526       va_end (args);
527     }
528   while (!done);
529 }
530
531 #ifdef DEBUG
532 /* The same as logprintf(), but does anything only if opt.debug is
533    non-zero.  */
534 #ifdef WGET_USE_STDARG
535 void
536 debug_logprintf (const char *fmt, ...)
537 #else  /* not WGET_USE_STDARG */
538 void
539 debug_logprintf (va_alist)
540      va_dcl
541 #endif /* not WGET_USE_STDARG */
542 {
543   if (opt.debug)
544     {
545       va_list args;
546 #ifndef WGET_USE_STDARG
547       const char *fmt;
548 #endif
549       struct logvprintf_state lpstate;
550       int done;
551
552       check_redirect_output ();
553       if (inhibit_logging)
554         return;
555
556       memset (&lpstate, '\0', sizeof (lpstate));
557       do
558         {
559           VA_START_1 (char *, fmt, args);
560           done = logvprintf (&lpstate, fmt, args);
561           va_end (args);
562         }
563       while (!done);
564     }
565 }
566 #endif /* DEBUG */
567 \f
568 /* Open FILE and set up a logging stream.  If FILE cannot be opened,
569    exit with status of 1.  */
570 void
571 log_init (const char *file, int appendp)
572 {
573   if (file)
574     {
575       logfp = fopen (file, appendp ? "a" : "w");
576       if (!logfp)
577         {
578           perror (opt.lfilename);
579           exit (1);
580         }
581     }
582   else
583     {
584       /* The log goes to stderr to avoid collisions with the output if
585          the user specifies `-O -'.  #### Francois Pinard suggests
586          that it's a better idea to print to stdout by default, and to
587          stderr only if the user actually specifies `-O -'.  He says
588          this inconsistency is harder to document, but is overall
589          easier on the user.  */
590       logfp = stderr;
591
592       /* If the output is a TTY, enable storing, which will make Wget
593          remember all the printed messages, to be able to dump them to
594          a log file in case SIGHUP or SIGUSR1 is received (or
595          Ctrl+Break is pressed under Windows).  */
596       if (1
597 #ifdef HAVE_ISATTY
598           && isatty (fileno (logfp))
599 #endif
600           )
601         {
602           save_context_p = 1;
603         }
604     }
605 }
606
607 /* Close LOGFP, inhibit further logging and free the memory associated
608    with it.  */
609 void
610 log_close (void)
611 {
612   int i;
613
614   if (logfp)
615     fclose (logfp);
616   logfp = NULL;
617   inhibit_logging = 1;
618   save_context_p = 0;
619
620   for (i = 0; i < SAVED_LOG_LINES; i++)
621     free_log_line (i);
622   log_line_current = -1;
623   trailing_line = 0;
624 }
625
626 /* Dump saved lines to logfp. */
627 static void
628 log_dump_context (void)
629 {
630   int num = log_line_current;
631   FILE *fp = get_log_fp ();
632   if (!fp)
633     return;
634
635   if (num == -1)
636     return;
637   if (trailing_line)
638     ROT_ADVANCE (num);
639   do
640     {
641       struct log_ln *ln = log_lines + num;
642       if (ln->content)
643         fputs (ln->content, fp);
644       ROT_ADVANCE (num);
645     }
646   while (num != log_line_current);
647   if (trailing_line)
648     if (log_lines[log_line_current].content)
649       fputs (log_lines[log_line_current].content, fp);
650   fflush (fp);
651 }
652 \f
653 /* When SIGHUP or SIGUSR1 are received, the output is redirected
654    elsewhere.  Such redirection is only allowed once. */
655 enum { RR_NONE, RR_REQUESTED, RR_DONE } redirect_request = RR_NONE;
656 static const char *redirect_request_signal_name;
657
658 /* Redirect output to `wget-log'.  */
659
660 static void
661 redirect_output (void)
662 {
663   char *logfile = unique_name (DEFAULT_LOGFILE);
664   fprintf (stderr, _("\n%s received, redirecting output to `%s'.\n"),
665            redirect_request_signal_name, logfile);
666   logfp = fopen (logfile, "w");
667   if (!logfp)
668     {
669       /* Eek!  Opening the alternate log file has failed.  Nothing we
670          can do but disable printing completely. */
671       fprintf (stderr, _("%s: %s; disabling logging.\n"),
672                logfile, strerror (errno));
673       inhibit_logging = 1;
674     }
675   else
676     {
677       /* Dump the context output to the newly opened log.  */
678       log_dump_context ();
679     }
680   xfree (logfile);
681   save_context_p = 0;
682 }
683
684 /* Check whether a signal handler requested the output to be
685    redirected. */
686
687 static void
688 check_redirect_output (void)
689 {
690   if (redirect_request == RR_REQUESTED)
691     {
692       redirect_request = RR_DONE;
693       redirect_output ();
694     }
695 }
696
697 /* Request redirection at a convenient time.  This may be called from
698    a signal handler. */
699
700 void
701 log_request_redirect_output (const char *signal_name)
702 {
703   if (redirect_request == RR_NONE && save_context_p)
704     /* Request output redirection.  The request will be processed by
705        check_redirect_output(), which is called from entry point log
706        functions. */
707     redirect_request = RR_REQUESTED;
708   redirect_request_signal_name = signal_name;
709 }