/*
* debug support code
* Part of:
* bjnp backend for the Common UNIX Printing System (CUPS).
* Copyright 2008-2014 by Louis Lagendijk
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include
#include
#include
#include
#include "bjnp.h"
#ifdef __GNUC__
# define UNUSED(v) (void) v
#else
# define UNUSED(v)
#endif
typedef struct {
bjnp_loglevel_t level;
char string[10];
} logtable_entry_t;
static logtable_entry_t logtable[] = {
{LOG_NONE, "NONE"},
{LOG_EMERG, "EMERG"},
{LOG_ALERT, "ALERT"},
{LOG_CRIT, "CRIT"},
{LOG_ERROR, "ERROR"},
{LOG_WARN, "WARNING"},
{LOG_NOTICE, "NOTICE"},
{LOG_INFO, "INFO"},
{LOG_DEBUG, "DEBUG"},
{LOG_DEBUG2, "DEBUG2"},
{LOG_END, ""}
};
/*
* static data
*/
static bjnp_loglevel_t debug_level = LOG_ERROR;
static FILE *debug_file = NULL;
static time_t start_sec = 0;
static int start_msec;
/*
* local functions
*/
#ifndef NDEBUG
static void
u8tohex(uint8_t x, char *str)
{
static const char hdigit[16] = {
'0', '1', '2', '3', '4', '5', '6', '7',
'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
};
str[0] = hdigit[(x >> 4) & 0xf];
str[1] = hdigit[x & 0xf];
str[2] = '\0';
}
static void
u8tochar(uint8_t x, char *str)
{
if ((x > 0x20) && (x < 0x7f)) {
str[0] = (char) x;
} else {
str[0] = (char) '.';
}
}
static void
u32tohex(uint32_t x, char *str)
{
u8tohex(x >> 24, str);
u8tohex(x >> 16, str + 2);
u8tohex(x >> 8, str + 4);
u8tohex(x, str + 6);
}
char *
level2str(bjnp_loglevel_t level)
{
int i;
for (i = 0; logtable[i].level != LOG_END; i++) {
if (logtable[i].level == level) {
return logtable[i].string;
}
}
return "UNDEF";
}
bjnp_loglevel_t
str2level(const char *level)
{
int i;
for (i = 0; strlen(logtable[i].string) != 0; i++) {
if (strncasecmp(level, logtable[i].string, 10) == 0) {
return logtable[i].level;
}
}
return LOG_END;
}
void
bjnp_hexdump(bjnp_loglevel_t level, char *header, const void *d_,
unsigned len)
{
const uint8_t *d = (const uint8_t *)(d_);
unsigned ofs, c;
char line[100]; /* actually only 1+8+1+8*3+1+8*3+1+4+16 = 80 bytes needed */
if (level > debug_level) {
return;
}
bjnp_debug(level, "%s\n", header);
ofs = 0;
while (ofs < len) {
char *p;
memset(line, ' ', sizeof(line));
line[0] = ' ';
u32tohex(ofs, line + 1);
line[9] = ':';
p = line + 10;
for (c = 0; c != 16 && (ofs + c) < len; c++) {
u8tohex(d[ofs + c], p);
p[2] = ' ';
p += 3;
if (c == 7) {
p[0] = ' ';
p++;
}
}
p[0] = p[1] = p[2] = ' ';
p = line + 61;
for (c = 0; c != 16 && (ofs + c) < len; c++) {
u8tochar(d[ofs + c], p);
p++;
if (c == 7) {
p[0] = ' ';
p++;
}
}
p[0] = '\0';
bjnp_debug(level, "%s\n", line);
ofs += c;
}
bjnp_debug(level, "\n\n");
}
#endif /* NDEBUG */
void
bjnp_debug(bjnp_loglevel_t level, const char *fmt, ...)
{
va_list ap;
char printbuf[1024];
struct timeb timebuf;
int sec;
int msec;
if (level <= debug_level) {
/* print received data into a string */
va_start(ap, fmt);
vsnprintf(printbuf, sizeof(printbuf), fmt, ap);
va_end(ap);
/* we only send real errors & warnings to the cups logging facility */
if (level <= LOG_WARN) {
fprintf(stderr, "%s: %s", level2str(level), printbuf);
}
/* all log messages may go to the own logfile */
if (debug_file != NULL) {
ftime(&timebuf);
if ((msec = timebuf.millitm - start_msec) < 0) {
msec += 1000;
timebuf.time -= 1;
}
sec = timebuf.time - start_sec;
fprintf(debug_file, "%8s: %03d.%03d %s", level2str(level), sec, msec,
printbuf);
fflush(debug_file);
}
}
}
void
bjnp_set_debug_level(const char *level, const char *filename)
{
/*
* set debug level to level (string)
*/
struct timeb timebuf;
char loglevel[16];
ftime(&timebuf);
start_sec = timebuf.time;
start_msec = timebuf.millitm;
/*
* Set log level
*/
if (level == NULL) {
debug_level = LOG_ERROR;
} else {
strncpy(loglevel, level, 15);
loglevel[15] = '\0';
debug_level = str2level(loglevel);
}
if (filename == NULL) {
filename = CUPS_LOGDIR "/" LOGFILE;
}
if ((debug_file = fopen(filename, "w")) == NULL) {
bjnp_debug(LOG_WARN,
"Cannot open logfile: %s - %s\n",
filename, strerror(errno));
return;
}
bjnp_debug(LOG_WARN, "BJNP logging to %s, debug level = %s\n", filename, level2str(debug_level));
}