dmake: do not set MAKEFLAGS=k
[unleashed/tickless.git] / usr / src / cmd / nscd / server.c
blob1c94911be591188e76ce46eaed1e4d693804c8a8
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1994, 2010, Oracle and/or its affiliates. All rights reserved.
23 * Copyright (c) 2016 by Delphix. All rights reserved.
27 * Simple doors name server cache daemon
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <fcntl.h>
33 #include <string.h>
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <locale.h>
37 #include <sys/stat.h>
38 #include <zone.h>
39 #include <signal.h>
40 #include <sys/resource.h>
41 #include "cache.h"
42 #include "nscd_log.h"
43 #include "nscd_selfcred.h"
44 #include "nscd_frontend.h"
45 #include "nscd_common.h"
46 #include "nscd_admin.h"
47 #include "nscd_door.h"
48 #include "nscd_switch.h"
50 extern int optind;
51 extern int opterr;
52 extern int optopt;
53 extern char *optarg;
55 #define NSCDOPT "S:Kf:c:ge:p:n:i:l:d:s:h:o:GFR"
57 /* assume this is a single nscd or, if multiple, the main nscd */
58 int _whoami = NSCD_MAIN;
59 int _doorfd = -1;
60 extern int _logfd;
61 static char *cfgfile = NULL;
63 extern nsc_ctx_t *cache_ctx_p[];
65 static void usage(char *);
66 static void detachfromtty(void);
68 static char debug_level[32] = { 0 };
69 static char logfile[128] = { 0 };
70 static int will_become_server;
72 static char *
73 getcacheopt(char *s)
75 while (*s && *s != ',')
76 s++;
77 return ((*s == ',') ? (s + 1) : NULL);
81 * declaring this causes the files backend to use hashing
82 * this is of course an utter hack, but provides a nice
83 * quiet back door to enable this feature for only the nscd.
85 void
86 __nss_use_files_hash(void)
90 static int saved_argc = 0;
91 static char **saved_argv = NULL;
92 static char saved_execname[MAXPATHLEN];
94 static void
95 save_execname()
97 const char *name = getexecname();
99 saved_execname[0] = 0;
101 if (name[0] != '/') { /* started w/ relative path */
102 (void) getcwd(saved_execname, MAXPATHLEN);
103 (void) strlcat(saved_execname, "/", MAXPATHLEN);
105 (void) strlcat(saved_execname, name, MAXPATHLEN);
109 main(int argc, char ** argv)
111 int opt;
112 int errflg = 0;
113 int showstats = 0;
114 int doset = 0;
115 nscd_rc_t rc;
116 char *me = "main()";
117 char *ret_locale;
118 char *ret_textdomain;
119 char msg[128];
120 struct rlimit rl;
122 ret_locale = setlocale(LC_ALL, "");
123 if (ret_locale == NULL)
124 (void) fprintf(stderr, gettext("Unable to set locale\n"));
126 ret_textdomain = textdomain(TEXT_DOMAIN);
127 if (ret_textdomain == NULL)
128 (void) fprintf(stderr, gettext("Unable to set textdomain\n"));
131 * Special case non-root user here - he can just print stats
133 if (geteuid()) {
134 if (argc != 2 ||
135 (strcmp(argv[1], "-g") && strcmp(argv[1], "-G"))) {
136 (void) fprintf(stderr,
137 gettext("Must be root to use any option other than -g\n\n"));
138 usage(argv[0]);
141 if (_nscd_doorcall(NSCD_PING) != NSS_SUCCESS) {
142 (void) fprintf(stderr,
143 gettext("%s doesn't appear to be running.\n"),
144 argv[0]);
145 exit(1);
147 if (_nscd_client_getadmin(argv[1][1]) != 0) {
148 (void) fprintf(stderr,
149 gettext("unable to get configuration and statistics data\n"));
150 exit(1);
153 _nscd_client_showstats();
154 exit(0);
158 * Determine if there is already a daemon (main nscd) running.
159 * If not, will start it. Forker NSCD will always become a
160 * daemon.
162 will_become_server = (_nscd_doorcall(NSCD_PING) != NSS_SUCCESS);
163 if (argc >= 2 && strcmp(argv[1], "-F") == 0) {
164 will_become_server = 1;
165 _whoami = NSCD_FORKER;
168 * allow time for the main nscd to get ready
169 * to receive the IMHERE door request this
170 * process will send later
172 (void) usleep(100000);
176 * first get the config file path. Also detect
177 * invalid option as soon as possible.
179 while ((opt = getopt(argc, argv, NSCDOPT)) != EOF) {
180 switch (opt) {
182 case 'f':
183 if ((cfgfile = strdup(optarg)) == NULL)
184 exit(1);
185 break;
186 case 'g':
187 if (will_become_server) {
188 (void) fprintf(stderr,
189 gettext("nscd not running, no statistics to show\n\n"));
190 errflg++;
192 break;
193 case 'i':
194 if (will_become_server) {
195 (void) fprintf(stderr,
196 gettext("nscd not running, no cache to invalidate\n\n"));
197 errflg++;
199 break;
201 case '?':
202 errflg++;
203 break;
207 if (errflg)
208 usage(argv[0]);
211 * perform more initialization and load configuration
212 * if to become server
214 if (will_become_server) {
216 /* initialize switch engine and config/stats management */
217 if ((rc = _nscd_init(cfgfile)) != NSCD_SUCCESS) {
218 (void) fprintf(stderr,
219 gettext("initialization of switch failed (rc = %d)\n"), rc);
220 exit(1);
222 _nscd_get_log_info(debug_level, sizeof (debug_level),
223 logfile, sizeof (logfile));
226 * initialize cache store
228 if ((rc = init_cache(0)) != NSCD_SUCCESS) {
229 (void) fprintf(stderr,
230 gettext("initialization of cache store failed (rc = %d)\n"), rc);
231 exit(1);
236 * process usual options
238 optind = 1; /* this is a rescan */
239 *msg = '\0';
240 while ((opt = getopt(argc, argv, NSCDOPT)) != EOF) {
242 switch (opt) {
244 case 'K': /* undocumented feature */
245 (void) _nscd_doorcall(NSCD_KILLSERVER);
246 exit(0);
247 break;
249 case 'G':
250 case 'g':
251 showstats++;
252 break;
254 case 'p':
255 doset++;
256 if (_nscd_add_admin_mod(optarg, 'p',
257 getcacheopt(optarg),
258 msg, sizeof (msg)) == -1)
259 errflg++;
260 break;
262 case 'n':
263 doset++;
264 if (_nscd_add_admin_mod(optarg, 'n',
265 getcacheopt(optarg),
266 msg, sizeof (msg)) == -1)
267 errflg++;
268 break;
270 case 'c':
271 doset++;
272 if (_nscd_add_admin_mod(optarg, 'c',
273 getcacheopt(optarg),
274 msg, sizeof (msg)) == -1)
275 errflg++;
276 break;
278 case 'i':
279 doset++;
280 if (_nscd_add_admin_mod(optarg, 'i', NULL,
281 msg, sizeof (msg)) == -1)
282 errflg++;
283 break;
285 case 'l':
286 doset++;
287 (void) strlcpy(logfile, optarg, sizeof (logfile));
288 break;
290 case 'd':
291 doset++;
292 (void) strlcpy(debug_level, optarg,
293 sizeof (debug_level));
294 break;
296 case 'S':
297 /* silently ignore secure-mode */
298 break;
300 case 's':
301 /* silently ignore suggested-size */
302 break;
304 case 'o':
305 /* silently ignore old-data-ok */
306 break;
308 case 'h':
309 doset++;
310 if (_nscd_add_admin_mod(optarg, 'h',
311 getcacheopt(optarg),
312 msg, sizeof (msg)) == -1)
313 errflg++;
314 break;
316 case 'e':
317 doset++;
318 if (_nscd_add_admin_mod(optarg, 'e',
319 getcacheopt(optarg),
320 msg, sizeof (msg)) == -1)
321 errflg++;
322 break;
324 case 'F':
325 _whoami = NSCD_FORKER;
326 break;
328 default:
329 errflg++;
330 break;
335 if (errflg) {
336 if (*msg != '\0')
337 (void) fprintf(stderr, "\n%s: %s\n\n", argv[0], msg);
338 usage(argv[0]);
342 * if main nscd already running and not forker nscd,
343 * can only do admin work
345 if (_whoami == NSCD_MAIN) {
346 if (!will_become_server) {
347 if (showstats) {
348 if (_nscd_client_getadmin('g')) {
349 (void) fprintf(stderr,
350 gettext("Cannot contact nscd properly(?)\n"));
351 exit(1);
353 _nscd_client_showstats();
356 if (doset) {
357 if (_nscd_client_setadmin() < 0) {
358 (void) fprintf(stderr,
359 gettext("Error during admin call\n"));
360 exit(1);
363 if (!showstats && !doset) {
364 (void) fprintf(stderr,
365 gettext("%s already running.... no administration option specified\n"),
366 argv[0]);
368 exit(0);
373 * daemon from here on
376 if (_whoami == NSCD_MAIN) {
378 /* save enough info in case need to restart or fork */
379 saved_argc = argc;
380 saved_argv = argv;
381 save_execname();
384 * if a log file is not specified, set it to
385 * "stderr" or "/dev/null" based on debug level
387 if (*logfile == '\0') {
388 if (*debug_level != '\0')
389 /* we're debugging... */
390 (void) strcpy(logfile, "stderr");
391 else
392 (void) strcpy(logfile, "/dev/null");
394 (void) _nscd_add_admin_mod(NULL, 'l', logfile,
395 msg, sizeof (msg));
396 (void) _nscd_add_admin_mod(NULL, 'd', debug_level,
397 msg, sizeof (msg));
399 /* activate command options */
400 if (_nscd_server_setadmin(NULL) != NSCD_SUCCESS) {
401 (void) fprintf(stderr,
402 gettext("unable to set command line options\n"));
403 exit(1);
406 if (*debug_level != '\0') {
407 /* we're debugging, no forking of nscd */
410 * forker nscd will be started if self credential
411 * is configured
413 _nscd_start_forker(saved_execname, saved_argc,
414 saved_argv);
415 } else {
417 * daemonize the nscd (forker nscd will also
418 * be started if self credential is configured)
420 detachfromtty();
422 } else { /* NSCD_FORKER */
424 * To avoid PUN (Per User Nscd) processes from becoming
425 * zombies after they exit, the forking nscd should
426 * ignore the SIGCLD signal so that it does not
427 * need to wait for every child PUN to exit.
429 (void) signal(SIGCLD, SIG_IGN);
430 (void) open("/dev/null", O_RDWR, 0);
431 (void) dup(0);
432 if (_logfd != 2)
433 (void) dup(0);
436 /* set NOFILE to unlimited */
437 rl.rlim_cur = rl.rlim_max = RLIM_INFINITY;
438 if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
439 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
440 (me, "Cannot set open file limit: %s\n", strerror(errno));
441 exit(1);
444 /* set up door and establish our own server thread pool */
445 if ((_doorfd = _nscd_setup_server(saved_execname, saved_argv)) == -1) {
446 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
447 (me, "unable to set up door\n");
448 exit(1);
451 /* inform the main nscd that this forker is ready */
452 if (_whoami == NSCD_FORKER) {
453 int ret;
455 for (ret = NSS_ALTRETRY; ret == NSS_ALTRETRY; )
456 ret = _nscd_doorcall_sendfd(_doorfd,
457 NSCD_IMHERE | (NSCD_FORKER & NSCD_WHOAMI),
458 NULL, 0, NULL);
461 for (;;) {
462 (void) pause();
463 (void) _nscd_doorcall(NSCD_REFRESH);
466 /* NOTREACHED */
467 /*LINTED E_FUNC_HAS_NO_RETURN_STMT*/
470 static void
471 usage(char *s)
473 (void) fprintf(stderr,
474 "Usage: %s [-d debug_level] [-l logfilename]\n", s);
475 (void) fprintf(stderr,
476 " [-p cachename,positive_time_to_live]\n");
477 (void) fprintf(stderr,
478 " [-n cachename,negative_time_to_live]\n");
479 (void) fprintf(stderr,
480 " [-i cachename]\n");
481 (void) fprintf(stderr,
482 " [-h cachename,keep_hot_count]\n");
483 (void) fprintf(stderr,
484 " [-e cachename,\"yes\"|\"no\"] [-g] " \
485 "[-c cachename,\"yes\"|\"no\"]\n");
486 (void) fprintf(stderr,
487 " [-f configfilename] \n");
488 (void) fprintf(stderr,
489 "\n Supported caches:\n");
490 (void) fprintf(stderr,
491 " auth_attr, bootparams, ethers\n");
492 (void) fprintf(stderr,
493 " exec_attr, group, hosts, ipnodes, netmasks\n");
494 (void) fprintf(stderr,
495 " networks, passwd, printers, prof_attr, project\n");
496 (void) fprintf(stderr,
497 " protocols, rpc, services\n");
498 (void) fprintf(stderr,
499 " user_attr\n");
500 exit(1);
504 * detach from tty
506 static void
507 detachfromtty(void)
509 nscd_rc_t rc;
510 char *me = "detachfromtty";
512 if (_logfd > 0) {
513 int i;
514 for (i = 0; i < _logfd; i++)
515 (void) close(i);
516 closefrom(_logfd + 1);
517 } else
518 closefrom(0);
520 (void) chdir("/");
522 switch (fork1()) {
523 case (pid_t)-1:
525 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
526 (me, "unable to fork: pid = %d, %s\n",
527 getpid(), strerror(errno));
529 exit(1);
530 break;
531 case 0:
532 /* start the forker nscd if so configured */
533 _nscd_start_forker(saved_execname, saved_argc, saved_argv);
534 break;
535 default:
536 exit(0);
539 (void) setsid();
540 (void) open("/dev/null", O_RDWR, 0);
541 (void) dup(0);
542 if (_logfd != 2)
543 (void) dup(0);
546 * start monitoring the states of the name service clients
548 rc = _nscd_init_smf_monitor();
549 if (rc != NSCD_SUCCESS) {
550 _NSCD_LOG(NSCD_LOG_FRONT_END, NSCD_LOG_LEVEL_ERROR)
551 (me, "unable to start the SMF monitor (rc = %d)\n", rc);
553 exit(-1);