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-2013 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 *
get_debug_name(time_t t,int n)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
suppress_error_traceback(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
debug_logging_handler(const gchar * log_domain G_GNUC_UNUSED,GLogLevelFlags log_level,const gchar * message,gpointer user_data G_GNUC_UNUSED)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
debug_setup_logging(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
add_amanda_log_handler(amanda_log_handler_t * hdlr)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
amanda_log_syslog(GLogLevelFlags log_level,const gchar * message)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
amanda_log_stderr(GLogLevelFlags log_level,const gchar * message)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
amanda_log_null(GLogLevelFlags log_level G_GNUC_UNUSED,const gchar * message G_GNUC_UNUSED)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
debug_setup_1(char * config,char * subdir)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
debug_unlink_old(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     if (!config_is_initialized())
345 	return;
346     pname = get_pname();
347     pname_len = strlen(pname);
348 
349     if((d = opendir(dbgdir)) == NULL) {
350 	error(_("open debug directory \"%s\": %s"),
351 	      dbgdir, strerror(errno));
352 	/*NOTREACHED*/
353     }
354     test_name = get_debug_name(open_time - (getconf_int(CNF_DEBUG_DAYS) * 24 * 60 * 60), 0);
355     test_name_len = strlen(test_name);
356     while((entry = readdir(d)) != NULL) {
357 	if(is_dot_or_dotdot(entry->d_name)) {
358 	    continue;
359 	}
360 	d_name_len = strlen(entry->d_name);
361 	if(strncmp(entry->d_name, pname, pname_len) != 0
362 	   || entry->d_name[pname_len] != '.'
363 	   || d_name_len < 6
364 	   || strcmp(entry->d_name + d_name_len - 6, ".debug") != 0) {
365 	    continue;				/* not one of our debug files */
366 	}
367 	e = newvstralloc(e, dbgdir, entry->d_name, NULL);
368 	if(d_name_len < test_name_len) {
369 	    /*
370 	     * Create a "pretend" name based on the last modification
371 	     * time.  This name will be used to decide if the real name
372 	     * should be removed.  If not, it will be used to rename the
373 	     * real name.
374 	     */
375 	    if(stat(e, &sbuf) != 0) {
376 		continue;			/* ignore errors */
377 	    }
378 	    amfree(dbfilename);
379 	    dbfilename = get_debug_name((time_t)sbuf.st_mtime, 0);
380 	    do_rename = 1;
381 	} else {
382 	    dbfilename = newstralloc(dbfilename, entry->d_name);
383 	    do_rename = 0;
384 	}
385 	if(strcmp(dbfilename, test_name) < 0) {
386 	    (void) unlink(e);			/* get rid of old file */
387 	    continue;
388 	}
389 	if(do_rename) {
390 	    i = 0;
391 	    while(dbfilename != NULL
392 		  && (s = newvstralloc(s, dbgdir, dbfilename, NULL)) != NULL
393 		  && rename(e, s) != 0 && errno != ENOENT) {
394 		amfree(dbfilename);
395 		dbfilename = get_debug_name((time_t)sbuf.st_mtime, ++i);
396 	    }
397 	    if(dbfilename == NULL) {
398 		error(_("cannot rename old debug file \"%s\""), entry->d_name);
399 		/*NOTREACHED*/
400 	    }
401 	}
402     }
403     amfree(dbfilename);
404     amfree(e);
405     amfree(s);
406     amfree(test_name);
407     closedir(d);
408 }
409 
410 /* Given an already-opened debug file, set the file's ownership
411  * appropriately, move its file descriptor above MIN_DB_FD, and
412  * add an initial log entry to the file.
413  *
414  * This function records the file's identity in the globals
415  * db_filename, db_fd, and db_file.  It does *not* set db_name.
416  * db_file is not set if fd is -1
417  *
418  * This function uses the global 'open_time', which is set by
419  * debug_setup_1.
420  *
421  * @param s: the filename of the debug file; string should be malloc'd,
422  * and should *not* be freed by the caller.
423  * @param fd: the descriptor connected to the debug file, or -1 if
424  * no decriptor moving should take place.
425  * @param annotation: an extra string to include in the initial
426  * log entry.
427  */
428 static void
debug_setup_2(char * s,int fd,char * annotation)429 debug_setup_2(
430     char *	s,
431     int		fd,
432     char *	annotation)
433 {
434     int i;
435     int fd_close[MIN_DB_FD+1];
436 
437     amfree(db_filename);
438     db_filename = s;
439     s = NULL;
440 
441     /* If we're root, change the ownership of the debug files.  If we're not root,
442      * this would either be redundant or an error. */
443     if (geteuid() == 0) {
444 	if (chown(db_filename, get_client_uid(), get_client_gid()) < 0) {
445 	    dbprintf(_("chown(%s, %d, %d) failed: %s"),
446 		     db_filename, (int)get_client_uid(), (int)get_client_gid(), strerror(errno));
447 	}
448     }
449 
450     /*
451      * Move the file descriptor up high so it stays out of the way
452      * of other processing, e.g. sendbackup.
453      */
454     if (fd >= 0) {
455 	i = 0;
456 	fd_close[i++] = fd;
457 	while((db_fd = dup(fd)) < MIN_DB_FD) {
458 	    fd_close[i++] = db_fd;
459 	}
460 	while(--i >= 0) {
461 	    close(fd_close[i]);
462 	}
463 	db_file = fdopen(db_fd, "a");
464     }
465 
466     if (annotation) {
467 	/*
468 	 * Make the first debug log file entry.
469 	 */
470 	debug_printf(_("pid %ld ruid %ld euid %ld version %s: %s at %s"),
471 		     (long)getpid(),
472 		     (long)getuid(), (long)geteuid(),
473 		     VERSION,
474 		     annotation,
475 		     ctime(&open_time));
476     }
477 }
478 
479 /* Get current GMT time and return a message timestamp.
480  * Used for g_printf calls to logs and such.  The return value
481  * is to a static buffer, so it should be used immediately.
482  *
483  * @returns: timestamp
484  */
485 static char *
msg_timestamp(void)486 msg_timestamp(void)
487 {
488     static char  timestamp[128];
489     char        *r;
490     time_t       curtime;
491 
492     time(&curtime);
493     ctime_r(&curtime, timestamp);
494     r = strchr(timestamp, '\n');
495     if (r)
496 	*r = '\0';
497 
498     return timestamp;
499 }
500 
501 /* Get current GMT time and return a message timestamp.
502  * Used for g_printf calls to logs and such.  The return value
503  * is to a static buffer, so it should be used immediately.
504  *
505  * @returns: timestamp
506  */
507 static char *
msg_thread(void)508 msg_thread(void)
509 {
510     static char  thread[128];
511 
512     sprintf(thread, "thd-%p", g_thread_self());
513 
514     return thread;
515 }
516 
517 /*
518  * ---- public functions
519  */
520 
521 void
debug_init(void)522 debug_init(void)
523 {
524     debug_setup_logging();
525 
526     /* the scriptutil context does not create a debug log, since such
527      * processes are invoked many times.
528      */
529     if (get_pcontext() != CONTEXT_SCRIPTUTIL) {
530 	debug_open(get_ptype());
531     }
532 }
533 
534 void
debug_open(char * subdir)535 debug_open(char *subdir)
536 {
537     int fd = -1;
538     int i;
539     char *s = NULL;
540     mode_t mask;
541 
542     /* create AMANDA_TMPDIR */
543     make_amanda_tmpdir();
544 
545     /* set up logging while we're here */
546     debug_setup_logging();
547 
548     /* set 'dbgdir' and clean out old debug files */
549     debug_setup_1(NULL, subdir);
550 
551     /*
552      * Create the new file with a unique sequence number.
553      */
554     mask = (mode_t)umask((mode_t)0037); /* Allow the group read bit through */
555 
556     /* iteratate through sequence numbers until we find one that
557      * is not already in use */
558     for(i = 0; fd < 0; i++) {
559 	amfree(db_name);
560 	if ((db_name = get_debug_name(open_time, i)) == NULL) {
561 	    error(_("Cannot create debug file name in %d tries."), i);
562 	    /*NOTREACHED*/
563 	}
564 
565 	if ((s = newvstralloc(s, dbgdir, db_name, NULL)) == NULL) {
566 	    error(_("Cannot allocate debug file name memory"));
567 	    /*NOTREACHED*/
568 	}
569 
570 	if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
571 	    if (errno != EEXIST) {
572 	        error(_("Cannot create debug file \"%s\": %s"),
573 			s, strerror(errno));
574 	        /*NOTREACHED*/
575 	    }
576 	    amfree(s);
577 	}
578     }
579     (void)umask(mask); /* Restore mask */
580 
581     /*
582      * Finish setup.
583      *
584      * Note: we release control of the string 's' points to.
585      */
586     debug_setup_2(s, fd, "start");
587 }
588 
589 void
debug_reopen(char * dbfilename,char * annotation)590 debug_reopen(
591     char *	dbfilename,
592     char *	annotation)
593 {
594     char *s = NULL;
595     int fd;
596 
597     if (dbfilename == NULL) {
598 	return;
599     }
600 
601     /* set 'dbgdir' and clean out old debug files */
602     debug_setup_1(NULL, NULL);
603 
604     /*
605      * Reopen the file.
606      */
607     if (*dbfilename == '/') {
608 	s = stralloc(dbfilename);
609     } else {
610 	s = newvstralloc(s, dbgdir, dbfilename, NULL);
611     }
612     if ((fd = open(s, O_RDWR|O_APPEND)) < 0) {
613 	error(_("cannot reopen debug file %s"), dbfilename);
614 	/*NOTREACHED*/
615     }
616 
617     /*
618      * Finish setup.
619      *
620      * Note: we release control of the string 's' points to.
621      */
622     debug_setup_2(s, fd, annotation);
623 }
624 
625 void
debug_rename(char * config,char * subdir)626 debug_rename(
627     char *config,
628     char *subdir)
629 {
630     int fd = -1;
631     int i;
632     char *s = NULL;
633     mode_t mask;
634 
635     if (!db_filename)
636 	return;
637 
638     if (get_pcontext() == CONTEXT_SCRIPTUTIL) {
639 	return;
640     }
641 
642     /* Remove old log from source directory */
643     debug_unlink_old();
644     /* set 'dbgdir' and clean out old debug files */
645     debug_setup_1(config, subdir);
646     /* Remove old log from destination directory */
647     debug_unlink_old();
648 
649     s = newvstralloc(s, dbgdir, db_name, NULL);
650 
651     if (strcmp(db_filename, s) == 0) {
652 	amfree(s);
653 	return;
654     }
655 
656     mask = (mode_t)umask((mode_t)0037);
657 
658 #if defined(__CYGWIN__)
659     /*
660      * On cygwin, rename will not overwrite an existing file nor
661      * will it rename a file that is open for writing...
662      *
663      * Rename file directly.  Expect failure if file already exists
664      * or is open by another user.
665      */
666 
667     i = 0;
668     while (rename(db_filename, s) < 0) {
669 	if (errno != EEXIST) {
670 	    /*
671 	     * If the failure was not due to the target file name already
672 	     * existing then we have bigger issues at hand so we keep
673 	     * the existing file.
674 	     */
675 	    dbprintf(_("Cannot rename \"%s\" to \"%s\": %s\n"),
676 		     db_filename, s, strerror(errno));
677 	    s = newvstralloc(s, db_filename, NULL);
678 	    i = -1;
679 	    break;
680 	}
681 
682 	/*
683 	 * Files already exists:
684 	 * Continue searching for a unique file name that will work.
685 	 */
686 	amfree(db_name);
687 	if ((db_name = get_debug_name(open_time, i++)) == NULL) {
688 	    dbprintf(_("Cannot create unique debug file name"));
689 	    break;
690 	}
691 	s = newvstralloc(s, dbgdir, db_name, NULL);
692     }
693     if (i >= 0) {
694 	/*
695 	 * We need to close and reopen the original file handle to
696 	 * release control of the original debug file name.
697 	 */
698 	if ((fd = open(s, O_WRONLY|O_APPEND, 0640)) >= 0) {
699 	    /*
700 	     * We can safely close the the original log file
701 	     * since we now have a new working handle.
702 	     */
703 	    db_fd = 2;
704 	    fclose(db_file);
705 	    db_file = NULL;
706 	}
707     }
708 #else
709     /* check if a file with the same name already exists. */
710     if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
711 	for(i = 0; fd < 0; i++) {
712 	    amfree(db_name);
713 	    if ((db_name = get_debug_name(open_time, i)) == NULL) {
714 		dbprintf(_("Cannot create debug file"));
715 		break;
716 	    }
717 
718 	    s = newvstralloc(s, dbgdir, db_name, NULL);
719 	    if ((fd = open(s, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0640)) < 0) {
720 		if (errno != EEXIST) {
721 		    dbprintf(_("Cannot create debug file: %s"),
722 			      strerror(errno));
723 		    break;
724 		}
725 	    }
726 	}
727     }
728 
729     if (fd >= 0) {
730 	close(fd);
731 	if (rename(db_filename, s) == -1) {
732 	    dbprintf(_("Cannot rename \"%s\" to \"%s\": %s\n"),
733 		     db_filename, s, strerror(errno));
734 	}
735 	fd = -1;
736     }
737 #endif
738 
739     (void)umask(mask); /* Restore mask */
740     /*
741      * Finish setup.
742      *
743      * Note: we release control of the string 's' points to.
744      */
745     debug_setup_2(s, fd, "rename");
746 }
747 
748 void debug_ressource_usage(void);
749 void
debug_ressource_usage(void)750 debug_ressource_usage(void)
751 {
752     struct rusage usage;
753 
754     getrusage(RUSAGE_SELF, &usage);
755 
756     g_debug("ru_utime   : %ld", usage.ru_utime.tv_sec);
757     g_debug("ru_stime   : %ld", usage.ru_stime.tv_sec);
758     g_debug("ru_maxrss  : %ld", usage.ru_maxrss  );
759     g_debug("ru_ixrss   : %ld", usage.ru_ixrss   );
760     g_debug("ru_idrss   : %ld", usage.ru_idrss   );
761     g_debug("ru_isrss   : %ld", usage.ru_isrss   );
762     g_debug("ru_minflt  : %ld", usage.ru_minflt  );
763     g_debug("ru_majflt  : %ld", usage.ru_majflt  );
764     g_debug("ru_nswap   : %ld", usage.ru_nswap   );
765     g_debug("ru_inblock : %ld", usage.ru_inblock );
766     g_debug("ru_oublock : %ld", usage.ru_oublock );
767     g_debug("ru_msgsnd  : %ld", usage.ru_msgsnd  );
768     g_debug("ru_msgrcv  : %ld", usage.ru_msgrcv  );
769     g_debug("ru_nsignals: %ld", usage.ru_nsignals);
770     g_debug("ru_nvcsw   : %ld", usage.ru_nvcsw   );
771     g_debug("ru_nivcsw  : %ld", usage.ru_nivcsw  );
772 }
773 
774 void
debug_close(void)775 debug_close(void)
776 {
777     time_t curtime;
778 
779     if (get_pcontext() == CONTEXT_SCRIPTUTIL) {
780 	return;
781     }
782 
783     debug_ressource_usage();
784 
785     debug_unlink_old();
786 
787     time(&curtime);
788     debug_printf(_("pid %ld finish time %s"), (long)getpid(), ctime(&curtime));
789 
790     if(db_file && fclose(db_file) == EOF) {
791 	int save_errno = errno;
792 
793 	db_file = NULL;				/* prevent recursion */
794 	g_fprintf(stderr, _("close debug file: %s"), strerror(save_errno));
795 	/*NOTREACHED*/
796     }
797     db_fd = 2;
798     db_file = NULL;
799     amfree(db_filename);
800     amfree(db_name);
801 }
802 
803 /*
804  * Format and write a debug message to the process debug file.
805  */
printf_arglist_function(void debug_printf,const char *,format)806 printf_arglist_function(void debug_printf, const char *, format)
807 {
808     va_list argp;
809     int save_errno;
810 
811     /*
812      * It is common in the code to call dbprintf to write out
813      * syserrno(errno) and then turn around and try to do something else
814      * with errno (e.g. g_printf() or log()), so we make sure errno goes
815      * back out with the same value it came in with.
816      */
817 
818     save_errno = errno;
819 
820     /* handle the default (stderr) if debug_open hasn't been called yet */
821     if(db_file == NULL && db_fd == 2) {
822 	db_file = stderr;
823     }
824     if(db_file != NULL) {
825 	char *prefix;
826 	char *text;
827 
828 	if (db_file != stderr)
829 	    prefix = g_strdup_printf("%s: %s: %s:", msg_timestamp(), msg_thread(), get_pname());
830 	else
831 	    prefix = g_strdup_printf("%s:", get_pname());
832 	arglist_start(argp, format);
833 	text = g_strdup_vprintf(format, argp);
834 	arglist_end(argp);
835 	fprintf(db_file, "%s %s", prefix, text);
836 	amfree(prefix);
837 	amfree(text);
838 	fflush(db_file);
839     }
840     errno = save_errno;
841 }
842 
843 int
debug_fd(void)844 debug_fd(void)
845 {
846     return db_fd;
847 }
848 
849 FILE *
debug_fp(void)850 debug_fp(void)
851 {
852     return db_file;
853 }
854 
855 char *
debug_fn(void)856 debug_fn(void)
857 {
858     return db_filename;
859 }
860 
861 void
debug_dup_stderr_to_debug(void)862 debug_dup_stderr_to_debug(void)
863 {
864     if(db_fd != -1 && db_fd != STDERR_FILENO)
865     {
866        if(dup2(db_fd, STDERR_FILENO) != STDERR_FILENO)
867        {
868 	   error(_("can't redirect stderr to the debug file: %d, %s"), db_fd, strerror(errno));
869 	   g_assert_not_reached();
870        }
871     }
872 }
873 
874