]> sjero.net Git - wget/blobdiff - src/log.c
[svn] Fix a possible race condition when opening files.
[wget] / src / log.c
index e3e697b0b66d9614733920599e86bc09a9956ae4..2511513fc0ef95bb9ab0763d9a22499188508554 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -29,16 +29,6 @@ so, delete this exception statement from your version.  */
 
 #include <config.h>
 
-/* Use stdarg only if the compiler supports ANSI C and stdarg.h is
-   present.  We check for both because there are configurations where
-   stdarg.h exists, but doesn't work. */
-#undef WGET_USE_STDARG
-#ifdef __STDC__
-# ifdef HAVE_STDARG_H
-#  define WGET_USE_STDARG
-# endif
-#endif
-
 #include <stdio.h>
 #ifdef HAVE_STRING_H
 # include <string.h>
@@ -59,6 +49,7 @@ so, delete this exception statement from your version.  */
 
 #include "wget.h"
 #include "utils.h"
+#include "log.h"
 
 #ifndef errno
 extern int errno;
@@ -229,7 +220,7 @@ saved_append_1 (const char *start, const char *end)
            {
              /* Allocate memory and concatenate the old and the new
                  contents. */
-             ln->malloced_line = xmalloc (old_len + len + 1);
+             ln->malloced_line = (char *)xmalloc (old_len + len + 1);
              memcpy (ln->malloced_line, ln->static_line,
                      old_len);
              memcpy (ln->malloced_line + old_len, start, len);
@@ -346,15 +337,20 @@ struct logvprintf_state {
 /* Print a message to the log.  A copy of message will be saved to
    saved_log, for later reusal by log_dump_context().
 
-   It is not possible to code this function in a "natural" way, using
-   a loop, because of the braindeadness of the varargs API.
-   Specifically, each call to vsnprintf() must be preceded by va_start
-   and followed by va_end.  And this is possible only in the function
-   that contains the `...' declaration.  The alternative would be to
-   use va_copy, but that's not portable.  */
+   Normally we'd want this function to loop around vsnprintf until
+   sufficient room is allocated, as the Linux man page recommends.
+   However each call to vsnprintf() must be preceded by va_start and
+   followed by va_end.  Since calling va_start/va_end is possible only
+   in the function that contains the `...' declaration, we cannot call
+   vsnprintf more than once.  Therefore this function saves its state
+   to logvprintf_state and signals the parent to call it again.
+
+   (An alternative approach would be to use va_copy, but that's not
+   portable.)  */
 
 static int
-logvprintf (struct logvprintf_state *state, const char *fmt, va_list args)
+log_vprintf_internal (struct logvprintf_state *state, const char *fmt,
+                     va_list args)
 {
   char smallmsg[128];
   char *write_ptr = smallmsg;
@@ -387,10 +383,10 @@ logvprintf (struct logvprintf_state *state, const char *fmt, va_list args)
   /* vsnprintf() will not step over the limit given by available_size.
      If it fails, it will return either -1 (POSIX?) or the number of
      characters that *would have* been written, if there had been
-     enough room.  In the former case, we double the available_size
-     and malloc() to get a larger buffer, and try again.  In the
-     latter case, we use the returned information to build a buffer of
-     the correct size.  */
+     enough room (C99).  In the former case, we double the
+     available_size and malloc to get a larger buffer, and try again.
+     In the latter case, we use the returned information to build a
+     buffer of the correct size.  */
 
   if (numwritten == -1)
     {
@@ -470,79 +466,51 @@ log_set_save_context (int savep)
   return old;
 }
 
+/* Handle difference in va_start between pre-ANSI and ANSI C.  Note
+   that we always use `...' in function definitions and let ansi2knr
+   convert it for us.  */
+
 #ifdef WGET_USE_STDARG
-# define VA_START_1(arg1_type, arg1, args) va_start(args, arg1)
-# define VA_START_2(arg1_type, arg1, arg2_type, arg2, args) va_start(args, arg2)
-#else  /* not WGET_USE_STDARG */
-# define VA_START_1(arg1_type, arg1, args) do {        \
-  va_start (args);                                                     \
-  arg1 = va_arg (args, arg1_type);                                     \
-} while (0)
-# define VA_START_2(arg1_type, arg1, arg2_type, arg2, args) do {       \
-  va_start (args);                                                     \
-  arg1 = va_arg (args, arg1_type);                                     \
-  arg2 = va_arg (args, arg2_type);                                     \
-} while (0)
-#endif /* not WGET_USE_STDARG */
+# define VA_START(args, arg1) va_start (args, arg1)
+#else
+# define VA_START(args, ignored) va_start (args)
+#endif
 
-/* Portability with pre-ANSI compilers makes these two functions look
-   like @#%#@$@#$.  */
+/* Print a message to the screen or to the log.  The first argument
+   defines the verbosity of the message, and the rest are as in
+   printf(3).  */
 
-#ifdef WGET_USE_STDARG
 void
 logprintf (enum log_options o, const char *fmt, ...)
-#else  /* not WGET_USE_STDARG */
-void
-logprintf (va_alist)
-     va_dcl
-#endif /* not WGET_USE_STDARG */
 {
   va_list args;
   struct logvprintf_state lpstate;
   int done;
 
-#ifndef WGET_USE_STDARG
-  enum log_options o;
-  const char *fmt;
-
-  /* Perform a "dry run" of VA_START_2 to get the value of O. */
-  VA_START_2 (enum log_options, o, char *, fmt, args);
-  va_end (args);
-#endif
-
   check_redirect_output ();
   if (inhibit_logging)
     return;
   CHECK_VERBOSE (o);
 
-  memset (&lpstate, '\0', sizeof (lpstate));
+  xzero (lpstate);
   do
     {
-      VA_START_2 (enum log_options, o, char *, fmt, args);
-      done = logvprintf (&lpstate, fmt, args);
+      VA_START (args, fmt);
+      done = log_vprintf_internal (&lpstate, fmt, args);
       va_end (args);
     }
   while (!done);
 }
 
-#ifdef DEBUG
+#ifdef ENABLE_DEBUG
 /* The same as logprintf(), but does anything only if opt.debug is
    non-zero.  */
-#ifdef WGET_USE_STDARG
 void
 debug_logprintf (const char *fmt, ...)
-#else  /* not WGET_USE_STDARG */
-void
-debug_logprintf (va_alist)
-     va_dcl
-#endif /* not WGET_USE_STDARG */
 {
   if (opt.debug)
     {
       va_list args;
-#ifndef WGET_USE_STDARG
-      const char *fmt;
-#endif
       struct logvprintf_state lpstate;
       int done;
 
@@ -550,17 +518,17 @@ debug_logprintf (va_alist)
       if (inhibit_logging)
        return;
 
-      memset (&lpstate, '\0', sizeof (lpstate));
+      xzero (lpstate);
       do
        {
-         VA_START_1 (char *, fmt, args);
-         done = logvprintf (&lpstate, fmt, args);
+         VA_START (args, fmt);
+         done = log_vprintf_internal (&lpstate, fmt, args);
          va_end (args);
        }
       while (!done);
     }
 }
-#endif /* DEBUG */
+#endif /* ENABLE_DEBUG */
 \f
 /* Open FILE and set up a logging stream.  If FILE cannot be opened,
    exit with status of 1.  */
@@ -572,7 +540,7 @@ log_init (const char *file, int appendp)
       logfp = fopen (file, appendp ? "a" : "w");
       if (!logfp)
        {
-         perror (opt.lfilename);
+         fprintf (stderr, "%s: %s: %s\n", exec_name, file, strerror (errno));
          exit (1);
        }
     }
@@ -586,16 +554,16 @@ log_init (const char *file, int appendp)
          easier on the user.  */
       logfp = stderr;
 
-      /* If the output is a TTY, enable storing, which will make Wget
-         remember all the printed messages, to be able to dump them to
-         a log file in case SIGHUP or SIGUSR1 is received (or
-         Ctrl+Break is pressed under Windows).  */
       if (1
 #ifdef HAVE_ISATTY
          && isatty (fileno (logfp))
 #endif
          )
        {
+         /* If the output is a TTY, enable save context, i.e. store
+            the most recent several messages ("context") and dump
+            them to a log file in case SIGHUP or SIGUSR1 is received
+            (or Ctrl+Break is pressed under Windows).  */
          save_context_p = 1;
        }
     }
@@ -657,24 +625,25 @@ static const char *redirect_request_signal_name;
 static void
 redirect_output (void)
 {
-  char *logfile = unique_name (DEFAULT_LOGFILE);
-  fprintf (stderr, _("\n%s received, redirecting output to `%s'.\n"),
-          redirect_request_signal_name, logfile);
-  logfp = fopen (logfile, "w");
-  if (!logfp)
+  char *logfile;
+  logfp = unique_create (DEFAULT_LOGFILE, 0, &logfile);
+  if (logfp)
+    {
+      fprintf (stderr, _("\n%s received, redirecting output to `%s'.\n"),
+              redirect_request_signal_name, logfile);
+      xfree (logfile);
+      /* Dump the context output to the newly opened log.  */
+      log_dump_context ();
+    }
+  else
     {
       /* Eek!  Opening the alternate log file has failed.  Nothing we
          can do but disable printing completely. */
+      fprintf (stderr, _("\n%s received.\n"), redirect_request_signal_name);
       fprintf (stderr, _("%s: %s; disabling logging.\n"),
               logfile, strerror (errno));
       inhibit_logging = 1;
     }
-  else
-    {
-      /* Dump the context output to the newly opened log.  */
-      log_dump_context ();
-    }
-  xfree (logfile);
   save_context_p = 0;
 }