/************************************************************************
 * error.c                                                              *
 *                                                                      *
 * Copyright (C) 2002 - 2016 Joshua Birnbaum <engineer@noorg.org>.      *
 * All Rights Reserved.                                                 *
 *                                                                      *
 * 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 SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS    *
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED    *
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE   *
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY      *
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL   *
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE    *
 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS        *
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,         *
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING            *
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS   *
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.         *
 *                                                                      *
 * You should have received a copy of the GNU General Public License    *
 * along with this program; see the file COPYING. If not, write to the  *
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, *
 * MA 02111-1307, USA.                                                  *
 ************************************************************************/

/*************************************************************
 * Project ifchk -- Host based network interface promiscuous *
 *                  mode detection and handling.             *
 *                                                           *
 * Version:         1.0.2                                    *
 *                                                           *
 * --------------------------------------------------------- *
 *                                                           *
 * error.c          ifchk error logging subsystem.           *
 *                                                           *
 * Functions:     - Writes ifchk error messages to either    *
 *                  standard error or the syslog logging     *
 *                  facility, depending on how ifchk was     *
 *                  started (as either a daemon process      *
 *                  or in the foreground).                   *
 *************************************************************/
 
/**********************
 * include directives *
 **********************/

#include "error.h"


/***************************************************
 * errHandler() - Performs logging of ifchk error  *
 *                conditions via syslog(3), the    *
 *                standard error stream & variable *
 *                length argument lists.           *
 *                                                 *
 * Parameters:    *fmt: error message to log.      *
 *                                                 *
 * Returns:       Nothing.                         *
 ***************************************************/

void errHandler( const char *fmt, ... )
{
    pid_t pid = 0;				/* For getipd(). */
    time_t epochSecs = 0;			/* Seconds since epoch. */
    struct tm *curTime = NULL;			/* Date and time since epoch for local TZ. */
    char timeStamp[BUFSIZ] = "";		/* Current time in "HH:MM:SS" format. */
    char *timeFmt[] = { "%b %e %X", NULL };	/* Timestamp for error log entry. */
    char hostName[256] = "";			/* For gethostname(). */
    va_list varArg;				/* For va_start(). */
    char argBuf[ARGBUFSZ] = "";			/* Variable argument list buffer. */
    char *nlPtr = NULL;				/* Ptr for trailing newline processing. */

    memset( timeStamp, '\000', sizeof( timeStamp ) );
    memset( hostName, '\000', sizeof( hostName ) );
    memset( argBuf, '\000', sizeof( argBuf ) );

    /*
     * Initialize the syslog(3) subsystem.
     * Write log messages to /dev/console via the LOG_CONS logging option if
     * we cannot write to syslogd(1M).
     * LOG_CONS is safe to use in daemon processes that have no controlling
     * terminal (i.e., ifchk running as a daemon), since syslog(3) forks
     * before opening the console.
     * LOG_PERROR also writes the log message to standard error.
     */
    openlog( "ifchk", LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER );

    /*
     * Get our PID.
     */
    pid = getpid();

    /*
     * Get time in seconds since the epoch.
     */
    if( ( epochSecs = time( NULL ) ) == -1 )
    {
        syslog( LOG_CRIT, "ERROR: time(): %s", strerror( errno ) );
        exit( EXIT_FAILURE );
     }

    /*
     * Convert time in seconds since the
     * epoch to date & time for local TZ.
     */
    if( ( curTime = localtime( &epochSecs ) ) == NULL )
    {
        syslog( LOG_CRIT, "ERROR: localtime(): %s", strerror( errno ) );
        exit( EXIT_FAILURE );
     }   
   
    /*
     * Format time in "HH:MM:SS" format for locale.
     */
    if( ( strftime( timeStamp, BUFSIZ, timeFmt[0], curTime ) ) == 0 )
    {
	syslog( LOG_CRIT, "ERROR: strftime(): %s", strerror( errno ) );
        exit( EXIT_FAILURE );
     }

    /*
     * Get our hostname.
     */
    if( ( gethostname( hostName, sizeof( hostName ) ) ) == -1 )
    {
        syslog( LOG_CRIT, "ERROR: gethostname(): %s", strerror( errno ) );
        exit( EXIT_FAILURE );
     }

    /*
     * Initialize the variable length
     * argument list facility.
     */
    va_start( varArg, fmt );

    /*
     * Prepare to send our log
     * message to syslog(3).
     */
    if( vsnprintf( argBuf, sizeof( argBuf ), fmt, varArg ) == -1 )
    {
        syslog( LOG_CRIT, "ERROR: vsnprintf(): %s", strerror( errno ) );
        exit( EXIT_FAILURE );
     }

    argBuf[ARGBUFSZ - 1] = '\000';

    /*
     * Did the log message overrun
     * our logging buffer?
     */
    if( ( nlPtr = strchr( argBuf, '\n' ) ) == NULL )
    {
        syslog( LOG_CRIT, "could not process error message: message buffer full" );
        exit( EXIT_FAILURE );
     }

    /*
     * If not, strip trailing white space,
     * if needed, & then strip the newline.
     */
    else
    {
        if( *( nlPtr - 1 ) == ' ' )
        {
            *( nlPtr - 1 ) = '\000';
         }

        *nlPtr = '\000';

        /*
	 * Standard error is not a terminal - we're running as a daemon
	 * process. Write the error message to the standard error stream.
         */
        if( ( isatty( STDERR_FILENO ) ) == 0 )
        {
	    fprintf( stderr, "%s %s ifchk[%d]: %s\n", timeStamp, hostName, pid, argBuf );
         }

        /*
	 * Standard error is a terminal - we're running as a foreground
	 * process. Write the error message to the syslog facility.
         */
        else
        {
            syslog( LOG_CRIT, argBuf );
         }
     }

    /*
     * Deallocate list memory after use.
     */
    va_end( varArg );

    /*
     * Close the syslog(3) subsystem.
     */
    closelog();
}
