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
_nscd_door_getadmin(void * outbuf)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
_nscd_client_showstats()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
_nscd_server_setadmin(nscd_admin_mod_t * set)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
_nscd_door_setadmin(void * buf)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
_nscd_add_admin_mod(char * dbname,char opt,char * val,char * msg,int msglen)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
_nscd_client_getadmin(char opt)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
_nscd_client_setadmin()406 _nscd_client_setadmin()
407 {
408 return (_nscd_doorcall_data(NSCD_SETADMIN, &admin_mod,
409 sizeof (admin_mod), NULL, 0, NULL));
410 }
411