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