+/* 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 void
+debug_logging_handler(const gchar *log_domain G_GNUC_UNUSED,
+ GLogLevelFlags log_level,
+ const gchar *message,
+ gpointer user_data G_GNUC_UNUSED)
+{
+ GLogLevelFlags maxlevel;
+ char *levprefix = NULL;
+ pcontext_t context = get_pcontext();
+
+ /* glib allows a message to have multiple levels, so calculate the "worst"
+ * level */
+ if (log_level & G_LOG_LEVEL_ERROR) {
+ maxlevel = G_LOG_LEVEL_ERROR;
+ levprefix = _("error (fatal): ");
+ } else if (log_level & G_LOG_LEVEL_CRITICAL) {
+ maxlevel = G_LOG_LEVEL_CRITICAL;
+ levprefix = _("critical (fatal): ");
+ } else if (log_level & G_LOG_LEVEL_WARNING) {
+ maxlevel = G_LOG_LEVEL_WARNING;
+ levprefix = _("warning: ");
+ } else if (log_level & G_LOG_LEVEL_MESSAGE) {
+ maxlevel = G_LOG_LEVEL_MESSAGE;
+ levprefix = _("message: ");
+ } else if (log_level & G_LOG_LEVEL_INFO) {
+ maxlevel = G_LOG_LEVEL_INFO;
+ levprefix = _("info: ");
+ } else {
+ maxlevel = G_LOG_LEVEL_DEBUG;
+ levprefix = ""; /* no level displayed for debugging */
+ }
+
+ /* 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 */
+ debug_printf("%s%s\n", levprefix, message);
+ }
+
+ if (amanda_log_handlers) {
+ GSList *iter = amanda_log_handlers;
+ while (iter) {
+ amanda_log_handler_t *hdlr = (amanda_log_handler_t *)iter->data;
+ hdlr(maxlevel, message);
+ iter = g_slist_next(iter);
+ }
+ } else {
+ /* call the appropriate handlers, based on the context */
+ amanda_log_stderr(maxlevel, message);
+ if (context == CONTEXT_DAEMON)
+ amanda_log_syslog(maxlevel, message);
+ }
+
+ /* error and critical levels have special handling */
+ if (log_level & (G_LOG_LEVEL_ERROR|G_LOG_LEVEL_CRITICAL)) {
+#ifdef HAVE_GLIBC_BACKTRACE
+ /* try logging a traceback to the debug log */
+ if (!do_suppress_error_traceback && 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);
+ else
+ abort();
+ g_assert_not_reached();
+ }
+}
+
+/* Install our handler into the glib log handling system.
+ */
+static void
+debug_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);
+}
+
+void
+add_amanda_log_handler(amanda_log_handler_t *hdlr)
+{
+ amanda_log_handlers = g_slist_append(amanda_log_handlers, (gpointer)hdlr);
+}
+
+void
+amanda_log_syslog(GLogLevelFlags log_level, const gchar *message)
+{
+ int priority = LOG_ERR;
+ switch (log_level) {
+ case G_LOG_LEVEL_ERROR:
+ case G_LOG_LEVEL_CRITICAL:
+ priority = LOG_ERR;
+ break;
+
+ case G_LOG_LEVEL_WARNING:
+#ifdef LOG_WARNING
+ priority = LOG_WARNING;
+#endif
+ break;
+
+ default:
+ return;
+ }
+
+#ifdef LOG_DAEMON
+ openlog(get_pname(), LOG_PID, LOG_DAEMON);
+#else
+ openlog(get_pname(), LOG_PID, 0);
+#endif
+ syslog(priority, "%s", message);
+ closelog();
+
+}
+
+void
+amanda_log_stderr(GLogLevelFlags log_level, const gchar *message)
+{
+ switch (log_level) {
+ case G_LOG_LEVEL_ERROR:
+ case G_LOG_LEVEL_CRITICAL:
+ g_fprintf(stderr, "%s: %s\n", get_pname(), message);
+ break;
+
+ default:
+ return;
+ }
+}
+
+void
+amanda_log_null(GLogLevelFlags log_level G_GNUC_UNUSED, const gchar *message G_GNUC_UNUSED)
+{
+}
+
+/* Set the global dbgdir according to 'config' and 'subdir'
+ *
+ * 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 void
+debug_setup_1(char *config, char *subdir)
+{
+ char *sane_config = NULL;
+
+ /*
+ * 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);
+
+ time(&open_time);
+}
+
+/*
+ * 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.
+ */
+static void
+debug_unlink_old(void)