/* * 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. * Copyright 2012 Milan Jurik. All rights reserved. */ #include #include #include #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_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, rc); } else { NSCD_SET_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)); }