Merge branches 'hammer2' and 'master' of ssh://crater.dragonflybsd.org/repository...
[dragonfly.git] / sbin / nfsd / nfsd.c
1 /*
2  * Copyright (c) 1989, 1993, 1994
3  *      The Regents of the University of California.  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  * 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.
19  *
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.
31  *
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  */
36
37 #include <sys/param.h>
38 #include <sys/syslog.h>
39 #include <sys/wait.h>
40 #include <sys/mount.h>
41 #include <sys/linker.h>
42 #include <sys/module.h>
43
44 #include <rpc/rpc.h>
45 #include <rpc/pmap_clnt.h>
46
47 #include <netdb.h>
48 #include <arpa/inet.h>
49 #include <nfs/rpcv2.h>
50 #include <nfs/nfsproto.h>
51 #include <nfs/nfs.h>
52
53 #include <err.h>
54 #include <errno.h>
55 #include <signal.h>
56 #include <stdio.h>
57 #include <stdlib.h>
58 #include <string.h>
59 #include <unistd.h>
60
61 /* Global defs */
62 #ifdef DEBUG
63 #define syslog(e, s...) fprintf(stderr,s)
64 int     debug = 1;
65 #else
66 int     debug = 0;
67 #endif
68
69 struct nfsd_srvargs nsd;
70
71 #define MAXNFSDCNT      256
72 #define DEFNFSDCNT       4
73 pid_t   children[MAXNFSDCNT];   /* PIDs of children */
74 int     nfsdcnt;                /* number of children */
75
76 void    cleanup(int);
77 void    child_cleanup(int);
78 void    killchildren(void);
79 void    nfsd_exit(int);
80 void    nonfs(int);
81 void    reapchild(int);
82 int     setbindhost(struct addrinfo **ia, const char *bindhost,
83             struct addrinfo hints);
84 void    start_server(int);
85 void    unregistration(void);
86 void    usage(void);
87
88 /*
89  * Nfs server daemon mostly just a user context for nfssvc()
90  *
91  * 1 - do file descriptor and signal cleanup
92  * 2 - fork the nfsd(s)
93  * 3 - create server socket(s)
94  * 4 - register socket with rpcbind
95  *
96  * For connectionless protocols, just pass the socket into the kernel via.
97  * nfssvc().
98  * For connection based sockets, loop doing accepts. When you get a new
99  * socket from accept, pass the msgsock into the kernel via. nfssvc().
100  * The arguments are:
101  *      -r - reregister with rpcbind
102  *      -d - unregister with rpcbind
103  *      -t - support tcp nfs clients
104  *      -u - support udp nfs clients
105  * followed by "n" which is the number of nfsds' to fork off
106  */
107 int
108 main(int argc, char **argv)
109 {
110         struct nfsd_args nfsdargs;
111         struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
112         struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
113         struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
114         struct sockaddr_in inetpeer;
115         struct sockaddr_in6 inet6peer;
116         fd_set ready, sockbits;
117         fd_set v4bits, v6bits;
118         int ch, connect_type_cnt, i, maxsock, msgsock;
119         socklen_t len;
120         int on = 1, unregister, reregister, sock;
121         int tcp6sock, ip6flag, tcpflag, tcpsock;
122         int udpflag, ecode, s, srvcnt;
123         int bindhostc, bindanyflag, rpcbreg, rpcbregcnt;
124         char **bindhost = NULL;
125         pid_t pid;
126         struct vfsconf vfc;
127         int error;
128
129         error = getvfsbyname("nfs", &vfc);
130         if (error && vfsisloadable("nfs")) {
131                 if (vfsload("nfs"))
132                         err(1, "vfsload(nfs)");
133                 endvfsent();    /* flush cache */
134                 error = getvfsbyname("nfs", &vfc);
135         }
136         if (error)
137                 errx(1, "NFS is not available in the running kernel");
138
139         nfsdcnt = DEFNFSDCNT;
140         unregister = reregister = tcpflag = maxsock = 0;
141         bindanyflag = udpflag = connect_type_cnt = bindhostc = 0;
142 #define GETOPT  "ah:n:rdtu"
143 #define USAGE   "[-ardtu] [-n num_servers] [-h bindip]"
144         while ((ch = getopt(argc, argv, GETOPT)) != -1)
145                 switch (ch) {
146                 case 'a':
147                         bindanyflag = 1;
148                         break;
149                 case 'n':
150                         nfsdcnt = atoi(optarg);
151                         if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
152                                 warnx("nfsd count %d; reset to %d", nfsdcnt,
153                                     DEFNFSDCNT);
154                                 nfsdcnt = DEFNFSDCNT;
155                         }
156                         break;
157                 case 'h':
158                         bindhostc++;
159                         bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
160                         if (bindhost == NULL)
161                                 errx(1, "Out of memory");
162                         bindhost[bindhostc-1] = strdup(optarg);
163                         if (bindhost[bindhostc-1] == NULL)
164                                 errx(1, "Out of memory");
165                         break;
166                 case 'r':
167                         reregister = 1;
168                         break;
169                 case 'd':
170                         unregister = 1;
171                         break;
172                 case 't':
173                         tcpflag = 1;
174                         break;
175                 case 'u':
176                         udpflag = 1;
177                         break;
178                 default:
179                 case '?':
180                         usage();
181                 };
182         if (!tcpflag && !udpflag)
183                 udpflag = 1;
184         argv += optind;
185         argc -= optind;
186
187         /*
188          * XXX
189          * Backward compatibility, trailing number is the count of daemons.
190          */
191         if (argc > 1)
192                 usage();
193         if (argc == 1) {
194                 nfsdcnt = atoi(argv[0]);
195                 if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
196                         warnx("nfsd count %d; reset to %d", nfsdcnt,
197                             DEFNFSDCNT);
198                         nfsdcnt = DEFNFSDCNT;
199                 }
200         }
201
202         ip6flag = 1;
203         s = socket(AF_INET6, SOCK_DGRAM, IPPROTO_UDP);
204         if (s == -1) {
205                 if (errno != EPROTONOSUPPORT)
206                         err(1, "socket");
207                 ip6flag = 0;
208         } else if (getnetconfigent("udp6") == NULL ||
209                 getnetconfigent("tcp6") == NULL) {
210                 ip6flag = 0;
211         }
212         if (s != -1)
213                 close(s);
214
215         if (bindhostc == 0 || bindanyflag) {
216                 bindhostc++;
217                 bindhost = realloc(bindhost,sizeof(char *)*bindhostc);
218                 if (bindhost == NULL)
219                         errx(1, "Out of memory");
220                 bindhost[bindhostc-1] = strdup("*");
221                 if (bindhost[bindhostc-1] == NULL)
222                         errx(1, "Out of memory");
223         }
224
225         if (unregister) {
226                 unregistration();
227                 exit (0);
228         }
229         if (reregister) {
230                 if (udpflag) {
231                         memset(&hints, 0, sizeof hints);
232                         hints.ai_flags = AI_PASSIVE;
233                         hints.ai_family = AF_INET;
234                         hints.ai_socktype = SOCK_DGRAM;
235                         hints.ai_protocol = IPPROTO_UDP;
236                         ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
237                         if (ecode != 0)
238                                 err(1, "getaddrinfo udp: %s", gai_strerror(ecode));
239                         nconf_udp = getnetconfigent("udp");
240                         if (nconf_udp == NULL)
241                                 err(1, "getnetconfigent udp failed");
242                         nb_udp.buf = ai_udp->ai_addr;
243                         nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
244                         if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
245                             (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
246                                 err(1, "rpcb_set udp failed");
247                         freeaddrinfo(ai_udp);
248                 }
249                 if (udpflag && ip6flag) {
250                         memset(&hints, 0, sizeof hints);
251                         hints.ai_flags = AI_PASSIVE;
252                         hints.ai_family = AF_INET6;
253                         hints.ai_socktype = SOCK_DGRAM;
254                         hints.ai_protocol = IPPROTO_UDP;
255                         ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
256                         if (ecode != 0)
257                                 err(1, "getaddrinfo udp6: %s", gai_strerror(ecode));
258                         nconf_udp6 = getnetconfigent("udp6");
259                         if (nconf_udp6 == NULL)
260                                 err(1, "getnetconfigent udp6 failed");
261                         nb_udp6.buf = ai_udp6->ai_addr;
262                         nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
263                         if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
264                             (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
265                                 err(1, "rpcb_set udp6 failed");
266                         freeaddrinfo(ai_udp6);
267                 }
268                 if (tcpflag) {
269                         memset(&hints, 0, sizeof hints);
270                         hints.ai_flags = AI_PASSIVE;
271                         hints.ai_family = AF_INET;
272                         hints.ai_socktype = SOCK_STREAM;
273                         hints.ai_protocol = IPPROTO_TCP;
274                         ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
275                         if (ecode != 0)
276                                 err(1, "getaddrinfo tcp: %s", gai_strerror(ecode));
277                         nconf_tcp = getnetconfigent("tcp");
278                         if (nconf_tcp == NULL)
279                                 err(1, "getnetconfigent tcp failed");
280                         nb_tcp.buf = ai_tcp->ai_addr;
281                         nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
282                         if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp)) ||
283                             (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp)))
284                                 err(1, "rpcb_set tcp failed");
285                         freeaddrinfo(ai_tcp);
286                 }
287                 if (tcpflag && ip6flag) {
288                         memset(&hints, 0, sizeof hints);
289                         hints.ai_flags = AI_PASSIVE;
290                         hints.ai_family = AF_INET6;
291                         hints.ai_socktype = SOCK_STREAM;
292                         hints.ai_protocol = IPPROTO_TCP;
293                         ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
294                         if (ecode != 0)
295                                 err(1, "getaddrinfo tcp6: %s", gai_strerror(ecode));
296                         nconf_tcp6 = getnetconfigent("tcp6");
297                         if (nconf_tcp6 == NULL)
298                                 err(1, "getnetconfigent tcp6 failed");
299                         nb_tcp6.buf = ai_tcp6->ai_addr;
300                         nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
301                         if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
302                             (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
303                                 err(1, "rpcb_set tcp6 failed");
304                         freeaddrinfo(ai_tcp6);
305                 }
306                 exit (0);
307         }
308         if (debug == 0) {
309                 daemon(0, 0);
310                 signal(SIGHUP, SIG_IGN);
311                 signal(SIGINT, SIG_IGN);
312                 /*
313                  * nfsd sits in the kernel most of the time.  It needs
314                  * to ignore SIGTERM/SIGQUIT in order to stay alive as long
315                  * as possible during a shutdown, otherwise loopback
316                  * mounts will not be able to unmount.
317                  */
318                 signal(SIGTERM, SIG_IGN);
319                 signal(SIGQUIT, SIG_IGN);
320         }
321         signal(SIGSYS, nonfs);
322         signal(SIGCHLD, reapchild);
323
324         openlog("nfsd", LOG_PID, LOG_DAEMON);
325
326         /* If we use UDP only, we start the last server below. */
327         srvcnt = tcpflag ? nfsdcnt : nfsdcnt - 1;
328         for (i = 0; i < srvcnt; i++) {
329                 switch ((pid = fork())) {
330                 case -1:
331                         syslog(LOG_ERR, "fork: %m");
332                         nfsd_exit(1);
333                 case 0:
334                         break;
335                 default:
336                         children[i] = pid;
337                         continue;
338                 }
339                 signal(SIGUSR1, child_cleanup);
340                 setproctitle("server");
341
342                 start_server(0);
343         }
344
345         signal(SIGUSR1, cleanup);
346         FD_ZERO(&v4bits);
347         FD_ZERO(&v6bits);
348         FD_ZERO(&sockbits);
349
350         rpcbregcnt = 0;
351         /* Set up the socket for udp and rpcb register it. */
352         if (udpflag) {
353                 rpcbreg = 0;
354                 for (i = 0; i < bindhostc; i++) {
355                         memset(&hints, 0, sizeof hints);
356                         hints.ai_flags = AI_PASSIVE;
357                         hints.ai_family = AF_INET;
358                         hints.ai_socktype = SOCK_DGRAM;
359                         hints.ai_protocol = IPPROTO_UDP;
360                         if (setbindhost(&ai_udp, bindhost[i], hints) == 0) {
361                                 rpcbreg = 1;
362                                 rpcbregcnt++;
363                                 if ((sock = socket(ai_udp->ai_family,
364                                     ai_udp->ai_socktype,
365                                     ai_udp->ai_protocol)) < 0) {
366                                         syslog(LOG_ERR,
367                                             "can't create udp socket");
368                                         nfsd_exit(1);
369                                 }
370                                 if (bind(sock, ai_udp->ai_addr,
371                                     ai_udp->ai_addrlen) < 0) {
372                                         syslog(LOG_ERR,
373                                             "can't bind udp addr %s: %m",
374                                             bindhost[i]);
375                                         nfsd_exit(1);
376                                 }
377                                 freeaddrinfo(ai_udp);
378                                 nfsdargs.sock = sock;
379                                 nfsdargs.name = NULL;
380                                 nfsdargs.namelen = 0;
381                                 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
382                                         syslog(LOG_ERR, "can't Add UDP socket");
383                                         nfsd_exit(1);
384                                 }
385                                 close(sock);
386                         }
387                 }
388                 if (rpcbreg == 1) {
389                         memset(&hints, 0, sizeof hints);
390                         hints.ai_flags = AI_PASSIVE;
391                         hints.ai_family = AF_INET;
392                         hints.ai_socktype = SOCK_DGRAM;
393                         hints.ai_protocol = IPPROTO_UDP;
394                         ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
395                         if (ecode != 0) {
396                                 syslog(LOG_ERR, "getaddrinfo udp: %s",
397                                    gai_strerror(ecode));
398                                 nfsd_exit(1);
399                         }
400                         nconf_udp = getnetconfigent("udp");
401                         if (nconf_udp == NULL)
402                                 err(1, "getnetconfigent udp failed");
403                         nb_udp.buf = ai_udp->ai_addr;
404                         nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
405                         if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp)) ||
406                             (!rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)))
407                                 err(1, "rpcb_set udp failed");
408                         freeaddrinfo(ai_udp);
409                 }
410         }
411
412         /* Set up the socket for udp6 and rpcb register it. */
413         if (udpflag && ip6flag) {
414                 rpcbreg = 0;
415                 for (i = 0; i < bindhostc; i++) {
416                         memset(&hints, 0, sizeof hints);
417                         hints.ai_flags = AI_PASSIVE;
418                         hints.ai_family = AF_INET6;
419                         hints.ai_socktype = SOCK_DGRAM;
420                         hints.ai_protocol = IPPROTO_UDP;
421                         if (setbindhost(&ai_udp6, bindhost[i], hints) == 0) {
422                                 rpcbreg = 1;
423                                 rpcbregcnt++;
424                                 if ((sock = socket(ai_udp6->ai_family,
425                                     ai_udp6->ai_socktype,
426                                     ai_udp6->ai_protocol)) < 0) {
427                                         syslog(LOG_ERR,
428                                                 "can't create udp6 socket");
429                                         nfsd_exit(1);
430                                 }
431                                 if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
432                                     &on, sizeof on) < 0) {
433                                         syslog(LOG_ERR,
434                                             "can't set v6-only binding for "
435                                             "udp6 socket: %m");
436                                         nfsd_exit(1);
437                                 }
438                                 if (bind(sock, ai_udp6->ai_addr,
439                                     ai_udp6->ai_addrlen) < 0) {
440                                         syslog(LOG_ERR,
441                                             "can't bind udp6 addr %s: %m",
442                                             bindhost[i]);
443                                         nfsd_exit(1);
444                                 }
445                                 freeaddrinfo(ai_udp6);
446                                 nfsdargs.sock = sock;
447                                 nfsdargs.name = NULL;
448                                 nfsdargs.namelen = 0;
449                                 if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
450                                         syslog(LOG_ERR,
451                                             "can't add UDP6 socket");
452                                         nfsd_exit(1);
453                                 }
454                                 close(sock);
455                         }
456                 }
457                 if (rpcbreg == 1) {
458                         memset(&hints, 0, sizeof hints);
459                         hints.ai_flags = AI_PASSIVE;
460                         hints.ai_family = AF_INET6;
461                         hints.ai_socktype = SOCK_DGRAM;
462                         hints.ai_protocol = IPPROTO_UDP;
463                         ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
464                         if (ecode != 0) {
465                                 syslog(LOG_ERR, "getaddrinfo udp6: %s",
466                                    gai_strerror(ecode));
467                                 nfsd_exit(1);
468                         }
469                         nconf_udp6 = getnetconfigent("udp6");
470                         if (nconf_udp6 == NULL)
471                                 err(1, "getnetconfigent udp6 failed");
472                         nb_udp6.buf = ai_udp6->ai_addr;
473                         nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
474                         if ((!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6)) ||
475                             (!rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)))
476                                 err(1, "rpcb_set udp6 failed");
477                         freeaddrinfo(ai_udp6);
478                 }
479         }
480
481         /* Set up the socket for tcp and rpcb register it. */
482         if (tcpflag) {
483                 rpcbreg = 0;
484                 for (i = 0; i < bindhostc; i++) {
485                         memset(&hints, 0, sizeof hints);
486                         hints.ai_flags = AI_PASSIVE;
487                         hints.ai_family = AF_INET;
488                         hints.ai_socktype = SOCK_STREAM;
489                         hints.ai_protocol = IPPROTO_TCP;
490                         if (setbindhost(&ai_tcp, bindhost[i], hints) == 0) {
491                                 rpcbreg = 1;
492                                 rpcbregcnt++;
493                                 if ((tcpsock = socket(AF_INET, SOCK_STREAM,
494                                     0)) < 0) {
495                                         syslog(LOG_ERR,
496                                             "can't create tpc socket");
497                                         nfsd_exit(1);
498                                 }
499                                 if (setsockopt(tcpsock, SOL_SOCKET,
500                                     SO_REUSEADDR,
501                                     (char *)&on, sizeof(on)) < 0)
502                                         syslog(LOG_ERR,
503                                              "setsockopt SO_REUSEADDR: %m");
504                                 if (bind(tcpsock, ai_tcp->ai_addr,
505                                     ai_tcp->ai_addrlen) < 0) {
506                                         syslog(LOG_ERR,
507                                             "can't bind tcp addr %s: %m",
508                                             bindhost[i]);
509                                         nfsd_exit(1);
510                                 }
511                                 if (listen(tcpsock, 64) < 0) {
512                                         syslog(LOG_ERR, "listen failed");
513                                         nfsd_exit(1);
514                                 }
515                                 freeaddrinfo(ai_tcp);
516                                 FD_SET(tcpsock, &sockbits);
517                                 FD_SET(tcpsock, &v4bits);
518                                 maxsock = tcpsock;
519                                 connect_type_cnt++;
520                         }
521                 }
522                 if (rpcbreg == 1) {
523                         memset(&hints, 0, sizeof hints);
524                         hints.ai_flags = AI_PASSIVE;
525                         hints.ai_family = AF_INET;
526                         hints.ai_socktype = SOCK_STREAM;
527                         hints.ai_protocol = IPPROTO_TCP;
528                         ecode = getaddrinfo(NULL, "nfs", &hints,
529                              &ai_tcp);
530                         if (ecode != 0) {
531                                 syslog(LOG_ERR, "getaddrinfo tcp: %s",
532                                    gai_strerror(ecode));
533                                 nfsd_exit(1);
534                         }
535                         nconf_tcp = getnetconfigent("tcp");
536                         if (nconf_tcp == NULL)
537                                 err(1, "getnetconfigent tcp failed");
538                         nb_tcp.buf = ai_tcp->ai_addr;
539                         nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
540                         if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp,
541                             &nb_tcp)) || (!rpcb_set(RPCPROG_NFS, 3,
542                             nconf_tcp, &nb_tcp)))
543                                 err(1, "rpcb_set tcp failed");
544                         freeaddrinfo(ai_tcp);
545                 }
546         }
547
548         /* Set up the socket for tcp6 and rpcb register it. */
549         if (tcpflag && ip6flag) {
550                 rpcbreg = 0;
551                 for (i = 0; i < bindhostc; i++) {
552                         memset(&hints, 0, sizeof hints);
553                         hints.ai_flags = AI_PASSIVE;
554                         hints.ai_family = AF_INET6;
555                         hints.ai_socktype = SOCK_STREAM;
556                         hints.ai_protocol = IPPROTO_TCP;
557                         if (setbindhost(&ai_tcp6, bindhost[i], hints) == 0) {
558                                 rpcbreg = 1;
559                                 rpcbregcnt++;
560                                 if ((tcp6sock = socket(ai_tcp6->ai_family,
561                                     ai_tcp6->ai_socktype,
562                                     ai_tcp6->ai_protocol)) < 0) {
563                                         syslog(LOG_ERR,
564                                             "can't create tcp6 socket");
565                                         nfsd_exit(1);
566                                 }
567                                 if (setsockopt(tcp6sock, SOL_SOCKET,
568                                     SO_REUSEADDR,
569                                     (char *)&on, sizeof(on)) < 0)
570                                         syslog(LOG_ERR,
571                                             "setsockopt SO_REUSEADDR: %m");
572                                 if (setsockopt(tcp6sock, IPPROTO_IPV6,
573                                     IPV6_V6ONLY, &on, sizeof on) < 0) {
574                                         syslog(LOG_ERR,
575                                         "can't set v6-only binding for tcp6 "
576                                             "socket: %m");
577                                         nfsd_exit(1);
578                                 }
579                                 if (bind(tcp6sock, ai_tcp6->ai_addr,
580                                     ai_tcp6->ai_addrlen) < 0) {
581                                         syslog(LOG_ERR,
582                                             "can't bind tcp6 addr %s: %m",
583                                             bindhost[i]);
584                                         nfsd_exit(1);
585                                 }
586                                 if (listen(tcp6sock, 64) < 0) {
587                                         syslog(LOG_ERR, "listen failed");
588                                         nfsd_exit(1);
589                                 }
590                                 freeaddrinfo(ai_tcp6);
591                                 FD_SET(tcp6sock, &sockbits);
592                                 FD_SET(tcp6sock, &v6bits);
593                                 if (maxsock < tcp6sock)
594                                         maxsock = tcp6sock;
595                                 connect_type_cnt++;
596                         }
597                 }
598                 if (rpcbreg == 1) {
599                         memset(&hints, 0, sizeof hints);
600                         hints.ai_flags = AI_PASSIVE;
601                         hints.ai_family = AF_INET6;
602                         hints.ai_socktype = SOCK_STREAM;
603                         hints.ai_protocol = IPPROTO_TCP;
604                         ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
605                         if (ecode != 0) {
606                                 syslog(LOG_ERR, "getaddrinfo tcp6: %s",
607                                    gai_strerror(ecode));
608                                 nfsd_exit(1);
609                         }
610                         nconf_tcp6 = getnetconfigent("tcp6");
611                         if (nconf_tcp6 == NULL)
612                                 err(1, "getnetconfigent tcp6 failed");
613                         nb_tcp6.buf = ai_tcp6->ai_addr;
614                         nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
615                         if ((!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6)) ||
616                             (!rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)))
617                                 err(1, "rpcb_set tcp6 failed");
618                         freeaddrinfo(ai_tcp6);
619                 }
620         }
621
622         if (rpcbregcnt == 0) {
623                 syslog(LOG_ERR, "rpcb_set() failed, nothing to do: %m");
624                 nfsd_exit(1);
625         }
626
627         if (tcpflag && connect_type_cnt == 0) {
628                 syslog(LOG_ERR, "tcp connects == 0, nothing to do: %m");
629                 nfsd_exit(1);
630         }
631
632         setproctitle("master");
633         /*
634          * We always want a master to have a clean way to to shut nfsd down
635          * (with unregistration): if the master is killed, it unregisters and
636          * kills all children. If we run for UDP only (and so do not have to
637          * loop waiting waiting for accept), we instead make the parent
638          * a "server" too. start_server will not return.
639          */
640         if (!tcpflag)
641                 start_server(1);
642
643         /*
644          * Loop forever accepting connections and passing the sockets
645          * into the kernel for the mounts.
646          */
647         for (;;) {
648                 ready = sockbits;
649                 if (connect_type_cnt > 1) {
650                         if (select(maxsock + 1,
651                             &ready, NULL, NULL, NULL) < 1) {
652                                 syslog(LOG_ERR, "select failed: %m");
653                                 if (errno == EINTR)
654                                         continue;
655                                 nfsd_exit(1);
656                         }
657                 }
658                 for (tcpsock = 0; tcpsock <= maxsock; tcpsock++) {
659                         if (FD_ISSET(tcpsock, &ready)) {
660                                 if (FD_ISSET(tcpsock, &v4bits)) {
661                                         len = sizeof(inetpeer);
662                                         if ((msgsock = accept(tcpsock,
663                                             (struct sockaddr *)&inetpeer, &len)) < 0) {
664                                                 syslog(LOG_ERR, "accept failed: %m");
665                                                 if (errno == ECONNABORTED ||
666                                                     errno == EINTR)
667                                                         continue;
668                                                 nfsd_exit(1);
669                                         }
670                                         memset(inetpeer.sin_zero, 0,
671                                                 sizeof(inetpeer.sin_zero));
672                                         if (setsockopt(msgsock, SOL_SOCKET,
673                                             SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
674                                                 syslog(LOG_ERR,
675                                                     "setsockopt SO_KEEPALIVE: %m");
676                                         nfsdargs.sock = msgsock;
677                                         nfsdargs.name = (caddr_t)&inetpeer;
678                                         nfsdargs.namelen = len;
679                                         nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
680                                         close(msgsock);
681                                 } else if (FD_ISSET(tcpsock, &v6bits)) {
682                                         len = sizeof(inet6peer);
683                                         if ((msgsock = accept(tcpsock,
684                                             (struct sockaddr *)&inet6peer,
685                                             &len)) < 0) {
686                                                 syslog(LOG_ERR,
687                                                      "accept failed: %m");
688                                                 if (errno == ECONNABORTED ||
689                                                     errno == EINTR)
690                                                         continue;
691                                                 nfsd_exit(1);
692                                         }
693                                         if (setsockopt(msgsock, SOL_SOCKET,
694                                             SO_KEEPALIVE, (char *)&on,
695                                             sizeof(on)) < 0)
696                                                 syslog(LOG_ERR, "setsockopt "
697                                                     "SO_KEEPALIVE: %m");
698                                         nfsdargs.sock = msgsock;
699                                         nfsdargs.name = (caddr_t)&inet6peer;
700                                         nfsdargs.namelen = len;
701                                         nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
702                                         close(msgsock);
703                                 }
704                         }
705                 }
706         }
707 }
708
709 int
710 setbindhost(struct addrinfo **ai, const char *bindhost, struct addrinfo hints)
711 {
712         int ecode;
713         u_int32_t host_addr[4];  /* IPv4 or IPv6 */
714         const char *hostptr;
715
716         if (bindhost == NULL || strcmp("*", bindhost) == 0)
717                 hostptr = NULL;
718         else
719                 hostptr = bindhost;
720
721         if (hostptr != NULL) {
722                 switch (hints.ai_family) {
723                 case AF_INET:
724                         if (inet_pton(AF_INET, hostptr, host_addr) == 1) {
725                                 hints.ai_flags = AI_NUMERICHOST;
726                         } else {
727                                 if (inet_pton(AF_INET6, hostptr,
728                                     host_addr) == 1)
729                                         return (1);
730                         }
731                         break;
732                 case AF_INET6:
733                         if (inet_pton(AF_INET6, hostptr, host_addr) == 1) {
734                                 hints.ai_flags = AI_NUMERICHOST;
735                         } else {
736                                 if (inet_pton(AF_INET, hostptr,
737                                     host_addr) == 1)
738                                         return (1);
739                         }
740                         break;
741                 default:
742                         break;
743                 }
744         }
745
746         ecode = getaddrinfo(hostptr, "nfs", &hints, ai);
747         if (ecode != 0) {
748                 syslog(LOG_ERR, "getaddrinfo %s: %s", bindhost,
749                     gai_strerror(ecode));
750                 return (1);
751         }
752         return (0);
753 }
754
755 void
756 usage(void)
757 {
758         fprintf(stderr, "usage: nfsd %s\n", USAGE);
759         exit(1);
760 }
761
762 void
763 nonfs(int signo __unused)
764 {
765         syslog(LOG_ERR, "missing system call: NFS not available");
766 }
767
768 void
769 reapchild(int signo __unused)
770 {
771         pid_t pid;
772         int i;
773
774         while ((pid = wait3(NULL, WNOHANG, NULL)) > 0) {
775                 for (i = 0; i < nfsdcnt; i++)
776                         if (pid == children[i])
777                                 children[i] = -1;
778         }
779 }
780
781 void
782 unregistration(void)
783 {
784         if ((!rpcb_unset(RPCPROG_NFS, 2, NULL)) ||
785             (!rpcb_unset(RPCPROG_NFS, 3, NULL)))
786                 syslog(LOG_ERR, "rpcb_unset failed");
787 }
788
789 void
790 killchildren(void)
791 {
792         int i;
793
794         for (i = 0; i < nfsdcnt; i++) {
795                 if (children[i] > 0)
796                         kill(children[i], SIGKILL);
797         }
798 }
799
800 /*
801  * Cleanup master after SIGUSR1.
802  */
803 void
804 cleanup(__unused int signo)
805 {
806         nfsd_exit(0);
807 }
808
809 /*
810  * Cleanup child after SIGUSR1.
811  */
812 void
813 child_cleanup(__unused int signo)
814 {
815         exit(0);
816 }
817
818 void
819 nfsd_exit(int status)
820 {
821         killchildren();
822         unregistration();
823         exit(status);
824 }
825
826 void
827 start_server(int master)
828 {
829         int status;
830
831         status = 0;
832         nsd.nsd_nfsd = NULL;
833         if (nfssvc(NFSSVC_NFSD, &nsd) < 0) {
834                 syslog(LOG_ERR, "nfssvc: %m");
835                 status = 1;
836         }
837         if (master)
838                 nfsd_exit(status);
839         else
840                 exit(status);
841 }