#include "logfile.h" #include #include #include #include #include #include #include #include int protogen_debug = FALSE; /* HP-UX and Ultrix 4.3 defines sys_nerr etc. only for __cplusplus */ #if defined(hpux) || defined(ultrix) || defined(sun) extern void perror(const char*); extern char *sys_errlist[]; extern char *strerror (int); #endif #if defined(sun) extern int on_exit(void (*f)(), void *); # define atexit(f) on_exit(f, NULL) #endif #include #include #ifdef SYSLOG #include #endif static int min_level = LOG_LEVEL; /* set default log level threshold (jcp) */ static FILE * log_fp; static int mail_logfile = FALSE; static char log_path[ MAXPATHLEN ]; static char log_infix[10]; /* printed between time stamp and text */ static char *log_program = "logfile"; void log_init(char *l_program, char *l_path, char *l_infix) { if ( l_program != NULL ) { char * p = strrchr( l_program, '/' ); log_program = ( p == NULL ) ? l_program : p+1; } if ( l_path != NULL ) { strncpy( log_path, l_path, sizeof(log_path)-1 ); log_path[sizeof(log_path)-1] = 0; if ( strlen(l_path) >= sizeof(log_path) ) { lprintf( L_FATAL, "log_init: log file path too long!" ); } } if ( l_infix != NULL ) { sprintf( log_infix, "%.*s ", (int) sizeof(log_infix)-2, l_infix ); } } void log_level (int level) { if (level < 0) min_level = 0; else if (level > 7) min_level = 7; else min_level= level; return; } void logmail() { char ws[MAXPATHLEN+100]; char buf[512]; int l; FILE *pipe_fp; int log_fd; if ( mail_logfile ) { lprintf( L_MESG, "logmail: mailing logfile to %s...", ADMIN ); sprintf( ws, "%s %s", MAILER, ADMIN ); pipe_fp = popen( ws, "w" ); if ( pipe_fp == NULL ) { lprintf( L_ERROS, "logmail: cannot open pipe to %s", MAILER ); /* FIXME: write to console - last resort */ fprintf( stderr, "logmail: cannot open pipe to %s", MAILER ); return; } fprintf( pipe_fp, "Subject: fatal error in logfile\n" ); fprintf( pipe_fp, "To: %s\n", ADMIN ); fprintf( pipe_fp, "From: root (Fax Getty)\n" ); fprintf( pipe_fp, "\nA fatal error has occured! The logfile follows\n" ); log_fd = open( log_path, O_RDONLY ); if ( log_fd == -1 ) { fprintf( pipe_fp, "The logfile '%s' cannot be opened (errno=%d)\n", log_path, errno ); } else { do { l = read( log_fd, buf, sizeof( buf ) ); fwrite( buf, l, 1, pipe_fp ); } while( l == sizeof( buf ) ); fprintf( pipe_fp, "\n------ logfile ends here -----\n" ); } close( log_fd ); pclose( pipe_fp ); } mail_logfile = FALSE; } result lputc(int level, char ch) { if ( log_fp != NULL && level <= min_level ) { if ( isprint(ch) ) fputc( ch, log_fp ); else fprintf( log_fp, "[%02x]", (unsigned char) ch ); fflush( log_fp ); #ifdef LOG_CR_NEWLINE if ( ch == '\n' ) fputc( ch, log_fp ); #endif } return SUCCESS; } result lputs (int level, char * s) { int retcode = 0; if ( log_fp != NULL && level <= min_level ) { retcode = fputs( s, log_fp ); fflush( log_fp ); } return retcode; } result vlprintf(int level, const char *format, va_list pvar) { char ws[2000]; time_t ti; struct tm *tm; int errnr; char lchar = "FEEAWMNJ"[level]; if ( level > min_level ) /* log level high enough? */ { return SUCCESS; /* no -> return immediately */ } errnr = errno; if ( log_fp == NULL ) /* open log file, if necessary */ { if ( log_path[0] == 0 ) sprintf( log_path, LOG_PATH ); log_fp = fopen( log_path, "a" ); if ( log_fp == NULL ) /* opening log file failed */ { sprintf(ws, "cannot open logfile %s", log_path); perror(ws); /* use /dev/console for logging, if possible */ if ( ( log_fp = fopen( CONSOLE, "w" ) ) != NULL ) { fprintf( log_fp, "\n%s: resorting to logging to %s\n", log_program, CONSOLE ); } else /* give up, disable logging */ { sprintf( ws, "cannot log to %s, disable logging", CONSOLE ); perror( ws ); min_level = 0; } } /* make sure that the logfile is not accidently stdin, -out or -err */ if ( fileno( log_fp ) < 3 ) { int fd; if ( ( fd = fcntl( fileno( log_fp ), F_DUPFD, 3 ) ) > 2 ) { fclose( log_fp ); log_fp = fdopen( fd, "a" ); } } fprintf( log_fp, "\n--" ); #ifdef SYSLOG /* initialize syslog logging */ openlog( log_program, LOG_PID, SYSLOG_FC ); #endif } vsprintf( ws, format, pvar ); ti = time(NULL); tm = localtime(&ti); if ( level == L_AUDIT ) /* some little auditing */ { fprintf(log_fp, "\n%02d/%02d %02d:%02d:%02d ##### %s\n", tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, ws ); #ifdef SYSLOG syslog( LOG_NOTICE, "%s", ws ); #endif } else if ( level == L_ERROR ) { fprintf(log_fp, "\n%02d/%02d %02d:%02d:%02d %s %c %s", tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, log_infix, lchar, ws ); #ifdef SYSLOG syslog( LOG_ERR, "%s", ws ); #endif } else if ( level != L_ERROS && level != L_FATAL ) { fprintf(log_fp, "\n%02d/%02d %02d:%02d:%02d %s %c %s", tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, log_infix, lchar, ws ); } else /* ERROS or FATAL */ { fprintf(log_fp, "\n%02d/%02d %02d:%02d:%02d %s %c %s: %s", tm->tm_mon+1, tm->tm_mday, tm->tm_hour, tm->tm_min, tm->tm_sec, log_infix, lchar, ws, ( errnr <= sys_nerr ) ? sys_errlist[errnr]: "" ); #ifdef SYSLOG syslog( level == L_FATAL? LOG_ALERT: LOG_ERR, "%s: %m", ws ); #endif if ( level == L_FATAL ) /* write to console */ { FILE * cons_fp; if ( ( cons_fp = fopen( CONSOLE, "w" ) ) != NULL ) { fprintf( cons_fp, "\n%s FATAL: %s %s\n", log_program, log_infix, ws ); fclose( cons_fp ); } else /* last resort */ if ( !mail_logfile ) { atexit( logmail ); mail_logfile = TRUE; } } } /* end if ( L_ERROS or L_FATAL ) */ fflush(log_fp); return SUCCESS; } result lprintf(int level, const char *format, ...) { va_list pvar; result res; va_start( pvar, format ); res = vlprintf( level, format, pvar ); va_end( pvar ); return res; }