#include "timestamp.h"
#include "conffile.h"
+#ifdef HAVE_GLIBC_BACKTRACE
+#include <execinfo.h>
+#endif
+
/* 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.
static void (*logerror_fn)(char *) = NULL;
/* storage for global variables */
-erroutput_type_t erroutput_type = ERR_INTERACTIVE;
+erroutput_type_t erroutput_type = ERR_FROM_CONTEXT;
int error_exit_status = 1;
/* static function prototypes */
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 */
- /* 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);
+ 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)
+ 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 (erroutput_type & ERR_SYSLOG) {
+ if (local_erroutput & ERR_SYSLOG) {
#ifdef LOG_AUTH
openlog(get_pname(), LOG_PID, LOG_AUTH);
#else
closelog();
}
- if (erroutput_type & ERR_INTERACTIVE) {
- g_fprintf(stderr, "%s: %s: %s\n", get_pname(), msg_timestamp(), message);
+ 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
+
/* we're done */
if (log_level & G_LOG_LEVEL_CRITICAL)
exit(error_exit_status);
dbgdir = vstralloc(AMANDA_DBGDIR, "/", subdir, "/", NULL);
else
dbgdir = stralloc2(AMANDA_DBGDIR, "/");
- if(mkpdir(dbgdir, 02700, get_client_uid(), get_client_gid()) == -1) {
+ if(mkpdir(dbgdir, 0700, get_client_uid(), get_client_gid()) == -1) {
error(_("create debug directory \"%s\": %s"),
dbgdir, strerror(errno));
/*NOTREACHED*/
/*
* Make the first debug log file entry.
*/
- debug_printf(_("pid %ld ruid %ld euid %ld: %s at %s"),
+ debug_printf(_("pid %ld ruid %ld euid %ld version %s: %s at %s"),
(long)getpid(),
(long)getuid(), (long)geteuid(),
+ VERSION,
annotation,
ctime(&open_time));
}
* ---- 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 *))
{
db_file = stderr;
}
if(db_file != NULL) {
- g_fprintf(db_file, "%s: %s: ", msg_timestamp(), get_pname());
+ 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);
- g_vfprintf(db_file, format, argp);
+ 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;