2 * Copyright (C) 1995, 1997-1999 Jeffrey A. Uphoff
3 * Modified by Olaf Kirch, Oct. 1996.
4 * Modified by H.J. Lu, 1998.
5 * Modified by L. Hohberger of Mission Critical Linux, 2000.
23 #include <rpc/pmap_clnt.h>
25 #include <sys/resource.h>
33 /* Socket operations */
34 #include <sys/types.h>
35 #include <sys/socket.h>
37 int run_mode = 0; /* foreground logging mode */
39 /* LH - I had these local to main, but it seemed silly to have
40 * two copies of each - one in main(), one static in log.c...
41 * It also eliminates the 256-char static in log.c */
42 static char *name_p = NULL;
44 /* PRC: a high-availability callout program can be specified with -H
45 * When this is done, the program will receive callouts whenever clients
46 * are added or deleted to the notify list */
47 char *ha_callout_prog = NULL;
49 static struct option longopts[] =
51 { "foreground", 0, 0, 'F' },
52 { "no-syslog", 0, 0, 'd' },
53 { "help", 0, 0, 'h' },
54 { "version", 0, 0, 'v' },
55 { "outgoing-port", 1, 0, 'o' },
56 { "port", 1, 0, 'p' },
57 { "name", 1, 0, 'n' },
58 { "state-directory-path", 1, 0, 'P' },
59 { "notify-mode", 0, 0, 'N' },
60 { "ha-callout", 1, 0, 'H' },
61 { "no-notify", 0, 0, 'L' },
65 extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
68 extern void simulator (int, char **);
72 #ifdef HAVE_TCP_WRAPPER
73 #include "tcpwrapper.h"
76 sm_prog_1_wrapper (struct svc_req *rqstp, register SVCXPRT *transp)
78 struct sockaddr_in *sin = nfs_getrpccaller_in(transp);
80 /* remote host authorization check */
81 if (sin->sin_family == AF_INET &&
82 !check_default("statd", sin, rqstp->rq_proc, SM_PROG)) {
83 svcerr_auth (transp, AUTH_FAILED);
87 sm_prog_1 (rqstp, transp);
90 #define sm_prog_1 sm_prog_1_wrapper
94 statd_unregister(void) {
95 nfs_svc_unregister(SM_PROG, SM_VERS);
105 xlog_err ("Caught signal %d, un-registering and exiting", sig);
111 extern void my_svc_exit (void);
112 xlog(D_GENERAL, "Caught signal %d, re-notifying (state %d)", sig,
118 * Startup information.
120 static void log_modes(void)
122 char buf[128]; /* watch stack size... */
124 /* No flags = no message */
125 if (!run_mode) return;
128 sprintf(buf,"Flags: ");
129 if (run_mode & MODE_NODAEMON)
130 strcat(buf,"No-Daemon ");
131 if (run_mode & MODE_LOG_STDERR)
132 strcat(buf,"Log-STDERR ");
134 strcat(buf, "TI-RPC ");
141 * Since we do more than standard statd stuff, we might need to
142 * help the occasional admin.
147 fprintf(stderr,"usage: %s [options]\n", name_p);
148 fprintf(stderr," -h, -?, --help Print this help screen.\n");
149 fprintf(stderr," -F, --foreground Foreground (no-daemon mode)\n");
150 fprintf(stderr," -d, --no-syslog Verbose logging to stderr. Foreground mode only.\n");
151 fprintf(stderr," -p, --port Port to listen on\n");
152 fprintf(stderr," -o, --outgoing-port Port for outgoing connections\n");
153 fprintf(stderr," -V, -v, --version Display version information and exit.\n");
154 fprintf(stderr," -n, --name Specify a local hostname.\n");
155 fprintf(stderr," -P State directory path.\n");
156 fprintf(stderr," -N Run in notify only mode.\n");
157 fprintf(stderr," -L, --no-notify Do not perform any notification.\n");
158 fprintf(stderr," -H Specify a high-availability callout program.\n");
161 static const char *pidfile = "/var/run/rpc.statd.pid";
164 static void create_pidfile(void)
169 fp = fopen(pidfile, "w");
171 xlog_err("Opening %s failed: %m\n", pidfile);
172 fprintf(fp, "%d\n", getpid());
173 pidfd = dup(fileno(fp));
174 if (fclose(fp) < 0) {
175 xlog_warn("Flushing pid file failed: errno %d (%m)\n",
180 static void truncate_pidfile(void)
183 if (ftruncate(pidfd, 0) < 0) {
184 xlog_warn("truncating pid file failed: errno %d (%m)\n",
190 static void run_sm_notify(int outport)
196 av[ac++] = "/usr/sbin/sm-notify";
197 if (run_mode & MODE_NODAEMON)
200 sprintf(op, "-p%d", outport);
203 if (run_mode & STATIC_HOSTNAME) {
209 fprintf(stderr, "%s: failed to run %s\n", name_p, av[0]);
214 * Entry routine/main loop.
216 int main (int argc, char **argv)
221 int port = 0, out_port = 0;
224 int pipefds[2] = { -1, -1};
227 /* Default: daemon mode, no other options */
232 /* Set the basename */
233 if ((name_p = strrchr(argv[0],'/')) != NULL) {
242 /* Process command line switches */
243 while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:L", longopts, NULL)) != EOF) {
245 case 'V': /* Version */
247 printf("%s version " VERSION "\n",name_p);
249 case 'F': /* Foreground/nodaemon mode */
250 run_mode |= MODE_NODAEMON;
253 run_mode |= MODE_NOTIFY_ONLY;
255 case 'L': /* Listen only */
256 run_mode |= MODE_NO_NOTIFY;
258 case 'd': /* No daemon only - log to stderr */
259 run_mode |= MODE_LOG_STDERR;
262 out_port = atoi(optarg);
263 if (out_port < 1 || out_port > 65535) {
264 fprintf(stderr, "%s: bad port number: %s\n",
272 if (port < 1 || port > 65535) {
273 fprintf(stderr, "%s: bad port number: %s\n",
279 case 'n': /* Specify local hostname */
280 run_mode |= STATIC_HOSTNAME;
281 MY_NAME = xstrdup(optarg);
284 if (!nsm_setup_pathnames(argv[0], optarg))
287 case 'H': /* PRC: specify the ha-callout program */
288 if ((ha_callout_prog = xstrdup(optarg)) == NULL) {
289 fprintf(stderr, "%s: xstrdup(%s) failed!\n",
294 case '?': /* heeeeeelllllllpppp? heh */
298 default: /* oh dear ... heh */
304 if (port == out_port && port != 0) {
305 fprintf(stderr, "Listening and outgoing ports cannot be the same!\n");
309 if (run_mode & MODE_NOTIFY_ONLY) {
310 fprintf(stderr, "%s: -N deprecated, consider using /usr/sbin/sm-notify directly\n",
312 run_sm_notify(out_port);
315 if (!(run_mode & MODE_NODAEMON)) {
316 run_mode &= ~MODE_LOG_STDERR; /* Never log to console in
320 if (getrlimit (RLIMIT_NOFILE, &rlim) != 0)
321 fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n",
322 argv [0], strerror(errno));
324 /* glibc sunrpc code dies if getdtablesize > FD_SETSIZE */
325 if (rlim.rlim_cur > FD_SETSIZE) {
326 rlim.rlim_cur = FD_SETSIZE;
328 if (setrlimit (RLIMIT_NOFILE, &rlim) != 0) {
329 fprintf(stderr, "%s: setrlimit (RLIMIT_NOFILE) failed: %s\n",
330 argv [0], strerror(errno));
337 /* LH - I _really_ need to update simulator... */
338 simulator (--argc, ++argv); /* simulator() does exit() */
341 if (!(run_mode & MODE_NODAEMON)) {
344 if (pipe(pipefds)<0) {
345 perror("statd: unable to create pipe");
348 if ((pid = fork ()) < 0) {
349 perror ("statd: Could not fork");
351 } else if (pid != 0) {
353 * Wait for status from child.
356 if (read(pipefds[0], &status, 1) != 1)
364 while (pipefds[1] <= 2) {
365 pipefds[1] = dup(pipefds[1]);
367 perror("statd: dup");
371 tempfd = open("/dev/null", O_RDWR);
382 if (run_mode & MODE_LOG_STDERR) {
385 xlog_config(D_ALL, 1);
388 xlog(L_NOTICE, "Version " VERSION " starting");
392 signal (SIGHUP, killer);
393 signal (SIGINT, killer);
394 signal (SIGTERM, killer);
395 /* PRC: trap SIGUSR1 to re-read notify list from disk */
396 signal(SIGUSR1, sigusr);
397 /* WARNING: the following works on Linux and SysV, but not BSD! */
398 signal(SIGCHLD, SIG_IGN);
400 * Ignore SIGPIPE to avoid statd dying when peers close their
401 * TCP connection while we're trying to reply to them.
403 signal(SIGPIPE, SIG_IGN);
406 atexit(truncate_pidfile);
408 if (! (run_mode & MODE_NO_NOTIFY))
409 switch (pid = fork()) {
411 run_sm_notify(out_port);
416 waitpid(pid, NULL, 0);
419 /* Make sure we have a privilege port for calling into the kernel */
420 if (statd_get_socket() < 0)
423 /* If sm-notify didn't take all the state files, load
424 * state information into our notify-list so we can
425 * pass on any SM_NOTIFY that arrives
429 MY_STATE = nsm_get_state(0);
432 xlog(D_GENERAL, "Local NSM state number: %d", MY_STATE);
433 nsm_update_kernel_state(MY_STATE);
437 * Clear old listeners while still root, to override any
438 * permission checking done by rpcbind.
445 if (!nsm_drop_privileges(pidfd))
450 * Create RPC listeners after dropping privileges. This permits
451 * statd to unregister its own listeners when it exits.
453 if (nfs_svc_create("statd", SM_PROG, SM_VERS, sm_prog_1, port) == 0) {
454 xlog(L_ERROR, "failed to create RPC listeners, exiting");
457 atexit(statd_unregister);
459 /* If we got this far, we have successfully started, so notify parent */
460 if (pipefds[1] > 0) {
462 if (write(pipefds[1], &status, 1) != 1) {
463 xlog_warn("writing to parent pipe failed: errno %d (%s)\n",
464 errno, strerror(errno));
472 * Handle incoming requests: SM_NOTIFY socket requests, as
473 * well as callbacks from lockd.
475 my_svc_run(); /* I rolled my own, Olaf made it better... */
477 /* Only get here when simulating a crash so we should probably
478 * start sm-notify running again. As we have already dropped
479 * privileges, this might not work, but I don't think
480 * responding to SM_SIMU_CRASH is an important use cases to
483 if (! (run_mode & MODE_NO_NOTIFY))
484 switch (pid = fork()) {
486 run_sm_notify(out_port);
491 waitpid(pid, NULL, 0);