]> sjero.net Git - wget/blob - src/log.c
[svn] Check for requested verbosity in logputs.
[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   CHECK_VERBOSE (o);
311
312   fputs (s, fp);
313   if (save_context_p)
314     saved_append (s);
315   if (flush_log_p)
316     logflush ();
317   else
318     needs_flushing = 1;
319 }
320
321 struct logvprintf_state {
322   char *bigmsg;
323   int expected_size;
324   int allocated;
325 };
326
327 /* Print a message to the log.  A copy of message will be saved to
328    saved_log, for later reusal by log_dump_context().
329
330    It is not possible to code this function in a "natural" way, using
331    a loop, because of the braindeadness of the varargs API.
332    Specifically, each call to vsnprintf() must be preceded by va_start
333    and followed by va_end.  And this is possible only in the function
334    that contains the `...' declaration.  The alternative would be to
335    use va_copy, but that's not portable.  */
336
337 static int
338 logvprintf (struct logvprintf_state *state, const char *fmt, va_list args)
339 {
340   char smallmsg[128];
341   char *write_ptr = smallmsg;
342   int available_size = sizeof (smallmsg);
343   int numwritten;
344   FILE *fp = get_log_fp ();
345
346   if (!save_context_p)
347     {
348       /* In the simple case just call vfprintf(), to avoid needless
349          allocation and games with vsnprintf(). */
350       vfprintf (fp, fmt, args);
351       goto flush;
352     }
353
354   if (state->allocated != 0)
355     {
356       write_ptr = state->bigmsg;
357       available_size = state->allocated;
358     }
359
360   /* The GNU coding standards advise not to rely on the return value
361      of sprintf().  However, vsnprintf() is a relatively new function
362      missing from legacy systems.  Therefore I consider it safe to
363      assume that its return value is meaningful.  On the systems where
364      vsnprintf() is not available, we use the implementation from
365      snprintf.c which does return the correct value.  */
366   numwritten = vsnprintf (write_ptr, available_size, fmt, args);
367
368   /* vsnprintf() will not step over the limit given by available_size.
369      If it fails, it will return either -1 (POSIX?) or the number of
370      characters that *would have* been written, if there had been
371      enough room.  In the former case, we double the available_size
372      and malloc() to get a larger buffer, and try again.  In the
373      latter case, we use the returned information to build a buffer of
374      the correct size.  */
375
376   if (numwritten == -1)
377     {
378       /* Writing failed, and we don't know the needed size.  Try
379          again with doubled size. */
380       int newsize = available_size << 1;
381       state->bigmsg = xrealloc (state->bigmsg, newsize);
382       state->allocated = newsize;
383       return 0;
384     }
385   else if (numwritten >= available_size)
386     {
387       /* Writing failed, but we know exactly how much space we
388          need. */
389       int newsize = numwritten + 1;
390       state->bigmsg = xrealloc (state->bigmsg, newsize);
391       state->allocated = newsize;
392       return 0;
393     }
394
395   /* Writing succeeded. */
396   saved_append (write_ptr);
397   fputs (write_ptr, fp);
398   if (state->bigmsg)
399     xfree (state->bigmsg);
400
401  flush:
402   if (flush_log_p)
403     logflush ();
404   else
405     needs_flushing = 1;
406
407   return 1;
408 }
409
410 /* Flush LOGFP.  Useful while flushing is disabled.  */
411 void
412 logflush (void)
413 {
414   FILE *fp = get_log_fp ();
415   if (fp)
416     fflush (fp);
417   needs_flushing = 0;
418 }
419
420 /* Enable or disable log flushing. */
421 void
422 log_set_flush (int flush)
423 {
424   if (flush == flush_log_p)
425     return;
426
427   if (flush == 0)
428     {
429       /* Disable flushing by setting flush_log_p to 0. */
430       flush_log_p = 0;
431     }
432   else
433     {
434       /* Reenable flushing.  If anything was printed in no-flush mode,
435          flush the log now.  */
436       if (needs_flushing)
437         logflush ();
438       flush_log_p = 1;
439     }
440 }
441
442 /* (Temporarily) disable storing log to memory.  Returns the old
443    status of storing, with which this function can be called again to
444    reestablish storing. */
445
446 int
447 log_set_save_context (int savep)
448 {
449   int old = save_context_p;
450   save_context_p = savep;
451   return old;
452 }
453
454 #ifdef WGET_USE_STDARG
455 # define VA_START_1(arg1_type, arg1, args) va_start(args, arg1)
456 # define VA_START_2(arg1_type, arg1, arg2_type, arg2, args) va_start(args, arg2)
457 #else  /* not WGET_USE_STDARG */
458 # define VA_START_1(arg1_type, arg1, args) do { \
459   va_start (args);                                                      \
460   arg1 = va_arg (args, arg1_type);                                      \
461 } while (0)
462 # define VA_START_2(arg1_type, arg1, arg2_type, arg2, args) do {        \
463   va_start (args);                                                      \
464   arg1 = va_arg (args, arg1_type);                                      \
465   arg2 = va_arg (args, arg2_type);                                      \
466 } while (0)
467 #endif /* not WGET_USE_STDARG */
468
469 /* Portability with pre-ANSI compilers makes these two functions look
470    like @#%#@$@#$.  */
471
472 #ifdef WGET_USE_STDARG
473 void
474 logprintf (enum log_options o, const char *fmt, ...)
475 #else  /* not WGET_USE_STDARG */
476 void
477 logprintf (va_alist)
478      va_dcl
479 #endif /* not WGET_USE_STDARG */
480 {
481   va_list args;
482   struct logvprintf_state lpstate;
483   int done;
484
485 #ifndef WGET_USE_STDARG
486   enum log_options o;
487   const char *fmt;
488
489   /* Perform a "dry run" of VA_START_2 to get the value of O. */
490   VA_START_2 (enum log_options, o, char *, fmt, args);
491   va_end (args);
492 #endif
493
494   check_redirect_output ();
495   if (inhibit_logging)
496     return;
497   CHECK_VERBOSE (o);
498
499   memset (&lpstate, '\0', sizeof (lpstate));
500   do
501     {
502       VA_START_2 (enum log_options, o, char *, fmt, args);
503       done = logvprintf (&lpstate, fmt, args);
504       va_end (args);
505     }
506   while (!done);
507 }
508
509 #ifdef DEBUG
510 /* The same as logprintf(), but does anything only if opt.debug is
511    non-zero.  */
512 #ifdef WGET_USE_STDARG
513 void
514 debug_logprintf (const char *fmt, ...)
515 #else  /* not WGET_USE_STDARG */
516 void
517 debug_logprintf (va_alist)
518      va_dcl
519 #endif /* not WGET_USE_STDARG */
520 {
521   if (opt.debug)
522     {
523       va_list args;
524 #ifndef WGET_USE_STDARG
525       const char *fmt;
526 #endif
527       struct logvprintf_state lpstate;
528       int done;
529
530       check_redirect_output ();
531       if (inhibit_logging)
532         return;
533
534       memset (&lpstate, '\0', sizeof (lpstate));
535       do
536         {
537           VA_START_1 (char *, fmt, args);
538           done = logvprintf (&lpstate, fmt, args);
539           va_end (args);
540         }
541       while (!done);
542     }
543 }
544 #endif /* DEBUG */
545 \f
546 /* Open FILE and set up a logging stream.  If FILE cannot be opened,
547    exit with status of 1.  */
548 void
549 log_init (const char *file, int appendp)
550 {
551   if (file)
552     {
553       logfp = fopen (file, appendp ? "a" : "w");
554       if (!logfp)
555         {
556           perror (opt.lfilename);
557           exit (1);
558         }
559     }
560   else
561     {
562       /* The log goes to stderr to avoid collisions with the output if
563          the user specifies `-O -'.  #### Francois Pinard suggests
564          that it's a better idea to print to stdout by default, and to
565          stderr only if the user actually specifies `-O -'.  He says
566          this inconsistency is harder to document, but is overall
567          easier on the user.  */
568       logfp = stderr;
569
570       /* If the output is a TTY, enable storing, which will make Wget
571          remember all the printed messages, to be able to dump them to
572          a log file in case SIGHUP or SIGUSR1 is received (or
573          Ctrl+Break is pressed under Windows).  */
574       if (1
575 #ifdef HAVE_ISATTY
576           && isatty (fileno (logfp))
577 #endif
578           )
579         {
580           save_context_p = 1;
581         }
582     }
583 }
584
585 /* Close LOGFP, inhibit further logging and free the memory associated
586    with it.  */
587 void
588 log_close (void)
589 {
590   int i;
591
592   if (logfp)
593     fclose (logfp);
594   logfp = NULL;
595   inhibit_logging = 1;
596   save_context_p = 0;
597
598   for (i = 0; i < SAVED_LOG_LINES; i++)
599     free_log_line (i);
600   log_line_current = -1;
601   trailing_line = 0;
602 }
603
604 /* Dump saved lines to logfp. */
605 static void
606 log_dump_context (void)
607 {
608   int num = log_line_current;
609   FILE *fp = get_log_fp ();
610   if (!fp)
611     return;
612
613   if (num == -1)
614     return;
615   if (trailing_line)
616     ROT_ADVANCE (num);
617   do
618     {
619       struct log_ln *ln = log_lines + num;
620       if (ln->content)
621         fputs (ln->content, fp);
622       ROT_ADVANCE (num);
623     }
624   while (num != log_line_current);
625   if (trailing_line)
626     if (log_lines[log_line_current].content)
627       fputs (log_lines[log_line_current].content, fp);
628   fflush (fp);
629 }
630 \f
631 /* When SIGHUP or SIGUSR1 are received, the output is redirected
632    elsewhere.  Such redirection is only allowed once. */
633 enum { RR_NONE, RR_REQUESTED, RR_DONE } redirect_request = RR_NONE;
634 static const char *redirect_request_signal_name;
635
636 /* Redirect output to `wget-log'.  */
637
638 static void
639 redirect_output (void)
640 {
641   char *logfile = unique_name (DEFAULT_LOGFILE);
642   fprintf (stderr, _("\n%s received, redirecting output to `%s'.\n"),
643            redirect_request_signal_name, logfile);
644   logfp = fopen (logfile, "w");
645   if (!logfp)
646     {
647       /* Eek!  Opening the alternate log file has failed.  Nothing we
648          can do but disable printing completely. */
649       fprintf (stderr, _("%s: %s; disabling logging.\n"),
650                logfile, strerror (errno));
651       inhibit_logging = 1;
652     }
653   else
654     {
655       /* Dump the context output to the newly opened log.  */
656       log_dump_context ();
657     }
658   xfree (logfile);
659   save_context_p = 0;
660 }
661
662 /* Check whether a signal handler requested the output to be
663    redirected. */
664
665 static void
666 check_redirect_output (void)
667 {
668   if (redirect_request == RR_REQUESTED)
669     {
670       redirect_request = RR_DONE;
671       redirect_output ();
672     }
673 }
674
675 /* Request redirection at a convenient time.  This may be called from
676    a signal handler. */
677
678 void
679 log_request_redirect_output (const char *signal_name)
680 {
681   if (redirect_request == RR_NONE && save_context_p)
682     /* Request output redirection.  The request will be processed by
683        check_redirect_output(), which is called from entry point log
684        functions. */
685     redirect_request = RR_REQUESTED;
686   redirect_request_signal_name = signal_name;
687 }