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