Fix parsing of option type Kint (integer, stored in K). Bug 2348
[exim.git] / src / src / readconf.c
index fbf6d6b493f17ed7a0f31c1aae4a46e53f444477..44452baa6dec2382f76aa2283cc86a8eecfeb0df 100644 (file)
@@ -15,6 +15,9 @@ implementation of the conditional .ifdef etc. */
 # include "macro_predef.h"
 #endif
 
+#define READCONF_DEBUG if (FALSE)      /* Change to TRUE to enable */
+
+
 static uschar * syslog_facility_str;
 static void fn_smtp_receive_timeout(const uschar *, const uschar *);
 
@@ -237,6 +240,10 @@ static optionlist optionlist_config[] = {
 #endif
   { "pid_file_path",            opt_stringptr,   &pid_file_path },
   { "pipelining_advertise_hosts", opt_stringptr, &pipelining_advertise_hosts },
+#ifdef EXPERIMENTAL_PIPE_CONNECT
+  { "pipelining_connect_advertise_hosts", opt_stringptr,
+                                                &pipe_connect_advertise_hosts },
+#endif
 #ifndef DISABLE_PRDR
   { "prdr_enable",              opt_bool,        &prdr_enable },
 #endif
@@ -409,6 +416,19 @@ for (ai = auths_available; ai->driver_name[0]; ai++)
   }
 }
 
+void
+options_logging(void)
+{
+bit_table * bp;
+uschar buf[64];
+
+for (bp = log_options; bp < log_options + log_options_count; bp++)
+  {
+  spf(buf, sizeof(buf), US"_LOG_%T", bp->name);
+  builtin_macro_create(buf);
+  }
+}
+
 
 #else  /*!MACRO_PREDEF*/
 
@@ -614,7 +634,7 @@ macro_create(const uschar * name, const uschar * val, BOOL command_line)
 {
 macro_item * m = store_get(sizeof(macro_item));
 
-/* fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val); */
+READCONF_DEBUG fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val);
 m->next = NULL;
 m->command_line = command_line;
 m->namelen = Ustrlen(name);
@@ -807,7 +827,8 @@ if (*s) for (m = *s == '_' ? macros : macros_user; m; m = m->next)
     {
     int moveby;
 
-/* fprintf(stderr, "%s: matched '%s' in '%s'\n", __FUNCTION__, m->name, ss); */
+    READCONF_DEBUG fprintf(stderr, "%s: matched '%s' in '%.*s'\n", __FUNCTION__,
+      m->name, (int) Ustrlen(ss)-1, ss);
     /* Expand the buffer if necessary */
 
     while (*newlen - m->namelen + m->replen + 1 > big_buffer_size)
@@ -2109,7 +2130,7 @@ switch (type)
   inttype = US"octal ";
 
   /*  Integer: a simple(ish) case; allow octal and hex formats, and
-  suffixes K, M and G. The different types affect output, not input. */
+  suffixes K, M, G, and T.  The different types affect output, not input. */
 
   case opt_mkint:
   case opt_int:
@@ -2124,80 +2145,75 @@ switch (type)
       log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "%sinteger expected for %s",
         inttype, name);
 
-    if (errno != ERANGE)
-      if (tolower(*endptr) == 'k')
-        {
-        if (lvalue > INT_MAX/1024 || lvalue < INT_MIN/1024) errno = ERANGE;
-          else lvalue *= 1024;
-        endptr++;
-        }
-      else if (tolower(*endptr) == 'm')
-        {
-        if (lvalue > INT_MAX/(1024*1024) || lvalue < INT_MIN/(1024*1024))
-          errno = ERANGE;
-        else lvalue *= 1024*1024;
-        endptr++;
-        }
-      else if (tolower(*endptr) == 'g')
-        {
-        if (lvalue > INT_MAX/(1024*1024*1024) || lvalue < INT_MIN/(1024*1024*1024))
-          errno = ERANGE;
-        else lvalue *= 1024*1024*1024;
-        endptr++;
-        }
+    if (errno != ERANGE && *endptr)
+      {
+      uschar * mp = US"TtGgMmKk\0";    /* YyZzEePpTtGgMmKk */
+
+      if ((mp = Ustrchr(mp, *endptr)))
+       {
+       endptr++;
+       do
+         {
+         if (lvalue > INT_MAX/1024 || lvalue < INT_MIN/1024)
+           {
+           errno = ERANGE;
+           break;
+           }
+         lvalue *= 1024;
+         }
+       while (*(mp += 2));
+       }
+      }
 
     if (errno == ERANGE || lvalue > INT_MAX || lvalue < INT_MIN)
       log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
         "absolute value of integer \"%s\" is too large (overflow)", s);
 
     while (isspace(*endptr)) endptr++;
-    if (*endptr != 0)
+    if (*endptr)
       extra_chars_error(endptr, inttype, US"integer value for ", name);
 
     value = (int)lvalue;
     }
 
-  if (data_block == NULL)
-    *((int *)(ol->value)) = value;
+  if (data_block)
+    *(int *)(US data_block + (long int)ol->value) = value;
   else
-    *((int *)(US data_block + (long int)(ol->value))) = value;
+    *(int *)ol->value = value;
   break;
 
-  /*  Integer held in K: again, allow octal and hex formats, and suffixes K, M
-  and G. */
-  /*XXX consider moving to int_eximarith_t (but mind the overflow test 0415) */
+  /*  Integer held in K: again, allow formats and suffixes as above. */
 
   case opt_Kint:
     {
     uschar *endptr;
     errno = 0;
-    value = strtol(CS s, CSS &endptr, intbase);
+    int_eximarith_t lvalue = strtol(CS s, CSS &endptr, intbase);
 
     if (endptr == s)
       log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "%sinteger expected for %s",
         inttype, name);
 
-    if (errno != ERANGE)
-      if (tolower(*endptr) == 'g')
-        {
-        if (value > INT_MAX/(1024*1024) || value < INT_MIN/(1024*1024))
-         errno = ERANGE;
-       else
-         value *= 1024*1024;
-        endptr++;
-        }
-      else if (tolower(*endptr) == 'm')
-        {
-        if (value > INT_MAX/1024 || value < INT_MIN/1024)
-         errno = ERANGE;
-       else
-         value *= 1024;
-        endptr++;
-        }
-      else if (tolower(*endptr) == 'k')
-        endptr++;
+    if (errno != ERANGE && *endptr)
+      {
+      uschar * mp = US"ZzEePpTtGgMmKk\0";      /* YyZzEePpTtGgMmKk */
+
+      if ((mp = Ustrchr(mp, *endptr)))
+       {
+       endptr++;
+       while (*(mp += 2))
+         {
+         if (lvalue > EXIM_ARITH_MAX/1024 || lvalue < EXIM_ARITH_MIN/1024)
+           {
+           errno = ERANGE;
+           break;
+           }
+         lvalue *= 1024;
+         }
+       }
       else
-        value = (value + 512)/1024;
+       lvalue = (lvalue + 512)/1024;
+      }
 
     if (errno == ERANGE) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
       "absolute value of integer \"%s\" is too large (overflow)", s);
@@ -2205,13 +2221,13 @@ switch (type)
     while (isspace(*endptr)) endptr++;
     if (*endptr != 0)
       extra_chars_error(endptr, inttype, US"integer value for ", name);
-    }
 
-  if (data_block == NULL)
-    *((int *)(ol->value)) = value;
-  else
-    *((int *)(US data_block + (long int)(ol->value))) = value;
-  break;
+    if (data_block)
+      *(int_eximarith_t *)(US data_block + (long int)ol->value) = lvalue;
+    else
+      *(int_eximarith_t *)ol->value = lvalue;
+    break;
+    }
 
   /*  Fixed-point number: held to 3 decimal places. */
 
@@ -2410,7 +2426,7 @@ if (!ol)
 /* Non-admin callers cannot see options that have been flagged secure by the
 "hide" prefix. */
 
-if (!admin_user && ol->type & opt_secure)
+if (!f.admin_user && ol->type & opt_secure)
   {
   if (no_labels)
     printf("%s\n", hidden);
@@ -2468,11 +2484,13 @@ switch(ol->type & opt_mask)
 
   case opt_Kint:
     {
-    int x = *((int *)value);
+    int_eximarith_t x = *((int_eximarith_t *)value);
     if (!no_labels) printf("%s = ", name);
     if (x == 0) printf("0\n");
-    else if ((x & 1023) == 0) printf("%dM\n", x >> 10);
-    else printf("%dK\n", x);
+    else if ((x & ((1<<30)-1)) == 0) printf(PR_EXIM_ARITH "T\n", x >> 30);
+    else if ((x & ((1<<20)-1)) == 0) printf(PR_EXIM_ARITH "G\n", x >> 20);
+    else if ((x & ((1<<10)-1)) == 0) printf(PR_EXIM_ARITH "M\n", x >> 10);
+    else printf(PR_EXIM_ARITH "K\n", x);
     }
     break;
 
@@ -2769,7 +2787,7 @@ if (!type)
 
   if (Ustrcmp(name, "config") == 0)
     {
-    print_config(admin_user, no_labels);
+    print_config(f.admin_user, no_labels);
     return TRUE;
     }
 
@@ -2870,7 +2888,7 @@ else if (Ustrcmp(type, "macro") == 0)
   {
   /* People store passwords in macros and they were previously not available
   for printing.  So we have an admin_users restriction. */
-  if (!admin_user)
+  if (!f.admin_user)
     {
     fprintf(stderr, "exim: permission denied\n");
     return FALSE;
@@ -2880,6 +2898,8 @@ else if (Ustrcmp(type, "macro") == 0)
       {
       if (names_only)
         printf("%s\n", CS m->name);
+      else if (no_labels)
+        printf("%s\n", CS m->replacement);
       else
         printf("%s=%s\n", CS m->name, CS m->replacement);
       if (name)
@@ -3275,7 +3295,7 @@ if (Uchdir("/") < 0)
 /* Check the status of the file we have opened, if we have retained root
 privileges and the file isn't /dev/null (which *should* be 0666). */
 
-if (trusted_config && Ustrcmp(filename, US"/dev/null"))
+if (f.trusted_config && Ustrcmp(filename, US"/dev/null"))
   {
   if (fstat(fileno(config_file), &statbuf) != 0)
     log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to stat configuration file %s",
@@ -4191,6 +4211,9 @@ static void
 auths_init(void)
 {
 auth_instance *au, *bu;
+#ifdef EXPERIMENTAL_PIPE_CONNECT
+int nauths = 0;
+#endif
 
 readconf_driver_init(US"authenticator",
   (driver_instance **)(&auths),      /* chain anchor */
@@ -4214,7 +4237,13 @@ for (au = auths; au; au = au->next)
           "(%s and %s) have the same public name (%s)",
           au->client ? US"client" : US"server", au->name, bu->name,
           au->public_name);
+#ifdef EXPERIMENTAL_PIPE_CONNECT
+  nauths++;
+#endif
   }
+#ifdef EXPERIMENTAL_PIPE_CONNECT
+f.smtp_in_early_pipe_no_auth = nauths > 16;
+#endif
 }
 
 
@@ -4401,7 +4430,7 @@ void
 readconf_save_config(const uschar *s)
 {
 save_config_line(string_sprintf("# Exim Configuration (%s)",
-  running_in_test_harness ? US"X" : s));
+  f.running_in_test_harness ? US"X" : s));
 }
 
 static void