/***************************************************************************
*
* Copyright (c) 1999 BalaBit Computing
*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* 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, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
* $Id: werror.c,v 1.12 2005/05/03 15:49:35 bazsi Exp $
*
***************************************************************************/
#include "werror.h"
#include "format.h"
#include "gc.h"
#include "io.h"
#include "xalloc.h"
#include <netinet/in.h>
#include <arpa/inet.h>
#include <assert.h>
/* #include <stdio.h> */
#include <stdarg.h>
#include <ctype.h>
#include <string.h>
#if HAVE_UNISTD_H
#include <unistd.h>
#endif
#if HAVE_SYSLOG_H
#include <syslog.h>
#endif
#if HAVE_ALLOCA_H
#include <alloca.h>
#endif
int debug_flag = 0;
int quiet_flag = 0;
int verbose_flag = 0;
int syslog_flag = 0;
int error_fd = STDERR_FILENO;
#define MAX_BUF_SIZE 65536
static int write_file(int level, UINT32 length, UINT8 *data);
int (*error_write)(int level, UINT32 length, UINT8 *data) = write_file;
#if HAVE_SYSLOG
static int write_syslog(int level UNUSED, UINT32 length, UINT8 *data)
{
UINT8 string_buffer[length + 1];
UINT32 to_copy;
/* Make sure the message is properly terminated with \0. */
/* snprintf(string_buffer, (BUF_SIZE > length) ? BUF_SIZE : length, "%s", data); */
to_copy = LIBOL_MIN(length, sizeof(string_buffer) - 1);
memcpy(string_buffer, data, to_copy);
string_buffer[to_copy] = 0;
/* FIXME: Should we use different log levels for werror, verbose and
* debug? */
syslog(LOG_NOTICE, "%s", string_buffer);
return 0; /* FIXME */
}
void set_error_syslog(const char *progname)
{
error_write = write_syslog;
openlog(progname, LOG_PID, LOG_DAEMON);
error_fd = -1;
}
#endif /* HAVE_SYSLOG */
static int write_ignore(int level,
UINT32 length UNUSED, UINT8 *data UNUSED)
{
return 1;
}
static int (*fd_write)(int fd, UINT32 length, UINT8 *data) = write_raw;
static int write_file(int level, UINT32 length, UINT8 *data)
{
return fd_write(error_fd, length, data);
}
void set_error_stream(int fd, int with_poll)
{
error_fd = fd;
error_write = write_file;
fd_write = with_poll ? write_raw_with_poll : write_raw;
}
void set_error_ignore(void)
{
error_write = write_ignore;
}
#define MSG_WRITE(v, l, d) (error_write((v), (l), (d)))
void msg_vformat(int level, const char *f, va_list args)
{
UINT32 length;
va_list args_copy;
/* NOTE: some platforms require that you iterate over va_list
* once, at least according to Aaron Schrab, therefore we
* need to copy it first.
*/
va_copy(args_copy, args);
length = c_vformat_length(f, args_copy);
if (length <= MAX_BUF_SIZE) {
char errorbuf[length];
c_vformat_write(f, sizeof(errorbuf), (UINT8 *) errorbuf, args);
MSG_WRITE(level, length, (UINT8 *) errorbuf);
}
else {
fatal("Internal error, too long message to werror()");
}
va_end(args_copy);
}
void werror(const char *format, ...)
{
va_list args;
if (!quiet_flag)
{
va_start(args, format);
msg_vformat(MSG_ERROR, format, args);
va_end(args);
}
}
void notice(const char *format, ...)
{
va_list args;
if (!quiet_flag)
{
va_start(args, format);
msg_vformat(MSG_NOTICE, format, args);
va_end(args);
}
}
void debug(const char *format, ...)
{
va_list args;
if (debug_flag)
{
va_start(args, format);
msg_vformat(MSG_DEBUG, format, args);
va_end(args);
}
}
void verbose(const char *format, ...)
{
va_list args;
if (verbose_flag)
{
va_start(args, format);
msg_vformat(MSG_VERBOSE, format, args);
va_end(args);
}
}
void fatal(const char *format, ...)
{
va_list args;
va_start(args, format);
msg_vformat(MSG_FATAL, format, args);
va_end(args);
abort();
}
#if 0
char error_buffer[MAX_BUF_SIZE];
int error_pos = 0;
static void werror_flush(void)
{
if (error_pos)
{
write(2, error_buffer, error_pos);
error_pos = 0;
}
}
static void werror_putc(UINT8 c)
{
if (error_pos == MAX_BUF_SIZE)
werror_flush();
error_buffer[error_pos++] = c;
if (c == '\n')
werror_flush();
}
static void werror_write(UINT32 length, UINT8 *msg)
{
if (error_pos + length <= MAX_BUF_SIZE)
{
memcpy(error_buffer + error_pos, msg, length);
error_pos += length;
if (length && (msg[length-1] == '\n'))
werror_flush();
}
else
{
werror_flush();
write(2, msg, length);
}
}
static void werror_cstring(char *s) { werror_write(strlen(s), s); }
static void werror_decimal(UINT32 n)
{
unsigned length = format_size_in_decimal(n);
char *buffer = alloca(length);
unsigned i;
for (i = 0; i<length; i++)
{
buffer[length - i - 1] = '0' + n % 10;
n /= 10;
}
werror_write(length, buffer);
}
static unsigned format_size_in_hex(UINT32 n);
static void werror_hex_digit(unsigned digit)
{
werror_putc("0123456789abcdef"[digit]);
}
static void werror_hex_putc(UINT8 c)
{
werror_hex_digit(c / 16);
werror_hex_digit(c % 16);
}
static void werror_hex(UINT32 n)
{
unsigned left = 8;
while ( (left > 1)
&& (n & 0xf0000000UL))
{
left --;
n <<= 4;
}
while (left--)
{
werror_hex_digit((n >> 28) & 0xf);
n <<= 4;
}
}
void werror_hexdump(UINT8 *msg, UINT32 length, UINT8 *data)
{
UINT32 i;
werror_decimal(time(NULL));
werror_putc(' ');
werror_cstring(msg);
for (i=0; i<length; i++)
{
if (! (i%16))
{
unsigned j = format_size_in_hex((UINT32) data + i);
werror_cstring("\n0x");
for ( ; j < 8; j++)
werror_putc('0');
werror_hex((UINT32) data + i);
werror_cstring(": ");
}
werror_hex_putc(data[i]);
werror_putc(' ');
}
werror_putc('\n');
}
static void werror_paranoia_putc(UINT8 c)
{
switch (c)
{
case '\\':
werror_cstring("\\\\");
break;
case '\r':
/* Ignore */
break;
default:
if (!isprint(c))
{
werror_putc('\\');
werror_hex_putc(c);
break;
}
/* Fall through */
case '\n':
werror_putc(c);
break;
}
}
static unsigned format_size_in_hex(UINT32 n)
{
int i;
int e;
/* Table of 16^(2^n) */
static const UINT32 powers[] = { 0x10UL, 0x100UL, 0x10000UL };
#define SIZE (sizeof(powers) / sizeof(powers[0]))
/* Determine the smallest e such that n < 10^e */
for (i = SIZE - 1 , e = 0; i >= 0; i--)
{
if (n >= powers[i])
{
e += 1UL << i;
n /= powers[i];
}
}
#undef SIZE
return e+1;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1