[BACK]Return to Log.c++ CVS log [TXT][DIR] Up to [Development] / fam / fam

File: [Development] / fam / fam / Log.c++ (download)

Revision 1.1.1.1 (vendor branch), Thu Apr 24 19:08:26 2003 UTC (14 years, 6 months ago) by trev
Branch: sgi-fam, MAIN
CVS Tags: fam-2-6-10, HEAD
Changes since 1.1: +0 -0 lines

Initial FAM CVS repository build..

-- Trev


//  Copyright (C) 1999-2002 Silicon Graphics, Inc.  All Rights Reserved.
//
//  This program is free software; you can redistribute it and/or modify it
//  under the terms of version 2 of the GNU General Public License as
//  published by the Free Software Foundation.
//
//  This program is distributed in the hope that it would be useful, but
//  WITHOUT ANY WARRANTY; without even the implied warranty of
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  Further, any
//  license provided herein, whether implied or otherwise, is limited to
//  this program in accordance with the express provisions of the GNU
//  General Public License.  Patent licenses, if any, provided herein do not
//  apply to combinations of this program with other product or programs, or
//  any other product whatsoever.  This program is distributed without any
//  warranty that the program is delivered free of the rightful claim of any
//  third person by way of infringement or the like.  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 the Free Software Foundation, Inc., 59
//  Temple Place - Suite 330, Boston MA 02111-1307, USA.

#include "Log.h"

#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
#ifdef HAVE_AUDIT
#include <sat.h>
#endif

Log::LogLevel Log::level         = ERROR;
bool       Log::log_to_stderr = false;
const char   *Log::program_name  = "fam";
bool       Log::syslog_open   = false;
unsigned      Log::count         = 0;
#ifdef HAVE_AUDIT
bool       Log::audit_enabled = true;
#endif

void
Log::debug()
{
    level = DEBUG;
    info("log level is LOG_DEBUG");
}

void
Log::info()
{
    level = INFO;
    info("log level is LOG_INFO");
}

void
Log::error()
{
    level = INFO;
    info("log level is LOG_ERR");
    level = ERROR;
}

void
Log::disable_audit()
{
#ifdef HAVE_AUDIT
    audit_enabled = false;
    info("disabling security audit trail");
#endif
}

void
Log::foreground()
{
    log_to_stderr = true;
    if (syslog_open)
    {   closelog();
	syslog_open = false;
    }
}

void
Log::background()
{
    log_to_stderr = false;
}

void
Log::name(const char *newname)
{
    program_name = newname;
    audit(true, "fam changing process name to \"%s\"", newname);
}

void
Log::debug(const char *fmt, ...)
{
    if (level >= DEBUG)
    {
	va_list a;
	va_start(a, fmt);
	vlog(DEBUG, fmt, a);
	va_end(a);
    }
}

void
Log::info(const char *fmt, ...)
{
    if (level >= INFO)
    {
	va_list a;
	va_start(a, fmt);
	vlog(INFO, fmt, a);
	va_end(a);
    }
}

void
Log::error(const char *fmt, ...)
{
    if (level >= ERROR)
    {
	va_list a;
	va_start(a, fmt);
	vlog(ERROR, fmt, a);
	va_end(a);
    }
}

void
Log::critical(const char *fmt, ...)
{
    if (level >= CRITICAL)
    {
	va_list a;
	va_start(a, fmt);
	vlog(CRITICAL, fmt, a);
	va_end(a);
    }
}

void
Log::perror(const char *format, ...)
{
    if (level >= ERROR)
    {   char * buf = new char[strlen(format) + 5];
	(void) strcpy(buf, format);
	(void) strcat(buf, ": %m");
	va_list args;
	va_start(args, format);
	vlog(ERROR, buf, args);
	va_end(args);
        delete[] buf;
    }
}

void
Log::audit(bool success, const char *format, ...)
{
#ifdef HAVE_AUDIT
    if (audit_enabled)
    {
        //  This is not so good.  If there were a version of satwrite
        //  which took a va_list, this buffer would not need to be here.
        char buf[SAT_MAX_USER_REC];
        va_list args;
        va_start(args, format);
        int len = vsnprintf(buf, SAT_MAX_USER_REC, format, args);
        va_end(args);
        if(len > 0) satwrite(SAT_AE_CUSTOM, success ? SAT_SUCCESS : SAT_FAILURE,
                             buf, len);
    }
#endif
}

//  This is like debug(), info(), & error(), but it logs regardless of the
//  current log level.
void
Log::log(LogLevel l, const char *fmt, ...)
{
    va_list a;
    va_start(a, fmt);
    vlog(l, fmt, a);
    va_end(a);
}

void
Log::vlog(LogLevel l, const char *format, va_list args)
{
    if (log_to_stderr)
        vfglog(format, args);
    else {
        if (!syslog_open) {
            openlog(program_name, LOG_PID, LOG_DAEMON);
            syslog_open = true;
        }
        int ll;
        switch (l) {
        case DEBUG:
            ll = LOG_DEBUG; break;
        case INFO:
            ll = LOG_INFO;  break;
        case ERROR:
            ll = LOG_ERR;   break;
        case CRITICAL:
        default:
            ll = LOG_CRIT;   break;
        }
        vsyslog(ll, format, args);
    }
}

void
Log::vfglog(const char *format, va_list args)
{
    // Count number of %'s in the format string.  That's the max
    // number of %m's that there can be.
    int numPercents = 0;
    const char *pt = format;
    while(*pt) {
        if (*pt++ == '%') numPercents++;
    }
    char * err;

    // Only get the error string if there's a chance we'll use it.
    if (numPercents > 0) {
        err =  strerror(errno);
        if (err == NULL) {
            err = "Unknown error";
        }
    } else {
        err = "";
    }

    //  This 2 is for the \n and the null terminator added by the strcpy.
    char *buf = new char[strlen(format) + 2 + strlen(err) *
                        numPercents];
    char *p = buf;
    while (*format) {
        if (format[0] == '%' && format[1] == 'm') {
            p += strlen(strcpy(p, err));
            format += 2;
        } else {
            *p++ = *format++;
        }
    }
    (void) strcpy(p, "\n");
    (void) fprintf(stderr, "%s[%d]: ", program_name, getpid());
    (void) vfprintf(stderr, buf, args);
    delete[] buf;
}

#ifndef NDEBUG

//  New back end for assert() will log to syslog, put core file
//  in known directory.

void __assert(const char *msg, const char *file, int line)
{
    char *dirname = new char[strlen(Log::getName()) + 20];
    (void) sprintf(dirname, "/usr/tmp/%s.%d", Log::getName(), getpid());
    Log::error("Assertion failed at %s line %d: %s", file, line, msg);
    Log::error("Dumping core in %s/core", dirname);

    if (setreuid(0, 0) < 0)
	Log::perror("setreuid");
    if (mkdir(dirname, 0755) < 0)
	Log::perror("mkdir");
    if (chdir(dirname) < 0)
	Log::perror("chdir");
    struct rlimit rl = { RLIM_INFINITY, RLIM_INFINITY };
    if (setrlimit(RLIMIT_CORE, &rl) < 0)
	Log::perror("setrlimit(RLIMIT_CORE)");
    delete[] dirname;
    abort();
}

#endif /* !NDEBUG */

#ifdef HAPPY_PURIFY

Log::Log()
{
    count++;
}

Log::~Log()
{
    if (!--count)
    {   if (syslog_open)
	{   closelog();
	    syslog_open = false;
	}
    }
}

#endif /* HAPPY_PURIFY */

#ifdef UNIT_TEST_Log

#include <fcntl.h>
#include <sys/stat.h>

int
main()
{
    Log::name("unit test");
    Log::debug();
    Log::foreground();
    Log::debug("De bug is in %s.", "de rug");
    Log::info("Thank %s for sharing %s.", "you", "that");
    Log::error("The %s in %s falls.", "rain", "Spain");
    if (open("/foo%bar", 0) < 0)
	Log::perror("/foo%c%s", '%', "bar");
    if (chmod("/", 0777) < 0)
	Log::error("%m on chmod(\"%s\", 0%o)", "/", 0777);
    return 0;
}

#endif /* UNIT_TEST_Log */