* University of Maryland at College Park
*/
/*
- * $Id: debug.c,v 1.17.4.3.4.3.2.9.2.1 2005/09/20 19:06:37 jrjackson Exp $
+ * $Id: debug.c,v 1.40 2006/07/26 11:49:32 martinea Exp $
*
- * debug log subroutines
+ * Logging support
*/
#include "amanda.h"
-#include "clock.h"
#include "util.h"
#include "arglist.h"
+#include "clock.h"
+#include "timestamp.h"
+#include "conffile.h"
-#ifndef AMANDA_DBGDIR
-# define AMANDA_DBGDIR AMANDA_TMPDIR
+#ifdef HAVE_GLIBC_BACKTRACE
+#include <execinfo.h>
#endif
-#ifdef DEBUG_CODE
-
-int debug = 1;
-
+/* Minimum file descriptor on which to keep the debug file. This is intended
+ * to keep the descriptor "out of the way" of other processing. It's not clear
+ * that this is required any longer, but it doesn't hurt anything.
+ */
#define MIN_DB_FD 10
-static int db_fd = 2; /* default is stderr */
-static FILE *db_file = NULL; /* stderr may not be a constant */
-static char *db_filename = NULL;
+/* information on the current debug file */
+static int db_fd = 2; /* file descriptor (default stderr) */
+static FILE *db_file = NULL; /* stdio stream */
+static char *db_name = NULL; /* unqualified filename */
+static char *db_filename = NULL; /* fully qualified pathname */
-static pid_t debug_prefix_pid = 0;
+/* directory containing debug file, including trailing slash */
+static char *dbgdir = NULL;
-/*
- * Format and write a debug message to the process debug file.
- */
-printf_arglist_function(void debug_printf, char *, format)
-{
- va_list argp;
- int save_errno;
+/* time debug log was opened (timestamp of the file) */
+static time_t open_time;
- /*
- * It is common in the code to call dbprintf to write out
- * syserrno(errno) and then turn around and try to do something else
- * with errno (e.g. printf() or log()), so we make sure errno goes
- * back out with the same value it came in with.
- */
- save_errno = errno;
+/* pointer to logfile.c's 'logerror()', if we're linked
+ * with it */
+static void (*logerror_fn)(char *) = NULL;
- if(db_file == NULL && db_fd == 2) {
- db_file = stderr;
- }
- if(db_file != NULL) {
- arglist_start(argp, format);
- vfprintf(db_file, format, argp);
- fflush(db_file);
- arglist_end(argp);
- }
+/* storage for global variables */
+erroutput_type_t erroutput_type = ERR_FROM_CONTEXT;
+int error_exit_status = 1;
- errno = save_errno;
-}
+/* static function prototypes */
+static char *get_debug_name(time_t t, int n);
+static void debug_setup_1(char *config, char *subdir);
+static void debug_setup_2(char *s, int fd, char *annotation);
+static char *msg_timestamp(void);
+
+static void debug_logging_handler(const gchar *log_domain,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data);
+static void debug_setup_logging(void);
/*
* Generate a debug file name. The name is based on the program name,
* followed by a timestamp, an optional sequence number, and ".debug".
+ *
+ * @param t: timestamp
+ * @param n: sequence number between 1 and 1000; if zero, no sequence number
+ * is included.
*/
static char *
-get_debug_name(t, n)
- time_t t;
- int n;
+get_debug_name(
+ time_t t,
+ int n)
{
char number[NUM_STR_SIZE];
char *ts;
if(n < 0 || n > 1000) {
return NULL;
}
- ts = construct_timestamp(&t);
+ ts = get_timestamp_from_time(t);
if(n == 0) {
number[0] = '\0';
} else {
- ap_snprintf(number, sizeof(number), "%03d", n - 1);
+ g_snprintf(number, SIZEOF(number), "%03d", n - 1);
}
result = vstralloc(get_pname(), ".", ts, number, ".debug", NULL);
amfree(ts);
return result;
}
-static char *dbgdir = NULL;
-static time_t curtime;
+/* A GLogFunc to handle g_log calls. This function assumes that user_data
+ * is either NULL or a pointer to one of the debug_* configuration variables
+ * in conffile.c, indicating whether logging for this log domain is enabled.
+ *
+ * @param log_domain: the log domain, or NULL for general logging
+ * @param log_level: level, fatality, and recursion flags
+ * @param message: the message to log
+ * @param user_pointer: unused
+ */
+static void
+debug_logging_handler(const gchar *log_domain G_GNUC_UNUSED,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data G_GNUC_UNUSED)
+{
+ char *maxlevel = NULL;
+ pcontext_t context = get_pcontext();
+
+ /* scriptutil context doesn't do any logging except for critical
+ * and error levels */
+ if (context != CONTEXT_SCRIPTUTIL) {
+ /* convert the highest level to a string and dbprintf it */
+ if (log_level & G_LOG_LEVEL_ERROR)
+ maxlevel = _("error (fatal): ");
+ else if (log_level & G_LOG_LEVEL_CRITICAL)
+ maxlevel = _("critical (fatal): ");
+ else if (log_level & G_LOG_LEVEL_WARNING)
+ maxlevel = _("warning: ");
+ else if (log_level & G_LOG_LEVEL_MESSAGE)
+ maxlevel = _("message: ");
+ else if (log_level & G_LOG_LEVEL_INFO)
+ maxlevel = _("info: ");
+ else
+ maxlevel = ""; /* no level displayed for debugging */
+
+ debug_printf("%s%s\n", maxlevel, message);
+ }
+
+ /* error and critical levels have special handling */
+ if (log_level & (G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL)) {
+ erroutput_type_t local_erroutput;
+
+ /* Calculate a local version of erroutput_type, based on the
+ * context if the process has not set erroutput_type explicitly */
+ if (!(erroutput_type & ERR_FROM_CONTEXT)) {
+ local_erroutput = erroutput_type;
+ } else {
+ switch (context) {
+ case CONTEXT_SCRIPTUTIL:
+ local_erroutput = ERR_INTERACTIVE;
+ break;
+
+ case CONTEXT_DAEMON:
+ local_erroutput = ERR_INTERACTIVE
+ | ERR_AMANDALOG
+ | ERR_SYSLOG;
+ break;
+
+ case CONTEXT_CMDLINE:
+ case CONTEXT_DEFAULT:
+ default:
+ local_erroutput = ERR_INTERACTIVE;
+ break;
+ }
+ }
+
+ if (local_erroutput & ERR_AMANDALOG && logerror_fn != NULL)
+ (*logerror_fn)((char *)message); /* discard 'const' */
+
+ if (local_erroutput & ERR_SYSLOG) {
+#ifdef LOG_AUTH
+ openlog(get_pname(), LOG_PID, LOG_AUTH);
+#else
+ openlog(get_pname(), LOG_PID, 0);
+#endif
+ syslog(LOG_NOTICE, "%s", message);
+ closelog();
+ }
+
+ if (local_erroutput & ERR_INTERACTIVE) {
+ g_fprintf(stderr, "%s: %s\n", get_pname(), message);
+ fflush(stderr);
+ }
+
+#ifdef HAVE_GLIBC_BACKTRACE
+ /* try logging a traceback to the debug log */
+ if (db_fd != -1) {
+ void *stack[32];
+ int naddrs;
+ naddrs = backtrace(stack, sizeof(stack)/sizeof(*stack));
+ backtrace_symbols_fd(stack, naddrs, db_fd);
+ }
+#endif
-static void debug_setup_1()
+ /* we're done */
+ if (log_level & G_LOG_LEVEL_CRITICAL)
+ exit(error_exit_status);
+ else
+ abort();
+ g_assert_not_reached();
+ }
+}
+
+/* Install our handler into the glib log handling system.
+ */
+static void
+debug_setup_logging(void)
+{
+ /* g_error and g_critical should be fatal, although the log handler
+ * takes care of this anyway */
+ g_log_set_always_fatal(G_LOG_LEVEL_ERROR | G_LOG_LEVEL_CRITICAL);
+
+ /* set up handler (g_log_set_default_handler is new in glib-2.6, and
+ * hence not useable here) */
+ g_log_set_handler(NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
+ debug_logging_handler, NULL);
+}
+
+/* Set the global dbgdir according to 'config' and 'subdir', and clean
+ * old debug files out of that directory
+ *
+ * The global open_time is set to the current time, and used to delete
+ * old files.
+ *
+ * @param config: configuration or NULL
+ * @param subdir: subdirectory (server, client, etc.) or NULL
+ */
+static void
+debug_setup_1(char *config, char *subdir)
{
- struct passwd *pwent;
char *pname;
size_t pname_len;
char *e = NULL;
DIR *d;
struct dirent *entry;
int do_rename;
- char *test_name = NULL;
+ char *test_name;
size_t test_name_len;
size_t d_name_len;
struct stat sbuf;
char *dbfilename = NULL;
+ char *sane_config = NULL;
int i;
- if(client_uid == (uid_t) -1 && (pwent = getpwnam(CLIENT_LOGIN)) != NULL) {
- client_uid = pwent->pw_uid;
- client_gid = pwent->pw_gid;
- endpwent();
- }
+ memset(&sbuf, 0, SIZEOF(sbuf));
pname = get_pname();
pname_len = strlen(pname);
* Create the debug directory if it does not yet exist.
*/
amfree(dbgdir);
- dbgdir = stralloc2(AMANDA_DBGDIR, "/");
- if(mkpdir(dbgdir, 02700, client_uid, client_gid) == -1) {
- error("create debug directory \"%s\": %s",
- AMANDA_DBGDIR, strerror(errno));
+ if (config)
+ sane_config = sanitise_filename(config);
+ if (sane_config && subdir)
+ dbgdir = vstralloc(AMANDA_DBGDIR, "/", subdir, "/", sane_config,
+ "/", NULL);
+ else if (sane_config)
+ dbgdir = vstralloc(AMANDA_DBGDIR, "/", sane_config, "/", NULL);
+ else if (subdir)
+ dbgdir = vstralloc(AMANDA_DBGDIR, "/", subdir, "/", NULL);
+ else
+ dbgdir = stralloc2(AMANDA_DBGDIR, "/");
+ if(mkpdir(dbgdir, 0700, get_client_uid(), get_client_gid()) == -1) {
+ error(_("create debug directory \"%s\": %s"),
+ dbgdir, strerror(errno));
+ /*NOTREACHED*/
}
+ amfree(sane_config);
/*
* Clean out old debug files. We also rename files with old style
* We assume no system has 17 digit PID-s :-) and that there will
* not be a conflict between an old and new name.
*/
- if((d = opendir(AMANDA_DBGDIR)) == NULL) {
- error("open debug directory \"%s\": %s",
- AMANDA_DBGDIR, strerror(errno));
+ if((d = opendir(dbgdir)) == NULL) {
+ error(_("open debug directory \"%s\": %s"),
+ dbgdir, strerror(errno));
+ /*NOTREACHED*/
}
- time(&curtime);
- test_name = get_debug_name(curtime - (AMANDA_DEBUG_DAYS * 24 * 60 * 60), 0);
+ time(&open_time);
+ test_name = get_debug_name(open_time - (AMANDA_DEBUG_DAYS * 24 * 60 * 60), 0);
test_name_len = strlen(test_name);
while((entry = readdir(d)) != NULL) {
if(is_dot_or_dotdot(entry->d_name)) {
dbfilename = get_debug_name((time_t)sbuf.st_mtime, ++i);
}
if(dbfilename == NULL) {
- error("cannot rename old debug file \"%s\"", entry->d_name);
+ error(_("cannot rename old debug file \"%s\""), entry->d_name);
+ /*NOTREACHED*/
}
}
}
closedir(d);
}
-static void debug_setup_2(s, fd, notation)
- char *s;
- int fd;
- char *notation;
+/* Given an already-opened debug file, set the file's ownership
+ * appropriately, move its file descriptor above MIN_DB_FD, and
+ * add an initial log entry to the file.
+ *
+ * This function records the file's identity in the globals
+ * db_filename, db_fd, and db_file. It does *not* set db_name.
+ * db_file is not set if fd is -1
+ *
+ * This function uses the global 'open_time', which is set by
+ * debug_setup_1.
+ *
+ * @param s: the filename of the debug file; string should be malloc'd,
+ * and should *not* be freed by the caller.
+ * @param fd: the descriptor connected to the debug file, or -1 if
+ * no decriptor moving should take place.
+ * @param annotation: an extra string to include in the initial
+ * log entry.
+ */
+static void
+debug_setup_2(
+ char * s,
+ int fd,
+ char * annotation)
{
- int saved_debug;
int i;
int fd_close[MIN_DB_FD+1];
amfree(db_filename);
db_filename = s;
s = NULL;
- (void) chown(db_filename, client_uid, client_gid);
+
+ /* If we're root, change the ownership of the debug files. If we're not root,
+ * this would either be redundant or an error. */
+ if (geteuid() == 0) {
+ if (chown(db_filename, get_client_uid(), get_client_gid()) < 0) {
+ dbprintf(_("chown(%s, %d, %d) failed: %s"),
+ db_filename, (int)get_client_uid(), (int)get_client_gid(), strerror(errno));
+ }
+ }
amfree(dbgdir);
/*
* Move the file descriptor up high so it stays out of the way
* of other processing, e.g. sendbackup.
*/
- i = 0;
- fd_close[i++] = fd;
- while((db_fd = dup(fd)) < MIN_DB_FD) {
- fd_close[i++] = db_fd;
- }
- while(--i >= 0) {
- close(fd_close[i]);
+ if (fd >= 0) {
+ i = 0;
+ fd_close[i++] = fd;
+ while((db_fd = dup(fd)) < MIN_DB_FD) {
+ fd_close[i++] = db_fd;
+ }
+ while(--i >= 0) {
+ close(fd_close[i]);
+ }
+ db_file = fdopen(db_fd, "a");
}
- db_file = fdopen(db_fd, "a");
- if (notation) {
+ if (annotation) {
/*
* Make the first debug log file entry.
*/
- saved_debug = debug; debug = 1;
- debug_printf("%s: debug %d pid %ld ruid %ld euid %ld: %s at %s",
- get_pname(), saved_debug, (long)getpid(),
+ debug_printf(_("pid %ld ruid %ld euid %ld version %s: %s at %s"),
+ (long)getpid(),
(long)getuid(), (long)geteuid(),
- notation,
- ctime(&curtime));
- debug = saved_debug;
+ VERSION,
+ annotation,
+ ctime(&open_time));
}
}
-void debug_open()
+/* Get current GMT time and return a message timestamp.
+ * Used for g_printf calls to logs and such. The return value
+ * is to a static buffer, so it should be used immediately.
+ *
+ * @returns: timestamp
+ */
+static char *
+msg_timestamp(void)
+{
+ static char timestamp[128];
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ g_snprintf(timestamp, SIZEOF(timestamp), "%lld.%06ld",
+ (long long)tv.tv_sec, (long)tv.tv_usec);
+
+ return timestamp;
+}
+
+/*
+ * ---- public functions
+ */
+
+void
+debug_init(void)
+{
+ debug_setup_logging();
+
+ /* the scriptutil context does not create a debug log, since such
+ * processes are invoked many times.
+ */
+ if (get_pcontext() != CONTEXT_SCRIPTUTIL) {
+ debug_open(get_ptype());
+ }
+}
+
+void
+set_logerror(void (*f)(char *))
+{
+ logerror_fn = f;
+}
+
+void
+debug_open(char *subdir)
{
- char *dbfilename = NULL;
int fd = -1;
int i;
char *s = NULL;
+ mode_t mask;
- /*
- * Do initial setup.
- */
- debug_setup_1();
+ /* set up logging while we're here */
+ debug_setup_logging();
+
+ /* set 'dbgdir' and clean out old debug files */
+ debug_setup_1(NULL, subdir);
/*
- * Create the new file.
+ * Create the new file with a unique sequence number.
*/
- for(i = 0;
- (dbfilename = get_debug_name(curtime, i)) != NULL
- && (s = newvstralloc(s, dbgdir, dbfilename, NULL)) != NULL
- && (fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0600)) < 0;
- i++, free(dbfilename)) {}
- if(dbfilename == NULL) {
- error("cannot create %s debug file", get_pname());
+ mask = (mode_t)umask((mode_t)0037); /* Allow the group read bit through */
+
+ /* iteratate through sequence numbers until we find one that
+ * is not already in use */
+ for(i = 0; fd < 0; i++) {
+ amfree(db_name);
+ if ((db_name = get_debug_name(open_time, i)) == NULL) {
+ error(_("Cannot create debug file name in %d tries."), i);
+ /*NOTREACHED*/
+ }
+
+ if ((s = newvstralloc(s, dbgdir, db_name, NULL)) == NULL) {
+ error(_("Cannot allocate debug file name memory"));
+ /*NOTREACHED*/
+ }
+
+ if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
+ if (errno != EEXIST) {
+ error(_("Cannot create debug file \"%s\": %s"),
+ s, strerror(errno));
+ /*NOTREACHED*/
+ }
+ amfree(s);
+ }
}
- amfree(dbfilename);
+ (void)umask(mask); /* Restore mask */
/*
* Finish setup.
debug_setup_2(s, fd, "start");
}
-void debug_reopen(dbfilename, notation)
- char *dbfilename;
- char *notation;
+void
+debug_reopen(
+ char * dbfilename,
+ char * annotation)
{
char *s = NULL;
- int fd = -1;
+ int fd;
if (dbfilename == NULL) {
return;
}
- /*
- * Do initial setup.
- */
- debug_setup_1();
+ /* set 'dbgdir' and clean out old debug files */
+ debug_setup_1(NULL, NULL);
/*
* Reopen the file.
} else {
s = newvstralloc(s, dbgdir, dbfilename, NULL);
}
- if ((fd = open(s, O_RDWR|O_APPEND, 0600)) < 0) {
- error("cannot reopen %s debug file %s", get_pname(), dbfilename);
+ if ((fd = open(s, O_RDWR|O_APPEND)) < 0) {
+ error(_("cannot reopen debug file %s"), dbfilename);
+ /*NOTREACHED*/
+ }
+
+ /*
+ * Finish setup.
+ *
+ * Note: we release control of the string 's' points to.
+ */
+ debug_setup_2(s, fd, annotation);
+}
+
+void
+debug_rename(
+ char *config,
+ char *subdir)
+{
+ int fd = -1;
+ int i;
+ char *s = NULL;
+ mode_t mask;
+
+ if (!db_filename)
+ return;
+
+ /* set 'dbgdir' and clean out old debug files */
+ debug_setup_1(config, subdir);
+
+ s = newvstralloc(s, dbgdir, db_name, NULL);
+
+ if (strcmp(db_filename, s) == 0) {
+ amfree(s);
+ return;
+ }
+
+ mask = (mode_t)umask((mode_t)0037);
+
+#if defined(__CYGWIN__)
+ /*
+ * On cygwin, rename will not overwrite an existing file nor
+ * will it rename a file that is open for writing...
+ *
+ * Rename file directly. Expect failure if file already exists
+ * or is open by another user.
+ */
+
+ i = 0;
+ while (rename(db_filename, s) < 0) {
+ if (errno != EEXIST) {
+ /*
+ * If the failure was not due to the target file name already
+ * existing then we have bigger issues at hand so we keep
+ * the existing file.
+ */
+ dbprintf(_("Cannot rename \"%s\" to \"%s\": %s\n"),
+ db_filename, s, strerror(errno));
+ s = newvstralloc(s, db_filename, NULL);
+ i = -1;
+ break;
+ }
+
+ /*
+ * Files already exists:
+ * Continue searching for a unique file name that will work.
+ */
+ amfree(db_name);
+ if ((db_name = get_debug_name(open_time, i++)) == NULL) {
+ dbprintf(_("Cannot create unique debug file name"));
+ break;
+ }
+ s = newvstralloc(s, dbgdir, db_name, NULL);
+ }
+ if (i >= 0) {
+ /*
+ * We need to close and reopen the original file handle to
+ * release control of the original debug file name.
+ */
+ if ((fd = open(s, O_WRONLY|O_APPEND, 0640)) >= 0) {
+ /*
+ * We can safely close the the original log file
+ * since we now have a new working handle.
+ */
+ db_fd = 2;
+ fclose(db_file);
+ db_file = NULL;
+ }
+ }
+#else
+ /* check if a file with the same name already exists. */
+ if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
+ for(i = 0; fd < 0; i++) {
+ amfree(db_name);
+ if ((db_name = get_debug_name(open_time, i)) == NULL) {
+ dbprintf(_("Cannot create debug file"));
+ break;
+ }
+
+ s = newvstralloc(s, dbgdir, db_name, NULL);
+ if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
+ if (errno != EEXIST) {
+ dbprintf(_("Cannot create debug file: %s"),
+ strerror(errno));
+ break;
+ }
+ }
+ }
}
+ if (fd >= 0) {
+ close(fd);
+ if (rename(db_filename, s) == -1) {
+ dbprintf(_("Cannot rename \"%s\" to \"%s\": %s\n"),
+ db_filename, s, strerror(errno));
+ }
+ fd = -1;
+ }
+#endif
+
+ (void)umask(mask); /* Restore mask */
/*
* Finish setup.
*
* Note: we release control of the string 's' points to.
*/
- debug_setup_2(s, fd, notation);
+ debug_setup_2(s, fd, "rename");
}
-void debug_close()
+void
+debug_close(void)
{
time_t curtime;
- int save_debug;
- pid_t save_pid;
time(&curtime);
- save_debug = debug;
- debug = 1;
- save_pid = debug_prefix_pid;
- debug_prefix_pid = 0;
- debug_printf("%s: pid %ld finish time %s",
- debug_prefix_time(NULL),
- (long)getpid(),
- ctime(&curtime));
- debug_prefix_pid = save_pid;
- debug = save_debug;
+ debug_printf(_("pid %ld finish time %s"), (long)getpid(), ctime(&curtime));
if(db_file && fclose(db_file) == EOF) {
int save_errno = errno;
db_file = NULL; /* prevent recursion */
- error("close debug file: %s", strerror(save_errno));
+ g_fprintf(stderr, _("close debug file: %s"), strerror(save_errno));
+ /*NOTREACHED*/
}
- db_fd = -1;
+ db_fd = 2;
db_file = NULL;
amfree(db_filename);
+ amfree(db_name);
}
-int debug_fd()
+/*
+ * Format and write a debug message to the process debug file.
+ */
+printf_arglist_function(void debug_printf, const char *, format)
{
- return db_fd;
-}
+ va_list argp;
+ int save_errno;
-FILE *debug_fp()
-{
- return db_file;
+ /*
+ * It is common in the code to call dbprintf to write out
+ * syserrno(errno) and then turn around and try to do something else
+ * with errno (e.g. g_printf() or log()), so we make sure errno goes
+ * back out with the same value it came in with.
+ */
+
+ save_errno = errno;
+
+ /* handle the default (stderr) if debug_open hasn't been called yet */
+ if(db_file == NULL && db_fd == 2) {
+ db_file = stderr;
+ }
+ if(db_file != NULL) {
+ char *prefix;
+ char *text;
+
+ if (db_file != stderr)
+ prefix = g_strdup_printf("%s: %s:", msg_timestamp(), get_pname());
+ else
+ prefix = g_strdup_printf("%s:", get_pname());
+ arglist_start(argp, format);
+ text = g_strdup_vprintf(format, argp);
+ arglist_end(argp);
+ fprintf(db_file, "%s %s", prefix, text);
+ amfree(prefix);
+ amfree(text);
+ fflush(db_file);
+ }
+ errno = save_errno;
}
-char *debug_fn()
+int
+debug_fd(void)
{
- return db_filename;
+ return db_fd;
}
-/*
- * Routines for returning a common debug file line prefix. Always starts
- * with the current program name, possibly with an optional suffix.
- * May then be followed by a PID. May then be followed by an elapsed
- * time indicator.
- */
-
-void set_debug_prefix_pid(p)
- pid_t p;
+FILE *
+debug_fp(void)
{
- debug_prefix_pid = p;
+ return db_file;
}
-char *debug_prefix(suffix)
- char *suffix;
+char *
+debug_fn(void)
{
- static char *s = NULL;
- char debug_pid[NUM_STR_SIZE];
-
- s = newvstralloc(s, get_pname(), suffix, NULL);
- if (debug_prefix_pid != (pid_t) 0) {
- ap_snprintf(debug_pid, sizeof(debug_pid),
- "%ld",
- (long) debug_prefix_pid);
- s = newvstralloc(s, s, "[", debug_pid, "]", NULL);
- }
- return s;
+ return db_filename;
}
-char *debug_prefix_time(suffix)
- char *suffix;
+void
+debug_dup_stderr_to_debug(void)
{
- static char *s = NULL;
- char *t1;
- char *t2;
-
- if (clock_is_running()) {
- t1 = ": time ";
- t2 = walltime_str(curclock());
- } else {
- t1 = t2 = NULL;
+ if(db_fd != -1 && db_fd != STDERR_FILENO)
+ {
+ if(dup2(db_fd, STDERR_FILENO) != STDERR_FILENO)
+ {
+ error(_("can't redirect stderr to the debug file"));
+ g_assert_not_reached();
+ }
}
-
- s = newvstralloc(s, debug_prefix(suffix), t1, t2, NULL);
-
- return s;
}
-#endif
+