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