]> sjero.net Git - wget/blob - src/log.c
[svn] Update ansi2knr.c and ansi2knr.1.
[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 (C99).  In the former case, we double the
394      available_size and malloc to get a larger buffer, and try again.
395      In the latter case, we use the returned information to build a
396      buffer of 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 /* Handle difference in va_start between pre-ANSI and ANSI C.  Note
477    that we always use `...' in function definitions and let ansi2knr
478    convert it for us.  */
479
480 #ifdef WGET_USE_STDARG
481 # define VA_START(args, arg1) va_start (args, arg1)
482 #else
483 # define VA_START(args, ignored) va_start (args)
484 #endif
485
486 /* Print a message to the screen or to the log.  The first argument
487    defines the verbosity of the message, and the rest are as in
488    printf(3).  */
489
490 void
491 logprintf (enum log_options o, const char *fmt, ...)
492 {
493   va_list args;
494   struct logvprintf_state lpstate;
495   int done;
496
497   check_redirect_output ();
498   if (inhibit_logging)
499     return;
500   CHECK_VERBOSE (o);
501
502   memset (&lpstate, '\0', sizeof (lpstate));
503   do
504     {
505       VA_START (args, fmt);
506       done = logvprintf (&lpstate, fmt, args);
507       va_end (args);
508     }
509   while (!done);
510 }
511
512 #ifdef DEBUG
513 /* The same as logprintf(), but does anything only if opt.debug is
514    non-zero.  */
515 void
516 debug_logprintf (const char *fmt, ...)
517 {
518   if (opt.debug)
519     {
520       va_list args;
521       struct logvprintf_state lpstate;
522       int done;
523
524       check_redirect_output ();
525       if (inhibit_logging)
526         return;
527
528       memset (&lpstate, '\0', sizeof (lpstate));
529       do
530         {
531           VA_START (args, fmt);
532           done = logvprintf (&lpstate, fmt, args);
533           va_end (args);
534         }
535       while (!done);
536     }
537 }
538 #endif /* DEBUG */
539 \f
540 /* Open FILE and set up a logging stream.  If FILE cannot be opened,
541    exit with status of 1.  */
542 void
543 log_init (const char *file, int appendp)
544 {
545   if (file)
546     {
547       logfp = fopen (file, appendp ? "a" : "w");
548       if (!logfp)
549         {
550           perror (opt.lfilename);
551           exit (1);
552         }
553     }
554   else
555     {
556       /* The log goes to stderr to avoid collisions with the output if
557          the user specifies `-O -'.  #### Francois Pinard suggests
558          that it's a better idea to print to stdout by default, and to
559          stderr only if the user actually specifies `-O -'.  He says
560          this inconsistency is harder to document, but is overall
561          easier on the user.  */
562       logfp = stderr;
563
564       /* If the output is a TTY, enable storing, which will make Wget
565          remember the last several printed messages, to be able to
566          dump them to a log file in case SIGHUP or SIGUSR1 is received
567          (or Ctrl+Break is pressed under Windows).  */
568       if (1
569 #ifdef HAVE_ISATTY
570           && isatty (fileno (logfp))
571 #endif
572           )
573         {
574           save_context_p = 1;
575         }
576     }
577 }
578
579 /* Close LOGFP, inhibit further logging and free the memory associated
580    with it.  */
581 void
582 log_close (void)
583 {
584   int i;
585
586   if (logfp)
587     fclose (logfp);
588   logfp = NULL;
589   inhibit_logging = 1;
590   save_context_p = 0;
591
592   for (i = 0; i < SAVED_LOG_LINES; i++)
593     free_log_line (i);
594   log_line_current = -1;
595   trailing_line = 0;
596 }
597
598 /* Dump saved lines to logfp. */
599 static void
600 log_dump_context (void)
601 {
602   int num = log_line_current;
603   FILE *fp = get_log_fp ();
604   if (!fp)
605     return;
606
607   if (num == -1)
608     return;
609   if (trailing_line)
610     ROT_ADVANCE (num);
611   do
612     {
613       struct log_ln *ln = log_lines + num;
614       if (ln->content)
615         fputs (ln->content, fp);
616       ROT_ADVANCE (num);
617     }
618   while (num != log_line_current);
619   if (trailing_line)
620     if (log_lines[log_line_current].content)
621       fputs (log_lines[log_line_current].content, fp);
622   fflush (fp);
623 }
624 \f
625 /* When SIGHUP or SIGUSR1 are received, the output is redirected
626    elsewhere.  Such redirection is only allowed once. */
627 enum { RR_NONE, RR_REQUESTED, RR_DONE } redirect_request = RR_NONE;
628 static const char *redirect_request_signal_name;
629
630 /* Redirect output to `wget-log'.  */
631
632 static void
633 redirect_output (void)
634 {
635   char *logfile = unique_name (DEFAULT_LOGFILE, 0);
636   fprintf (stderr, _("\n%s received, redirecting output to `%s'.\n"),
637            redirect_request_signal_name, logfile);
638   logfp = fopen (logfile, "w");
639   if (!logfp)
640     {
641       /* Eek!  Opening the alternate log file has failed.  Nothing we
642          can do but disable printing completely. */
643       fprintf (stderr, _("%s: %s; disabling logging.\n"),
644                logfile, strerror (errno));
645       inhibit_logging = 1;
646     }
647   else
648     {
649       /* Dump the context output to the newly opened log.  */
650       log_dump_context ();
651     }
652   xfree (logfile);
653   save_context_p = 0;
654 }
655
656 /* Check whether a signal handler requested the output to be
657    redirected. */
658
659 static void
660 check_redirect_output (void)
661 {
662   if (redirect_request == RR_REQUESTED)
663     {
664       redirect_request = RR_DONE;
665       redirect_output ();
666     }
667 }
668
669 /* Request redirection at a convenient time.  This may be called from
670    a signal handler. */
671
672 void
673 log_request_redirect_output (const char *signal_name)
674 {
675   if (redirect_request == RR_NONE && save_context_p)
676     /* Request output redirection.  The request will be processed by
677        check_redirect_output(), which is called from entry point log
678        functions. */
679     redirect_request = RR_REQUESTED;
680   redirect_request_signal_name = signal_name;
681 }