getcwd: Return proper error codes.
[dragonfly.git] / sbin / nfsd / nfsd.c
blob5a4d0d0496e82310423e83a48180efd4a986b209
1 /*
2 * Copyright (c) 1989, 1993, 1994
3 * The Regents of the University of California. All rights reserved.
5 * This code is derived from software contributed to Berkeley by
6 * Rick Macklem at The University of Guelph.
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 * 4. Neither the name of the University nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
32 * @(#) Copyright (c) 1989, 1993, 1994 The Regents of the University of California. All rights reserved.
33 * @(#)nfsd.c 8.9 (Berkeley) 3/29/95
34 * $FreeBSD: src/usr.sbin/nfsd/nfsd.c,v 1.34 2005/12/21 10:12:05 delphij Exp $
35 * $DragonFly: src/sbin/nfsd/nfsd.c,v 1.10 2006/12/27 23:06:29 corecode Exp $
38 #include <sys/param.h>
39 #include <sys/syslog.h>
40 #include <sys/wait.h>
41 #include <sys/mount.h>
42 #include <sys/linker.h>
43 #include <sys/module.h>
45 #include <rpc/rpc.h>
46 #include <rpc/pmap_clnt.h>
48 #include <netdb.h>
49 #include <arpa/inet.h>
50 #include <nfs/rpcv2.h>
51 #include <nfs/nfsproto.h>
52 #include <nfs/nfs.h>
54 #include <err.h>
55 #include <errno.h>
56 #include <signal.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61 #include <netdb.h>
63 /* Global defs */
64 #ifdef DEBUG
65 #define syslog(e, s...) fprintf(stderr,s)
66 int debug = 1;
67 #else
68 int debug = 0;
69 #endif
71 struct nfsd_srvargs nsd;
73 #define MAXNFSDCNT 256
74 #define DEFNFSDCNT 4
75 pid_t children[MAXNFSDCNT]; /* PIDs of children */
76 int nfsdcnt; /* number of children */
78 void cleanup(int);
79 void child_cleanup(int);
80 void killchildren(void);
81 void nfsd_exit(int);
82 void nonfs(int);
83 void reapchild(int);
84 int setbindhost(struct addrinfo **ia, const char *bindhost,
85 struct addrinfo hints);
86 void start_server(int);
87 void unregistration(void);
88 void usage(void);
91 * Nfs server daemon mostly just a user context for nfssvc()
93 * 1 - do file descriptor and signal cleanup
94 * 2 - fork the nfsd(s)
95 * 3 - create server socket(s)
96 * 4 - register socket with rpcbind
98 * For connectionless protocols, just pass the socket into the kernel via.
99 * nfssvc().
100 * For connection based sockets, loop doing accepts. When you get a new
101 * socket from accept, pass the msgsock into the kernel via. nfssvc().
102 * The arguments are:
103 * -r - reregister with rpcbind
104 * -d - unregister with rpcbind
105 * -t - support tcp nfs clients
106 * -u - support udp nfs clients
107 * followed by "n" which is the number of nfsds' to fork off
110 main(int argc, char **argv)
112 struct nfsd_args nfsdargs;
113 struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
114 struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
115 struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
116 struct sockaddr_in inetpeer;
117 struct sockaddr_in6 inet6peer;
118 fd_set ready, sockbits;
119 fd_set v4bits, v6bits;
120 int ch, connect_type_cnt, i, maxsock, msgsock;
121 socklen_t len;
122 int on = 1, unregister, reregister, sock;
123 int tcp6sock, ip6flag, tcpflag, tcpsock;
124 int udpflag, ecode, s, srvcnt;
125 int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
126 char **bindhost = NULL;
127 pid_t pid;
128 struct vfsconf vfc;
129 int error;
131 error = getvfsbyname("nfs", &vfc);
132 if (error && vfsisloadable("nfs")) {
133 if (vfsload("nfs"))
134 err(1, "vfsload(nfs)");
135 endvfsent(); /* flush cache */
136 error = getvfsbyname("nfs", &vfc);
138 if (error)
139 errx(1, "NFS is not available in the running kernel");
141 nfsdcnt = DEFNFSDCNT;
142 unregister = reregister = tcpflag = maxsock = 0;
143 bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
144 #define GETOPT "ah:n:rdtu"
145 #define USAGE "[-ardtu] [-n num_servers] [-h bindip]"
146 while ((ch = getopt(argc, argv, GETOPT)) != -1)
147 switch (ch) {
148 case 'a':
149 bindanyflag = 1;
150 break;
151 case 'n':
152 nfsdcnt = atoi(optarg);
153 if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
154 warnx("nfsd count %d; reset to %d", nfsdcnt,
155 DEFNFSDCNT);
156 nfsdcnt = DEFNFSDCNT;
158 break;
159 case 'h':
160 bindhostc++;
161 bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
162 if (bindhost == NULL)
163 errx(1, "Out of memory");
164 bindhost[bindhostc-1] = strdup(optarg);
165 if (bindhost[bindhostc-1] == NULL)
166 errx(1, "Out of memory");
167 break;
168 case 'r':
169 reregister = 1;
170 break;
171 case 'd':
172 unregister = 1;
173 break;
174 case 't':
175 tcpflag = 1;
176 break;
177 case 'u':
178 udpflag = 1;
179 break;
180 default:
181 case '?':
182 usage();
184 if (!tcpflag && !udpflag)
185 udpflag = 1;
186 argv += optind;
187 argc -= optind;
190 * XXX
191 * Backward compatibility, trailing number is the count of daemons.
193 if (argc > 1)
194 usage();
195 if (argc == 1) {
196 nfsdcnt = atoi(argv[0]);
197 if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
198 warnx("nfsd count %d; reset to %d", nfsdcnt,
199 DEFNFSDCNT);
200 nfsdcnt = DEFNFSDCNT;
204 ip6flag = 1;
205 s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
206 if (s == -1) {
207 if (errno != EPROTONOSUPPORT)
208 err(1, "socket");
209 ip6flag = 0;
210 } else if (getnetconfigent("udp6") == NULL ||
211 getnetconfigent("tcp6") == NULL) {
212 ip6flag = 0;
214 if (s != -1)
215 close(s);
217 if (bindhostc == 0 || bindanyflag) {
218 bindhostc++;
219 bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
220 if (bindhost == NULL)
221 errx(1, "Out of memory");
222 bindhost[bindhostc-1] = strdup("*");
223 if (bindhost[bindhostc-1] == NULL)
224 errx(1, "Out of memory");
227 if (unregister) {
228 unregistration();
229 exit (0);
231 if (reregister) {
232 if (udpflag) {
233 memset(&hints, 0, sizeof hints);
234 hints.ai_flags = AI_PASSIVE;
235 hints.ai_family = AF_INET;
236 hints.ai_socktype = SOCK_DGRAM;
237 hints.ai_protocol = IPPROTO_UDP;
238 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
239 if (ecode != 0)
240 err(1, "getaddrinfo udp: %s", gai_strerror(ecode));
241 nconf_udp = getnetconfigent("udp");
242 if (nconf_udp == NULL)
243 err(1, "getnetconfigent udp failed");
244 nb_udp.buf = ai_udp->ai_addr;
245 nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
246 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
247 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
248 err(1, "rpcb_set udp failed");
249 freeaddrinfo(ai_udp);
251 if (udpflag && ip6flag) {
252 memset(&hints, 0, sizeof hints);
253 hints.ai_flags = AI_PASSIVE;
254 hints.ai_family = AF_INET6;
255 hints.ai_socktype = SOCK_DGRAM;
256 hints.ai_protocol = IPPROTO_UDP;
257 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
258 if (ecode != 0)
259 err(1, "getaddrinfo udp6: %s", gai_strerror(ecode));
260 nconf_udp6 = getnetconfigent("udp6");
261 if (nconf_udp6 == NULL)
262 err(1, "getnetconfigent udp6 failed");
263 nb_udp6.buf = ai_udp6->ai_addr;
264 nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
265 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
266 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
267 err(1, "rpcb_set udp6 failed");
268 freeaddrinfo(ai_udp6);
270 if (tcpflag) {
271 memset(&hints, 0, sizeof hints);
272 hints.ai_flags = AI_PASSIVE;
273 hints.ai_family = AF_INET;
274 hints.ai_socktype = SOCK_STREAM;
275 hints.ai_protocol = IPPROTO_TCP;
276 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
277 if (ecode != 0)
278 err(1, "getaddrinfo tcp: %s", gai_strerror(ecode));
279 nconf_tcp = getnetconfigent("tcp");
280 if (nconf_tcp == NULL)
281 err(1, "getnetconfigent tcp failed");
282 nb_tcp.buf = ai_tcp->ai_addr;
283 nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
284 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) ||
285 (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp)))
286 err(1, "rpcb_set tcp failed");
287 freeaddrinfo(ai_tcp);
289 if (tcpflag && ip6flag) {
290 memset(&hints, 0, sizeof hints);
291 hints.ai_flags = AI_PASSIVE;
292 hints.ai_family = AF_INET6;
293 hints.ai_socktype = SOCK_STREAM;
294 hints.ai_protocol = IPPROTO_TCP;
295 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
296 if (ecode != 0)
297 err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode));
298 nconf_tcp6 = getnetconfigent("tcp6");
299 if (nconf_tcp6 == NULL)
300 err(1, "getnetconfigent tcp6 failed");
301 nb_tcp6.buf = ai_tcp6->ai_addr;
302 nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
303 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
304 (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
305 err(1, "rpcb_set tcp6 failed");
306 freeaddrinfo(ai_tcp6);
308 exit (0);
310 if (debug == 0) {
311 daemon(0, 0);
312 signal(SIGHUP, SIG_IGN);
313 signal(SIGINT, SIG_IGN);
315 * nfsd sits in the kernel most of the time. It needs
316 * to ignore SIGTERM/SIGQUIT in order to stay alive as long
317 * as possible during a shutdown, otherwise loopback
318 * mounts will not be able to unmount.
320 signal(SIGTERM, SIG_IGN);
321 signal(SIGQUIT, SIG_IGN);
323 signal(SIGSYS, nonfs);
324 signal(SIGCHLD, reapchild);
326 openlog("nfsd", LOG_PID, LOG_DAEMON);
328 /* If we use UDP only, we start the last server below. */
329 srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1;
330 for (i = 0; i < srvcnt; i++) {
331 switch ((pid = fork())) {
332 case -1:
333 syslog(LOG_ERR, "fork: %m");
334 nfsd_exit(1);
335 case 0:
336 break;
337 default:
338 children[i] = pid;
339 continue;
341 signal(SIGUSR1, child_cleanup);
342 setproctitle("server");
344 start_server(0);
347 signal(SIGUSR1, cleanup);
348 FD_ZERO(&v4bits);
349 FD_ZERO(&v6bits);
350 FD_ZERO(&sockbits);
352 rpcbregcnt = 0;
353 /* Set up the socket for udp and rpcb register it. */
354 if (udpflag) {
355 rpcbreg = 0;
356 for (i = 0; i < bindhostc; i++) {
357 memset(&hints, 0, sizeof hints);
358 hints.ai_flags = AI_PASSIVE;
359 hints.ai_family = AF_INET;
360 hints.ai_socktype = SOCK_DGRAM;
361 hints.ai_protocol = IPPROTO_UDP;
362 if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
363 rpcbreg = 1;
364 rpcbregcnt++;
365 if ((sock = socket(ai_udp->ai_family,
366 ai_udp->ai_socktype,
367 ai_udp->ai_protocol)) < 0) {
368 syslog(LOG_ERR,
369 "can't create udp socket");
370 nfsd_exit(1);
372 if (bind(sock, ai_udp->ai_addr,
373 ai_udp->ai_addrlen) < 0) {
374 syslog(LOG_ERR,
375 "can't bind udp addr %s: %m",
376 bindhost[i]);
377 nfsd_exit(1);
379 freeaddrinfo(ai_udp);
380 nfsdargs.sock = sock;
381 nfsdargs.name = NULL;
382 nfsdargs.namelen = 0;
383 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
384 syslog(LOG_ERR, "can't Add UDP socket");
385 nfsd_exit(1);
387 close(sock);
390 if (rpcbreg == 1) {
391 memset(&hints, 0, sizeof hints);
392 hints.ai_flags = AI_PASSIVE;
393 hints.ai_family = AF_INET;
394 hints.ai_socktype = SOCK_DGRAM;
395 hints.ai_protocol = IPPROTO_UDP;
396 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
397 if (ecode != 0) {
398 syslog(LOG_ERR, "getaddrinfo udp: %s",
399 gai_strerror(ecode));
400 nfsd_exit(1);
402 nconf_udp = getnetconfigent("udp");
403 if (nconf_udp == NULL)
404 err(1, "getnetconfigent udp failed");
405 nb_udp.buf = ai_udp->ai_addr;
406 nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
407 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
408 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
409 err(1, "rpcb_set udp failed");
410 freeaddrinfo(ai_udp);
414 /* Set up the socket for udp6 and rpcb register it. */
415 if (udpflag && ip6flag) {
416 rpcbreg = 0;
417 for (i = 0; i < bindhostc; i++) {
418 memset(&hints, 0, sizeof hints);
419 hints.ai_flags = AI_PASSIVE;
420 hints.ai_family = AF_INET6;
421 hints.ai_socktype = SOCK_DGRAM;
422 hints.ai_protocol = IPPROTO_UDP;
423 if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
424 rpcbreg = 1;
425 rpcbregcnt++;
426 if ((sock = socket(ai_udp6->ai_family,
427 ai_udp6->ai_socktype,
428 ai_udp6->ai_protocol)) < 0) {
429 syslog(LOG_ERR,
430 "can't create udp6 socket");
431 nfsd_exit(1);
433 if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
434 &on, sizeof on) < 0) {
435 syslog(LOG_ERR,
436 "can't set v6-only binding for "
437 "udp6 socket: %m");
438 nfsd_exit(1);
440 if (bind(sock, ai_udp6->ai_addr,
441 ai_udp6->ai_addrlen) < 0) {
442 syslog(LOG_ERR,
443 "can't bind udp6 addr %s: %m",
444 bindhost[i]);
445 nfsd_exit(1);
447 freeaddrinfo(ai_udp6);
448 nfsdargs.sock = sock;
449 nfsdargs.name = NULL;
450 nfsdargs.namelen = 0;
451 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
452 syslog(LOG_ERR,
453 "can't add UDP6 socket");
454 nfsd_exit(1);
456 close(sock);
459 if (rpcbreg == 1) {
460 memset(&hints, 0, sizeof hints);
461 hints.ai_flags = AI_PASSIVE;
462 hints.ai_family = AF_INET6;
463 hints.ai_socktype = SOCK_DGRAM;
464 hints.ai_protocol = IPPROTO_UDP;
465 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
466 if (ecode != 0) {
467 syslog(LOG_ERR, "getaddrinfo udp6: %s",
468 gai_strerror(ecode));
469 nfsd_exit(1);
471 nconf_udp6 = getnetconfigent("udp6");
472 if (nconf_udp6 == NULL)
473 err(1, "getnetconfigent udp6 failed");
474 nb_udp6.buf = ai_udp6->ai_addr;
475 nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
476 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
477 (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
478 err(1, "rpcb_set udp6 failed");
479 freeaddrinfo(ai_udp6);
483 /* Set up the socket for tcp and rpcb register it. */
484 if (tcpflag) {
485 rpcbreg = 0;
486 for (i = 0; i < bindhostc; i++) {
487 memset(&hints, 0, sizeof hints);
488 hints.ai_flags = AI_PASSIVE;
489 hints.ai_family = AF_INET;
490 hints.ai_socktype = SOCK_STREAM;
491 hints.ai_protocol = IPPROTO_TCP;
492 if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
493 rpcbreg = 1;
494 rpcbregcnt++;
495 if ((tcpsock = socket(AF_INET, SOCK_STREAM,
496 0)) < 0) {
497 syslog(LOG_ERR,
498 "can't create tpc socket");
499 nfsd_exit(1);
501 if (setsockopt(tcpsock, SOL_SOCKET,
502 SO_REUSEADDR,
503 (char *)&on, sizeof(on)) < 0)
504 syslog(LOG_ERR,
505 "setsockopt SO_REUSEADDR: %m");
506 if (bind(tcpsock, ai_tcp->ai_addr,
507 ai_tcp->ai_addrlen) < 0) {
508 syslog(LOG_ERR,
509 "can't bind tcp addr %s: %m",
510 bindhost[i]);
511 nfsd_exit(1);
513 if (listen(tcpsock, 64) < 0) {
514 syslog(LOG_ERR, "listen failed");
515 nfsd_exit(1);
517 freeaddrinfo(ai_tcp);
518 FD_SET(tcpsock, &sockbits);
519 FD_SET(tcpsock, &v4bits);
520 maxsock = tcpsock;
521 connect_type_cnt++;
524 if (rpcbreg == 1) {
525 memset(&hints, 0, sizeof hints);
526 hints.ai_flags = AI_PASSIVE;
527 hints.ai_family = AF_INET;
528 hints.ai_socktype = SOCK_STREAM;
529 hints.ai_protocol = IPPROTO_TCP;
530 ecode = getaddrinfo(NULL, "nfs", &hints,
531 &ai_tcp);
532 if (ecode != 0) {
533 syslog(LOG_ERR, "getaddrinfo tcp: %s",
534 gai_strerror(ecode));
535 nfsd_exit(1);
537 nconf_tcp = getnetconfigent("tcp");
538 if (nconf_tcp == NULL)
539 err(1, "getnetconfigent tcp failed");
540 nb_tcp.buf = ai_tcp->ai_addr;
541 nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
542 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp,
543 &nb_tcp)) || (!rpcb_set(RPCPROG_NFS, 3,
544 nconf_tcp, &nb_tcp)))
545 err(1, "rpcb_set tcp failed");
546 freeaddrinfo(ai_tcp);
550 /* Set up the socket for tcp6 and rpcb register it. */
551 if (tcpflag && ip6flag) {
552 rpcbreg = 0;
553 for (i = 0; i < bindhostc; i++) {
554 memset(&hints, 0, sizeof hints);
555 hints.ai_flags = AI_PASSIVE;
556 hints.ai_family = AF_INET6;
557 hints.ai_socktype = SOCK_STREAM;
558 hints.ai_protocol = IPPROTO_TCP;
559 if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
560 rpcbreg = 1;
561 rpcbregcnt++;
562 if ((tcp6sock = socket(ai_tcp6->ai_family,
563 ai_tcp6->ai_socktype,
564 ai_tcp6->ai_protocol)) < 0) {
565 syslog(LOG_ERR,
566 "can't create tcp6 socket");
567 nfsd_exit(1);
569 if (setsockopt(tcp6sock, SOL_SOCKET,
570 SO_REUSEADDR,
571 (char *)&on, sizeof(on)) < 0)
572 syslog(LOG_ERR,
573 "setsockopt SO_REUSEADDR: %m");
574 if (setsockopt(tcp6sock, IPPROTO_IPV6,
575 IPV6_V6ONLY, &on, sizeof on) < 0) {
576 syslog(LOG_ERR,
577 "can't set v6-only binding for tcp6 "
578 "socket: %m");
579 nfsd_exit(1);
581 if (bind(tcp6sock, ai_tcp6->ai_addr,
582 ai_tcp6->ai_addrlen) < 0) {
583 syslog(LOG_ERR,
584 "can't bind tcp6 addr %s: %m",
585 bindhost[i]);
586 nfsd_exit(1);
588 if (listen(tcp6sock, 64) < 0) {
589 syslog(LOG_ERR, "listen failed");
590 nfsd_exit(1);
592 freeaddrinfo(ai_tcp6);
593 FD_SET(tcp6sock, &sockbits);
594 FD_SET(tcp6sock, &v6bits);
595 if (maxsock < tcp6sock)
596 maxsock = tcp6sock;
597 connect_type_cnt++;
600 if (rpcbreg == 1) {
601 memset(&hints, 0, sizeof hints);
602 hints.ai_flags = AI_PASSIVE;
603 hints.ai_family = AF_INET6;
604 hints.ai_socktype = SOCK_STREAM;
605 hints.ai_protocol = IPPROTO_TCP;
606 ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
607 if (ecode != 0) {
608 syslog(LOG_ERR, "getaddrinfo tcp6: %s",
609 gai_strerror(ecode));
610 nfsd_exit(1);
612 nconf_tcp6 = getnetconfigent("tcp6");
613 if (nconf_tcp6 == NULL)
614 err(1, "getnetconfigent tcp6 failed");
615 nb_tcp6.buf = ai_tcp6->ai_addr;
616 nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
617 if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
618 (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
619 err(1, "rpcb_set tcp6 failed");
620 freeaddrinfo(ai_tcp6);
624 if (rpcbregcnt == 0) {
625 syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
626 nfsd_exit(1);
629 if (tcpflag && connect_type_cnt == 0) {
630 syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
631 nfsd_exit(1);
634 setproctitle("master");
636 * We always want a master to have a clean way to to shut nfsd down
637 * (with unregistration): if the master is killed, it unregisters and
638 * kills all children. If we run for UDP only (and so do not have to
639 * loop waiting waiting for accept), we instead make the parent
640 * a "server" too. start_server will not return.
642 if (!tcpflag)
643 start_server(1);
646 * Loop forever accepting connections and passing the sockets
647 * into the kernel for the mounts.
649 for (;;) {
650 ready = sockbits;
651 if (connect_type_cnt > 1) {
652 if (select(maxsock + 1,
653 &ready, NULL, NULL, NULL) < 1) {
654 syslog(LOG_ERR, "select failed: %m");
655 if (errno == EINTR)
656 continue;
657 nfsd_exit(1);
660 for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
661 if (FD_ISSET(tcpsock, &ready)) {
662 if (FD_ISSET(tcpsock, &v4bits)) {
663 len = sizeof(inetpeer);
664 if ((msgsock = accept(tcpsock,
665 (struct sockaddr *)&inetpeer, &len)) < 0) {
666 syslog(LOG_ERR, "accept failed: %m");
667 if (errno == ECONNABORTED ||
668 errno == EINTR)
669 continue;
670 nfsd_exit(1);
672 memset(inetpeer.sin_zero, 0,
673 sizeof(inetpeer.sin_zero));
674 if (setsockopt(msgsock, SOL_SOCKET,
675 SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
676 syslog(LOG_ERR,
677 "setsockopt SO_KEEPALIVE: %m");
678 nfsdargs.sock = msgsock;
679 nfsdargs.name = (caddr_t)&inetpeer;
680 nfsdargs.namelen = len;
681 nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
682 close(msgsock);
683 } else if (FD_ISSET(tcpsock, &v6bits)) {
684 len = sizeof(inet6peer);
685 if ((msgsock = accept(tcpsock,
686 (struct sockaddr *)&inet6peer,
687 &len)) < 0) {
688 syslog(LOG_ERR,
689 "accept failed: %m");
690 if (errno == ECONNABORTED ||
691 errno == EINTR)
692 continue;
693 nfsd_exit(1);
695 if (setsockopt(msgsock, SOL_SOCKET,
696 SO_KEEPALIVE, (char *)&on,
697 sizeof(on)) < 0)
698 syslog(LOG_ERR, "setsockopt "
699 "SO_KEEPALIVE: %m");
700 nfsdargs.sock = msgsock;
701 nfsdargs.name = (caddr_t)&inet6peer;
702 nfsdargs.namelen = len;
703 nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
704 close(msgsock);
712 setbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints)
714 int ecode;
715 u_int32_t host_addr[4]; /* IPv4 or IPv6 */
716 const char *hostptr;
718 if (bindhost == NULL || strcmp("*", bindhost) == 0)
719 hostptr = NULL;
720 else
721 hostptr = bindhost;
723 if (hostptr != NULL) {
724 switch (hints.ai_family) {
725 case AF_INET:
726 if (inet_pton(AF_INET, hostptr, host_addr) == 1) {
727 hints.ai_flags = AI_NUMERICHOST;
728 } else {
729 if (inet_pton(AF_INET6, hostptr,
730 host_addr) == 1)
731 return (1);
733 break;
734 case AF_INET6:
735 if (inet_pton(AF_INET6, hostptr, host_addr) == 1) {
736 hints.ai_flags = AI_NUMERICHOST;
737 } else {
738 if (inet_pton(AF_INET, hostptr,
739 host_addr) == 1)
740 return (1);
742 break;
743 default:
744 break;
748 ecode = getaddrinfo(hostptr, "nfs", &hints, ai);
749 if (ecode != 0) {
750 syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost,
751 gai_strerror(ecode));
752 return (1);
754 return (0);
757 void
758 usage(void)
760 fprintf(stderr, "usage: nfsd %s\n", USAGE);
761 exit(1);
764 void
765 nonfs(int signo __unused)
767 syslog(LOG_ERR, "missing system call: NFS not available");
770 void
771 reapchild(int signo __unused)
773 pid_t pid;
774 int i;
776 while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) {
777 for (i = 0; i < nfsdcnt; i++)
778 if (pid == children[i])
779 children[i] = -1;
783 void
784 unregistration(void)
786 if ((!rpcb_unset(RPCPROG_NFS, 2, NULL)) ||
787 (!rpcb_unset(RPCPROG_NFS, 3, NULL)))
788 syslog(LOG_ERR, "rpcb_unset failed");
791 void
792 killchildren(void)
794 int i;
796 for (i = 0; i < nfsdcnt; i++) {
797 if (children[i] > 0)
798 kill(children[i], SIGKILL);
803 * Cleanup master after SIGUSR1.
805 void
806 cleanup(__unused int signo)
808 nfsd_exit(0);
812 * Cleanup child after SIGUSR1.
814 void
815 child_cleanup(__unused int signo)
817 exit(0);
820 void
821 nfsd_exit(int status)
823 killchildren();
824 unregistration();
825 exit(status);
828 void
829 start_server(int master)
831 int status;
833 status = 0;
834 nsd.nsd_nfsd = NULL;
835 if (nfssvc(NFSSVC_NFSD, &nsd) < 0) {
836 syslog(LOG_ERR, "nfssvc: %m");
837 status = 1;
839 if (master)
840 nfsd_exit(status);
841 else
842 exit(status);