]> sjero.net Git - wget/blobdiff - src/log.c
[svn] Don't cast return type of malloc/realloc. Assume ANSI C signal handlers.
[wget] / src / log.c
index 814d2d456179b048a17725d7cf0b6c09cc995900..d0b5370a432e4f27cab1d6053fc6f9d4a745ce78 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -1,5 +1,5 @@
 /* Messages logging.
-   Copyright (C) 1998, 2000, 2001 Free Software Foundation, Inc.
+   Copyright (C) 2005 Free Software Foundation, Inc.
 
 This file is part of GNU Wget.
 
@@ -30,17 +30,9 @@ so, delete this exception statement from your version.  */
 #include <config.h>
 
 #include <stdio.h>
-#ifdef HAVE_STRING_H
-# include <string.h>
-#else
-# include <strings.h>
-#endif
+#include <string.h>
 #include <stdlib.h>
-#ifdef WGET_USE_STDARG
-# include <stdarg.h>
-#else
-# include <varargs.h>
-#endif
+#include <stdarg.h>
 #ifdef HAVE_UNISTD_H
 # include <unistd.h>
 #endif
@@ -51,10 +43,6 @@ so, delete this exception statement from your version.  */
 #include "utils.h"
 #include "log.h"
 
-#ifndef errno
-extern int errno;
-#endif
-
 /* This file impplement support for "logging".  Logging means printing
    output, plus several additional features:
 
@@ -137,7 +125,7 @@ static int log_line_current = -1;
    than create new ones.  */
 static int trailing_line;
 
-static void check_redirect_output PARAMS ((void));
+static void check_redirect_output (void);
 \f
 #define ROT_ADVANCE(num) do {                  \
   if (++num >= SAVED_LOG_LINES)                        \
@@ -220,7 +208,7 @@ saved_append_1 (const char *start, const char *end)
            {
              /* Allocate memory and concatenate the old and the new
                  contents. */
-             ln->malloced_line = (char *)xmalloc (old_len + len + 1);
+             ln->malloced_line = xmalloc (old_len + len + 1);
              memcpy (ln->malloced_line, ln->static_line,
                      old_len);
              memcpy (ln->malloced_line + old_len, start, len);
@@ -466,16 +454,6 @@ 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(args, arg1) va_start (args, arg1)
-#else
-# define VA_START(args, ignored) va_start (args)
-#endif
-
 /* 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).  */
@@ -495,7 +473,7 @@ logprintf (enum log_options o, const char *fmt, ...)
   xzero (lpstate);
   do
     {
-      VA_START (args, fmt);
+      va_start (args, fmt);
       done = log_vprintf_internal (&lpstate, fmt, args);
       va_end (args);
     }
@@ -521,7 +499,7 @@ debug_logprintf (const char *fmt, ...)
       xzero (lpstate);
       do
        {
-         VA_START (args, fmt);
+         va_start (args, fmt);
          done = log_vprintf_internal (&lpstate, fmt, args);
          va_end (args);
        }
@@ -618,11 +596,7 @@ log_dump_context (void)
 /* String escape functions. */
 
 /* Return the number of non-printable characters in SOURCE.
-
-   Non-printable characters are determined as per safe-ctype.h,
-   i.e. the non-printable characters of the "C" locale.  This code is
-   meant to be used to protect the user from binary characters in
-   (normally ASCII) server messages. */
+   Non-printable characters are determined as per safe-ctype.c.  */
 
 static int
 count_nonprint (const char *source)
@@ -635,46 +609,64 @@ count_nonprint (const char *source)
   return cnt;
 }
 
-/* Copy SOURCE to DEST, escaping non-printable characters.  If FOR_URI
-   is 0, they are escaped as \ooo; otherwise, they are escaped as
-   %xx.
+/* Copy SOURCE to DEST, escaping non-printable characters.
+
+   Non-printable refers to anything outside the non-control ASCII
+   range (32-126) which means that, for example, CR, LF, and TAB are
+   considered non-printable along with ESC, BS, and other control
+   chars.  This is by design: it makes sure that messages from remote
+   servers cannot be easily used to deceive the users by mimicking
+   Wget's output.  Disallowing non-ASCII characters is another
+   necessary security measure, which makes sure that remote servers
+   cannot garble the screen or guess the local charset and perform
+   homographic attacks.
+
+   Of course, the above mandates that escnonprint only be used in
+   contexts expected to be ASCII, such as when printing host names,
+   URL components, HTTP headers, FTP server messages, and the like.
+
+   ESCAPE is the leading character of the escape sequence.  BASE
+   should be the base of the escape sequence, and must be either 8 for
+   octal or 16 for hex.
 
    DEST must point to a location with sufficient room to store an
    encoded version of SOURCE.  */
 
 static void
-copy_and_escape (const char *source, char *dest, int for_uri)
+copy_and_escape (const char *source, char *dest, char escape, int base)
 {
-  const char *from;
-  char *to;
+  const char *from = source;
+  char *to = dest;
+  unsigned char c;
 
-  /* Copy the string, escaping non-printable chars. */
-  if (!for_uri)
+  /* Copy chars from SOURCE to DEST, escaping non-printable ones. */
+  switch (base)
     {
-      for (from = source, to = dest; *from; from++)
-       if (ISPRINT (*from))
-         *to++ = *from;
+    case 8:
+      while ((c = *from++) != '\0')
+       if (ISPRINT (c))
+         *to++ = c;
        else
          {
-           const unsigned char c = *from;
-           *to++ = '\\';
+           *to++ = escape;
            *to++ = '0' + (c >> 6);
            *to++ = '0' + ((c >> 3) & 7);
            *to++ = '0' + (c & 7);
          }
-    }
-  else
-    {
-      for (from = source, to = dest; *from; from++)
-       if (ISPRINT (*from))
-         *to++ = *from;
+      break;
+    case 16:
+      while ((c = *from++) != '\0')
+       if (ISPRINT (c))
+         *to++ = c;
        else
          {
-           const unsigned char c = *from;
-           *to++ = '%';
+           *to++ = escape;
            *to++ = XNUM_TO_DIGIT (c >> 4);
            *to++ = XNUM_TO_DIGIT (c & 0xf);
          }
+      break;
+    default:
+      abort ();
     }
   *to = '\0';
 }
@@ -684,14 +676,17 @@ struct ringel {
   char *buffer;
   int size;
 };
+static struct ringel ring[RING_SIZE];  /* ring data */
 
 static const char *
-escnonprint_internal (const char *str, int for_uri)
+escnonprint_internal (const char *str, char escape, int base)
 {
-  static struct ringel ring[RING_SIZE];        /* ring data */
   static int ringpos;                  /* current ring position */
+  int nprcnt;
+
+  assert (base == 8 || base == 16);
 
-  int nprcnt = count_nonprint (str);
+  nprcnt = count_nonprint (str);
   if (nprcnt == 0)
     /* If there are no non-printable chars in STR, don't bother
        copying anything, just return STR.  */
@@ -702,18 +697,21 @@ escnonprint_internal (const char *str, int for_uri)
        simply r->X instead of ring[ringpos].X. */
     struct ringel *r = ring + ringpos;
 
-    /* Every non-printable character is replaced with "\ooo",
-       i.e. with three *additional* chars (two in URI-mode).  Size
-       must also include the length of the original string and an
+    /* Every non-printable character is replaced with the escape char
+       and three (or two, depending on BASE) *additional* chars.  Size
+       must also include the length of the original string and one
        additional char for the terminating \0. */
-    int needed_size = strlen (str) + 1 + for_uri ? (2 * nprcnt) : (3 * nprcnt);
+    int needed_size = strlen (str) + 1 + (base == 8 ? 3 * nprcnt : 2 * nprcnt);
 
     /* If the current buffer is uninitialized or too small,
        (re)allocate it.  */
     if (r->buffer == NULL || r->size < needed_size)
-      r->buffer = xrealloc (r->buffer, needed_size);
+      {
+       r->buffer = xrealloc (r->buffer, needed_size);
+       r->size = needed_size;
+      }
 
-    copy_and_escape (str, r->buffer, for_uri);
+    copy_and_escape (str, r->buffer, escape, base);
     ringpos = (ringpos + 1) % RING_SIZE;
     return r->buffer;
   }
@@ -721,7 +719,20 @@ escnonprint_internal (const char *str, int for_uri)
 
 /* Return a pointer to a static copy of STR with the non-printable
    characters escaped as \ooo.  If there are no non-printable
-   characters in STR, STR is returned.
+   characters in STR, STR is returned.  See copy_and_escape for more
+   information on which characters are considered non-printable.
+
+   DON'T call this function on translated strings because escaping
+   will break them.  Don't call it on literal strings from the source,
+   which are by definition trusted.  If newlines are allowed in the
+   string, escape and print it line by line because escaping the whole
+   string will convert newlines to \012.  (This is so that expectedly
+   single-line messages cannot use embedded newlines to mimic Wget's
+   output and deceive the user.)
+
+   escnonprint doesn't quote its escape character because it is notf
+   meant as a general and reversible quoting mechanism, but as a quick
+   way to defang binary junk sent by malicious or buggy servers.
 
    NOTE: since this function can return a pointer to static data, be
    careful to copy its result before calling it again.  However, to be
@@ -733,20 +744,27 @@ escnonprint_internal (const char *str, int for_uri)
 const char *
 escnonprint (const char *str)
 {
-  return escnonprint_internal (str, 0);
+  return escnonprint_internal (str, '\\', 8);
 }
 
 /* Return a pointer to a static copy of STR with the non-printable
    characters escaped as %XX.  If there are no non-printable
    characters in STR, STR is returned.
 
-   This function returns a pointer to static data which will be
-   overwritten by subsequent calls -- see escnonprint for details.  */
+   See escnonprint for usage details.  */
 
 const char *
 escnonprint_uri (const char *str)
 {
-  return escnonprint_internal (str, 1);
+  return escnonprint_internal (str, '%', 16);
+}
+
+void
+log_cleanup (void)
+{
+  int i;
+  for (i = 0; i < countof (ring); i++)
+    xfree_null (ring[i].buffer);
 }
 \f
 /* When SIGHUP or SIGUSR1 are received, the output is redirected