/* * 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; }