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