summaryrefslogtreecommitdiff
path: root/debug.c
blob: d7d333bab567c6d9c59cc1a31c9b589fd22a0a79 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
/*
 * Copyright (C) 2007 Stig Venaas <venaas@uninett.no>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 */

#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <strings.h>
#include <time.h>
#include <sys/time.h>
#include <syslog.h>
#include <errno.h>
#include "debug.h"

static char *debug_ident = NULL;
static uint8_t debug_level = DBG_WARN;
static FILE *debug_file = NULL;
static int debug_syslogfacility = 0;

void debug_init(char *ident) {
    debug_file = stderr;
    setvbuf(debug_file, NULL, _IONBF, 0);
    debug_ident = ident;
}

void debug_set_level(uint8_t level) {
    debug_level = level;
}

uint8_t debug_get_level() {
    return debug_level;
}

int debug_set_destination(char *dest) {
    static const char *facstrings[] = { "LOG_DAEMON", "LOG_MAIL", "LOG_USER", "LOG_LOCAL0",
					"LOG_LOCAL1", "LOG_LOCAL2", "LOG_LOCAL3", "LOG_LOCAL4",
					"LOG_LOCAL5", "LOG_LOCAL6", "LOG_LOCAL7", NULL };
    static const int facvals[] = { LOG_DAEMON, LOG_MAIL, LOG_USER, LOG_LOCAL0,
				   LOG_LOCAL1, LOG_LOCAL2, LOG_LOCAL3, LOG_LOCAL4,
				   LOG_LOCAL5, LOG_LOCAL6, LOG_LOCAL7 };
    extern int errno;
    int i;
    
    if (!strncasecmp(dest, "file:///", 8)) {
	debug_file = fopen(dest + 7, "a");
	if (!debug_file)
	    debugx(1, DBG_ERR, "Failed to open logfile %s\n%s",
		   dest + 7, strerror(errno));
	setvbuf(debug_file, NULL, _IONBF, 0);
	return 1;
    }
    if (!strncasecmp(dest, "x-syslog://", 11)) {
	dest += 11;
	if (*dest) {
	    for (i = 0; facstrings[i]; i++)
		if (!strcasecmp(dest, facstrings[i]))
		    break;
	    if (!facstrings[i])
		debugx(1, DBG_ERR, "Unknown syslog facility %s", dest);
	    debug_syslogfacility = facvals[i];
	} else
	    debug_syslogfacility = LOG_DAEMON;
	openlog(debug_ident, LOG_PID, debug_syslogfacility);
	return 1;
    }
    debug(DBG_ERR, "Unknown log destination, exiting %s", dest);
    exit(1);
}

void debug_logit(uint8_t level, const char *format, va_list ap) {
    struct timeval now;
    char *timebuf;
    int priority;
    
    if (debug_syslogfacility) {
	switch (level) {
	case DBG_INFO:
	    priority = LOG_INFO;
	    break;
	case DBG_WARN:
	    priority = LOG_WARNING;
	    break;
	case DBG_ERR:
	    priority = LOG_ERR;
	    break;
	default:
	    priority = LOG_DEBUG;
	}
	vsyslog(priority, format, ap);
    } else {
	timebuf = malloc(256);
	if (timebuf) {
	    gettimeofday(&now, NULL);
	    ctime_r(&now.tv_sec, timebuf);
	    timebuf[strlen(timebuf) - 1] = '\0';
	    fprintf(debug_file, "%s: ", timebuf);
	    free(timebuf);
	}
	vfprintf(debug_file, format, ap);
	fprintf(debug_file, "\n");
    }
}

void debug(uint8_t level, char *format, ...) {
    va_list ap;
    if (level < debug_level)
	return;
    va_start(ap, format);
    debug_logit(level, format, ap);
    va_end(ap);
}

void debugx(int status, uint8_t level, char *format, ...) {
    if (level >= debug_level) {
	va_list ap;
	va_start(ap, format);
	debug_logit(level, format, ap);
	va_end(ap);
    }
    exit(status);
}