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