root/usr/src/cmd/nscd/nscd_nswcfgst.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 2006 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include "nscd_config.h"
#include "nscd_log.h"
#include "nscd_switch.h"

/*
 * Configuration data for the nscd switch functions.
 */
nscd_cfg_global_switch_t        nscd_switch_cfg_g;
nscd_cfg_switch_t               *nscd_switch_cfg;

/*
 * statistics of the nscd switch functions.
 */
nscd_cfg_stat_global_switch_t   nscd_switch_stats_g;
nscd_cfg_stat_switch_t          *nscd_switch_stats;

/*
 * cookie is set up by the verify function for passing to
 * the notify function
 */
typedef struct {
        struct __nsw_switchconfig_v1    *cfg;
        char                            *cfgstr;
} nsw_cfg_cookie_t;

nscd_rc_t
_nscd_alloc_switch_cfg()
{
        nscd_switch_cfg  = calloc(NSCD_NUM_DB, sizeof (nscd_cfg_switch_t));
        if (nscd_switch_cfg == NULL)
                return (NSCD_NO_MEMORY);

        return (NSCD_SUCCESS);
}

nscd_rc_t
_nscd_alloc_switch_stats()
{

        nscd_switch_stats = calloc(NSCD_NUM_DB,
                sizeof (nscd_cfg_stat_switch_t));
        if (nscd_switch_stats == NULL)
                return (NSCD_NO_MEMORY);

        return (NSCD_SUCCESS);
}

/* ARGSUSED */
nscd_rc_t
_nscd_cfg_switch_notify(
        void                            *data,
        struct nscd_cfg_param_desc      *pdesc,
        nscd_cfg_id_t                   *nswdb,
        nscd_cfg_flag_t                 dflag,
        nscd_cfg_error_t                **errorp,
        void                            *cookie)
{

        void                            *dp;
        nscd_rc_t                       rc;
        nsw_cfg_cookie_t                *ck = (nsw_cfg_cookie_t *)cookie;

        if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) ||
                _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {
                /*
                 * group data is received, copy in the
                 * entire strcture
                 */
                if (_nscd_cfg_flag_is_set(pdesc->pflag,
                        NSCD_CFG_PFLAG_GLOBAL)) {
                        nscd_switch_cfg_g = *(nscd_cfg_global_switch_t *)data;
                } else {
                        nscd_switch_cfg[nswdb->index] =
                                *(nscd_cfg_switch_t *)data;

                }
        } else {
                /*
                 * individual paramater is received: copy in the
                 * parameter value except for nsw-config-string.
                 */
                if (_nscd_cfg_flag_is_set(pdesc->pflag,
                        NSCD_CFG_PFLAG_GLOBAL)) {
                        dp = (char *)&nscd_switch_cfg_g + pdesc->p_offset;
                        (void) memcpy(dp, data, pdesc->p_size);
                } else {
                        dp = (char *)&nscd_switch_cfg[nswdb->index] +
                                pdesc->p_offset;
                        if (pdesc->p_offset !=
                                offsetof(nscd_cfg_switch_t, nsw_config_string))
                                (void) memcpy(dp, data, pdesc->p_size);
                }
        }

        /*
         * cookie contains data for the switch policy config
         */
        if (cookie != NULL) {
                rc = _nscd_create_sw_struct(nswdb->index, -1, nswdb->name,
                        ck->cfgstr, ck->cfg, NULL);
                if (rc != NSCD_SUCCESS) {
                        (void) __nsw_freeconfig_v1(ck->cfg);
                        free(ck);
                        return (rc);
                }
                free(ck);
        }

        if (_nscd_cfg_flag_is_not_set(dflag, NSCD_CFG_DFLAG_STATIC_DATA))
                free(data);

        return (NSCD_SUCCESS);
}

/* ARGSUSED */
nscd_rc_t
_nscd_cfg_switch_verify(
        void                            *data,
        struct  nscd_cfg_param_desc     *pdesc,
        nscd_cfg_id_t                   *nswdb,
        nscd_cfg_flag_t                 dflag,
        nscd_cfg_error_t                **errorp,
        void                            **cookie)
{
        char                            *me = "_nscd_cfg_switch_verify";
        nscd_cfg_switch_t               *cfg;
        char                            *nswcfgstr;
        int                             size;
        struct __nsw_switchconfig_v1    *switchcfg = NULL;
        enum __nsw_parse_err            err;
        nsw_cfg_cookie_t                *ck;
        char                            buf[MAX_NSSWITCH_CONFIG_STRING_SZ];
        char                            msg[NSCD_CFG_MAX_ERR_MSG_LEN];

        /*
         * global config data has nothing special to verify
         */
        if (_nscd_cfg_flag_is_set(pdesc->pflag, NSCD_CFG_PFLAG_GLOBAL))
                return (NSCD_SUCCESS);

        *cookie = NULL;

        /*
         * switch policy string is the one to parse and verify
         */

        if (_nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_INIT) ||
                _nscd_cfg_flag_is_set(dflag, NSCD_CFG_DFLAG_GROUP)) {

                /* get it from the group data */
                cfg = (nscd_cfg_switch_t *)data;
                nswcfgstr = cfg->nsw_config_string;
        } else {
                /* not group, and not the switch policy string, return */
                if (pdesc->p_offset != offsetof(nscd_cfg_switch_t,
                        nsw_config_string))
                return (NSCD_SUCCESS);

                /* the data itself is the string */
                nswcfgstr = (char *)data;
        }

        /*
         * convert the string into struct __nsw_switchconfig_v1
         */
        size = MAX_NSSWITCH_CONFIG_STRING_SZ;
        if (strlcpy(buf, nswcfgstr, size) >= size) {

                (void) snprintf(msg, sizeof (msg),
        gettext("switch policy string too long (\"%s : %s\" > %d)"),
                        nswdb->name, nswcfgstr, size);

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

                if (*errorp)
                        *errorp = _nscd_cfg_make_error(
                                NSCD_CFG_SYNTAX_ERROR, msg);

                return (NSCD_CFG_SYNTAX_ERROR);
        }
        switchcfg = _nsw_getoneconfig_v1(nswdb->name, buf, &err);
        if (switchcfg == NULL) {

                (void) snprintf(msg, sizeof (msg),
                gettext("syntax error: switch policy string (%s : %s) rc = %d"),
                nswdb->name, nswcfgstr, err);

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

                if (*errorp)
                        *errorp = _nscd_cfg_make_error(
                                NSCD_CFG_SYNTAX_ERROR, msg);

                return (NSCD_CFG_SYNTAX_ERROR);
        }

        /* save the __nsw_switchconfig_v1 for the notify function */
        ck = calloc(1, sizeof (nsw_cfg_cookie_t));
        if (ck == NULL) {
                (void) __nsw_freeconfig_v1(switchcfg);
                return (NSCD_CFG_SYNTAX_ERROR);
        }
        ck->cfg = switchcfg;
        ck->cfgstr = nswcfgstr;
        *cookie = ck;

        return (NSCD_SUCCESS);
}

/* ARGSUSED */
nscd_rc_t
_nscd_cfg_switch_get_stat(
        void                            **stat,
        struct nscd_cfg_stat_desc       *sdesc,
        nscd_cfg_id_t                   *nswdb,
        nscd_cfg_flag_t                 *dflag,
        void                            (**free_stat)(void *stat),
        nscd_cfg_error_t                **errorp)
{

        if (_nscd_cfg_flag_is_set(sdesc->sflag, NSCD_CFG_SFLAG_GLOBAL)) {
                *stat = &NSCD_SW_STATS_G;
        } else
                *stat = &NSCD_SW_STATS(nswdb->index);

        /* indicate the statistics are static, i.e., do not free */
        *dflag = _nscd_cfg_flag_set(*dflag, NSCD_CFG_DFLAG_STATIC_DATA);

        return (NSCD_SUCCESS);
}