* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) University of Cambridge 1995 - 2015 */
+/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
+const uschar * rc_names[] = { /* Mostly for debug output */
+ [OK] = US"OK",
+ [DEFER] = US"DEFER",
+ [FAIL] = US"FAIL",
+ [ERROR] = US"ERROR",
+ [FAIL_FORCED] = US"FAIL_FORCED",
+ [DECLINE] = US"DECLINE",
+ [PASS] = US"PASS",
+ [DISCARD] = US"DISCARD",
+ [SKIP] = US"SKIP",
+ [REROUTED] = US"REROUTED",
+ [PANIC] = US"PANIC",
+ [BAD64] = US"BAD64",
+ [UNEXPECTED] = US"UNEXPECTED",
+ [CANCELLED] = US"CANCELLED",
+ [FAIL_SEND] = US"FAIL_SEND",
+ [FAIL_DROP] = US"FAIL_DROP"
+};
+
+
/*************************************************
* Print tree *
*************************************************/
static void
tree_printsub(tree_node *p, int pos, int barswitch)
{
-int i;
-if (p->right != NULL) tree_printsub(p->right, pos+2, 1);
-for (i = 0; i <= pos-1; i++) debug_printf("%c", tree_printline[i]);
+if (p->right) tree_printsub(p->right, pos+2, 1);
+for (int i = 0; i <= pos-1; i++) debug_printf("%c", tree_printline[i]);
debug_printf("-->%s [%d]\n", p->name, p->balance);
tree_printline[pos] = barswitch? '|' : ' ';
-if (p->left != NULL)
+if (p->left)
{
tree_printline[pos+2] = '|';
tree_printsub(p->left, pos+2, 0);
void
debug_print_tree(tree_node *p)
{
-int i;
-for (i = 0; i < tree_printlinesize; i++) tree_printline[i] = ' ';
-if (p == NULL) debug_printf("Empty Tree\n"); else tree_printsub(p, 0, 0);
+for (int i = 0; i < tree_printlinesize; i++) tree_printline[i] = ' ';
+if (!p) debug_printf("Empty Tree\n"); else tree_printsub(p, 0, 0);
debug_printf("---- End of tree ----\n");
}
debug_print_argv(const uschar ** argv)
{
debug_printf("exec");
-while (*argv != NULL) debug_printf(" %.256s", *argv++);
+while (*argv) debug_printf(" %.256s", *argv++);
debug_printf("\n");
}
void
debug_print_string(uschar *debug_string)
{
-if (debug_string == NULL) return;
+if (!debug_string) return;
HDEBUG(D_any|D_v)
{
uschar *s = expand_string(debug_string);
- if (s == NULL)
+ if (!s)
debug_printf("failed to expand debug_output \"%s\": %s\n", debug_string,
expand_string_message);
else if (s[0] != 0)
(long int)getegid());
}
+/************************************************/
+
+/* Give a string for a return-code */
+
+const uschar *
+rc_to_string(int rc)
+{
+return rc < 0 || rc >= nelem(rc_names) ? US"?" : rc_names[rc];
+}
+
+
debug_printf_indent(const char * format, ...)
{
va_list ap;
-unsigned depth = acl_level + expand_level, i;
-
-if (!debug_file) return;
-if (depth > 0)
- {
- for (i = depth >> 2; i > 0; i--)
- fprintf(debug_file, " .");
- fprintf(debug_file, "%*s", depth & 3, "");
- }
-
va_start(ap, format);
-debug_vprintf(format, ap);
+debug_vprintf(acl_level + expand_level, format, ap);
va_end(ap);
}
-
void
debug_printf(const char *format, ...)
{
va_list ap;
va_start(ap, format);
-debug_vprintf(format, ap);
+debug_vprintf(0, format, ap);
va_end(ap);
}
void
-debug_vprintf(const char *format, va_list ap)
+debug_vprintf(int indent, const char *format, va_list ap)
{
int save_errno = errno;
{
DEBUG(D_timestamp)
{
- time_t now = time(NULL);
- struct tm *t = timestamps_utc? gmtime(&now) : localtime(&now);
- (void) sprintf(CS debug_ptr, "%02d:%02d:%02d ", t->tm_hour, t->tm_min,
- t->tm_sec);
- while(*debug_ptr != 0) debug_ptr++;
+ struct timeval now;
+ time_t tmp;
+ struct tm * t;
+
+ gettimeofday(&now, NULL);
+ tmp = now.tv_sec;
+ t = f.timestamps_utc ? gmtime(&tmp) : localtime(&tmp);
+ debug_ptr += sprintf(CS debug_ptr,
+ LOGGING(millisec) ? "%02d:%02d:%02d.%03d " : "%02d:%02d:%02d ",
+ t->tm_hour, t->tm_min, t->tm_sec, (int)(now.tv_usec/1000));
}
DEBUG(D_pid)
- {
- sprintf(CS debug_ptr, "%5d ", (int)getpid());
- while(*debug_ptr != 0) debug_ptr++;
- }
+ debug_ptr += sprintf(CS debug_ptr, "%5d ", (int)getpid());
/* Set up prefix if outputting for host checking and not debugging */
if (host_checking && debug_selector == 0)
{
- Ustrcpy(debug_ptr, ">>> ");
+ Ustrcpy(debug_ptr, US">>> ");
debug_ptr += 4;
}
debug_prefix_length = debug_ptr - debug_buffer;
}
-/* Use the checked formatting routine to ensure that the buffer
-does not overflow. Ensure there's space for a newline at the end. */
-
-if (!string_vformat(debug_ptr,
- sizeof(debug_buffer) - (debug_ptr - debug_buffer) - 1, format, ap))
+if (indent > 0)
{
- uschar *s = US"**** debug string too long - truncated ****\n";
- uschar *p = debug_buffer + Ustrlen(debug_buffer);
- int maxlen = sizeof(debug_buffer) - Ustrlen(s) - 3;
- if (p > debug_buffer + maxlen) p = debug_buffer + maxlen;
- if (p > debug_buffer && p[-1] != '\n') *p++ = '\n';
- Ustrcpy(p, s);
+ for (int i = indent >> 2; i > 0; i--)
+ DEBUG(D_noutf8)
+ {
+ Ustrcpy(debug_ptr, US" !");
+ debug_ptr += 4; /* 3 spaces + shriek */
+ debug_prefix_length += 4;
+ }
+ else
+ {
+ Ustrcpy(debug_ptr, US" " UTF8_VERT_2DASH);
+ debug_ptr += 6; /* 3 spaces + 3 UTF-8 octets */
+ debug_prefix_length += 6;
+ }
+
+ Ustrncpy(debug_ptr, US" ", indent &= 3);
+ debug_ptr += indent;
+ debug_prefix_length += indent;
}
-while(*debug_ptr != 0) debug_ptr++;
+/* Use the lengthchecked formatting routine to ensure that the buffer
+does not overflow. Ensure there's space for a newline at the end.
+However, use taint-unchecked routines for writing into the buffer
+so that we can write tainted info into the static debug_buffer -
+we trust that we will never expand the results. */
+
+ {
+ gstring gs = { .size = (int)sizeof(debug_buffer) - 1,
+ .ptr = debug_ptr - debug_buffer,
+ .s = debug_buffer };
+ if (!string_vformat(&gs, SVFMT_TAINT_NOCHK, format, ap))
+ {
+ uschar * s = US"**** debug string too long - truncated ****\n";
+ uschar * p = gs.s + gs.ptr;
+ int maxlen = gs.size - Ustrlen(s) - 2;
+ if (p > gs.s + maxlen) p = gs.s + maxlen;
+ if (p > gs.s && p[-1] != '\n') *p++ = '\n';
+ Ustrcpy(p, s);
+ while(*debug_ptr) debug_ptr++;
+ }
+ else
+ {
+ string_from_gstring(&gs);
+ debug_ptr = gs.s + gs.ptr;
+ }
+ }
/* Output the line if it is complete. If we added any prefix data and there
are internal newlines, make sure the prefix is on the continuation lines,