blob: 4aaedadbbe34f295feb7022f8118f1271e220a29 [file] [log] [blame] [edit]
/*
* Copyright (c) International Business Machines Corp., 2006
*
* 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.
*/
#include <stdio.h>
#include <stdarg.h>
#include <syslog.h>
#include <stdlib.h>
#include <sys/errno.h>
#include <string.h>
#include "error.h"
#define MAXLINE 4096
#define MAXWIDTH 80
static FILE *logfp = NULL;
static void err_doit(int, int, const char *, va_list);
int
read_procfile(FILE *fp_out, const char *procfile)
{
FILE *fp;
if (!fp_out)
return -ENXIO;
fp = fopen(procfile, "r");
if (!fp)
return -ENOENT;
while(!feof(fp)) {
int c = fgetc(fp);
if (c == EOF)
return 0;
if (putc(c, fp_out) == EOF)
return -EIO;
if (ferror(fp))
return -EIO;
}
return fclose(fp);
}
void
error_initlog(const char *logfile)
{
if (!logfile)
return;
logfp = fopen(logfile, "a+");
read_procfile(logfp, "/proc/cpuinfo");
}
void
info_msg(const char *fmt, ...)
{
FILE* fpout;
char buf[MAXLINE + 1];
va_list ap;
int n;
fpout = stdout;
va_start(ap, fmt);
vsnprintf(buf, MAXLINE, fmt, ap);
n = strlen(buf);
strcat(buf, "\n");
fputs(buf, fpout);
fflush(fpout);
if (fpout != stdout)
fclose(fpout);
va_end(ap);
return;
}
void
__err_ret(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, LOG_INFO, fmt, ap);
va_end(ap);
return;
}
void
__err_sys(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, LOG_ERR, fmt, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
void
__err_msg(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, LOG_INFO, fmt, ap);
va_end(ap);
return;
}
void
__err_quit(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(0, LOG_ERR, fmt, ap);
va_end(ap);
exit(EXIT_FAILURE);
}
void
__err_dump(const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
err_doit(1, LOG_ERR, fmt, ap);
va_end(ap);
abort(); /* dump core and terminate */
exit(EXIT_FAILURE); /* shouldn't get here */
}
/**
* If a logfile is used we must not print on stderr and stdout
* anymore. Since pfilfash might be used in a server context, it is
* even dangerous to write to those descriptors.
*/
static void
err_doit(int errnoflag, int level __attribute__((unused)),
const char *fmt, va_list ap)
{
FILE* fpout;
int errno_save, n;
char buf[MAXLINE + 1];
fpout = stderr;
errno_save = errno; /* value caller might want printed */
vsnprintf(buf, MAXLINE, fmt, ap); /* safe */
n = strlen(buf);
if (errnoflag)
snprintf(buf + n, MAXLINE - n, ": %s", strerror(errno_save));
strcat(buf, "\n");
if (logfp) {
fputs(buf, logfp);
fflush(logfp);
return; /* exit when logging completes */
}
if (fpout == stderr) {
/* perform line wrap when outputting to stderr */
int word_len, post_len, chars;
char *buf_ptr;
const char *frmt = "%*s%n %n";
chars = 0;
buf_ptr = buf;
while (sscanf(buf_ptr, frmt, &word_len, &post_len) != EOF) {
int i;
char word[word_len + 1];
char post[post_len + 1];
strncpy(word, buf_ptr, word_len);
word[word_len] = '\0';
buf_ptr += word_len;
post_len -= word_len;
if (chars + word_len > MAXWIDTH) {
fputc('\n', fpout);
chars = 0;
}
fputs(word, fpout);
chars += word_len;
if (post_len > 0) {
strncpy(post, buf_ptr, post_len);
post[post_len] = '\0';
buf_ptr += post_len;
}
for (i = 0; i < post_len; i++) {
int inc = 1, chars_new;
if (post[i] == '\t')
inc = 8;
if (post[i] == '\n') {
inc = 0;
chars_new = 0;
} else
chars_new = chars + inc;
if (chars_new > MAXWIDTH) {
fputc('\n', fpout);
chars_new = inc;
}
fputc(post[i], fpout);
chars = chars_new;
}
}
}
else
fputs(buf, fpout);
fflush(fpout);
if (fpout != stderr)
fclose(fpout);
return;
}