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