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