xref: /illumos-gate/usr/src/cmd/nscd/nscd_admin.c (revision ba2be53024c0b999e74ba9adcd7d80fec5df8c57)
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