386BSD 0.1 development
[unix-history] / usr / src / sbin / nfsd / nfsd.c
CommitLineData
0acaa060
WJ
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
38char 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
44static char sccsid[] = "@(#)nfsd.c 5.10 (Berkeley) 4/24/91";
45#endif not lint
46
47#include <sys/types.h>
48#include <sys/signal.h>
49#include <sys/ioctl.h>
50#include <sys/stat.h>
51#include <sys/wait.h>
52#include <sys/mount.h>
53#include <sys/socket.h>
54#include <sys/socketvar.h>
55#include <stdio.h>
56#include <syslog.h>
57#include <fcntl.h>
58#include <string.h>
59#include <netdb.h>
60#include <rpc/rpc.h>
61#include <rpc/pmap_clnt.h>
62#include <rpc/pmap_prot.h>
63#include <nfs/rpcv2.h>
64#include <nfs/nfsv2.h>
65
66/* Global defs */
67#ifdef DEBUG
68#define syslog(e, s) fprintf(stderr,(s))
69int debug = 1;
70#else
71int debug = 0;
72#endif
73struct hadr {
74 u_long ha_sad;
75 struct hadr *ha_next;
76};
77struct hadr hphead;
78char **Argv = NULL; /* pointer to argument vector */
79char *LastArg = NULL; /* end of argv */
80void reapchild();
81
82/*
83 * Nfs server daemon mostly just a user context for nfssvc()
84 * 1 - do file descriptor and signal cleanup
85 * 2 - create server socket
86 * 3 - register socket with portmap
87 * For SOCK_DGRAM, just fork children and send them into the kernel
88 * by calling nfssvc()
89 * For connection based sockets, loop doing accepts. When you get a new socket
90 * from accept, fork a child that drops into the kernel via. nfssvc.
91 * This child will return from nfssvc when the connection is closed, so
92 * just shutdown() and exit().
93 * The arguments are:
94 * -t - support tcp nfs clients
95 * -u - support udp nfs clients
96 */
97main(argc, argv, envp)
98 int argc;
99 char *argv[], *envp[];
100{
101 register int i;
102 register char *cp, *cp2;
103 register struct hadr *hp;
104 int udpcnt, sock, msgsock, tcpflag = 0, udpflag = 0, ret, len;
105 int reregister = 0;
106 char opt;
107 extern int optind;
108 extern char *optarg;
109 struct sockaddr_in saddr, msk, mtch, peername;
110
111
112 /*
113 * Save start and extent of argv for setproctitle.
114 */
115
116 Argv = argv;
117 if (envp == 0 || *envp == 0)
118 envp = argv;
119 while (*envp)
120 envp++;
121 LastArg = envp[-1] + strlen(envp[-1]);
122 while ((opt = getopt(argc, argv, "rt:u:")) != EOF)
123 switch (opt) {
124 case 'r':
125 reregister++;
126 break;
127 case 't':
128 tcpflag++;
129 if (cp = index(optarg, ',')) {
130 *cp++ = '\0';
131 msk.sin_addr.s_addr = inet_addr(optarg);
132 if (msk.sin_addr.s_addr == -1)
133 usage();
134 if (cp2 = index(cp, ','))
135 *cp2++ = '\0';
136 mtch.sin_addr.s_addr = inet_addr(cp);
137 if (mtch.sin_addr.s_addr == -1)
138 usage();
139 cp = cp2;
140 hphead.ha_next = (struct hadr *)0;
141 while (cp) {
142 if (cp2 = index(cp, ','))
143 *cp2++ = '\0';
144 hp = (struct hadr *)
145 malloc(sizeof (struct hadr));
146 hp->ha_sad = inet_addr(cp);
147 if (hp->ha_sad == -1)
148 usage();
149 hp->ha_next = hphead.ha_next;
150 hphead.ha_next = hp;
151 cp = cp2;
152 }
153 } else
154 usage();
155 break;
156 case 'u':
157 udpflag++;
158 if (cp = index(optarg, ',')) {
159 *cp++ = '\0';
160 msk.sin_addr.s_addr = inet_addr(optarg);
161 if (msk.sin_addr.s_addr == -1)
162 usage();
163 if (cp2 = index(cp, ','))
164 *cp2++ = '\0';
165 mtch.sin_addr.s_addr = inet_addr(cp);
166 if (mtch.sin_addr.s_addr == -1)
167 usage();
168 if (cp2)
169 udpcnt = atoi(cp2);
170 if (udpcnt < 1 || udpcnt > 20)
171 udpcnt = 1;
172 } else
173 usage();
174 break;
175 default:
176 case '?':
177 usage();
178 }
179
180 /*
181 * Default, if neither UDP nor TCP is specified,
182 * is to support UDP only; a numeric argument indicates
183 * the number of server daemons to run.
184 */
185 if (udpflag == 0 && tcpflag == 0) {
186 if (argc > 1)
187 udpcnt = atoi(*++argv);
188 if (udpcnt < 1 || udpcnt > 20)
189 udpcnt = 1;
190 msk.sin_addr.s_addr = mtch.sin_addr.s_addr = 0;
191 udpflag++;
192 }
193
194 if (debug == 0) {
195 daemon(0, 0);
196 signal(SIGINT, SIG_IGN);
197 signal(SIGQUIT, SIG_IGN);
198 signal(SIGTERM, SIG_IGN);
199 signal(SIGHUP, SIG_IGN);
200 }
201 signal(SIGCHLD, reapchild);
202
203 if (reregister) {
204 if (udpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP,
205 NFS_PORT)) {
206 fprintf(stderr,
207 "Can't register with portmap for UDP\n");
208 exit(1);
209 }
210 if (tcpflag && !pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP,
211 NFS_PORT)) {
212 fprintf(stderr,
213 "Can't register with portmap for TCP\n");
214 exit(1);
215 }
216 exit(0);
217 }
218 openlog("nfsd:", LOG_PID, LOG_DAEMON);
219#ifdef notdef
220 /* why? unregisters both protocols even if we restart only one */
221 pmap_unset(RPCPROG_NFS, NFS_VER2);
222#endif
223 if (udpflag) {
224 if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
225 syslog(LOG_ERR, "Can't create socket");
226 exit(1);
227 }
228 saddr.sin_family = AF_INET;
229 saddr.sin_addr.s_addr = INADDR_ANY;
230 saddr.sin_port = htons(NFS_PORT);
231 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
232 syslog(LOG_ERR, "Can't bind addr");
233 exit(1);
234 }
235 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
236 syslog(LOG_ERR, "Can't register with portmap");
237 exit(1);
238 }
239
240 /*
241 * Send the nfs datagram servers
242 * right down into the kernel
243 */
244 for (i = 0; i < udpcnt; i++)
245 if (fork() == 0) {
246 setproctitle("nfsd-udp",
247 (struct sockaddr_in *)NULL);
248 ret = nfssvc(sock, &msk, sizeof(msk),
249 &mtch, sizeof(mtch));
250 if (ret < 0)
251 syslog(LOG_ERR, "nfssvc() failed %m");
252 exit(1);
253 }
254 close(sock);
255 }
256
257 /*
258 * Now set up the master STREAM server waiting for tcp connections.
259 */
260 if (tcpflag) {
261 int on = 1;
262
263 if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
264 syslog(LOG_ERR, "Can't create socket");
265 exit(1);
266 }
267 if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
268 (char *) &on, sizeof(on)) < 0)
269 syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
270 saddr.sin_family = AF_INET;
271 saddr.sin_addr.s_addr = INADDR_ANY;
272 saddr.sin_port = htons(NFS_PORT);
273 if (bind(sock, (struct sockaddr *)&saddr, sizeof(saddr)) < 0) {
274 syslog(LOG_ERR, "Can't bind addr");
275 exit(1);
276 }
277 if (listen(sock, 5) < 0) {
278 syslog(LOG_ERR, "Listen failed");
279 exit(1);
280 }
281 if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
282 syslog(LOG_ERR, "Can't register with portmap");
283 exit(1);
284 }
285 setproctitle("nfsd-listen", (struct sockaddr_in *)NULL);
286 /*
287 * Loop forever accepting connections and sending the children
288 * into the kernel to service the mounts.
289 */
290 for (;;) {
291 len = sizeof(peername);
292 if ((msgsock = accept(sock,
293 (struct sockaddr *)&peername, &len)) < 0) {
294 syslog(LOG_ERR, "Accept failed: %m");
295 exit(1);
296 }
297 if ((peername.sin_addr.s_addr & msk.sin_addr.s_addr) !=
298 mtch.sin_addr.s_addr) {
299 hp = hphead.ha_next;
300 while (hp) {
301 if (peername.sin_addr.s_addr ==
302 hp->ha_sad)
303 break;
304 hp = hp->ha_next;
305 }
306 if (hp == NULL) {
307 shutdown(msgsock, 2);
308 close(msgsock);
309 continue;
310 }
311 }
312 if (fork() == 0) {
313 close(sock);
314 setproctitle("nfsd-tcp", &peername);
315 if (setsockopt(msgsock, SOL_SOCKET,
316 SO_KEEPALIVE, (char *) &on, sizeof(on)) < 0)
317 syslog(LOG_ERR,
318 "setsockopt SO_KEEPALIVE: %m");
319 ret = nfssvc(msgsock, &msk, sizeof(msk),
320 &mtch, sizeof(mtch));
321 shutdown(msgsock, 2);
322 if (ret < 0)
323 syslog(LOG_NOTICE,
324 "Nfssvc STREAM Failed");
325 exit(1);
326 }
327 close(msgsock);
328 }
329 }
330}
331
332usage()
333{
334 fprintf(stderr, "nfsd [-t msk,mtch[,addrs]] [-u msk,mtch,numprocs]\n");
335 exit(1);
336}
337
338void
339reapchild()
340{
341
342 while (wait3((int *) NULL, WNOHANG, (struct rusage *) NULL))
343 ;
344}
345
346setproctitle(a, sin)
347 char *a;
348 struct sockaddr_in *sin;
349{
350 register char *cp;
351 char buf[80];
352
353 cp = Argv[0];
354 if (sin)
355 (void) sprintf(buf, "%s [%s]", a, inet_ntoa(sin->sin_addr));
356 else
357 (void) sprintf(buf, "%s", a);
358 (void) strncpy(cp, buf, LastArg - cp);
359 cp += strlen(cp);
360 while (cp < LastArg)
361 *cp++ = ' ';
362}