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