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