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.
19 #include <rpc/pmap_clnt.h>
21 #include <sys/resource.h>
26 /* Socket operations */
27 #include <sys/types.h>
28 #include <sys/socket.h>
30 /* Added to enable specification of state directory path at run-time
31 * j_carlos_gomez@yahoo.com
34 char * DIR_BASE = DEFAULT_DIR_BASE;
36 char * SM_DIR = DEFAULT_SM_DIR;
37 char * SM_BAK_DIR = DEFAULT_SM_BAK_DIR;
38 char * SM_STAT_PATH = DEFAULT_SM_STAT_PATH;
40 /* ----- end of state directory path stuff ------- */
42 short int restart = 0;
43 int run_mode = 0; /* foreground logging mode */
45 /* LH - I had these local to main, but it seemed silly to have
46 * two copies of each - one in main(), one static in log.c...
47 * It also eliminates the 256-char static in log.c */
49 char *version_p = NULL;
51 static struct option longopts[] =
53 { "foreground", 0, 0, 'F' },
54 { "no-syslog", 0, 0, 'd' },
55 { "help", 0, 0, 'h' },
56 { "version", 0, 0, 'v' },
57 { "outgoing-port", 1, 0, 'o' },
58 { "port", 1, 0, 'p' },
59 { "name", 1, 0, 'n' },
60 { "state-directory-path", 1, 0, 'P' },
61 { "notify-mode", 0, 0, 'N' },
65 extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
66 extern int statd_get_socket(int port);
69 extern void simulator (int, char **);
73 #ifdef HAVE_TCP_WRAPPER
74 #include "tcpwrapper.h"
77 sm_prog_1_wrapper (struct svc_req *rqstp, register SVCXPRT *transp)
79 /* remote host authorization check */
80 if (!check_default("statd", svc_getcaller(transp),
81 rqstp->rq_proc, SM_PROG)) {
82 svcerr_auth (transp, AUTH_FAILED);
86 sm_prog_1 (rqstp, transp);
89 #define sm_prog_1 sm_prog_1_wrapper
98 note (N_FATAL, "Caught signal %d, un-registering and exiting.", sig);
99 if (!(run_mode & MODE_NOTIFY_ONLY))
100 pmap_unset (SM_PROG, SM_VERS);
106 * Startup information.
108 static void log_modes(void)
110 char buf[128]; /* watch stack size... */
112 /* No flags = no message */
113 if (!run_mode) return;
116 sprintf(buf,"Flags: ");
117 if (run_mode & MODE_NODAEMON)
118 strcat(buf,"No-Daemon ");
119 if (run_mode & MODE_LOG_STDERR)
120 strcat(buf,"Log-STDERR ");
122 if (run_mode & MODE_NOTIFY_ONLY)
124 strcat(buf,"Notify-Only ");
127 /* future: IP aliasing
128 if (run_mode & MODE_NOTIFY_ONLY)
130 dprintf(N_DEBUG,"Notify IP: %s",svr_addr);
135 * Since we do more than standard statd stuff, we might need to
136 * help the occasional admin.
141 fprintf(stderr,"usage: %s [options]\n", name_p);
142 fprintf(stderr," -h, -?, --help Print this help screen.\n");
143 fprintf(stderr," -F, --foreground Foreground (no-daemon mode)\n");
144 fprintf(stderr," -d, --no-syslog Verbose logging to stderr. Foreground mode only.\n");
145 fprintf(stderr," -p, --port Port to listen on\n");
146 fprintf(stderr," -o, --outgoing-port Port for outgoing connections\n");
147 fprintf(stderr," -V, -v, --version Display version information and exit.\n");
148 fprintf(stderr," -n, --name Specify a local hostname.\n");
149 fprintf(stderr," -P State directory path.\n");
150 fprintf(stderr," -N Run in notify only mode.\n");
153 static const char *pidfile = "/var/run/rpc.statd.pid";
156 static void create_pidfile(void)
161 fp = fopen(pidfile, "w");
163 die("Opening %s failed: %s\n",
164 pidfile, strerror(errno));
165 fprintf(fp, "%d\n", getpid());
166 pidfd = dup(fileno(fp));
168 note(N_WARNING, "Flushing pid file failed.\n");
171 static void truncate_pidfile(void)
177 static void drop_privs(void)
181 if (stat(SM_DIR, &st) == -1 &&
182 stat(DIR_BASE, &st) == -1)
185 if (st.st_uid == 0) {
186 note(N_WARNING, "statd running as root. chown %s to choose different user\n",
190 /* better chown the pid file before dropping, as if it
191 * if over nfs we might loose access
194 fchown(pidfd, st.st_uid, st.st_gid);
197 if (setgid(st.st_gid) == -1
198 || setuid(st.st_uid) == -1) {
199 note(N_ERROR, "Fail to drop privileges");
205 * Entry routine/main loop.
207 int main (int argc, char **argv)
212 int port = 0, out_port = 0;
215 int pipefds[2] = { -1, -1};
218 /* Default: daemon mode, no other options */
221 /* Set the basename */
222 if ((name_p = strrchr(argv[0],'/')) != NULL) {
228 /* Get the version */
229 if ((version_p = strrchr(VERSION,' ')) != NULL) {
238 /* Process command line switches */
239 while ((arg = getopt_long(argc, argv, "h?vVFNdn:p:o:P:", longopts, NULL)) != EOF) {
241 case 'V': /* Version */
243 printf("%s version %s\n",name_p,version_p);
245 case 'F': /* Foreground/nodaemon mode */
246 run_mode |= MODE_NODAEMON;
249 run_mode |= MODE_NOTIFY_ONLY;
251 case 'd': /* No daemon only - log to stderr */
252 run_mode |= MODE_LOG_STDERR;
255 out_port = atoi(optarg);
256 if (out_port < 1 || out_port > 65535) {
257 fprintf(stderr, "%s: bad port number: %s\n",
265 if (port < 1 || port > 65535) {
266 fprintf(stderr, "%s: bad port number: %s\n",
272 case 'n': /* Specify local hostname */
273 MY_NAME = xstrdup(optarg);
277 if ((DIR_BASE = xstrdup(optarg)) == NULL) {
278 fprintf(stderr, "%s: xstrdup(%s) failed!\n",
283 SM_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm"));
284 SM_BAK_DIR = xmalloc(strlen(DIR_BASE) + 1 + sizeof("sm.bak"));
285 SM_STAT_PATH = xmalloc(strlen(DIR_BASE) + 1 + sizeof("state"));
288 || (SM_BAK_DIR == NULL)
289 || (SM_STAT_PATH == NULL)) {
291 fprintf(stderr, "%s: xmalloc() failed!\n",
295 if (DIR_BASE[strlen(DIR_BASE)-1] == '/') {
296 sprintf(SM_DIR, "%ssm", DIR_BASE );
297 sprintf(SM_BAK_DIR, "%ssm.bak", DIR_BASE );
298 sprintf(SM_STAT_PATH, "%sstate", DIR_BASE );
300 sprintf(SM_DIR, "%s/sm", DIR_BASE );
301 sprintf(SM_BAK_DIR, "%s/sm.bak", DIR_BASE );
302 sprintf(SM_STAT_PATH, "%s/state", DIR_BASE );
305 case '?': /* heeeeeelllllllpppp? heh */
309 default: /* oh dear ... heh */
315 if (port == out_port && port != 0) {
316 fprintf(stderr, "Listening and outgoing ports cannot be the same!\n");
320 if (!(run_mode & MODE_NODAEMON)) {
321 run_mode &= ~MODE_LOG_STDERR; /* Never log to console in
325 if (getrlimit (RLIMIT_NOFILE, &rlim) != 0)
326 fprintf(stderr, "%s: getrlimit (RLIMIT_NOFILE) failed: %s\n",
327 argv [0], strerror(errno));
329 /* glibc sunrpc code dies if getdtablesize > FD_SETSIZE */
330 if (rlim.rlim_cur > FD_SETSIZE) {
331 rlim.rlim_cur = FD_SETSIZE;
333 if (setrlimit (RLIMIT_NOFILE, &rlim) != 0) {
334 fprintf(stderr, "%s: setrlimit (RLIMIT_NOFILE) failed: %s\n",
335 argv [0], strerror(errno));
342 /* LH - I _really_ need to update simulator... */
343 simulator (--argc, ++argv); /* simulator() does exit() */
346 if (!(run_mode & MODE_NODAEMON)) {
347 int filedes, fdmax, tempfd;
349 if (pipe(pipefds)<0) {
350 perror("statd: unable to create pipe");
353 if ((pid = fork ()) < 0) {
354 perror ("statd: Could not fork");
356 } else if (pid != 0) {
358 * Wait for status from child.
361 if (read(pipefds[0], &status, 1) != 1)
368 if (chdir (DIR_BASE) == -1) {
369 perror("statd: Could not chdir");
373 while (pipefds[1] <= 2) {
374 pipefds[1] = dup(pipefds[1]);
376 perror("statd: dup");
380 tempfd = open("/dev/null", O_RDWR);
381 close(0); dup2(tempfd, 0);
382 close(1); dup2(tempfd, 1);
383 close(2); dup2(tempfd, 2);
384 fdmax = sysconf (_SC_OPEN_MAX);
385 for (filedes = 3; filedes < fdmax; filedes++)
386 if (filedes != pipefds[1])
393 log_init (name_p,version_p);
397 signal (SIGHUP, killer);
398 signal (SIGINT, killer);
399 signal (SIGTERM, killer);
400 /* WARNING: the following works on Linux and SysV, but not BSD! */
401 signal(SIGCHLD, SIG_IGN);
403 /* initialize out_port */
404 statd_get_socket(out_port);
407 atexit(truncate_pidfile);
411 if (!(run_mode & MODE_NOTIFY_ONLY)) {
412 /* Do not do pmap_unset() when running in notify mode.
413 * We may clear the portmapper record for a statd not
414 * running in notify mode disabling it.
415 * Juan C. Gomez j_carlos_gomez@yahoo.com
417 pmap_unset (SM_PROG, SM_VERS);
420 shuffle_dirs (); /* Move directory names around */
422 /* If we got this far, we have successfully started, so notify parent */
423 if (pipefds[1] > 0) {
425 write(pipefds[1], &status, 1);
430 notify_hosts (); /* Send out notify requests */
433 /* this registers both UDP and TCP services */
434 if (!(run_mode & MODE_NOTIFY_ONLY)) {
435 rpc_init("statd", SM_PROG, SM_VERS, sm_prog_1, port);
439 * Handle incoming requests: SM_NOTIFY socket requests, as
440 * well as callbacks from lockd.
442 my_svc_run(); /* I rolled my own, Olaf made it better... */
444 if ((run_mode & MODE_NOTIFY_ONLY))