OpenSolaris_b135/cmd/nscd/nscd_admin.c

Compare this file to the similar file:
Show the results in this format:

/*
 * 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.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <stdlib.h>
#include <locale.h>
#include <string.h>
#include "cache.h"
#include "nscd_door.h"
#include "nscd_log.h"
#include "nscd_admin.h"

extern nsc_ctx_t	*cache_ctx_p[];
extern char 		*cache_name[];

static nscd_admin_t	admin_c = { 0 };
static nscd_admin_mod_t	admin_mod = { 0 };
static mutex_t		mod_lock = DEFAULTMUTEX;

/*ARGSUSED*/
int
_nscd_door_getadmin(void *outbuf)
{
	int			i;
	int			data_size = NSCD_N2N_DOOR_BUF_SIZE(admin_c);
	nss_pheader_t		*phdr = (nss_pheader_t *)outbuf;
	nscd_cfg_cache_t	cfg_default = NSCD_CFG_CACHE_DEFAULTS;

	/*
	 * if size of buffer is not big enough, tell the caller to
	 * increase it to the size returned
	 */
	if (phdr->pbufsiz < data_size)
		return (sizeof (admin_c));

	NSCD_SET_STATUS_SUCCESS(phdr);
	phdr->data_off = sizeof (nss_pheader_t);
	phdr->data_len = sizeof (admin_c);

	for (i = 0; i < CACHE_CTX_COUNT; i++) {
		if (cache_ctx_p[i] != NULL) {
			(void) rw_rdlock(&cache_ctx_p[i]->cfg_rwlp);
			admin_c.cache_cfg[i] = cache_ctx_p[i]->cfg;
			(void) rw_unlock(&cache_ctx_p[i]->cfg_rwlp);

			(void) mutex_lock(&cache_ctx_p[i]->stats_mutex);
			admin_c.cache_stats[i] = cache_ctx_p[i]->stats;
			(void) mutex_unlock(&cache_ctx_p[i]->stats_mutex);
		} else {
			admin_c.cache_cfg[i] = cfg_default;
			(void) memset(&admin_c.cache_stats[i], 0,
				sizeof (admin_c.cache_stats[0]));
		}
	}
	(void) memcpy(((char *)outbuf) + phdr->data_off,
		&admin_c, sizeof (admin_c));

	return (0);
}

void
_nscd_client_showstats()
{
	(void) printf("nscd configuration:\n\n");
	(void) printf("%10d  server debug level\n", admin_c.debug_level);
	(void) printf("\"%s\"  is server log file\n", admin_c.logfile);

	(void) nsc_info(NULL, NULL, admin_c.cache_cfg, admin_c.cache_stats);
}

/*ARGSUSED*/
nscd_rc_t
_nscd_server_setadmin(nscd_admin_mod_t *set)
{
	nscd_rc_t		rc = NSCD_ADMIN_FAIL_TO_SET;
	nscd_cfg_handle_t	*h;
	int			i, j;
	char			*group = "param-group-cache";
	char			*dbname;
	nscd_cfg_error_t	*err = NULL;
	char			*me = "_nscd_server_setadmin";

	if (set == NULL)
		set = &admin_mod;

	/* one setadmin at a time */
	(void) mutex_lock(&mod_lock);

	_NSCD_LOG_IF(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_DEBUG) {

		_nscd_logit(me, "total_size = %d\n", set->total_size);

		_nscd_logit(me, "debug_level_set = %d, debug_level = %d\n",
			set->debug_level_set, set->debug_level);

		_nscd_logit(me, "logfile_set = %d, logfile = %s\n",
			set->logfile_set, *set->logfile == '\0' ?
				"" : set->logfile);

		_nscd_logit(me, "cache_cfg_num = %d\n",
			set->cache_cfg_num);
		_nscd_logit(me, "cache_flush_num = %d\n",
			set->cache_flush_num);
	}

	/*
	 *  global admin stuff
	 */

	if (set->debug_level_set == nscd_true) {
		if (_nscd_set_debug_level(set->debug_level)
			!= NSCD_SUCCESS) {

			_NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR)
			(me, "unable to set debug level %d\n",
				set->debug_level);

			goto err_exit;
		}
		admin_c.debug_level = set->debug_level;
	}

	if (set->logfile_set == nscd_true) {
		if (_nscd_set_log_file(set->logfile) != NSCD_SUCCESS) {

			_NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR)
			(me, "unable to set log file %s\n", set->logfile);

			goto err_exit;
		}
		(void) strlcpy(admin_c.logfile, set->logfile,
				NSCD_LOGFILE_LEN);
	}

	/*
	 *  For caches to be changed
	 */
	if (set->cache_cfg_num > CACHE_CTX_COUNT) {

		_NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR)
		(me, "number of caches (%d) to change out of bound %s\n",
			set->cache_cfg_num);

		goto err_exit;
	}

	for (i = 0; i < set->cache_cfg_num; i++) {

		nscd_cfg_cache_t *new_cfg;

		j = set->cache_cfg_set[i];
		new_cfg = &set->cache_cfg[i];
		dbname = cache_name[j];
		if (cache_ctx_p[j] == NULL) {
			_NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR)
			(me, "unable to find cache context for %s\n",
			dbname);
		}

		rc = _nscd_cfg_get_handle(group, dbname, &h, NULL);
		if (rc != NSCD_SUCCESS) {
			_NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR)
			(me, "unable to get handle for < %s : %s >\n",
			dbname, group);

			goto err_exit;
		}

		rc = _nscd_cfg_set(h, new_cfg, &err);
		if (rc != NSCD_SUCCESS) {
			_NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR)
			(me, "unable to set admin data for < %s : %s >\n",
			dbname, group);

			_nscd_cfg_free_handle(h);

			goto err_exit;
		}
		_nscd_cfg_free_handle(h);
	}

	/*
	 *  For caches to be flushed
	 */
	if (set->cache_flush_num > CACHE_CTX_COUNT) {

		_NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR)
		(me, "number of caches (%d) to flush out of bound %s\n",
			set->cache_flush_num);

		goto err_exit;
	}

	for (i = 0; i < set->cache_flush_num; i++) {
		int j;

		j = set->cache_flush_set[i];

		if (cache_ctx_p[j] == NULL) {
			_NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR)
			(me, "unable to find cache context for %s\n",
			dbname);
		}
		nsc_invalidate(cache_ctx_p[j], NULL, NULL);
	}

	rc = NSCD_SUCCESS;
	err_exit:

	(void) mutex_unlock(&mod_lock);
	return (rc);
}


/*ARGSUSED*/
void
_nscd_door_setadmin(void *buf)
{
	nscd_rc_t	rc;
	nss_pheader_t	*phdr = (nss_pheader_t *)buf;
	char		*me = "_nscd_door_setadmin";

	rc = _nscd_server_setadmin(NSCD_N2N_DOOR_DATA(nscd_admin_mod_t, buf));
	if (rc != NSCD_SUCCESS) {
		_NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR)
		(me, "SETADMIN call failed\n");

		NSCD_RETURN_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, rc);
	} else {
		NSCD_RETURN_STATUS_SUCCESS(phdr);
	}
}

/*
 * for a database 'dbname', add config value 'val' of option 'opt'
 * to the global admin_mod structure
 */
int
_nscd_add_admin_mod(char *dbname, char opt,
	char *val, char *msg, int msglen) {
	int			i, j;
	nscd_cfg_cache_t	*cfg;
	nscd_cfg_group_info_t	gi = NSCD_CFG_GROUP_INFO_CACHE;
	char			dbn[64], *cp;

	/* set initial admin_mod size; assume no cache config to set */
	if (admin_mod.total_size == 0)
		admin_mod.total_size = sizeof (admin_mod) -
			sizeof (admin_mod.cache_cfg);

	/* global admin stuff */
	if (opt == 'l' || opt == 'd') {
		if (opt == 'l') {
			(void) strlcpy(admin_mod.logfile,
				val, NSCD_LOGFILE_LEN);
			admin_mod.logfile_set = nscd_true;
		} else {
			admin_mod.debug_level = atoi(val);
			admin_mod.debug_level_set = nscd_true;
		}
		return (0);
	}

	/* options to be processed next requires cache name */
	(void) strlcpy(dbn, dbname, sizeof (dbn));
	if ((cp = strchr(dbn, ',')) != NULL)
		*cp = '\0';
	i = get_cache_idx(dbn);
	if (i == -1) {
		(void) snprintf(msg, msglen,
			gettext("invalid cache name \"%s\""), dbn);
		return (-1);
	}

	/* flush cache ? */
	if (opt == 'i') {
		admin_mod.cache_flush_set[admin_mod.cache_flush_num++] = i;
		return (0);
	}

	/* options to be processed next requires a param value */
	if (val == NULL) {
		(void) snprintf(msg, msglen,
			gettext("value missing after \"%s\""), dbn);
		return (-1);
	}

	/* try to use an existing cache_cfg in admin_mod */
	for (j = 0; j < admin_mod.cache_cfg_num; j++) {
		if (admin_mod.cache_cfg_set[j] == i)
			break;
	}

	/* no existing one, set up another one */
	if (j == admin_mod.cache_cfg_num) {
		admin_mod.cache_cfg_set[j] = i;
		admin_mod.cache_cfg_num++;
		admin_mod.total_size += sizeof (admin_mod.cache_cfg[0]);
	}

	cfg = &admin_mod.cache_cfg[j];
	cfg->gi.num_param = gi.num_param;

	switch (opt) {

	case 'e':
		/* enable cache */

		_nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 0);
		if (strcmp(val, "yes") == 0)
		    cfg->enable = nscd_true;
		else if (strcmp(val, "no") == 0)
		    cfg->enable = nscd_false;
		else {
			(void) snprintf(msg, msglen,
	gettext("\"yes\" or \"no\" not specified after \"%s\""), dbn);
			return (-1);
		}
		break;

	case 'c':
		/* check files */

		_nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 3);
		if (strcmp(val, "yes") == 0)
		    cfg->check_files = nscd_true;
		else if (strcmp(val, "no") == 0)
		    cfg->check_files = nscd_false;
		else {
			(void) snprintf(msg, msglen,
	gettext("\"yes\" or \"no\" not specified after \"%s\""), dbn);
			return (-1);
		}
		break;

	case 'p':
		/* positive time to live */

		_nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 5);
		cfg->pos_ttl = atoi(val);
		break;

	case 'n':
		/* negative time to live */

		_nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 6);
		cfg->neg_ttl = atoi(val);
		break;

	case 'h':
		/* keep hot count */

		_nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 7);
		cfg->keephot = atoi(val);
		break;
	}

	return (0);
}

int
_nscd_client_getadmin(char opt)
{
	int		callnum;
	nss_pheader_t	phdr;

	if (opt == 'G')
		callnum = NSCD_GETPUADMIN;
	else
		callnum = NSCD_GETADMIN;

	(void) _nscd_doorcall_data(callnum, NULL, sizeof (admin_c),
		&admin_c, sizeof (admin_c), &phdr);

	if (NSCD_STATUS_IS_NOT_OK(&phdr)) {
		return (1);
	}

	return (0);
}

int
_nscd_client_setadmin()
{
	return (_nscd_doorcall_data(NSCD_SETADMIN, &admin_mod,
		sizeof (admin_mod), NULL, 0, NULL));
}