nfsd.c revision 1.3 1 /*
2 * Copyright (c) 1989 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #ifndef lint
38 char copyright[] =
39 "@(#) Copyright (c) 1989 Regents of the University of California.\n\
40 All rights reserved.\n";
41 #endif not lint
42
43 #ifndef lint
44 static char sccsid[] = "@(#)nfsd.c 5.10 (Berkeley) 4/24/91";
45 static char rcsid[] = "$Header: /tank/opengrok/rsync2/NetBSD/src/usr.sbin/nfsd/nfsd.c,v 1.3 1993/03/23 00:29:32 cgd Exp $";
46 #endif not lint
47
48 #include <sys/types.h>
49 #include <sys/signal.h>
50 #include <sys/ioctl.h>
51 #include <sys/stat.h>
52 #include <sys/wait.h>
53 #include <sys/mount.h>
54 #include <sys/socket.h>
55 #include <sys/socketvar.h>
56 #include <stdio.h>
57 #include <syslog.h>
58 #include <fcntl.h>
59 #include <string.h>
60 #include <netdb.h>
61 #include <rpc/rpc.h>
62 #include <rpc/pmap_clnt.h>
63 #include <rpc/pmap_prot.h>
64 #include <nfs/rpcv2.h>
65 #include <nfs/nfsv2.h>
66
67 /* Global defs */
68 #ifdef DEBUG
69 #define syslog(e, s) fprintf(stderr,(s))
70 int debug = 1;
71 #else
72 int debug = 0;
73 #endif
74 struct hadr {
75 u_long ha_sad;
76 struct hadr *ha_next;
77 };
78 struct hadr hphead;
79 char **Argv = NULL; /* pointer to argument vector */
80 char *LastArg = NULL; /* end of argv */
81 void reapchild();
82
83 /*
84 * Nfs server daemon mostly just a user context for nfssvc()
85 * 1 - do file descriptor and signal cleanup
86 * 2 - create server socket
87 * 3 - register socket with portmap
88 * For SOCK_DGRAM, just fork children and send them into the kernel
89 * by calling nfssvc()
90 * For connection based sockets, loop doing accepts. When you get a new socket
91 * from accept, fork a child that drops into the kernel via. nfssvc.
92 * This child will return from nfssvc when the connection is closed, so
93 * just shutdown() and exit().
94 * The arguments are:
95 * -t - support tcp nfs clients
96 * -u - support udp nfs clients
97 */
98 main(argc, argv, envp)
99 int argc;
100 char *argv[], *envp[];
101 {
102 register int i;
103 register char *cp, *cp2;
104 register struct hadr *hp;
105 int udpcnt, sock, msgsock, tcpflag = 0, udpflag = 0, ret, len;
106 int reregister = 0;
107 char opt;
108 extern int optind;
109 extern char *optarg;
110 struct sockaddr_in saddr, msk, mtch, peername;
111
112
113 /*
114 * Save start and extent of argv for setproctitle.
115 */
116
117 Argv = argv;
118 if (envp == 0 || *envp == 0)
119 envp = argv;
120 while (*envp)
121 envp++;
122 LastArg = envp[-1] + strlen(envp[-1]);
123 while ((opt = getopt(argc, argv, "rt:u:")) != EOF)
124 switch (opt) {
125 case 'r':
126 reregister++;
127 break;
128 case 't':
129 tcpflag++;
130 if (cp = index(optarg, ',')) {
131 *cp++ = '\0';
132 msk.sin_addr.s_addr = inet_addr(optarg);
133 if (msk.sin_addr.s_addr == -1)
134 usage();
135 if (cp2 = index(cp, ','))
136 *cp2++ = '\0';
137 mtch.sin_addr.s_addr = inet_addr(cp);
138 if (mtch.sin_addr.s_addr == -1)
139 usage();
140 cp = cp2;
141 hphead.ha_next = (struct hadr *)0;
142 while (cp) {
143 if (cp2 = index(cp, ','))
144 *cp2++ = '\0';
145 hp = (struct hadr *)
146 malloc(sizeof (struct hadr));
147 hp->ha_sad = inet_addr(cp);
148 if (hp->ha_sad == -1)
149 usage();
150 hp->ha_next = hphead.ha_next;
151 hphead.ha_next = hp;
152 cp = cp2;
153 }
154 } else
155 usage();
156 break;
157 case 'u':
158 udpflag++;
159 if (cp = index(optarg, ',')) {
160 *cp++ = '\0';
161 msk.sin_addr.s_addr = inet_addr(optarg);
162 if (msk.sin_addr.s_addr == -1)
163 usage();
164 if (cp2 = index(cp, ','))
165 *cp2++ = '\0';
166 mtch.sin_addr.s_addr = inet_addr(cp);
167 if (mtch.sin_addr.s_addr == -1)
168 usage();
169 if (cp2)
170 udpcnt = atoi(cp2);
171 if (udpcnt < 1 || udpcnt > 20)
172 udpcnt = 1;
173 } else
174 usage();
175 break;
176 default:
177 case '?':
178 usage();
179 }
180
181 /*
182 * Default, if neither UDP nor TCP is specified,
183 * is to support UDP only; a numeric argument indicates
184 * the number of server daemons to run.
185 */
186 if (udpflag == 0 && tcpflag == 0) {
187 if (argc > 1)
188 udpcnt = atoi(*++argv);
189 if (udpcnt < 1 || udpcnt > 20)
190 udpcnt = 1;
191 msk.sin_addr.s_addr = mtch.sin_addr.s_addr = 0;
192 udpflag++;
193 }
194
195 if (debug == 0) {
196 daemon(0, 0);
197 signal(SIGINT, SIG_IGN);
198 signal(SIGQUIT, SIG_IGN);
199 signal(SIGTERM, SIG_IGN);
200 signal(SIGHUP, SIG_IGN);
201 }
202 signal(SIGCHLD, reapchild);
203
204 if (reregister) {
205 if (udpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP,
206 NFS_PORT)) {
207 fprintf(stderr,
208 "Can't register with portmap for UDP\n");
209 exit(1);
210 }
211 if (tcpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP,
212 NFS_PORT)) {
213 fprintf(stderr,
214 "Can't register with portmap for TCP\n");
215 exit(1);
216 }
217 exit(0);
218 }
219 openlog("nfsd:", LOG_PID, LOG_DAEMON);
220 #ifdef notdef
221 /* why? unregisters both protocols even if we restart only one */
222 pmap_unset(RPCPROG_NFS, NFS_VER2);
223 #endif
224 if (udpflag) {
225 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
226 syslog(LOG_ERR, "Can't create socket");
227 exit(1);
228 }
229 saddr.sin_family = AF_INET;
230 saddr.sin_addr.s_addr = INADDR_ANY;
231 saddr.sin_port = htons(NFS_PORT);
232 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
233 syslog(LOG_ERR, "Can't bind addr");
234 exit(1);
235 }
236 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
237 syslog(LOG_ERR, "Can't register with portmap");
238 exit(1);
239 }
240
241 /*
242 * Send the nfs datagram servers
243 * right down into the kernel
244 */
245 for (i = 0; i < udpcnt; i++)
246 if (fork() == 0) {
247 setproctitle("nfsd-udp",
248 (struct sockaddr_in *)NULL);
249 ret = nfssvc(sock, &msk, sizeof(msk),
250 &mtch, sizeof(mtch));
251 if (ret < 0)
252 syslog(LOG_ERR, "nfssvc() failed %m");
253 exit(1);
254 }
255 close(sock);
256 }
257
258 /*
259 * Now set up the master STREAM server waiting for tcp connections.
260 */
261 if (tcpflag) {
262 int on = 1;
263
264 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
265 syslog(LOG_ERR, "Can't create socket");
266 exit(1);
267 }
268 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
269 (char *) &on, sizeof(on)) < 0)
270 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
271 saddr.sin_family = AF_INET;
272 saddr.sin_addr.s_addr = INADDR_ANY;
273 saddr.sin_port = htons(NFS_PORT);
274 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
275 syslog(LOG_ERR, "Can't bind addr");
276 exit(1);
277 }
278 if (listen(sock, 5) < 0) {
279 syslog(LOG_ERR, "Listen failed");
280 exit(1);
281 }
282 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
283 syslog(LOG_ERR, "Can't register with portmap");
284 exit(1);
285 }
286 setproctitle("nfsd-listen", (struct sockaddr_in *)NULL);
287 /*
288 * Loop forever accepting connections and sending the children
289 * into the kernel to service the mounts.
290 */
291 for (;;) {
292 len = sizeof(peername);
293 if ((msgsock = accept(sock,
294 (struct sockaddr *)&peername, &len)) < 0) {
295 syslog(LOG_ERR, "Accept failed: %m");
296 exit(1);
297 }
298 if ((peername.sin_addr.s_addr & msk.sin_addr.s_addr) !=
299 mtch.sin_addr.s_addr) {
300 hp = hphead.ha_next;
301 while (hp) {
302 if (peername.sin_addr.s_addr ==
303 hp->ha_sad)
304 break;
305 hp = hp->ha_next;
306 }
307 if (hp == NULL) {
308 shutdown(msgsock, 2);
309 close(msgsock);
310 continue;
311 }
312 }
313 if (fork() == 0) {
314 close(sock);
315 setproctitle("nfsd-tcp", &peername);
316 if (setsockopt(msgsock, SOL_SOCKET,
317 SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0)
318 syslog(LOG_ERR,
319 "setsockopt SO_KEEPALIVE: %m");
320 ret = nfssvc(msgsock, &msk, sizeof(msk),
321 &mtch, sizeof(mtch));
322 shutdown(msgsock, 2);
323 if (ret < 0)
324 syslog(LOG_NOTICE,
325 "Nfssvc STREAM Failed");
326 exit(1);
327 }
328 close(msgsock);
329 }
330 }
331 }
332
333 usage()
334 {
335 fprintf(stderr, "nfsd [-t msk,mtch[,addrs]] [-u msk,mtch,numprocs]\n");
336 exit(1);
337 }
338
339 void
340 reapchild()
341 {
342
343 while (wait3((int *) NULL, WNOHANG, (struct rusage *) NULL))
344 ;
345 }
346
347 setproctitle(a, sin)
348 char *a;
349 struct sockaddr_in *sin;
350 {
351 register char *cp;
352 char buf[80];
353
354 cp = Argv[0];
355 if (sin)
356 (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin->sin_addr));
357 else
358 (void) sprintf(buf, "%s", a);
359 (void) strncpy(cp, buf, LastArg - cp);
360 cp += strlen(cp);
361 while (cp < LastArg)
362 *cp++ = ' ';
363 }
364