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