xref: /illumos-gate/usr/src/cmd/nscd/nscd_admin.c (revision 7d7551bc)
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
_nscd_door_getadmin(void * outbuf)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
_nscd_client_showstats()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
_nscd_server_setadmin(nscd_admin_mod_t * set)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
_nscd_door_setadmin(void * buf)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
_nscd_add_admin_mod(char * dbname,char opt,char * val,char * msg,int msglen)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
_nscd_client_getadmin(char opt)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
_nscd_client_setadmin()405 _nscd_client_setadmin()
406 {
407 	return (_nscd_doorcall_data(NSCD_SETADMIN, &admin_mod,
408 	    sizeof (admin_mod), NULL, 0, NULL));
409 }
410