1cb5caa98Sdjl /* 2cb5caa98Sdjl * CDDL HEADER START 3cb5caa98Sdjl * 4cb5caa98Sdjl * The contents of this file are subject to the terms of the 5cb5caa98Sdjl * Common Development and Distribution License (the "License"). 6cb5caa98Sdjl * You may not use this file except in compliance with the License. 7cb5caa98Sdjl * 8cb5caa98Sdjl * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9cb5caa98Sdjl * or http://www.opensolaris.org/os/licensing. 10cb5caa98Sdjl * See the License for the specific language governing permissions 11cb5caa98Sdjl * and limitations under the License. 12cb5caa98Sdjl * 13cb5caa98Sdjl * When distributing Covered Code, include this CDDL HEADER in each 14cb5caa98Sdjl * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15cb5caa98Sdjl * If applicable, add the following below this CDDL HEADER, with the 16cb5caa98Sdjl * fields enclosed by brackets "[]" replaced with your own identifying 17cb5caa98Sdjl * information: Portions Copyright [yyyy] [name of copyright owner] 18cb5caa98Sdjl * 19cb5caa98Sdjl * CDDL HEADER END 20cb5caa98Sdjl */ 21cb5caa98Sdjl /* 22cb5caa98Sdjl * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23cb5caa98Sdjl * Use is subject to license terms. 24*7d7551bcSMilan Jurik * Copyright 2012 Milan Jurik. All rights reserved. 25cb5caa98Sdjl */ 26cb5caa98Sdjl 27cb5caa98Sdjl #include <stdlib.h> 28cb5caa98Sdjl #include <locale.h> 29cb5caa98Sdjl #include <string.h> 30cb5caa98Sdjl #include "cache.h" 31cb5caa98Sdjl #include "nscd_door.h" 32cb5caa98Sdjl #include "nscd_log.h" 33cb5caa98Sdjl #include "nscd_admin.h" 34cb5caa98Sdjl 35cb5caa98Sdjl extern nsc_ctx_t *cache_ctx_p[]; 36cb5caa98Sdjl extern char *cache_name[]; 37cb5caa98Sdjl 38cb5caa98Sdjl static nscd_admin_t admin_c = { 0 }; 39cb5caa98Sdjl static nscd_admin_mod_t admin_mod = { 0 }; 40cb5caa98Sdjl static mutex_t mod_lock = DEFAULTMUTEX; 41cb5caa98Sdjl 42cb5caa98Sdjl /*ARGSUSED*/ 43cb5caa98Sdjl int 44cb5caa98Sdjl _nscd_door_getadmin(void *outbuf) 45cb5caa98Sdjl { 46cb5caa98Sdjl int i; 47cb5caa98Sdjl int data_size = NSCD_N2N_DOOR_BUF_SIZE(admin_c); 48cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)outbuf; 49cb5caa98Sdjl nscd_cfg_cache_t cfg_default = NSCD_CFG_CACHE_DEFAULTS; 50cb5caa98Sdjl 51cb5caa98Sdjl /* 52cb5caa98Sdjl * if size of buffer is not big enough, tell the caller to 53cb5caa98Sdjl * increase it to the size returned 54cb5caa98Sdjl */ 55cb5caa98Sdjl if (phdr->pbufsiz < data_size) 56cb5caa98Sdjl return (sizeof (admin_c)); 57cb5caa98Sdjl 58cb5caa98Sdjl NSCD_SET_STATUS_SUCCESS(phdr); 59cb5caa98Sdjl phdr->data_off = sizeof (nss_pheader_t); 60cb5caa98Sdjl phdr->data_len = sizeof (admin_c); 61cb5caa98Sdjl 62cb5caa98Sdjl for (i = 0; i < CACHE_CTX_COUNT; i++) { 63cb5caa98Sdjl if (cache_ctx_p[i] != NULL) { 64cb5caa98Sdjl (void) rw_rdlock(&cache_ctx_p[i]->cfg_rwlp); 65cb5caa98Sdjl admin_c.cache_cfg[i] = cache_ctx_p[i]->cfg; 66cb5caa98Sdjl (void) rw_unlock(&cache_ctx_p[i]->cfg_rwlp); 67cb5caa98Sdjl 68cb5caa98Sdjl (void) mutex_lock(&cache_ctx_p[i]->stats_mutex); 69cb5caa98Sdjl admin_c.cache_stats[i] = cache_ctx_p[i]->stats; 70cb5caa98Sdjl (void) mutex_unlock(&cache_ctx_p[i]->stats_mutex); 71cb5caa98Sdjl } else { 72cb5caa98Sdjl admin_c.cache_cfg[i] = cfg_default; 73cb5caa98Sdjl (void) memset(&admin_c.cache_stats[i], 0, 74cb5caa98Sdjl sizeof (admin_c.cache_stats[0])); 75cb5caa98Sdjl } 76cb5caa98Sdjl } 77cb5caa98Sdjl (void) memcpy(((char *)outbuf) + phdr->data_off, 78cb5caa98Sdjl &admin_c, sizeof (admin_c)); 79cb5caa98Sdjl 80cb5caa98Sdjl return (0); 81cb5caa98Sdjl } 82cb5caa98Sdjl 83cb5caa98Sdjl void 84cb5caa98Sdjl _nscd_client_showstats() 85cb5caa98Sdjl { 86cb5caa98Sdjl (void) printf("nscd configuration:\n\n"); 87cb5caa98Sdjl (void) printf("%10d server debug level\n", admin_c.debug_level); 88cb5caa98Sdjl (void) printf("\"%s\" is server log file\n", admin_c.logfile); 89cb5caa98Sdjl 90cb5caa98Sdjl (void) nsc_info(NULL, NULL, admin_c.cache_cfg, admin_c.cache_stats); 91cb5caa98Sdjl } 92cb5caa98Sdjl 93cb5caa98Sdjl /*ARGSUSED*/ 94cb5caa98Sdjl nscd_rc_t 95cb5caa98Sdjl _nscd_server_setadmin(nscd_admin_mod_t *set) 96cb5caa98Sdjl { 97cb5caa98Sdjl nscd_rc_t rc = NSCD_ADMIN_FAIL_TO_SET; 98cb5caa98Sdjl nscd_cfg_handle_t *h; 99cb5caa98Sdjl int i, j; 100cb5caa98Sdjl char *group = "param-group-cache"; 101cb5caa98Sdjl char *dbname; 102cb5caa98Sdjl nscd_cfg_error_t *err = NULL; 103cb5caa98Sdjl char *me = "_nscd_server_setadmin"; 104cb5caa98Sdjl 105cb5caa98Sdjl if (set == NULL) 106cb5caa98Sdjl set = &admin_mod; 107cb5caa98Sdjl 108cb5caa98Sdjl /* one setadmin at a time */ 109cb5caa98Sdjl (void) mutex_lock(&mod_lock); 110cb5caa98Sdjl 111cb5caa98Sdjl _NSCD_LOG_IF(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_DEBUG) { 112cb5caa98Sdjl 113cb5caa98Sdjl _nscd_logit(me, "total_size = %d\n", set->total_size); 114cb5caa98Sdjl 115cb5caa98Sdjl _nscd_logit(me, "debug_level_set = %d, debug_level = %d\n", 116cb5caa98Sdjl set->debug_level_set, set->debug_level); 117cb5caa98Sdjl 118cb5caa98Sdjl _nscd_logit(me, "logfile_set = %d, logfile = %s\n", 119cb5caa98Sdjl set->logfile_set, *set->logfile == '\0' ? 120cb5caa98Sdjl "" : set->logfile); 121cb5caa98Sdjl 122cb5caa98Sdjl _nscd_logit(me, "cache_cfg_num = %d\n", 123cb5caa98Sdjl set->cache_cfg_num); 124cb5caa98Sdjl _nscd_logit(me, "cache_flush_num = %d\n", 125cb5caa98Sdjl set->cache_flush_num); 126cb5caa98Sdjl } 127cb5caa98Sdjl 128cb5caa98Sdjl /* 129cb5caa98Sdjl * global admin stuff 130cb5caa98Sdjl */ 131cb5caa98Sdjl 132cb5caa98Sdjl if (set->debug_level_set == nscd_true) { 133cb5caa98Sdjl if (_nscd_set_debug_level(set->debug_level) 134cb5caa98Sdjl != NSCD_SUCCESS) { 135cb5caa98Sdjl 136cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) 137cb5caa98Sdjl (me, "unable to set debug level %d\n", 138cb5caa98Sdjl set->debug_level); 139cb5caa98Sdjl 140cb5caa98Sdjl goto err_exit; 141cb5caa98Sdjl } 142cb5caa98Sdjl admin_c.debug_level = set->debug_level; 143cb5caa98Sdjl } 144cb5caa98Sdjl 145cb5caa98Sdjl if (set->logfile_set == nscd_true) { 146cb5caa98Sdjl if (_nscd_set_log_file(set->logfile) != NSCD_SUCCESS) { 147cb5caa98Sdjl 148cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) 149cb5caa98Sdjl (me, "unable to set log file %s\n", set->logfile); 150cb5caa98Sdjl 151cb5caa98Sdjl goto err_exit; 152cb5caa98Sdjl } 153cb5caa98Sdjl (void) strlcpy(admin_c.logfile, set->logfile, 154cb5caa98Sdjl NSCD_LOGFILE_LEN); 155cb5caa98Sdjl } 156cb5caa98Sdjl 157cb5caa98Sdjl /* 158cb5caa98Sdjl * For caches to be changed 159cb5caa98Sdjl */ 160cb5caa98Sdjl if (set->cache_cfg_num > CACHE_CTX_COUNT) { 161cb5caa98Sdjl 162cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) 163cb5caa98Sdjl (me, "number of caches (%d) to change out of bound %s\n", 164cb5caa98Sdjl set->cache_cfg_num); 165cb5caa98Sdjl 166cb5caa98Sdjl goto err_exit; 167cb5caa98Sdjl } 168cb5caa98Sdjl 169cb5caa98Sdjl for (i = 0; i < set->cache_cfg_num; i++) { 170cb5caa98Sdjl 171cb5caa98Sdjl nscd_cfg_cache_t *new_cfg; 172cb5caa98Sdjl 173cb5caa98Sdjl j = set->cache_cfg_set[i]; 174cb5caa98Sdjl new_cfg = &set->cache_cfg[i]; 175cb5caa98Sdjl dbname = cache_name[j]; 176cb5caa98Sdjl if (cache_ctx_p[j] == NULL) { 177cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) 178cb5caa98Sdjl (me, "unable to find cache context for %s\n", 179cb5caa98Sdjl dbname); 180cb5caa98Sdjl } 181cb5caa98Sdjl 182cb5caa98Sdjl rc = _nscd_cfg_get_handle(group, dbname, &h, NULL); 183cb5caa98Sdjl if (rc != NSCD_SUCCESS) { 184cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) 185cb5caa98Sdjl (me, "unable to get handle for < %s : %s >\n", 186cb5caa98Sdjl dbname, group); 187cb5caa98Sdjl 188cb5caa98Sdjl goto err_exit; 189cb5caa98Sdjl } 190cb5caa98Sdjl 191cb5caa98Sdjl rc = _nscd_cfg_set(h, new_cfg, &err); 192cb5caa98Sdjl if (rc != NSCD_SUCCESS) { 193cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) 194cb5caa98Sdjl (me, "unable to set admin data for < %s : %s >\n", 195cb5caa98Sdjl dbname, group); 196cb5caa98Sdjl 197cb5caa98Sdjl _nscd_cfg_free_handle(h); 198cb5caa98Sdjl 199cb5caa98Sdjl goto err_exit; 200cb5caa98Sdjl } 201cb5caa98Sdjl _nscd_cfg_free_handle(h); 202cb5caa98Sdjl } 203cb5caa98Sdjl 204cb5caa98Sdjl /* 205cb5caa98Sdjl * For caches to be flushed 206cb5caa98Sdjl */ 207cb5caa98Sdjl if (set->cache_flush_num > CACHE_CTX_COUNT) { 208cb5caa98Sdjl 209cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) 210cb5caa98Sdjl (me, "number of caches (%d) to flush out of bound %s\n", 211cb5caa98Sdjl set->cache_flush_num); 212cb5caa98Sdjl 213cb5caa98Sdjl goto err_exit; 214cb5caa98Sdjl } 215cb5caa98Sdjl 216cb5caa98Sdjl for (i = 0; i < set->cache_flush_num; i++) { 217cb5caa98Sdjl int j; 218cb5caa98Sdjl 219cb5caa98Sdjl j = set->cache_flush_set[i]; 220cb5caa98Sdjl 221cb5caa98Sdjl if (cache_ctx_p[j] == NULL) { 222cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) 223cb5caa98Sdjl (me, "unable to find cache context for %s\n", 224cb5caa98Sdjl dbname); 225cb5caa98Sdjl } 226cb5caa98Sdjl nsc_invalidate(cache_ctx_p[j], NULL, NULL); 227cb5caa98Sdjl } 228cb5caa98Sdjl 229cb5caa98Sdjl rc = NSCD_SUCCESS; 230cb5caa98Sdjl err_exit: 231cb5caa98Sdjl 232cb5caa98Sdjl (void) mutex_unlock(&mod_lock); 233cb5caa98Sdjl return (rc); 234cb5caa98Sdjl } 235cb5caa98Sdjl 236cb5caa98Sdjl 237cb5caa98Sdjl /*ARGSUSED*/ 238cb5caa98Sdjl void 239cb5caa98Sdjl _nscd_door_setadmin(void *buf) 240cb5caa98Sdjl { 241cb5caa98Sdjl nscd_rc_t rc; 242cb5caa98Sdjl nss_pheader_t *phdr = (nss_pheader_t *)buf; 243cb5caa98Sdjl char *me = "_nscd_door_setadmin"; 244cb5caa98Sdjl 245cb5caa98Sdjl rc = _nscd_server_setadmin(NSCD_N2N_DOOR_DATA(nscd_admin_mod_t, buf)); 246cb5caa98Sdjl if (rc != NSCD_SUCCESS) { 247cb5caa98Sdjl _NSCD_LOG(NSCD_LOG_ADMIN, NSCD_LOG_LEVEL_ERROR) 248cb5caa98Sdjl (me, "SETADMIN call failed\n"); 249cb5caa98Sdjl 250*7d7551bcSMilan Jurik NSCD_SET_N2N_STATUS(phdr, NSS_NSCD_PRIV, 0, rc); 251cb5caa98Sdjl } else { 252*7d7551bcSMilan Jurik NSCD_SET_STATUS_SUCCESS(phdr); 253cb5caa98Sdjl } 254cb5caa98Sdjl } 255cb5caa98Sdjl 256cb5caa98Sdjl /* 257cb5caa98Sdjl * for a database 'dbname', add config value 'val' of option 'opt' 258cb5caa98Sdjl * to the global admin_mod structure 259cb5caa98Sdjl */ 260cb5caa98Sdjl int 261cb5caa98Sdjl _nscd_add_admin_mod(char *dbname, char opt, 262cb5caa98Sdjl char *val, char *msg, int msglen) { 263cb5caa98Sdjl int i, j; 264cb5caa98Sdjl nscd_cfg_cache_t *cfg; 265cb5caa98Sdjl nscd_cfg_group_info_t gi = NSCD_CFG_GROUP_INFO_CACHE; 266cb5caa98Sdjl char dbn[64], *cp; 267cb5caa98Sdjl 268cb5caa98Sdjl /* set initial admin_mod size; assume no cache config to set */ 269cb5caa98Sdjl if (admin_mod.total_size == 0) 270cb5caa98Sdjl admin_mod.total_size = sizeof (admin_mod) - 271cb5caa98Sdjl sizeof (admin_mod.cache_cfg); 272cb5caa98Sdjl 273cb5caa98Sdjl /* global admin stuff */ 274cb5caa98Sdjl if (opt == 'l' || opt == 'd') { 275cb5caa98Sdjl if (opt == 'l') { 276cb5caa98Sdjl (void) strlcpy(admin_mod.logfile, 277cb5caa98Sdjl val, NSCD_LOGFILE_LEN); 278cb5caa98Sdjl admin_mod.logfile_set = nscd_true; 279cb5caa98Sdjl } else { 280cb5caa98Sdjl admin_mod.debug_level = atoi(val); 281cb5caa98Sdjl admin_mod.debug_level_set = nscd_true; 282cb5caa98Sdjl } 283cb5caa98Sdjl return (0); 284cb5caa98Sdjl } 285cb5caa98Sdjl 286cb5caa98Sdjl /* options to be processed next requires cache name */ 287cb5caa98Sdjl (void) strlcpy(dbn, dbname, sizeof (dbn)); 288cb5caa98Sdjl if ((cp = strchr(dbn, ',')) != NULL) 289cb5caa98Sdjl *cp = '\0'; 290cb5caa98Sdjl i = get_cache_idx(dbn); 291cb5caa98Sdjl if (i == -1) { 292cb5caa98Sdjl (void) snprintf(msg, msglen, 293cb5caa98Sdjl gettext("invalid cache name \"%s\""), dbn); 294cb5caa98Sdjl return (-1); 295cb5caa98Sdjl } 296cb5caa98Sdjl 297cb5caa98Sdjl /* flush cache ? */ 298cb5caa98Sdjl if (opt == 'i') { 299cb5caa98Sdjl admin_mod.cache_flush_set[admin_mod.cache_flush_num++] = i; 300cb5caa98Sdjl return (0); 301cb5caa98Sdjl } 302cb5caa98Sdjl 303cb5caa98Sdjl /* options to be processed next requires a param value */ 304cb5caa98Sdjl if (val == NULL) { 305cb5caa98Sdjl (void) snprintf(msg, msglen, 306cb5caa98Sdjl gettext("value missing after \"%s\""), dbn); 307cb5caa98Sdjl return (-1); 308cb5caa98Sdjl } 309cb5caa98Sdjl 310cb5caa98Sdjl /* try to use an existing cache_cfg in admin_mod */ 311cb5caa98Sdjl for (j = 0; j < admin_mod.cache_cfg_num; j++) { 312cb5caa98Sdjl if (admin_mod.cache_cfg_set[j] == i) 313cb5caa98Sdjl break; 314cb5caa98Sdjl } 315cb5caa98Sdjl 316cb5caa98Sdjl /* no existing one, set up another one */ 317cb5caa98Sdjl if (j == admin_mod.cache_cfg_num) { 318cb5caa98Sdjl admin_mod.cache_cfg_set[j] = i; 319cb5caa98Sdjl admin_mod.cache_cfg_num++; 320cb5caa98Sdjl admin_mod.total_size += sizeof (admin_mod.cache_cfg[0]); 321cb5caa98Sdjl } 322cb5caa98Sdjl 323cb5caa98Sdjl cfg = &admin_mod.cache_cfg[j]; 324cb5caa98Sdjl cfg->gi.num_param = gi.num_param; 325cb5caa98Sdjl 326cb5caa98Sdjl switch (opt) { 327cb5caa98Sdjl 328cb5caa98Sdjl case 'e': 329cb5caa98Sdjl /* enable cache */ 330cb5caa98Sdjl 331cb5caa98Sdjl _nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 0); 332cb5caa98Sdjl if (strcmp(val, "yes") == 0) 333cb5caa98Sdjl cfg->enable = nscd_true; 334cb5caa98Sdjl else if (strcmp(val, "no") == 0) 335cb5caa98Sdjl cfg->enable = nscd_false; 336cb5caa98Sdjl else { 337cb5caa98Sdjl (void) snprintf(msg, msglen, 338cb5caa98Sdjl gettext("\"yes\" or \"no\" not specified after \"%s\""), dbn); 339cb5caa98Sdjl return (-1); 340cb5caa98Sdjl } 341cb5caa98Sdjl break; 342cb5caa98Sdjl 343cb5caa98Sdjl case 'c': 344cb5caa98Sdjl /* check files */ 345cb5caa98Sdjl 346cb5caa98Sdjl _nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 3); 347cb5caa98Sdjl if (strcmp(val, "yes") == 0) 348cb5caa98Sdjl cfg->check_files = nscd_true; 349cb5caa98Sdjl else if (strcmp(val, "no") == 0) 350cb5caa98Sdjl cfg->check_files = nscd_false; 351cb5caa98Sdjl else { 352cb5caa98Sdjl (void) snprintf(msg, msglen, 353cb5caa98Sdjl gettext("\"yes\" or \"no\" not specified after \"%s\""), dbn); 354cb5caa98Sdjl return (-1); 355cb5caa98Sdjl } 356cb5caa98Sdjl break; 357cb5caa98Sdjl 358cb5caa98Sdjl case 'p': 359cb5caa98Sdjl /* positive time to live */ 360cb5caa98Sdjl 361cb5caa98Sdjl _nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 5); 362cb5caa98Sdjl cfg->pos_ttl = atoi(val); 363cb5caa98Sdjl break; 364cb5caa98Sdjl 365cb5caa98Sdjl case 'n': 366cb5caa98Sdjl /* negative time to live */ 367cb5caa98Sdjl 368cb5caa98Sdjl _nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 6); 369cb5caa98Sdjl cfg->neg_ttl = atoi(val); 370cb5caa98Sdjl break; 371cb5caa98Sdjl 372cb5caa98Sdjl case 'h': 373cb5caa98Sdjl /* keep hot count */ 374cb5caa98Sdjl 375cb5caa98Sdjl _nscd_cfg_bitmap_set_nth(cfg->gi.bitmap, 7); 376cb5caa98Sdjl cfg->keephot = atoi(val); 377cb5caa98Sdjl break; 378cb5caa98Sdjl } 379cb5caa98Sdjl 380cb5caa98Sdjl return (0); 381cb5caa98Sdjl } 382cb5caa98Sdjl 383cb5caa98Sdjl int 384cb5caa98Sdjl _nscd_client_getadmin(char opt) 385cb5caa98Sdjl { 386cb5caa98Sdjl int callnum; 387cb5caa98Sdjl nss_pheader_t phdr; 388cb5caa98Sdjl 389cb5caa98Sdjl if (opt == 'G') 390cb5caa98Sdjl callnum = NSCD_GETPUADMIN; 391cb5caa98Sdjl else 392cb5caa98Sdjl callnum = NSCD_GETADMIN; 393cb5caa98Sdjl 394cb5caa98Sdjl (void) _nscd_doorcall_data(callnum, NULL, sizeof (admin_c), 395cb5caa98Sdjl &admin_c, sizeof (admin_c), &phdr); 396cb5caa98Sdjl 397cb5caa98Sdjl if (NSCD_STATUS_IS_NOT_OK(&phdr)) { 398cb5caa98Sdjl return (1); 399cb5caa98Sdjl } 400cb5caa98Sdjl 401cb5caa98Sdjl return (0); 402cb5caa98Sdjl } 403cb5caa98Sdjl 404cb5caa98Sdjl int 405cb5caa98Sdjl _nscd_client_setadmin() 406cb5caa98Sdjl { 407cb5caa98Sdjl return (_nscd_doorcall_data(NSCD_SETADMIN, &admin_mod, 408cb5caa98Sdjl sizeof (admin_mod), NULL, 0, NULL)); 409cb5caa98Sdjl } 410