root/usr/src/cmd/nscd/nscd_init.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <locale.h>
#include <unistd.h>
#include <string.h>
#include <time.h>
#include "nscd_common.h"
#include "nscd_config.h"
#include "nscd_log.h"
#include "nscd_switch.h"
#include "nscd_frontend.h"

static char     *cfgfile_save = NULL;
static mutex_t  time_mutex = DEFAULTMUTEX;
static time_t   start_time = 0;

void
_nscd_set_start_time(int reset)
{
        (void) mutex_lock(&time_mutex);
        if (start_time == 0 || reset == 1)
                start_time = time(NULL);
        (void) mutex_unlock(&time_mutex);
}

time_t
_nscd_get_start_time()
{
        return (start_time);
}

nscd_rc_t
_nscd_init(
        char                    *cfgfile)
{
        char                    *me = "nscd_init";
        nscd_rc_t               rc;
        nscd_cfg_error_t        *err;

        /*
         * remember when main or forker nscd starts.
         */
        _nscd_set_start_time(0);

        /*
         * allocate the space for tables
         */
        if ((rc = _nscd_alloc_nsw_config()) != NSCD_SUCCESS ||
            (rc = _nscd_alloc_service_state_table()) != NSCD_SUCCESS ||
            (rc = _nscd_alloc_nsw_state_base()) != NSCD_SUCCESS ||
            (rc = _nscd_alloc_nsw_be_info_db()) != NSCD_SUCCESS ||
            (rc = _nscd_alloc_getent_ctx_base()) != NSCD_SUCCESS)
                return (rc);

        /*
         * allocate the space for local configuration
         * and statistics
         */
        if ((rc = _nscd_alloc_switch_cfg()) != NSCD_SUCCESS ||
            (rc = _nscd_alloc_frontend_cfg()) != NSCD_SUCCESS ||
            (rc = _nscd_alloc_switch_stats()) != NSCD_SUCCESS)
                return (rc);

        /*
         * Create and init the internal address database to keep
         * track of the memory allocated by _nscd_alloc
         */
        if (_nscd_create_int_addrDB() == NULL) {
                _NSCD_LOG(NSCD_LOG_INT_ADDR, NSCD_LOG_LEVEL_ERROR)
                (me, "_nscd_create_int_addrDB failed\n");
                return (NSCD_NO_MEMORY);
        }

        /*
         * Create and init the internal context database to keep
         * track of the getent context currently being used
         */
        if (_nscd_create_getent_ctxDB() == NULL) {
                _NSCD_LOG(NSCD_LOG_GETENT_CTX, NSCD_LOG_LEVEL_ERROR)
                (me, "_nscd_create_getent_ctx_addrDB failed\n");
                return (NSCD_NO_MEMORY);
        }

        /*
         * Create the backend info database for each possible source
         */
        if ((rc = _nscd_init_all_nsw_be_info_db()) != NSCD_SUCCESS) {
                _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
                (me, "_nscd_init_all_nsw_be_info_db failed (rc = %d)\n",
                    rc);
                return (rc);
        }

        /*
         * Create the nscd_nsw_config_t for each possible nss database
         */
        if ((rc = _nscd_init_all_nsw_config()) != NSCD_SUCCESS) {
                _NSCD_LOG(NSCD_LOG_NSW_STATE, NSCD_LOG_LEVEL_ERROR)
                (me, "_nscd_init_all_nsw_config failed (rc = %d)\n", rc);
                return (rc);
        }

        /*
         * initialize config/stats management
         */
        rc = _nscd_cfg_init(&err);
        if (rc != NSCD_SUCCESS) {
                if (err != NULL)
                        _nscd_cfg_free_error(err);
                return (rc);
        }

        /*
         * read in the nsswitch configuration
         */
        rc = _nscd_cfg_read_nsswitch_file("/etc/nsswitch.conf", &err);
        if (rc != NSCD_SUCCESS) {
                (void) printf(
                gettext("reading config file %s failed with rc = %d, %s\n"),
                    "/etc/nsswitch.conf", rc, NSCD_ERR2MSG(err));
                if (err != NULL)
                        _nscd_cfg_free_error(err);

                _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
        (me, "unable to read /etc/nsswitch.conf (rc = %d)\n", rc);
                return (rc);
        }
        /*
         * remember which version of /etc/nsswitch.conf that was read
         */
        _nscd_restart_if_cfgfile_changed();

        /*
         * read in the nscd configuration
         */
        if (cfgfile == NULL) {
                cfgfile = "/etc/nscd.conf";
                if (access(cfgfile, R_OK) != 0) {
                        _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
                (me, "unable to read /etc/nscd.conf (rc = %d)\n", rc);

                        return (NSCD_CFG_FILE_ACCESS_ERROR);
                }
        }
        rc = _nscd_cfg_read_file(cfgfile, &err);
        if (rc != NSCD_SUCCESS) {
                (void) printf(
                gettext("reading config file %s failed with rc = %d, %s\n"),
                    cfgfile, rc, NSCD_ERR2MSG(err));
                if (err != NULL)
                        _nscd_cfg_free_error(err);

                _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
                (me, "unable to read configuration from %s (rc = %d)\n",
                    cfgfile, rc);

                return (rc);
        }
        /*
         * remember the name of the config file
         * in case refresh is requested later
         */
        if (cfgfile != NULL) {
                cfgfile_save = strdup(cfgfile);
                if (cfgfile_save == NULL)
                        return (NSCD_NO_MEMORY);
        }

        return (NSCD_SUCCESS);
}

nscd_rc_t
_nscd_refresh()
{
        char                    *me = "nscd_refresh";
        char                    *cfgfile;
        nscd_rc_t               rc;
        nscd_cfg_error_t        *err;
        char                    errmsg[1024];

        /*
         * re-read the nscd configuration
         */
        if (cfgfile_save == NULL)
                cfgfile = "/etc/nscd.conf";
        else
                cfgfile = cfgfile_save;

        if (access(cfgfile, R_OK) != 0) {
                (void) snprintf(errmsg, sizeof (errmsg),
                "unable to read the config file %s (rc = %d), %s\n",
                    cfgfile, NSCD_CFG_FILE_ACCESS_ERROR,
                    strerror(errno));

                goto error_exit;
        }

        rc = _nscd_cfg_read_file(cfgfile, &err);
        if (rc != NSCD_SUCCESS) {
                (void) snprintf(errmsg, sizeof (errmsg),
                    "unable to parse the config file %s (rc = %d), %s\n",
                    cfgfile, rc, NSCD_ERR2MSG(err));

                goto error_exit;
        }

        _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ALL)
        (me, "nscd configuration refreshed successfully\n");

        return (NSCD_SUCCESS);

        error_exit:

        if (err != NULL)
                _nscd_cfg_free_error(err);

        _NSCD_LOG(NSCD_LOG_CONFIG, NSCD_LOG_LEVEL_ERROR)
        (me, "%s\n", errmsg);

        return (rc);
}