2001-08-17 Ragnar Kjørstad <nfs@ragnark.vestdata.no>
[nfs-utils.git] / utils / statd / statd.c
1 /* 
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.
6  *
7  * NSM for Linux.
8  */
9
10 #include "config.h"
11 #include <limits.h>
12 #include <signal.h>
13 #include <unistd.h>
14 #include <fcntl.h>
15 #include <string.h>
16 #include <getopt.h>
17 #include <rpc/rpc.h>
18 #include <rpc/pmap_clnt.h>
19 #include <rpcmisc.h>
20 #include "statd.h"
21 #include "version.h"
22
23 /* Socket operations */
24 #include <sys/types.h>
25 #include <sys/socket.h>
26
27
28 short int restart = 0;
29 int     run_mode = 0;           /* foreground logging mode */
30
31 /* LH - I had these local to main, but it seemed silly to have 
32  * two copies of each - one in main(), one static in log.c... 
33  * It also eliminates the 256-char static in log.c */
34 char *name_p = NULL;
35 char *version_p = NULL;
36
37 static struct option longopts[] =
38 {
39         { "foreground", 0, 0, 'F' },
40         { "no-syslog", 0, 0, 'd' },
41         { "help", 0, 0, 'h' },
42         { "version", 0, 0, 'v' },
43         { "outgoing-port", 1, 0, 'o' },
44         { "port", 1, 0, 'p' },
45         { "name", 1, 0, 'n' },
46         { NULL, 0, 0, 0 }
47 };
48
49 extern void sm_prog_1 (struct svc_req *, register SVCXPRT *);
50 extern int statd_get_socket(int port);
51
52 #ifdef SIMULATIONS
53 extern void simulator (int, char **);
54 #endif
55
56
57 #ifdef HAVE_TCP_WRAPPER 
58 #include "tcpwrapper.h"
59
60 static void 
61 sm_prog_1_wrapper (struct svc_req *rqstp, register SVCXPRT *transp)
62 {
63         /* remote host authorization check */
64         if (!check_default("statd", svc_getcaller(transp),
65                                  rqstp->rq_proc, SM_PROG)) {
66                 svcerr_auth (transp, AUTH_FAILED);
67                 return;
68         }
69
70         sm_prog_1 (rqstp, transp);
71 }
72
73 #define sm_prog_1 sm_prog_1_wrapper
74 #endif
75
76 /*
77  * Signal handler.
78  */
79 static void 
80 killer (int sig)
81 {
82         log (L_FATAL, "Caught signal %d, un-registering and exiting.", sig);
83         pmap_unset (SM_PROG, SM_VERS);
84         exit (0);
85 }
86
87 /*
88  * Startup information.
89  */
90 static void log_modes(void)
91 {
92         char buf[128];          /* watch stack size... */
93
94         /* No flags = no message */
95         if (!run_mode) return;
96
97         memset(buf,0,128);
98         sprintf(buf,"Flags: ");
99         if (run_mode & MODE_NODAEMON)
100                 strcat(buf,"No-Daemon ");
101         if (run_mode & MODE_LOG_STDERR)
102                 strcat(buf,"Log-STDERR ");
103         /* future: IP aliasing
104         if (run_mode & MODE_NOTIFY_ONLY)
105         {
106                 strcat(buf,"Notify-Only ");
107         } */
108         log(L_WARNING,buf);
109         /* future: IP aliasing
110         if (run_mode & MODE_NOTIFY_ONLY)
111         {
112                 dprintf(L_DEBUG,"Notify IP: %s",svr_addr);
113         } */
114 }
115
116 /*
117  * Since we do more than standard statd stuff, we might need to
118  * help the occasional admin. 
119  */
120 static void 
121 usage()
122 {
123         fprintf(stderr,"usage: %s [options]\n", name_p);
124         fprintf(stderr,"      -h, -?, --help       Print this help screen.\n");
125         fprintf(stderr,"      -F, --foreground     Foreground (no-daemon mode)\n");
126         fprintf(stderr,"      -d, --no-syslog      Verbose logging to stderr.  Foreground mode only.\n");
127         fprintf(stderr,"      -p, --port           Port to listen on\n");
128         fprintf(stderr,"      -o, --outgoing-port  Port for outgoing connections\n");
129         fprintf(stderr,"      -V, -v, --version    Display version information and exit.\n");
130         fprintf(stderr,"      -n, --name           Specify a local hostname.\n");
131 }
132
133 /* 
134  * Entry routine/main loop.
135  */
136 int main (int argc, char **argv)
137 {
138         extern char *optarg;
139         int pid;
140         int arg;
141         int port = 0, out_port = 0;
142
143         /* Default: daemon mode, no other options */
144         run_mode = 0;
145
146         /* Set the basename */
147         if ((name_p = strrchr(argv[0],'/')) != NULL) {
148                 name_p ++;
149         } else {
150                 name_p = argv[0];
151         }
152
153         /* Get the version */
154         if ((version_p = strrchr(VERSION,' ')) != NULL) {
155                 version_p++;
156         } else {
157                 version_p = VERSION;
158         }
159         
160         /* Set hostname */
161         MY_NAME = NULL;
162
163         /* Process command line switches */
164         while ((arg = getopt_long(argc, argv, "h?vVFdn:p:o:", longopts, NULL)) != EOF) {
165                 switch (arg) {
166                 case 'V':       /* Version */
167                 case 'v':
168                         printf("%s version %s\n",name_p,version_p);
169                         exit(0);
170                 case 'F':       /* Foreground/nodaemon mode */
171                         run_mode |= MODE_NODAEMON;
172                         break;
173                 case 'd':       /* No daemon only - log to stderr */
174                         run_mode |= MODE_LOG_STDERR;
175                         break;
176                 case 'o':
177                         out_port = atoi(optarg);
178                         if (out_port < 1 || out_port > 65535) {
179                                 fprintf(stderr, "%s: bad port number: %s\n",
180                                         argv[0], optarg);
181                                 usage();
182                                 exit(1);
183                         }
184                         break;
185                 case 'p':
186                         port = atoi(optarg);
187                         if (port < 1 || port > 65535) {
188                                 fprintf(stderr, "%s: bad port number: %s\n",
189                                         argv[0], optarg);
190                                 usage();
191                                 exit(1);
192                         }
193                         break;
194                 case 'n':       /* Specify local hostname */
195                         MY_NAME = xstrdup(optarg);
196                         break;
197                 case '?':       /* heeeeeelllllllpppp? heh */
198                 case 'h':
199                         usage();
200                         exit (0);
201                 default:        /* oh dear ... heh */
202                         usage();
203                         exit(-1);
204                 }
205         }
206
207         if (port == out_port && port != 0) {
208                 fprintf(stderr, "Listening and outgoing ports cannot be the same!\n");
209                 exit(-1);
210         }
211
212         if (!(run_mode & MODE_NODAEMON)) {
213                 run_mode &= ~MODE_LOG_STDERR;   /* Never log to console in
214                                                    daemon mode. */
215         }
216
217         log_init (name_p,version_p);
218
219         log_modes();
220
221 #ifdef SIMULATIONS
222         if (argc > 1)
223                 /* LH - I _really_ need to update simulator... */
224                 simulator (--argc, ++argv);     /* simulator() does exit() */
225 #endif
226         
227         if (!(run_mode & MODE_NODAEMON)) {
228                 int filedes, fdmax, tempfd;
229
230                 if ((pid = fork ()) < 0) {
231                         perror ("Could not fork");
232                         exit (1);
233                 } else if (pid != 0) {
234                         /* Parent. */
235                         exit (0);
236                 }
237                 /* Child.       */
238                 setsid ();
239                 chdir (DIR_BASE);
240
241                 tempfd = open("/dev/null", O_RDWR);
242                 close(0); dup2(tempfd, 0);
243                 close(1); dup2(tempfd, 1);
244                 close(2); dup2(tempfd, 2);
245                 fdmax = sysconf (_SC_OPEN_MAX);
246                 for (filedes = 3; filedes < fdmax; filedes++) {
247                         close (filedes);
248                 }
249         }
250
251         /* Child. */
252         signal (SIGHUP, killer);
253         signal (SIGINT, killer);
254         signal (SIGTERM, killer);
255         /* WARNING: the following works on Linux and SysV, but not BSD! */
256         signal(SIGCHLD, SIG_IGN);
257
258         /* initialize out_port */
259         statd_get_socket(out_port);
260
261         for (;;) {
262                 pmap_unset (SM_PROG, SM_VERS);
263                 change_state ();
264                 shuffle_dirs ();        /* Move directory names around */
265                 notify_hosts ();        /* Send out notify requests */
266                 ++restart;
267
268                 /* future: IP aliasing 
269                 if (!(run_mode & MODE_NOTIFY_ONLY)) {
270                         rpc_init("statd", SM_PROG, SM_VERS, sm_prog_1, port);
271                 } */
272                 /* this registers both UDP and TCP services */
273                 rpc_init("statd", SM_PROG, SM_VERS, sm_prog_1, port);
274
275                 /*
276                  * Handle incoming requests:  SM_NOTIFY socket requests, as
277                  * well as callbacks from lockd.
278                  */
279                 my_svc_run();   /* I rolled my own, Olaf made it better... */
280         }
281         return 0;
282 }