
/******************************************************************************
**
**  This program is free software; you can redistribute it and/or
**  modify it, however, you cannot sell it.
**
**  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.
**
**  You should have received a copy of the license attached to the
**  use of this software.  If not, visit www.shmoo.com/osiris for
**  details.
**
******************************************************************************/

/*****************************************************************************
**
**  File:    md_hosts.c
**  Date:    May 24, 2002
**
**  Author:  Brian Wotring
**  Purpose: interact with local file system to read in host information from
**	         hosts directory.
**
******************************************************************************/

#include "libosiris.h"
#include "libosirism.h"
#include "libosirisdb.h"
#include "libosirisctl.h"
#include "libfileapi.h"

#include "md_hosts.h"
#include "md_compare.h"

#include "common.h"
#include "logging.h"

extern char root_path[MAX_PATH_LENGTH];

OSI_HOST * osi_host_new()
{
    OSI_HOST *host = osi_malloc( sizeof( OSI_HOST ) );
    osi_set_host_defaults( host );

    /* initialize the list of configs and databases. */

    host->configs   = list_new();
    host->databases = list_new();
    host->logs      = list_new();

    return host;
}

void osi_host_destroy( OSI_HOST *host )
{
    if( host != NULL )
    {
        /* this assumes we only have config and database brief */
        /* structures, no complicated free methods required.   */

        if( host->configs != NULL )
        {
            list_destroy_with_function( host->configs,
                                        (void (*)(void *))&osi_free );
        }

        if( host->databases != NULL )
        {
            list_destroy_with_function( host->databases,
                                        (void (*)(void *))&osi_free );
        }

        if( host->logs != NULL )
        {
            list_destroy_with_function( host->logs,
                                        (void (*)(void *))&osi_free );
        }

        osi_free( host );
    }
}


void osi_set_host_defaults( OSI_HOST *host )
{
    if( host != NULL )
    {
        memset( host, 0, sizeof( OSI_HOST ) );
        
        host->enabled = 1;
        host->type = OSI_HOST_TYPE_GENERIC;

        host->file_log_enabled = 0;
        host->archive_databases = 1;

        host->notify_enabled = 0;
        host->notify_always = 0;

        host->schedule_start = 0;
        host->schedule_period = 0;
        
        memset( host->session_key, 0, sizeof( host->session_key ) );
        memset( host->base_db, 0, sizeof( host->base_db ) );
    }
}


osi_list osi_read_hosts()
{
    OSI_DIRECTORY directory;
    OSI_HOST *host;
    
    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };

    osi_list new_hosts = NULL;
    memset( &directory, 0, sizeof( directory ) );

    new_hosts = list_new();
        
    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );

    if( osi_open_directory( path, &directory ) )
    {
        log_info( LOG_HIGH, NULL, "reading hosts, opened  root directory: %s",
                  root_path );

        do
        {
            if( ( strcmp( directory.filename, "." ) == 0 ) ||
                ( strcmp( directory.filename, ".." ) == 0 ) )
            {
                continue;
            }

            host = osi_read_host( directory.filename );

            if( host != NULL )
            {
                log_info( LOG_HIGH, NULL, "read host: %s", directory.filename );
                list_add( new_hosts, host );
            }

        } while( osi_get_next_file( &directory ) );

        /* close root directory. */

        osi_close_directory( &directory );
    }

    else
    {
        log_error( LOG_MEDIUM, NULL, "unable to open root hosts directory: %s.",
                   root_path );
    }

    return new_hosts;
}

osi_list osi_read_host_briefs()
{
    OSI_DIRECTORY directory;
    OSI_HOST_BRIEF *host;
    
    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };

    osi_list new_hosts = NULL;
    memset( &directory, 0, sizeof( directory ) );

    new_hosts = list_new();
        
    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );

    if( osi_open_directory( path, &directory ) )
    {
        log_info( LOG_HIGH, NULL, "reading hosts, opened root directory: %s.",
                  root_path );

        do
        {
            if( ( strcmp( directory.filename, "." ) == 0 ) ||
                ( strcmp( directory.filename, ".." ) == 0 ) )
            {
                continue;
            }

            host = osi_read_host_brief( directory.filename );

            if( host != NULL )
            {
                log_info( LOG_HIGH, NULL, "found host: %s.",
                          directory.filename );

                list_add( new_hosts, host );
            }

        } while( osi_get_next_file( &directory ) );

        /* close root directory. */

        osi_close_directory( &directory );
    }

    else
    {
        log_error( LOG_MEDIUM, NULL, "unable to open root hosts directory: %s.",
                   root_path );
    }

    return new_hosts;
}

OSI_HOST * osi_read_host( const char *name )
{
    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };
    
    OSI_HOST *host = NULL;
    OSI_HOST_BRIEF host_brief;
    
    osi_bool result;

    if( name == NULL  )
    {
        return NULL;
    }

    /* create a default host structure and copy in the name */

    if( osi_host_exists( name ) == FALSE )
    {
        return NULL;
    }

    host = osi_host_new();

    /* construct full path to config file. */
    
    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, name, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOST_CONFIG_FILE_NAME, sizeof( path ) );

    /* parse the given file into a config, then take what we need */
    /* out of it.                                                 */
            
    result = osi_host_brief_read_file( path, &host_brief );

    if( result )
    {
        osi_strlcpy( host->host, host_brief.host, sizeof( host->host ) );

        osi_strlcpy( host->description, host_brief.description,
                     sizeof( host->description ) );

        osi_strlcpy( host->session_key, host_brief.session_key,
                     sizeof( host->session_key ) );

        osi_strlcpy( host->base_db, host_brief.base_db,
                     sizeof( host->base_db ) );
            
        host->file_log_enabled  = host_brief.file_log_enabled; 
        host->archive_databases = host_brief.archive_databases;

        host->notify_enabled   = host_brief.notify_enabled;
        host->notify_always    = host_brief.notify_always;

        host->enabled          = host_brief.enabled;
        host->type             = host_brief.type;

        host->schedule_start   = host_brief.schedule_start;
        host->schedule_period  = host_brief.schedule_period;
    }
            
    /* put in name, after the host has been populated. */
            
    osi_strlcpy( host->name, name, sizeof( host->name ) );
                      
    /* we don't get databases or configs, they need to be */
    /* requested later.                                   */

    return host;
}

osi_bool osi_write_host( OSI_HOST *host )
{
    osi_bool result = FALSE;

    char path[MAX_PATH_LENGTH];
    char temp_path[MAX_PATH_LENGTH];

    char config_path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };
    
    OSI_HOST_BRIEF host_brief;

    if( host == NULL  )
    {
        return FALSE;
    }

    /* construct full path to directory. */

    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, host->name, sizeof( path ) );

    /* construct full path to config file. */

    osi_strlcpy( config_path, path, sizeof( config_path ) );
    osi_strlcat( config_path, path_separator, sizeof( config_path ) );
    osi_strlcat( config_path, HOST_CONFIG_FILE_NAME, sizeof( config_path ) );
            
    /* if host doesn't exist, create directory structure for it including */
    /* the directories, and the master config file for this host.         */

    if( osi_host_exists( host->name ) == FALSE )
    {
        if( osi_create_directory( path ) != OSI_FILE_OK )
        {
            return FALSE;
        }

        /* now create the config, log, and database directories. */

        osi_strlcpy( temp_path, path, sizeof( temp_path ) );
        osi_strlcat( temp_path, path_separator, sizeof( temp_path ) );

        osi_strlcat( temp_path, HOST_CONFIG_DIRECTORY_NAME,
                     sizeof( temp_path ) );

        if( osi_create_directory( temp_path ) != OSI_FILE_OK )
        {
            return FALSE;
        }

        osi_strlcpy( temp_path, path, sizeof( temp_path ) );
        osi_strlcat( temp_path, path_separator, sizeof( temp_path ) );
        osi_strlcat( temp_path, HOST_LOG_DIRECTORY_NAME, sizeof( temp_path ) );

        if( osi_create_directory( temp_path ) != OSI_FILE_OK )
        {
            return FALSE;
        }

        osi_strlcpy( temp_path, path, sizeof( temp_path ) );
        osi_strlcat( temp_path, path_separator, sizeof( temp_path ) );

        osi_strlcat( temp_path, HOST_DATABASE_DIRECTORY_NAME,
                     sizeof( temp_path ) );

        if( osi_create_directory( temp_path ) != OSI_FILE_OK )
        {
            return FALSE;
        }

        /* now create the host.conf file. */

        if( osi_create_file( config_path, HOST_CONFIG_PERMISSIONS ) !=
                             OSI_FILE_OK )
        {
            return FALSE;
        }
    }
        
    /* now populate our host brief structure with this host so we */
    /* can quickly and efficiently write a basic config to disk.  */

    osi_strlcpy( host_brief.host, host->host, sizeof( host_brief.host ) );

    osi_strlcpy( host_brief.description, host->description,
                 sizeof( host_brief.description ) );

    osi_strlcpy( host_brief.session_key, host->session_key,
                 sizeof( host_brief.session_key ) );

    osi_strlcpy( host_brief.base_db, host->base_db,
                 sizeof( host_brief.base_db ) );
       
    host_brief.file_log_enabled  = host->file_log_enabled; 
    host_brief.archive_databases = host->archive_databases;

    host_brief.notify_enabled   = host->notify_enabled;
    host_brief.notify_always    = host->notify_always;

    host_brief.enabled          = host->enabled;
    host_brief.type             = host->type;

    host_brief.schedule_start   = host->schedule_start;
    host_brief.schedule_period  = host->schedule_period;
                
    result = osi_host_brief_write_file( config_path, &host_brief );

    return result;
}


OSI_HOST_BRIEF * osi_read_host_brief( const char *name )
{
    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };
    
    OSI_HOST_BRIEF *host_brief = NULL;
    OSI_HOST_CONFIG *config    = NULL;

    if( name == NULL )
    {
        return NULL;
    }

    /* create a default host structure and copy in the name */

    if( osi_host_exists( name ) )
    {
        host_brief = (OSI_HOST_BRIEF *)osi_malloc( sizeof(OSI_HOST_BRIEF) );
        osi_set_host_brief_defaults( host_brief );
            
        /* construct full path to config file. */
    
        osi_strlcpy( path, root_path, sizeof( path ) );
        osi_strlcat( path, path_separator, sizeof( path ) );
        osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );
        osi_strlcat( path, path_separator, sizeof( path ) );
        osi_strlcat( path, name, sizeof( path ) );
        osi_strlcat( path, path_separator, sizeof( path ) );
        osi_strlcat( path, HOST_CONFIG_FILE_NAME, sizeof( path ) );

        /* now use the management library to acquire this host brief. */

        osi_host_brief_read_file( path, host_brief );
            
        /* set name after brief has been populated. */
            
        osi_strlcpy( host_brief->name, name, sizeof( host_brief->name ) );
    }

    return host_brief;
}


osi_bool osi_write_host_brief( OSI_HOST_BRIEF *host_brief )
{
    osi_bool result = FALSE;
    
    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };
    
    if( host_brief == NULL )
    {            
        return FALSE;
    }

    /* construct full path to config file. */

    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, host_brief->name, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOST_CONFIG_FILE_NAME, sizeof( path ) );
            
    result = osi_host_brief_write_file( path, host_brief );
    return result;
}

osi_bool osi_host_exists( const char *name )
{
    osi_bool result = FALSE;

    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };

    if( name == NULL )
    {
        return FALSE;
    }

    /* we verify that this host exists by verifying */
    /* that the directory exists                    */

    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, name, sizeof( path ) );

    if( osi_directory_exists( path ) )
    {
        result = TRUE;
    }

    return result;
}

OSI_HOST_CONFIG * osi_host_read_host_config_with_name( const char *name )
{
    OSI_HOST_CONFIG *config;
    
    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };
    
    if( name == NULL )
    {            
        return NULL;
    }

    /* construct full path to config file. */

    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, name, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOST_CONFIG_FILE_NAME, sizeof( path ) );
            
    config = osi_host_config_new_from_file( path );
    return config;
}

osi_bool osi_host_write_host_config_with_name( OSI_HOST_CONFIG *config,
                                               const char *name )
{
    osi_bool result = FALSE;
    
    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };
    
    if( name == NULL )
    {            
        return FALSE;
    }

    /* construct full path to config file. */

    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, name, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOST_CONFIG_FILE_NAME, sizeof( path ) );
            
    result = osi_host_config_write_file( path, config );
    return result;
}



unsigned long osi_host_get_config_count( const char *name )
{
    unsigned long count = 0;

    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };

    OSI_DIRECTORY directory;
    memset( &directory, 0, sizeof( OSI_DIRECTORY ) );

    if( name == NULL )
    {
        return count;
    }

    /* first, we construct path to database directory. */

    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, name, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOST_CONFIG_DIRECTORY_NAME, sizeof( path ) );

    log_info( LOG_HIGH, name, "counting configs." );

    /* now traverse the directory, creating db brief objects and */
    /* adding them to this host's list of databases.             */

    if( osi_open_directory( path, &directory ) )
    {
        do
        {
            char file_path[MAX_PATH_LENGTH];

            /* create full path to the current filename. */

            osi_strlcpy( file_path, path, sizeof( file_path ) );
            osi_strlcat( file_path, path_separator, sizeof( file_path ) );
            osi_strlcat( file_path, directory.filename, sizeof( file_path ) );

            if( osi_file_is_regular_file( file_path ) )
            {
                count++;
            }

        } while( osi_get_next_file( &directory ) );

        osi_close_directory( &directory );
    }

    else
    {
        log_error( LOG_MEDIUM, name, "no configs directory found." );
    }

    return count;
}

unsigned long osi_host_get_database_count( const char *name )
{
    unsigned long count = 0;

    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };

    OSI_DIRECTORY directory;
    memset( &directory, 0, sizeof( OSI_DIRECTORY ) );

    if( name == NULL )
    {
        return count;
    }

    /* first, we construct path to database directory. */

    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, name, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOST_DATABASE_DIRECTORY_NAME, sizeof( path ) );

    log_info( LOG_HIGH, name, "counting databases." );

    /* now traverse the directory, creating db brief objects and */
    /* adding them to this host's list of databases.             */

    if( osi_open_directory( path, &directory ) )
    {
        do
        {
            char file_path[MAX_PATH_LENGTH];

            /* create full path to the current filename. */

            osi_strlcpy( file_path, path, sizeof( file_path ) );
            osi_strlcat( file_path, path_separator, sizeof( file_path ) );
            osi_strlcat( file_path, directory.filename, sizeof( file_path ) );

            if( osi_file_is_regular_file( file_path ) )
            {
                count++;
            }

        } while( osi_get_next_file( &directory ) );

        osi_close_directory( &directory );
    }

    else
    {
        log_error( LOG_MEDIUM, name, "no database directory." );
    }

    return count;
}

unsigned long osi_host_get_log_count( const char *name )
{
    unsigned long count = 0;

    char path[MAX_PATH_LENGTH];
    char path_separator[2] = { PATH_SEPARATOR, '\0' };

    OSI_DIRECTORY directory;
    memset( &directory, 0, sizeof( OSI_DIRECTORY ) );

    if( name == NULL )
    {
        return count;
    }

    /* first, we construct path to database directory. */

    osi_strlcpy( path, root_path, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOSTS_DIRECTORY_NAME, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, name, sizeof( path ) );
    osi_strlcat( path, path_separator, sizeof( path ) );
    osi_strlcat( path, HOST_LOG_DIRECTORY_NAME, sizeof( path ) );

    log_info( LOG_HIGH, name, "counting logs." );

    /* now traverse the directory, creating db brief objects and */
    /* adding them to this host's list of databases.             */

    if( osi_open_directory( path, &directory ) )
    {
        do
        {
            char file_path[MAX_PATH_LENGTH];

            /* create full path to the current filename. */

            osi_strlcpy( file_path, path, sizeof( file_path ) );
            osi_strlcat( file_path, path_separator, sizeof( file_path ) );
            osi_strlcat( file_path, directory.filename, sizeof( file_path ) );

            if( osi_file_is_regular_file( file_path ) )
            {
                count++;
            }

        } while( osi_get_next_file( &directory ) );

        osi_close_directory( &directory );
    }

    else
    {
        log_error( LOG_MEDIUM, name, "no log directory." );
    }

    return count;
}


