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