xref: /netbsd-src/usr.sbin/nfsd/nfsd.c (revision 8b0f9554ff8762542c4defc4f70e1eb76fb508fa)
1 /*	$NetBSD: nfsd.c,v 1.51 2007/07/11 04:59:19 yamt Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1993, 1994
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Rick Macklem at The University of Guelph.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __COPYRIGHT("@(#) Copyright (c) 1989, 1993, 1994\n\
38 	The Regents of the University of California.  All rights reserved.\n");
39 #endif /* not lint */
40 
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)nfsd.c	8.9 (Berkeley) 3/29/95";
44 #else
45 __RCSID("$NetBSD: nfsd.c,v 1.51 2007/07/11 04:59:19 yamt Exp $");
46 #endif
47 #endif /* not lint */
48 
49 #include <sys/param.h>
50 #include <sys/ioctl.h>
51 #include <sys/stat.h>
52 #include <sys/wait.h>
53 #include <sys/uio.h>
54 #include <sys/ucred.h>
55 #include <sys/mount.h>
56 #include <sys/socket.h>
57 #include <sys/socketvar.h>
58 #include <poll.h>
59 
60 #include <rpc/rpc.h>
61 #include <rpc/pmap_clnt.h>
62 #include <rpc/pmap_prot.h>
63 
64 #ifdef ISO
65 #include <netiso/iso.h>
66 #endif
67 #include <nfs/rpcv2.h>
68 #include <nfs/nfsproto.h>
69 #include <nfs/nfs.h>
70 
71 #include <err.h>
72 #include <errno.h>
73 #include <fcntl.h>
74 #include <grp.h>
75 #include <pwd.h>
76 #include <pthread.h>
77 #include <signal.h>
78 #include <stdio.h>
79 #include <stdlib.h>
80 #include <string.h>
81 #include <syslog.h>
82 #include <unistd.h>
83 #include <netdb.h>
84 
85 /* Global defs */
86 #ifdef DEBUG
87 #define	syslog(e, s)	fprintf(stderr,(s))
88 int	debug = 1;
89 #else
90 int	debug = 0;
91 #endif
92 
93 int	main __P((int, char **));
94 void	nonfs __P((int));
95 void	usage __P((void));
96 
97 static void *
98 child(void *dummy)
99 {
100 	struct	nfsd_srvargs nsd;
101 	int nfssvc_flag;
102 
103 	pthread_setname_np(pthread_self(), "slave", NULL);
104 	nfssvc_flag = NFSSVC_NFSD;
105 	memset(&nsd, 0, sizeof(nsd));
106 	while (nfssvc(nfssvc_flag, &nsd) < 0) {
107 		if (errno != ENEEDAUTH) {
108 			syslog(LOG_ERR, "nfssvc: %m");
109 			exit(1);
110 		}
111 		nfssvc_flag = NFSSVC_NFSD | NFSSVC_AUTHINFAIL;
112 	}
113 
114 	return NULL;
115 }
116 
117 /*
118  * Nfs server daemon mostly just a user context for nfssvc()
119  *
120  * 1 - do file descriptor and signal cleanup
121  * 2 - create the nfsd thread(s)
122  * 3 - create server socket(s)
123  * 4 - register socket with portmap
124  *
125  * For connectionless protocols, just pass the socket into the kernel via
126  * nfssvc().
127  * For connection based sockets, loop doing accepts. When you get a new
128  * socket from accept, pass the msgsock into the kernel via nfssvc().
129  * The arguments are:
130  *	-c - support iso cltp clients
131  *	-r - reregister with portmapper
132  *	-t - support tcp nfs clients
133  *	-u - support udp nfs clients
134  * followed by "n" which is the number of nfsd threads to create
135  */
136 int
137 main(argc, argv)
138 	int argc;
139 	char *argv[];
140 {
141 	struct nfsd_args nfsdargs;
142 	struct addrinfo *ai_udp, *ai_tcp, *ai_udp6, *ai_tcp6, hints;
143 	struct netconfig *nconf_udp, *nconf_tcp, *nconf_udp6, *nconf_tcp6;
144 	struct netbuf nb_udp, nb_tcp, nb_udp6, nb_tcp6;
145 	struct sockaddr_in inetpeer;
146 	struct sockaddr_in6 inet6peer;
147 #ifdef ISO
148 	struct sockaddr_iso isoaddr, isopeer;
149 #endif
150 	struct pollfd set[4];
151 	socklen_t len;
152 	int ch, cltpflag, connect_type_cnt, i, maxsock, msgsock;
153 	int nfsdcnt, on = 1, reregister, sock, tcpflag, tcpsock;
154 	int tcp6sock, ip6flag;
155 	int tp4cnt, tp4flag, tpipcnt, tpipflag, udpflag, ecode, s;
156 
157 #define	MAXNFSDCNT	1024
158 #define	DEFNFSDCNT	 4
159 	nfsdcnt = DEFNFSDCNT;
160 	cltpflag = reregister = tcpflag = tp4cnt = tp4flag = tpipcnt = 0;
161 	tpipflag = udpflag = ip6flag = 0;
162 	nconf_udp = nconf_tcp = nconf_udp6 = nconf_tcp6 = NULL;
163 	maxsock = 0;
164 	tcpsock = tcp6sock = -1;
165 #ifdef ISO
166 #define	GETOPT	"6cn:rtu"
167 #define	USAGE	"[-crtu] [-n num_servers]"
168 #else
169 #define	GETOPT	"6n:rtu"
170 #define	USAGE	"[-rtu] [-n num_servers]"
171 #endif
172 	while ((ch = getopt(argc, argv, GETOPT)) != -1) {
173 		switch (ch) {
174 		case '6':
175 			ip6flag = 1;
176 			s = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP);
177 			if (s < 0 && (errno == EPROTONOSUPPORT ||
178 			    errno == EPFNOSUPPORT || errno == EAFNOSUPPORT))
179 				ip6flag = 0;
180 			else
181 				close(s);
182 			break;
183 		case 'n':
184 			nfsdcnt = atoi(optarg);
185 			if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
186 				warnx("nfsd count %d; reset to %d", nfsdcnt, DEFNFSDCNT);
187 				nfsdcnt = DEFNFSDCNT;
188 			}
189 			break;
190 		case 'r':
191 			reregister = 1;
192 			break;
193 		case 't':
194 			tcpflag = 1;
195 			break;
196 		case 'u':
197 			udpflag = 1;
198 			break;
199 #ifdef ISO
200 		case 'c':
201 			cltpflag = 1;
202 			break;
203 #ifdef notyet
204 		case 'i':
205 			tp4cnt = 1;
206 			break;
207 		case 'p':
208 			tpipcnt = 1;
209 			break;
210 #endif /* notyet */
211 #endif /* ISO */
212 		default:
213 		case '?':
214 			usage();
215 		};
216 	}
217 	argv += optind;
218 	argc -= optind;
219 
220 	/*
221 	 * XXX
222 	 * Backward compatibility, trailing number is the count of daemons.
223 	 */
224 	if (argc > 1)
225 		usage();
226 	if (argc == 1) {
227 		nfsdcnt = atoi(argv[0]);
228 		if (nfsdcnt < 1 || nfsdcnt > MAXNFSDCNT) {
229 			warnx("nfsd count %d; reset to %d", nfsdcnt, DEFNFSDCNT);
230 			nfsdcnt = DEFNFSDCNT;
231 		}
232 	}
233 
234 	/*
235 	 * If none of TCP or UDP are specified, default to UDP only.
236 	 */
237 	if (tcpflag == 0 && udpflag == 0)
238 		udpflag = 1;
239 
240 	if (debug == 0) {
241 		daemon(0, 0);
242 		(void)signal(SIGHUP, SIG_IGN);
243 		(void)signal(SIGINT, SIG_IGN);
244 		(void)signal(SIGQUIT, SIG_IGN);
245 		(void)signal(SIGSYS, nonfs);
246 	}
247 
248 	if (udpflag) {
249 		memset(&hints, 0, sizeof hints);
250 		hints.ai_flags = AI_PASSIVE;
251 		hints.ai_family = PF_INET;
252 		hints.ai_socktype = SOCK_DGRAM;
253 		hints.ai_protocol = IPPROTO_UDP;
254 
255 		ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp);
256 		if (ecode != 0) {
257 			syslog(LOG_ERR, "getaddrinfo udp: %s",
258 			    gai_strerror(ecode));
259 			exit(1);
260 		}
261 
262 		nconf_udp = getnetconfigent("udp");
263 
264 		if (nconf_udp == NULL)
265 			err(1, "getnetconfigent udp failed");
266 
267 		nb_udp.buf = ai_udp->ai_addr;
268 		nb_udp.len = nb_udp.maxlen = ai_udp->ai_addrlen;
269 		if (reregister)
270 			if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp))
271 				err(1, "rpcb_set udp failed");
272 	}
273 
274 	if (tcpflag) {
275 		memset(&hints, 0, sizeof hints);
276 		hints.ai_flags = AI_PASSIVE;
277 		hints.ai_family = PF_INET;
278 		hints.ai_socktype = SOCK_STREAM;
279 		hints.ai_protocol = IPPROTO_TCP;
280 
281 		ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp);
282 		if (ecode != 0) {
283 			syslog(LOG_ERR, "getaddrinfo tcp: %s",
284 			    gai_strerror(ecode));
285 			exit(1);
286 		}
287 
288 		nconf_tcp = getnetconfigent("tcp");
289 
290 		if (nconf_tcp == NULL)
291 			err(1, "getnetconfigent tcp failed");
292 
293 		nb_tcp.buf = ai_tcp->ai_addr;
294 		nb_tcp.len = nb_tcp.maxlen = ai_tcp->ai_addrlen;
295 		if (reregister)
296 			if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp))
297 				err(1, "rpcb_set tcp failed");
298 	}
299 
300 	if (udpflag && ip6flag) {
301 		memset(&hints, 0, sizeof hints);
302 		hints.ai_flags = AI_PASSIVE;
303 		hints.ai_family = PF_INET6;
304 		hints.ai_socktype = SOCK_DGRAM;
305 		hints.ai_protocol = IPPROTO_UDP;
306 
307 		ecode = getaddrinfo(NULL, "nfs", &hints, &ai_udp6);
308 		if (ecode != 0) {
309 			syslog(LOG_ERR, "getaddrinfo udp: %s",
310 			    gai_strerror(ecode));
311 			exit(1);
312 		}
313 
314 		nconf_udp6 = getnetconfigent("udp6");
315 
316 		if (nconf_udp6 == NULL)
317 			err(1, "getnetconfigent udp6 failed");
318 
319 		nb_udp6.buf = ai_udp6->ai_addr;
320 		nb_udp6.len = nb_udp6.maxlen = ai_udp6->ai_addrlen;
321 		if (reregister)
322 			if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6))
323 				err(1, "rpcb_set udp6 failed");
324 	}
325 
326 	if (tcpflag && ip6flag) {
327 		memset(&hints, 0, sizeof hints);
328 		hints.ai_flags = AI_PASSIVE;
329 		hints.ai_family = PF_INET6;
330 		hints.ai_socktype = SOCK_STREAM;
331 		hints.ai_protocol = IPPROTO_TCP;
332 
333 		ecode = getaddrinfo(NULL, "nfs", &hints, &ai_tcp6);
334 		if (ecode != 0) {
335 			syslog(LOG_ERR, "getaddrinfo tcp: %s",
336 			    gai_strerror(ecode));
337 			exit(1);
338 		}
339 
340 		nconf_tcp6 = getnetconfigent("tcp6");
341 
342 		if (nconf_tcp6 == NULL)
343 			err(1, "getnetconfigent tcp6 failed");
344 
345 		nb_tcp6.buf = ai_tcp6->ai_addr;
346 		nb_tcp6.len = nb_tcp6.maxlen = ai_tcp6->ai_addrlen;
347 		if (reregister)
348 			if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6))
349 				err(1, "rpcb_set tcp6 failed");
350 	}
351 
352 	openlog("nfsd", LOG_PID, LOG_DAEMON);
353 
354 	for (i = 0; i < nfsdcnt; i++) {
355 		pthread_t t;
356 		int error;
357 
358 		error = pthread_create(&t, NULL, child, NULL);
359 		if (error) {
360 			errno = error;
361 			syslog(LOG_ERR, "pthread_create: %m");
362 			exit (1);
363 		}
364 	}
365 
366 	/* If we are serving udp, set up the socket. */
367 	if (udpflag) {
368 		if ((sock = socket(ai_udp->ai_family, ai_udp->ai_socktype,
369 		    ai_udp->ai_protocol)) < 0) {
370 			syslog(LOG_ERR, "can't create udp socket");
371 			exit(1);
372 		}
373 		if (bind(sock, ai_udp->ai_addr, ai_udp->ai_addrlen) < 0) {
374 			syslog(LOG_ERR, "can't bind udp addr");
375 			exit(1);
376 		}
377 		if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp, &nb_udp) ||
378 		    !rpcb_set(RPCPROG_NFS, 3, nconf_udp, &nb_udp)) {
379 			syslog(LOG_ERR, "can't register with udp portmap");
380 			exit(1);
381 		}
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 			exit(1);
388 		}
389 		(void)close(sock);
390 	}
391 
392 	if (udpflag &&ip6flag) {
393 		if ((sock = socket(ai_udp6->ai_family, ai_udp6->ai_socktype,
394 		    ai_udp6->ai_protocol)) < 0) {
395 			syslog(LOG_ERR, "can't create udp socket");
396 			exit(1);
397 		}
398 		if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
399 		    &on, sizeof on) < 0) {
400 			syslog(LOG_ERR, "can't set v6-only binding for udp6 "
401 					"socket: %m");
402 			exit(1);
403 		}
404 		if (bind(sock, ai_udp6->ai_addr, ai_udp6->ai_addrlen) < 0) {
405 			syslog(LOG_ERR, "can't bind udp addr");
406 			exit(1);
407 		}
408 		if (!rpcb_set(RPCPROG_NFS, 2, nconf_udp6, &nb_udp6) ||
409 		    !rpcb_set(RPCPROG_NFS, 3, nconf_udp6, &nb_udp6)) {
410 			syslog(LOG_ERR, "can't register with udp portmap");
411 			exit(1);
412 		}
413 		nfsdargs.sock = sock;
414 		nfsdargs.name = NULL;
415 		nfsdargs.namelen = 0;
416 		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
417 			syslog(LOG_ERR, "can't add UDP6 socket");
418 			exit(1);
419 		}
420 		(void)close(sock);
421 	}
422 
423 #ifdef ISO
424 	/* If we are serving cltp, set up the socket. */
425 	if (cltpflag) {
426 		if ((sock = socket(AF_ISO, SOCK_DGRAM, 0)) < 0) {
427 			syslog(LOG_ERR, "can't create cltp socket");
428 			exit(1);
429 		}
430 		memset(&isoaddr, 0, sizeof(isoaddr));
431 		isoaddr.siso_family = AF_ISO;
432 		isoaddr.siso_tlen = 2;
433 		cp = TSEL(&isoaddr);
434 		*cp++ = (NFS_PORT >> 8);
435 		*cp = (NFS_PORT & 0xff);
436 		isoaddr.siso_len = sizeof(isoaddr);
437 		if (bind(sock,
438 		    (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
439 			syslog(LOG_ERR, "can't bind cltp addr");
440 			exit(1);
441 		}
442 #ifdef notyet
443 		/*
444 		 * XXX
445 		 * Someday this should probably use "rpcbind", the son of
446 		 * portmap.
447 		 */
448 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_UDP, NFS_PORT)) {
449 			syslog(LOG_ERR, "can't register with udp portmap");
450 			exit(1);
451 		}
452 #endif /* notyet */
453 		nfsdargs.sock = sock;
454 		nfsdargs.name = NULL;
455 		nfsdargs.namelen = 0;
456 		if (nfssvc(NFSSVC_ADDSOCK, &nfsdargs) < 0) {
457 			syslog(LOG_ERR, "can't add UDP socket");
458 			exit(1);
459 		}
460 		close(sock);
461 	}
462 #endif /* ISO */
463 
464 	/* Now set up the master server socket waiting for tcp connections. */
465 	on = 1;
466 	connect_type_cnt = 0;
467 	if (tcpflag) {
468 		if ((tcpsock = socket(ai_tcp->ai_family, ai_tcp->ai_socktype,
469 		    ai_tcp->ai_protocol)) < 0) {
470 			syslog(LOG_ERR, "can't create tcp socket");
471 			exit(1);
472 		}
473 		if (setsockopt(tcpsock,
474 		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
475 			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
476 		if (bind(tcpsock, ai_tcp->ai_addr, ai_tcp->ai_addrlen) < 0) {
477 			syslog(LOG_ERR, "can't bind tcp addr");
478 			exit(1);
479 		}
480 		if (listen(tcpsock, 5) < 0) {
481 			syslog(LOG_ERR, "listen failed");
482 			exit(1);
483 		}
484 		if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp, &nb_tcp) ||
485 		    !rpcb_set(RPCPROG_NFS, 3, nconf_tcp, &nb_tcp)) {
486 			syslog(LOG_ERR, "can't register tcp with rpcbind");
487 			exit(1);
488 		}
489 		set[0].fd = tcpsock;
490 		set[0].events = POLLIN;
491 		connect_type_cnt++;
492 	} else
493 		set[0].fd = -1;
494 
495 	if (tcpflag && ip6flag) {
496 		if ((tcp6sock = socket(ai_tcp6->ai_family, ai_tcp6->ai_socktype,
497 		    ai_tcp6->ai_protocol)) < 0) {
498 			syslog(LOG_ERR, "can't create tcp socket");
499 			exit(1);
500 		}
501 		if (setsockopt(tcp6sock,
502 		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
503 			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
504 		if (setsockopt(tcp6sock, IPPROTO_IPV6, IPV6_V6ONLY,
505 		    &on, sizeof on) < 0) {
506 			syslog(LOG_ERR, "can't set v6-only binding for tcp6 "
507 					"socket: %m");
508 			exit(1);
509 		}
510 		if (bind(tcp6sock, ai_tcp6->ai_addr, ai_tcp6->ai_addrlen) < 0) {
511 			syslog(LOG_ERR, "can't bind tcp6 addr");
512 			exit(1);
513 		}
514 		if (listen(tcp6sock, 5) < 0) {
515 			syslog(LOG_ERR, "listen failed");
516 			exit(1);
517 		}
518 		if (!rpcb_set(RPCPROG_NFS, 2, nconf_tcp6, &nb_tcp6) ||
519 		    !rpcb_set(RPCPROG_NFS, 3, nconf_tcp6, &nb_tcp6)) {
520 			syslog(LOG_ERR, "can't register tcp6 with rpcbind");
521 			exit(1);
522 		}
523 		set[1].fd = tcp6sock;
524 		set[1].events = POLLIN;
525 		connect_type_cnt++;
526 	} else
527 		set[1].fd = -1;
528 
529 #ifdef notyet
530 	/* Now set up the master server socket waiting for tp4 connections. */
531 	if (tp4flag) {
532 		if ((tp4sock = socket(AF_ISO, SOCK_SEQPACKET, 0)) < 0) {
533 			syslog(LOG_ERR, "can't create tp4 socket");
534 			exit(1);
535 		}
536 		if (setsockopt(tp4sock,
537 		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
538 			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
539 		memset(&isoaddr, 0, sizeof(isoaddr));
540 		isoaddr.siso_family = AF_ISO;
541 		isoaddr.siso_tlen = 2;
542 		cp = TSEL(&isoaddr);
543 		*cp++ = (NFS_PORT >> 8);
544 		*cp = (NFS_PORT & 0xff);
545 		isoaddr.siso_len = sizeof(isoaddr);
546 		if (bind(tp4sock,
547 		    (struct sockaddr *)&isoaddr, sizeof(isoaddr)) < 0) {
548 			syslog(LOG_ERR, "can't bind tp4 addr");
549 			exit(1);
550 		}
551 		if (listen(tp4sock, 5) < 0) {
552 			syslog(LOG_ERR, "listen failed");
553 			exit(1);
554 		}
555 		/*
556 		 * XXX
557 		 * Someday this should probably use "rpcbind", the son of
558 		 * portmap.
559 		 */
560 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
561 			syslog(LOG_ERR, "can't register tcp with portmap");
562 			exit(1);
563 		}
564 		set[2].fd = tp4sock;
565 		set[2].events = POLLIN;
566 		connect_type_cnt++;
567 	} else
568 		set[2].fd = -1;
569 
570 	/* Now set up the master server socket waiting for tpip connections. */
571 	if (tpipflag) {
572 		if ((tpipsock = socket(AF_INET, SOCK_SEQPACKET, 0)) < 0) {
573 			syslog(LOG_ERR, "can't create tpip socket");
574 			exit(1);
575 		}
576 		if (setsockopt(tpipsock,
577 		    SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)) < 0)
578 			syslog(LOG_ERR, "setsockopt SO_REUSEADDR: %m");
579 		inetaddr.sin_family = AF_INET;
580 		inetaddr.sin_addr.s_addr = INADDR_ANY;
581 		inetaddr.sin_port = htons(NFS_PORT);
582 		inetaddr.sin_len = sizeof(inetaddr);
583 		memset(inetaddr.sin_zero, 0, sizeof(inetaddr.sin_zero));
584 		if (bind(tpipsock,
585 		    (struct sockaddr *)&inetaddr, sizeof (inetaddr)) < 0) {
586 			syslog(LOG_ERR, "can't bind tcp addr");
587 			exit(1);
588 		}
589 		if (listen(tpipsock, 5) < 0) {
590 			syslog(LOG_ERR, "listen failed");
591 			exit(1);
592 		}
593 		/*
594 		 * XXX
595 		 * Someday this should probably use "rpcbind", the son of
596 		 * portmap.
597 		 */
598 		if (!pmap_set(RPCPROG_NFS, NFS_VER2, IPPROTO_TCP, NFS_PORT)) {
599 			syslog(LOG_ERR, "can't register tcp with portmap");
600 			exit(1);
601 		}
602 		set[3].fd = tpipsock;
603 		set[3].events = POLLIN;
604 		connect_type_cnt++;
605 	} else
606 		set[3].fd = -1;
607 #else
608 	set[2].fd = -1;
609 	set[3].fd = -1;
610 #endif /* notyet */
611 
612 	if (connect_type_cnt == 0)
613 		exit(0);
614 
615 	pthread_setname_np(pthread_self(), "master", NULL);
616 
617 	/*
618 	 * Loop forever accepting connections and passing the sockets
619 	 * into the kernel for the mounts.
620 	 */
621 	for (;;) {
622 		if (poll(set, 4, INFTIM) < 1) {
623 			syslog(LOG_ERR, "poll failed: %m");
624 			exit(1);
625 		}
626 
627 		if (set[0].revents & POLLIN) {
628 			len = sizeof(inetpeer);
629 			if ((msgsock = accept(tcpsock,
630 			    (struct sockaddr *)&inetpeer, &len)) < 0) {
631 				syslog(LOG_ERR, "accept failed: %m");
632 				exit(1);
633 			}
634 			memset(inetpeer.sin_zero, 0, sizeof(inetpeer.sin_zero));
635 			if (setsockopt(msgsock, SOL_SOCKET,
636 			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
637 				syslog(LOG_ERR,
638 				    "setsockopt SO_KEEPALIVE: %m");
639 			nfsdargs.sock = msgsock;
640 			nfsdargs.name = (caddr_t)&inetpeer;
641 			nfsdargs.namelen = sizeof(inetpeer);
642 			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
643 			(void)close(msgsock);
644 		}
645 
646 		if (set[1].revents & POLLIN) {
647 			len = sizeof(inet6peer);
648 			if ((msgsock = accept(tcp6sock,
649 			    (struct sockaddr *)&inet6peer, &len)) < 0) {
650 				syslog(LOG_ERR, "accept failed: %m");
651 				exit(1);
652 			}
653 			if (setsockopt(msgsock, SOL_SOCKET,
654 			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
655 				syslog(LOG_ERR,
656 				    "setsockopt SO_KEEPALIVE: %m");
657 			nfsdargs.sock = msgsock;
658 			nfsdargs.name = (caddr_t)&inet6peer;
659 			nfsdargs.namelen = sizeof(inet6peer);
660 			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
661 			(void)close(msgsock);
662 		}
663 
664 #ifdef notyet
665 		if (set[2].revents & POLLIN) {
666 			len = sizeof(isopeer);
667 			if ((msgsock = accept(tp4sock,
668 			    (struct sockaddr *)&isopeer, &len)) < 0) {
669 				syslog(LOG_ERR, "accept failed: %m");
670 				exit(1);
671 			}
672 			if (setsockopt(msgsock, SOL_SOCKET,
673 			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
674 				syslog(LOG_ERR,
675 				    "setsockopt SO_KEEPALIVE: %m");
676 			nfsdargs.sock = msgsock;
677 			nfsdargs.name = (caddr_t)&isopeer;
678 			nfsdargs.namelen = len;
679 			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
680 			(void)close(msgsock);
681 		}
682 
683 		if (set[3].revents & POLLIN) {
684 			len = sizeof(inetpeer);
685 			if ((msgsock = accept(tpipsock,
686 			    (struct sockaddr *)&inetpeer, &len)) < 0) {
687 				syslog(LOG_ERR, "accept failed: %m");
688 				exit(1);
689 			}
690 			if (setsockopt(msgsock, SOL_SOCKET,
691 			    SO_KEEPALIVE, (char *)&on, sizeof(on)) < 0)
692 				syslog(LOG_ERR, "setsockopt SO_KEEPALIVE: %m");
693 			nfsdargs.sock = msgsock;
694 			nfsdargs.name = (caddr_t)&inetpeer;
695 			nfsdargs.namelen = len;
696 			nfssvc(NFSSVC_ADDSOCK, &nfsdargs);
697 			(void)close(msgsock);
698 		}
699 #endif /* notyet */
700 	}
701 }
702 
703 void
704 usage()
705 {
706 	(void)fprintf(stderr, "usage: nfsd %s\n", USAGE);
707 	exit(1);
708 }
709 
710 void
711 nonfs(signo)
712 	int signo;
713 {
714 	syslog(LOG_ERR, "missing system call: NFS not available.");
715 }
716