📄 debug.c
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-1998 University of Maryland at College Park * All Rights Reserved. * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of U.M. not be used in advertising or * publicity pertaining to distribution of the software without specific, * written prior permission. U.M. makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M. * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. * * Author: James da Silva, Systems Design and Analysis Group * Computer Science Department * University of Maryland at College Park *//* * $Id: debug.c,v 1.40 2006/07/26 11:49:32 martinea Exp $ * * Logging support */#include "amanda.h"#include "util.h"#include "arglist.h"#include "clock.h"#include "timestamp.h"#include "conffile.h"/* 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/* 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 *//* directory containing debug file, including trailing slash */static char *dbgdir = NULL;/* time debug log was opened (timestamp of the file) */static time_t open_time;/* pointer to logfile.c's 'logerror()', if we're linked * with it */static void (*logerror_fn)(char *) = NULL;/* storage for global variables */erroutput_type_t erroutput_type = ERR_INTERACTIVE;int error_exit_status = 1;/* 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( time_t t, int n){ char number[NUM_STR_SIZE]; char *ts; char *result; if(n < 0 || n > 1000) { return NULL; } ts = get_timestamp_from_time(t); if(n == 0) { number[0] = '\0'; } else { g_snprintf(number, SIZEOF(number), "%03d", n - 1); } result = vstralloc(get_pname(), ".", ts, number, ".debug", NULL); amfree(ts); return result;}/* 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 voiddebug_logging_handler(const gchar *log_domain G_GNUC_UNUSED, GLogLevelFlags log_level, const gchar *message, gpointer user_data G_GNUC_UNUSED){ char *maxlevel = NULL; /* 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)) { if (erroutput_type & ERR_AMANDALOG && logerror_fn != NULL) (*logerror_fn)((char *)message); /* discard 'const' */ if (erroutput_type & 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 (erroutput_type & ERR_INTERACTIVE) { g_fprintf(stderr, "%s: %s\n", get_pname(), message); fflush(stderr); } /* 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 voiddebug_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 voiddebug_setup_1(char *config, char *subdir){ char *pname; size_t pname_len; char *e = NULL; char *s = NULL; DIR *d; struct dirent *entry; int do_rename; 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; memset(&sbuf, 0, SIZEOF(sbuf)); pname = get_pname(); pname_len = strlen(pname); /* * Create the debug directory if it does not yet exist. */ amfree(dbgdir); 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 * names (XXX.debug or XXX.$PID.debug) into the new name format. * 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(dbgdir)) == NULL) { error(_("open debug directory \"%s\": %s"), dbgdir, strerror(errno)); /*NOTREACHED*/ } 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)) { continue; } d_name_len = strlen(entry->d_name); if(strncmp(entry->d_name, pname, pname_len) != 0 || entry->d_name[pname_len] != '.' || d_name_len < 6 || strcmp(entry->d_name + d_name_len - 6, ".debug") != 0) { continue; /* not one of our debug files */ } e = newvstralloc(e, dbgdir, entry->d_name, NULL); if(d_name_len < test_name_len) { /* * Create a "pretend" name based on the last modification * time. This name will be used to decide if the real name * should be removed. If not, it will be used to rename the * real name. */ if(stat(e, &sbuf) != 0) { continue; /* ignore errors */ } amfree(dbfilename); dbfilename = get_debug_name((time_t)sbuf.st_mtime, 0); do_rename = 1; } else { dbfilename = newstralloc(dbfilename, entry->d_name); do_rename = 0; } if(strcmp(dbfilename, test_name) < 0) { (void) unlink(e); /* get rid of old file */ continue; } if(do_rename) { i = 0; while(dbfilename != NULL && (s = newvstralloc(s, dbgdir, dbfilename, NULL)) != NULL && rename(e, s) != 0 && errno != ENOENT) { amfree(dbfilename); dbfilename = get_debug_name((time_t)sbuf.st_mtime, ++i); } if(dbfilename == NULL) { error(_("cannot rename old debug file \"%s\""), entry->d_name); /*NOTREACHED*/ } } } amfree(dbfilename); amfree(e); amfree(s); amfree(test_name); closedir(d);}/* 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 voiddebug_setup_2( char * s, int fd, char * annotation){ int i; int fd_close[MIN_DB_FD+1]; amfree(db_filename); db_filename = s; s = NULL; /* 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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -