Imported Upstream version 3.3.3
[debian/amanda] / common-src / debug.c
1 /*
2  * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3  * Copyright (c) 1991-1998 University of Maryland at College Park
4  * Copyright (c) 2007-2012 Zmanda, Inc.  All Rights Reserved.
5  * All Rights Reserved.
6  *
7  * Permission to use, copy, modify, distribute, and sell this software and its
8  * documentation for any purpose is hereby granted without fee, provided that
9  * the above copyright notice appear in all copies and that both that
10  * copyright notice and this permission notice appear in supporting
11  * documentation, and that the name of U.M. not be used in advertising or
12  * publicity pertaining to distribution of the software without specific,
13  * written prior permission.  U.M. makes no representations about the
14  * suitability of this software for any purpose.  It is provided "as is"
15  * without express or implied warranty.
16  *
17  * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19  * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21  * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23  *
24  * Author: James da Silva, Systems Design and Analysis Group
25  *                         Computer Science Department
26  *                         University of Maryland at College Park
27  */
28 /*
29  * $Id: debug.c,v 1.40 2006/07/26 11:49:32 martinea Exp $
30  *
31  * Logging support
32  */
33
34 #include "amanda.h"
35 #include "util.h"
36 #include "arglist.h"
37 #include "clock.h"
38 #include "timestamp.h"
39 #include "conffile.h"
40
41 #ifdef HAVE_GLIBC_BACKTRACE
42 #include <execinfo.h>
43 #endif
44
45 /* Minimum file descriptor on which to keep the debug file.  This is intended
46  * to keep the descriptor "out of the way" of other processing.  It's not clear
47  * that this is required any longer, but it doesn't hurt anything.
48  */
49 #define MIN_DB_FD                       10
50
51 /* information on the current debug file */
52 static int db_fd = 2;                   /* file descriptor (default stderr) */
53 static FILE *db_file = NULL;            /* stdio stream */
54 static char *db_name  = NULL;           /* unqualified filename */
55 static char *db_filename = NULL;        /* fully qualified pathname */
56
57 /* directory containing debug file, including trailing slash */
58 static char *dbgdir = NULL;
59
60 /* time debug log was opened (timestamp of the file) */
61 static time_t open_time;
62
63 /* storage for global variables */
64 int error_exit_status = 1;
65
66 /* static function prototypes */
67 static char *get_debug_name(time_t t, int n);
68 static void debug_unlink_old(void);
69 static void debug_setup_1(char *config, char *subdir);
70 static void debug_setup_2(char *s, int fd, char *annotation);
71 static char *msg_timestamp(void);
72 static char *msg_thread(void);
73
74 static void debug_logging_handler(const gchar *log_domain,
75         GLogLevelFlags log_level,
76         const gchar *message,
77         gpointer user_data);
78 static void debug_setup_logging(void);
79
80 /* By default, do not suppress tracebacks */
81 static gboolean do_suppress_error_traceback = FALSE;
82
83 /* configured amanda_log_handlers */
84 static GSList *amanda_log_handlers = NULL;
85
86 /*
87  * Generate a debug file name.  The name is based on the program name,
88  * followed by a timestamp, an optional sequence number, and ".debug".
89  *
90  * @param t: timestamp
91  * @param n: sequence number between 1 and 1000; if zero, no sequence number
92  * is included.
93  */
94 static char *
95 get_debug_name(
96     time_t      t,
97     int         n)
98 {
99     char number[NUM_STR_SIZE];
100     char *ts;
101     char *result;
102
103     if(n < 0 || n > 1000) {
104         return NULL;
105     }
106     ts = get_timestamp_from_time(t);
107     if(n == 0) {
108         number[0] = '\0';
109     } else {
110         g_snprintf(number, SIZEOF(number), "%03d", n - 1);
111     }
112     result = vstralloc(get_pname(), ".", ts, number, ".debug", NULL);
113     amfree(ts);
114     return result;
115 }
116
117 /* Call this to suppress tracebacks on error() or g_critical().  This is used
118  * when a critical error is indicated in perl, and the traceback will not be
119  * useful. */
120 void
121 suppress_error_traceback(void)
122 {
123     do_suppress_error_traceback = 1;
124 }
125
126 /* A GLogFunc to handle g_log calls.  This function assumes that user_data
127  * is either NULL or a pointer to one of the debug_* configuration variables
128  * in conffile.c, indicating whether logging for this log domain is enabled.
129  *
130  * @param log_domain: the log domain, or NULL for general logging
131  * @param log_level: level, fatality, and recursion flags
132  * @param message: the message to log
133  * @param user_pointer: unused
134  */
135 static void
136 debug_logging_handler(const gchar *log_domain G_GNUC_UNUSED,
137             GLogLevelFlags log_level,
138             const gchar *message,
139             gpointer user_data G_GNUC_UNUSED)
140 {
141     GLogLevelFlags maxlevel;
142     char *levprefix = NULL;
143     pcontext_t context = get_pcontext();
144
145     /* glib allows a message to have multiple levels, so calculate the "worst"
146      * level */
147     if (log_level & G_LOG_LEVEL_ERROR) {
148         maxlevel = G_LOG_LEVEL_ERROR;
149         levprefix = _("error (fatal): ");
150     } else if (log_level & G_LOG_LEVEL_CRITICAL) {
151         maxlevel = G_LOG_LEVEL_CRITICAL;
152         levprefix = _("critical (fatal): ");
153     } else if (log_level & G_LOG_LEVEL_WARNING) {
154         maxlevel = G_LOG_LEVEL_WARNING;
155         levprefix = _("warning: ");
156     } else if (log_level & G_LOG_LEVEL_MESSAGE) {
157         maxlevel = G_LOG_LEVEL_MESSAGE;
158         levprefix = _("message: ");
159     } else if (log_level & G_LOG_LEVEL_INFO) {
160         maxlevel = G_LOG_LEVEL_INFO;
161         levprefix = _("info: ");
162     } else {
163         maxlevel = G_LOG_LEVEL_DEBUG;
164         levprefix = ""; /* no level displayed for debugging */
165     }
166
167     /* scriptutil context doesn't do any logging except for critical
168      * and error levels */
169     if (context != CONTEXT_SCRIPTUTIL) {
170         /* convert the highest level to a string and dbprintf it */
171         debug_printf("%s%s\n", levprefix, message);
172     }
173
174     if (amanda_log_handlers) {
175         GSList *iter = amanda_log_handlers;
176         while (iter) {
177             amanda_log_handler_t *hdlr = (amanda_log_handler_t *)iter->data;
178             hdlr(maxlevel, message);
179             iter = g_slist_next(iter);
180         }
181     } else {
182         /* call the appropriate handlers, based on the context */
183         amanda_log_stderr(maxlevel, message);
184         if (context == CONTEXT_DAEMON)
185             amanda_log_syslog(maxlevel, message);
186     }
187
188     /* error and critical levels have special handling */
189     if (log_level & (G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL)) {
190 #ifdef HAVE_GLIBC_BACKTRACE
191         /* try logging a traceback to the debug log */
192         if (!do_suppress_error_traceback && db_fd != -1) {
193             void *stack[32];
194             int naddrs;
195             naddrs = backtrace(stack, sizeof(stack)/sizeof(*stack));
196             backtrace_symbols_fd(stack, naddrs, db_fd);
197         }
198 #endif
199
200         /* we're done */
201         if (log_level & G_LOG_LEVEL_CRITICAL)
202             exit(error_exit_status);
203         else
204             abort();
205         g_assert_not_reached();
206     }
207 }
208
209 /* Install our handler into the glib log handling system.
210  */
211 static void
212 debug_setup_logging(void)
213 {
214     /* g_error and g_critical should be fatal, although the log handler
215      * takes care of this anyway */
216     g_log_set_always_fatal(G_LOG_LEVEL_ERROR |  G_LOG_LEVEL_CRITICAL);
217
218     /* set up handler (g_log_set_default_handler is new in glib-2.6, and
219      * hence not useable here) */
220     g_log_set_handler(NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL | G_LOG_FLAG_RECURSION,
221                       debug_logging_handler, NULL);
222 }
223
224 void
225 add_amanda_log_handler(amanda_log_handler_t *hdlr)
226 {
227     amanda_log_handlers = g_slist_append(amanda_log_handlers, (gpointer)hdlr);
228 }
229
230 void
231 amanda_log_syslog(GLogLevelFlags log_level, const gchar *message)
232 {
233     int priority = LOG_ERR;
234     switch (log_level) {
235         case G_LOG_LEVEL_ERROR:
236         case G_LOG_LEVEL_CRITICAL:
237             priority = LOG_ERR;
238             break;
239
240         case G_LOG_LEVEL_WARNING:
241 #ifdef LOG_WARNING
242             priority = LOG_WARNING;
243 #endif
244             break;
245
246         default:
247             return;
248     }
249
250 #ifdef LOG_DAEMON
251     openlog(get_pname(), LOG_PID, LOG_DAEMON);
252 #else
253     openlog(get_pname(), LOG_PID, 0);
254 #endif
255     syslog(priority, "%s", message);
256     closelog();
257
258 }
259
260 void
261 amanda_log_stderr(GLogLevelFlags log_level, const gchar *message)
262 {
263     switch (log_level) {
264         case G_LOG_LEVEL_ERROR:
265         case G_LOG_LEVEL_CRITICAL:
266             g_fprintf(stderr, "%s: %s\n", get_pname(), message);
267             break;
268
269         default:
270             return;
271     }
272 }
273
274 void
275 amanda_log_null(GLogLevelFlags log_level G_GNUC_UNUSED, const gchar *message G_GNUC_UNUSED)
276 {
277 }
278
279 /* Set the global dbgdir according to 'config' and 'subdir'
280  *
281  * The global open_time is set to the current time, and used to delete
282  * old files.
283  *
284  * @param config: configuration or NULL
285  * @param subdir: subdirectory (server, client, etc.) or NULL
286  */
287 static void
288 debug_setup_1(char *config, char *subdir)
289 {
290     char *sane_config = NULL;
291
292     /*
293      * Create the debug directory if it does not yet exist.
294      */
295     amfree(dbgdir);
296     if (config)
297         sane_config = sanitise_filename(config);
298     if (sane_config && subdir)
299         dbgdir = vstralloc(AMANDA_DBGDIR, "/", subdir, "/", sane_config,
300                            "/", NULL);
301     else if (sane_config)
302         dbgdir = vstralloc(AMANDA_DBGDIR, "/", sane_config, "/", NULL);
303     else if (subdir)
304         dbgdir = vstralloc(AMANDA_DBGDIR, "/", subdir, "/", NULL);
305     else
306         dbgdir = stralloc2(AMANDA_DBGDIR, "/");
307     if(mkpdir(dbgdir, 0700, get_client_uid(), get_client_gid()) == -1) {
308         error(_("create debug directory \"%s\": %s"),
309               dbgdir, strerror(errno));
310         /*NOTREACHED*/
311     }
312     amfree(sane_config);
313
314     time(&open_time);
315 }
316
317 /*
318  * Clean out old debug files.  We also rename files with old style
319  * names (XXX.debug or XXX.$PID.debug) into the new name format.
320  * We assume no system has 17 digit PID-s :-) and that there will
321  * not be a conflict between an old and new name.
322  */
323 static void
324 debug_unlink_old(void)
325 {
326     char *pname;
327     size_t pname_len;
328     char *e = NULL;
329     char *s = NULL;
330     struct dirent *entry;
331     int do_rename;
332     char *test_name;
333     size_t test_name_len;
334     size_t d_name_len;
335     char *dbfilename = NULL;
336     int i;
337     DIR *d;
338     struct stat sbuf;
339
340     assert(dbgdir != NULL);
341
342     memset(&sbuf, 0, SIZEOF(sbuf));
343
344     pname = get_pname();
345     pname_len = strlen(pname);
346
347     if((d = opendir(dbgdir)) == NULL) {
348         error(_("open debug directory \"%s\": %s"),
349               dbgdir, strerror(errno));
350         /*NOTREACHED*/
351     }
352     test_name = get_debug_name(open_time - (getconf_int(CNF_DEBUG_DAYS) * 24 * 60 * 60), 0);
353     test_name_len = strlen(test_name);
354     while((entry = readdir(d)) != NULL) {
355         if(is_dot_or_dotdot(entry->d_name)) {
356             continue;
357         }
358         d_name_len = strlen(entry->d_name);
359         if(strncmp(entry->d_name, pname, pname_len) != 0
360            || entry->d_name[pname_len] != '.'
361            || d_name_len < 6
362            || strcmp(entry->d_name + d_name_len - 6, ".debug") != 0) {
363             continue;                           /* not one of our debug files */
364         }
365         e = newvstralloc(e, dbgdir, entry->d_name, NULL);
366         if(d_name_len < test_name_len) {
367             /*
368              * Create a "pretend" name based on the last modification
369              * time.  This name will be used to decide if the real name
370              * should be removed.  If not, it will be used to rename the
371              * real name.
372              */
373             if(stat(e, &sbuf) != 0) {
374                 continue;                       /* ignore errors */
375             }
376             amfree(dbfilename);
377             dbfilename = get_debug_name((time_t)sbuf.st_mtime, 0);
378             do_rename = 1;
379         } else {
380             dbfilename = newstralloc(dbfilename, entry->d_name);
381             do_rename = 0;
382         }
383         if(strcmp(dbfilename, test_name) < 0) {
384             (void) unlink(e);                   /* get rid of old file */
385             continue;
386         }
387         if(do_rename) {
388             i = 0;
389             while(dbfilename != NULL
390                   && (s = newvstralloc(s, dbgdir, dbfilename, NULL)) != NULL
391                   && rename(e, s) != 0 && errno != ENOENT) {
392                 amfree(dbfilename);
393                 dbfilename = get_debug_name((time_t)sbuf.st_mtime, ++i);
394             }
395             if(dbfilename == NULL) {
396                 error(_("cannot rename old debug file \"%s\""), entry->d_name);
397                 /*NOTREACHED*/
398             }
399         }
400     }
401     amfree(dbfilename);
402     amfree(e);
403     amfree(s);
404     amfree(test_name);
405     closedir(d);
406 }
407
408 /* Given an already-opened debug file, set the file's ownership
409  * appropriately, move its file descriptor above MIN_DB_FD, and
410  * add an initial log entry to the file.
411  *
412  * This function records the file's identity in the globals
413  * db_filename, db_fd, and db_file.  It does *not* set db_name.
414  * db_file is not set if fd is -1
415  *
416  * This function uses the global 'open_time', which is set by
417  * debug_setup_1.
418  *
419  * @param s: the filename of the debug file; string should be malloc'd,
420  * and should *not* be freed by the caller.
421  * @param fd: the descriptor connected to the debug file, or -1 if
422  * no decriptor moving should take place.
423  * @param annotation: an extra string to include in the initial
424  * log entry.
425  */
426 static void
427 debug_setup_2(
428     char *      s,
429     int         fd,
430     char *      annotation)
431 {
432     int i;
433     int fd_close[MIN_DB_FD+1];
434
435     amfree(db_filename);
436     db_filename = s;
437     s = NULL;
438
439     /* If we're root, change the ownership of the debug files.  If we're not root,
440      * this would either be redundant or an error. */
441     if (geteuid() == 0) {
442         if (chown(db_filename, get_client_uid(), get_client_gid()) < 0) {
443             dbprintf(_("chown(%s, %d, %d) failed: %s"),
444                      db_filename, (int)get_client_uid(), (int)get_client_gid(), strerror(errno));
445         }
446     }
447
448     /*
449      * Move the file descriptor up high so it stays out of the way
450      * of other processing, e.g. sendbackup.
451      */
452     if (fd >= 0) {
453         i = 0;
454         fd_close[i++] = fd;
455         while((db_fd = dup(fd)) < MIN_DB_FD) {
456             fd_close[i++] = db_fd;
457         }
458         while(--i >= 0) {
459             close(fd_close[i]);
460         }
461         db_file = fdopen(db_fd, "a");
462     }
463
464     if (annotation) {
465         /*
466          * Make the first debug log file entry.
467          */
468         debug_printf(_("pid %ld ruid %ld euid %ld version %s: %s at %s"),
469                      (long)getpid(),
470                      (long)getuid(), (long)geteuid(),
471                      VERSION,
472                      annotation,
473                      ctime(&open_time));
474     }
475 }
476
477 /* Get current GMT time and return a message timestamp.
478  * Used for g_printf calls to logs and such.  The return value
479  * is to a static buffer, so it should be used immediately.
480  *
481  * @returns: timestamp
482  */
483 static char *
484 msg_timestamp(void)
485 {
486     static char  timestamp[128];
487     char        *r;
488     time_t       curtime;
489
490     time(&curtime);
491     ctime_r(&curtime, timestamp);
492     r = strchr(timestamp, '\n');
493     if (r)
494         *r = '\0';
495
496     return timestamp;
497 }
498
499 /* Get current GMT time and return a message timestamp.
500  * Used for g_printf calls to logs and such.  The return value
501  * is to a static buffer, so it should be used immediately.
502  *
503  * @returns: timestamp
504  */
505 static char *
506 msg_thread(void)
507 {
508     static char  thread[128];
509
510     sprintf(thread, "thd-%p", g_thread_self());
511
512     return thread;
513 }
514
515 /*
516  * ---- public functions
517  */
518
519 void
520 debug_init(void)
521 {
522     debug_setup_logging();
523
524     /* the scriptutil context does not create a debug log, since such
525      * processes are invoked many times.
526      */
527     if (get_pcontext() != CONTEXT_SCRIPTUTIL) {
528         debug_open(get_ptype());
529     }
530 }
531
532 void
533 debug_open(char *subdir)
534 {
535     int fd = -1;
536     int i;
537     char *s = NULL;
538     mode_t mask;
539
540     /* create AMANDA_TMPDIR */
541     make_amanda_tmpdir();
542
543     /* set up logging while we're here */
544     debug_setup_logging();
545
546     /* set 'dbgdir' and clean out old debug files */
547     debug_setup_1(NULL, subdir);
548
549     /*
550      * Create the new file with a unique sequence number.
551      */
552     mask = (mode_t)umask((mode_t)0037); /* Allow the group read bit through */
553
554     /* iteratate through sequence numbers until we find one that
555      * is not already in use */
556     for(i = 0; fd < 0; i++) {
557         amfree(db_name);
558         if ((db_name = get_debug_name(open_time, i)) == NULL) {
559             error(_("Cannot create debug file name in %d tries."), i);
560             /*NOTREACHED*/
561         }
562
563         if ((s = newvstralloc(s, dbgdir, db_name, NULL)) == NULL) {
564             error(_("Cannot allocate debug file name memory"));
565             /*NOTREACHED*/
566         }
567
568         if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
569             if (errno != EEXIST) {
570                 error(_("Cannot create debug file \"%s\": %s"),
571                         s, strerror(errno));
572                 /*NOTREACHED*/
573             }
574             amfree(s);
575         }
576     }
577     (void)umask(mask); /* Restore mask */
578
579     /*
580      * Finish setup.
581      *
582      * Note: we release control of the string 's' points to.
583      */
584     debug_setup_2(s, fd, "start");
585 }
586
587 void
588 debug_reopen(
589     char *      dbfilename,
590     char *      annotation)
591 {
592     char *s = NULL;
593     int fd;
594
595     if (dbfilename == NULL) {
596         return;
597     }
598
599     /* set 'dbgdir' and clean out old debug files */
600     debug_setup_1(NULL, NULL);
601
602     /*
603      * Reopen the file.
604      */
605     if (*dbfilename == '/') {
606         s = stralloc(dbfilename);
607     } else {
608         s = newvstralloc(s, dbgdir, dbfilename, NULL);
609     }
610     if ((fd = open(s, O_RDWR|O_APPEND)) < 0) {
611         error(_("cannot reopen debug file %s"), dbfilename);
612         /*NOTREACHED*/
613     }
614
615     /*
616      * Finish setup.
617      *
618      * Note: we release control of the string 's' points to.
619      */
620     debug_setup_2(s, fd, annotation);
621 }
622
623 void
624 debug_rename(
625     char *config,
626     char *subdir)
627 {
628     int fd = -1;
629     int i;
630     char *s = NULL;
631     mode_t mask;
632
633     if (!db_filename)
634         return;
635
636     if (get_pcontext() == CONTEXT_SCRIPTUTIL) {
637         return;
638     }
639
640     /* Remove old log from source directory */
641     debug_unlink_old();
642     /* set 'dbgdir' and clean out old debug files */
643     debug_setup_1(config, subdir);
644     /* Remove old log from destination directory */
645     debug_unlink_old();
646
647     s = newvstralloc(s, dbgdir, db_name, NULL);
648
649     if (strcmp(db_filename, s) == 0) {
650         amfree(s);
651         return;
652     }
653
654     mask = (mode_t)umask((mode_t)0037);
655
656 #if defined(__CYGWIN__)
657     /*
658      * On cygwin, rename will not overwrite an existing file nor
659      * will it rename a file that is open for writing...
660      *
661      * Rename file directly.  Expect failure if file already exists
662      * or is open by another user.
663      */
664
665     i = 0;
666     while (rename(db_filename, s) < 0) {
667         if (errno != EEXIST) {
668             /*
669              * If the failure was not due to the target file name already
670              * existing then we have bigger issues at hand so we keep 
671              * the existing file.
672              */
673             dbprintf(_("Cannot rename \"%s\" to \"%s\": %s\n"),
674                      db_filename, s, strerror(errno));
675             s = newvstralloc(s, db_filename, NULL);
676             i = -1;
677             break;
678         }
679
680         /*
681          * Files already exists:
682          * Continue searching for a unique file name that will work.
683          */
684         amfree(db_name);
685         if ((db_name = get_debug_name(open_time, i++)) == NULL) {
686             dbprintf(_("Cannot create unique debug file name"));
687             break;
688         }
689         s = newvstralloc(s, dbgdir, db_name, NULL);
690     }
691     if (i >= 0) {
692         /*
693          * We need to close and reopen the original file handle to
694          * release control of the original debug file name.
695          */
696         if ((fd = open(s, O_WRONLY|O_APPEND, 0640)) >= 0) {
697             /*
698              * We can safely close the the original log file
699              * since we now have a new working handle.
700              */
701             db_fd = 2;
702             fclose(db_file);
703             db_file = NULL;
704         }
705     }
706 #else
707     /* check if a file with the same name already exists. */
708     if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
709         for(i = 0; fd < 0; i++) {
710             amfree(db_name);
711             if ((db_name = get_debug_name(open_time, i)) == NULL) {
712                 dbprintf(_("Cannot create debug file"));
713                 break;
714             }
715
716             s = newvstralloc(s, dbgdir, db_name, NULL);
717             if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
718                 if (errno != EEXIST) {
719                     dbprintf(_("Cannot create debug file: %s"),
720                               strerror(errno));
721                     break;
722                 }
723             }
724         }
725     }
726
727     if (fd >= 0) {
728         close(fd);
729         if (rename(db_filename, s) == -1) {
730             dbprintf(_("Cannot rename \"%s\" to \"%s\": %s\n"),
731                      db_filename, s, strerror(errno));
732         }
733         fd = -1;
734     }
735 #endif
736
737     (void)umask(mask); /* Restore mask */
738     /*
739      * Finish setup.
740      *
741      * Note: we release control of the string 's' points to.
742      */
743     debug_setup_2(s, fd, "rename");
744 }
745
746 void
747 debug_close(void)
748 {
749     time_t curtime;
750
751     if (get_pcontext() == CONTEXT_SCRIPTUTIL) {
752         return;
753     }
754
755     debug_unlink_old();
756
757     time(&curtime);
758     debug_printf(_("pid %ld finish time %s"), (long)getpid(), ctime(&curtime));
759
760     if(db_file && fclose(db_file) == EOF) {
761         int save_errno = errno;
762
763         db_file = NULL;                         /* prevent recursion */
764         g_fprintf(stderr, _("close debug file: %s"), strerror(save_errno));
765         /*NOTREACHED*/
766     }
767     db_fd = 2;
768     db_file = NULL;
769     amfree(db_filename);
770     amfree(db_name);
771 }
772
773 /*
774  * Format and write a debug message to the process debug file.
775  */
776 printf_arglist_function(void debug_printf, const char *, format)
777 {
778     va_list argp;
779     int save_errno;
780
781     /*
782      * It is common in the code to call dbprintf to write out
783      * syserrno(errno) and then turn around and try to do something else
784      * with errno (e.g. g_printf() or log()), so we make sure errno goes
785      * back out with the same value it came in with.
786      */
787
788     save_errno = errno;
789
790     /* handle the default (stderr) if debug_open hasn't been called yet */
791     if(db_file == NULL && db_fd == 2) {
792         db_file = stderr;
793     }
794     if(db_file != NULL) {
795         char *prefix;
796         char *text;
797
798         if (db_file != stderr)
799             prefix = g_strdup_printf("%s: %s: %s:", msg_timestamp(), msg_thread(), get_pname());
800         else 
801             prefix = g_strdup_printf("%s:", get_pname());
802         arglist_start(argp, format);
803         text = g_strdup_vprintf(format, argp);
804         arglist_end(argp);
805         fprintf(db_file, "%s %s", prefix, text);
806         amfree(prefix);
807         amfree(text);
808         fflush(db_file);
809     }
810     errno = save_errno;
811 }
812
813 int
814 debug_fd(void)
815 {
816     return db_fd;
817 }
818
819 FILE *
820 debug_fp(void)
821 {
822     return db_file;
823 }
824
825 char *
826 debug_fn(void)
827 {
828     return db_filename;
829 }
830
831 void
832 debug_dup_stderr_to_debug(void)
833 {
834     if(db_fd != -1 && db_fd != STDERR_FILENO)
835     {
836        if(dup2(db_fd, STDERR_FILENO) != STDERR_FILENO)
837        {
838            error(_("can't redirect stderr to the debug file: %d, %s"), db_fd, strerror(errno));
839            g_assert_not_reached();
840        }
841     }
842 }
843