xref: /openbsd/usr.sbin/amd/amd/nfs_start.c (revision 898184e3)
1 /*
2  * Copyright (c) 1990 Jan-Simon Pendry
3  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4  * Copyright (c) 1990, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Jan-Simon Pendry at Imperial College, London.
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  *	from: @(#)nfs_start.c	8.1 (Berkeley) 6/6/93
35  *	$Id: nfs_start.c,v 1.15 2004/10/21 20:57:08 millert Exp $
36  */
37 
38 #include "am.h"
39 #include "amq.h"
40 #include <signal.h>
41 #include <unistd.h>
42 #include <setjmp.h>
43 
44 extern jmp_buf select_intr;
45 extern int select_intr_valid;
46 
47 #ifdef HAS_TFS
48 /*
49  * Use replacement for RPC/UDP transport
50  * so that we do NFS gatewaying.
51  */
52 #define	svcudp_create svcudp2_create
53 extern SVCXPRT *svcudp2_create(int);
54 #endif /* HAS_TFS */
55 
56 extern void nfs_program_2();
57 extern void amq_program_1();
58 
59 unsigned short nfs_port;
60 SVCXPRT *nfsxprt, *lnfsxprt;
61 SVCXPRT *amqp, *lamqp;
62 
63 extern int fwd_sock;
64 int max_fds = -1;
65 
66 #ifdef DEBUG
67 /*
68  * Check that we are not burning resources
69  */
70 static void
71 checkup(void)
72 {
73 	static int max_fd = 0;
74 	static char *max_mem = 0;
75 
76 	int next_fd = dup(0);
77 	extern caddr_t sbrk(int);
78 	caddr_t next_mem = sbrk(0);
79 	close(next_fd);
80 
81 	/*if (max_fd < 0) {
82 		max_fd = next_fd;
83 	} else*/ if (max_fd < next_fd) {
84 		dlog("%d new fds allocated; total is %d",
85 			next_fd - max_fd, next_fd);
86 		max_fd = next_fd;
87 	}
88 
89 	/*if (max_mem == 0) {
90 		max_mem = next_mem;
91 	} else*/ if (max_mem < next_mem) {
92 		dlog("%#lx bytes of memory allocated; total is %#lx (%ld pages)",
93 			(unsigned long)(next_mem - max_mem),
94 			(unsigned long)next_mem,
95 			((unsigned long)next_mem+getpagesize()-1)/getpagesize());
96 		max_mem = next_mem;
97 	}
98 }
99 #endif /* DEBUG */
100 
101 static int
102 do_select(sigset_t *mask, sigset_t *omask, int fds, fd_set *fdp,
103     struct timeval *tvp)
104 {
105 	int sig;
106 	int nsel;
107 
108 	if ((sig = setjmp(select_intr))) {
109 		select_intr_valid = 0;
110 		/* Got a signal */
111 		switch (sig) {
112 		case SIGINT:
113 		case SIGTERM:
114 			amd_state = Finishing;
115 			reschedule_timeout_mp();
116 			break;
117 		}
118 		nsel = -1;
119 		errno = EINTR;
120 	} else {
121 		select_intr_valid = 1;
122 		/*
123 		 * Invalidate the current clock value
124 		 */
125 		clock_valid = 0;
126 		/*
127 		 * Allow interrupts.  If a signal
128 		 * occurs, then it will cause a longjmp
129 		 * up above.
130 		 */
131 		sigprocmask(SIG_SETMASK, omask, NULL);
132 		/*
133 		 * Wait for input
134 		 */
135 		nsel = select(fds, fdp, NULL, NULL,
136 		    tvp->tv_sec ? tvp : (struct timeval *) 0);
137 
138 	}
139 
140 	sigprocmask(SIG_BLOCK, mask, NULL);
141 
142 	/*
143 	 * Perhaps reload the cache?
144 	 */
145 	if (do_mapc_reload < clocktime()) {
146 		mapc_reload();
147 		do_mapc_reload = clocktime() + ONE_HOUR;
148 	}
149 	return nsel;
150 }
151 
152 /*
153  * Determine whether anything is left in
154  * the RPC input queue.
155  */
156 static int
157 rpc_pending_now()
158 {
159 	struct timeval tvv;
160 	int nsel;
161 	fd_set *fdsp;
162 	int fdsn;
163 
164 	fdsn = howmany(max_fds+1, NFDBITS) * sizeof(fd_mask);
165 	if ((fdsp = (fd_set *)malloc(fdsn)) == NULL)
166 		return(0);
167 	memset(fdsp, 0, fdsn);
168 	FD_SET(fwd_sock, fdsp);
169 
170 	tvv.tv_sec = tvv.tv_usec = 0;
171 	nsel = select(max_fds+1, fdsp, NULL, NULL, &tvv);
172 	if (nsel < 1) {
173 		free(fdsp);
174 		return(0);
175 	}
176 	if (FD_ISSET(fwd_sock, fdsp)) {
177 		free(fdsp);
178 		return(1);
179 	}
180 	free(fdsp);
181 	return(0);
182 }
183 
184 static serv_state
185 run_rpc(void)
186 {
187 	sigset_t mask, omask;
188 
189 	sigemptyset(&mask);
190 	sigaddset(&mask, SIGINT);
191 	sigaddset(&mask, SIGTERM);
192 	sigaddset(&mask, SIGCHLD);
193 	sigaddset(&mask, SIGHUP);
194 	sigprocmask(SIG_BLOCK, &mask, &omask);
195 
196 	next_softclock = clocktime();
197 
198 	amd_state = Run;
199 
200 	/*
201 	 * Keep on trucking while we are in Run mode.  This state
202 	 * is switched to Quit after all the file systems have
203 	 * been unmounted.
204 	 */
205 	while ((int)amd_state <= (int)Finishing) {
206 		struct timeval tvv;
207 		int nsel;
208 		time_t now;
209 #ifdef RPC_4
210 #ifdef __OpenBSD__
211 		extern int __svc_fdsetsize;
212 		extern fd_set *__svc_fdset;
213 		fd_set *fdsp;
214 		int fdsn = __svc_fdsetsize;
215 		int bytes;
216 
217 		if (fwd_sock > fdsn)
218 			fdsn = fwd_sock;
219 		bytes = howmany(fdsn, NFDBITS) * sizeof(fd_mask);
220 
221 		fdsp = malloc(bytes);
222 		memset(fdsp, 0, bytes);
223 		memcpy(fdsp, __svc_fdset, bytes);
224 		FD_SET(fwd_sock, fdsp);
225 #else
226 		fd_set *fdsp;
227 		int fdsn = FDSETSIZE;
228 		bytes = howmany(fdsn, NFDBITS) * sizeof(fd_mask);
229 		fdsp = malloc(bytes);
230 		memcpy(fdsp, &svc_fdset, bytes);
231 		FD_SET(fwd_sock, fdsp);
232 #endif
233 #else
234 		fd_set readfds;
235 		FD_ZERO(&readfds);
236 		readfds.fds_bits[0] = svc_fds;
237 		FD_SET(fwd_sock, &readfds);
238 #endif /* RPC_4 */
239 
240 #ifdef DEBUG
241 		checkup();
242 #endif /* DEBUG */
243 
244 		/*
245 		 * If the full timeout code is not called,
246 		 * then recompute the time delta manually.
247 		 */
248 		now = clocktime();
249 
250 		if (next_softclock <= now) {
251 			if (amd_state == Finishing)
252 				umount_exported();
253 			tvv.tv_sec = softclock();
254 		} else {
255 			tvv.tv_sec = next_softclock - now;
256 		}
257 		tvv.tv_usec = 0;
258 
259 		if (amd_state == Finishing && last_used_map < 0) {
260 			flush_mntfs();
261 			amd_state = Quit;
262 			break;
263 		}
264 
265 #ifdef DEBUG
266 		if (tvv.tv_sec)
267 			dlog("Select waits for %ds", tvv.tv_sec);
268 		else
269 			dlog("Select waits for Godot");
270 #endif /* DEBUG */
271 
272 		nsel = do_select(&mask, &omask, fdsn + 1, fdsp, &tvv);
273 
274 
275 		switch (nsel) {
276 		case -1:
277 			if (errno == EINTR) {
278 #ifdef DEBUG
279 				dlog("select interrupted");
280 #endif /* DEBUG */
281 				continue;
282 			}
283 			perror("select");
284 			break;
285 
286 		case 0:
287 #ifdef DEBUG
288 			/*dlog("select returned 0");*/
289 #endif /* DEBUG */
290 			break;
291 
292 		default:
293 			/* Read all pending NFS responses at once to avoid
294 			   having responses queue up as a consequence of
295 			   retransmissions. */
296 			if (FD_ISSET(fwd_sock, fdsp)) {
297 				FD_CLR(fwd_sock, fdsp);
298 				--nsel;
299 				do {
300 					fwd_reply();
301 				} while (rpc_pending_now() > 0);
302 			}
303 
304 			if (nsel) {
305 				/*
306 				 * Anything left must be a normal
307 				 * RPC request.
308 				 */
309 #ifdef RPC_4
310 #ifdef __OpenBSD__
311 				svc_getreqset2(fdsp, fdsn);
312 #else
313 				svc_getreqset(fdsp);
314 #endif
315 #else
316 				svc_getreq(readfds.fds_bits[0]);
317 #endif /* RPC_4 */
318 			}
319 			break;
320 		}
321 		free(fdsp);
322 	}
323 
324 	sigprocmask(SIG_SETMASK, &omask, NULL);
325 
326 	if (amd_state == Quit)
327 		amd_state = Done;
328 
329 	return amd_state;
330 }
331 
332 static int
333 bindnfs_port(int so)
334 {
335 	unsigned short port;
336 	int error = bind_resv_port(so, &port);
337 	if (error == 0)
338 		nfs_port = port;
339 	return error;
340 }
341 
342 void
343 unregister_amq(void)
344 {
345 #ifdef DEBUG
346 	Debug(D_AMQ)
347 #endif /* DEBUG */
348 	(void) pmap_unset(AMQ_PROGRAM, AMQ_VERSION);
349 }
350 
351 int
352 mount_automounter(pid_t ppid)
353 {
354 	struct sockaddr_in sin;
355 	int so, so2, nmount;
356 	int sinlen;
357 	int on = 1;
358 
359 	so = socket(AF_INET, SOCK_DGRAM, 0);
360 
361 	if (so < 0 || bindnfs_port(so) < 0) {
362 		perror("Can't create privileged nfs port");
363 		return 1;
364 	}
365 
366 	if ((nfsxprt = svcudp_create(so)) == NULL ||
367 	    (amqp = svcudp_create(so)) == NULL) {
368 		plog(XLOG_FATAL, "cannot create rpc/udp service");
369 		return 2;
370 	}
371 
372 	sinlen = sizeof sin;
373 	if (getsockname(so, (struct sockaddr *)&sin, &sinlen) == -1) {
374 		perror("Can't get information on socket");
375 		return 1;
376 	}
377 
378 	so2 = socket(AF_INET, SOCK_DGRAM, 0);
379 	if (so2 < 0) {
380 		perror("Can't create 2nd socket");
381 		return 1;
382 	}
383 
384 	setsockopt(so2, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on);
385 
386 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
387 	if (bind(so2, (struct sockaddr *)&sin, sizeof sin) == -1) {
388 		perror("Can't bind 2nd socket");
389 		return 1;
390 	}
391 
392 	if ((lnfsxprt = svcudp_create(so2)) == NULL ||
393 	    (lamqp = svcudp_create(so2)) == NULL) {
394 		plog(XLOG_FATAL, "cannot create rpc/udp service");
395 		return 2;
396 	}
397 
398 	if (!svc_register(nfsxprt, NFS_PROGRAM, NFS_VERSION, nfs_program_2, 0)) {
399 		plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)");
400 		return 3;
401 	}
402 
403 	/*
404 	 * Start RPC forwarding
405 	 */
406 	if (fwd_init() != 0)
407 		return 3;
408 
409 	/*
410 	 * One or other of so, fwd_sock
411 	 * must be the highest fd on
412 	 * which to select.
413 	 */
414 	if (so > max_fds)
415 		max_fds = so;
416 	if (so2 > max_fds)
417 		max_fds = so2;
418 	if (fwd_sock > max_fds)
419 		max_fds = fwd_sock;
420 
421 	/*
422 	 * Construct the root automount node
423 	 */
424 	make_root_node();
425 
426 	/*
427 	 * Pick up the pieces from a previous run
428 	 * This is likely to (indirectly) need the rpc_fwd package
429 	 * so it *must* come after the call to fwd_init().
430 	 */
431 	if (restart_existing_mounts)
432 		restart();
433 
434 	/*
435 	 * Mount the top-level auto-mountpoints
436 	 */
437 	nmount = mount_exported();
438 
439 	/*
440 	 * Now safe to tell parent that we are up and running
441 	 */
442 	if (ppid)
443 		kill(ppid, SIGQUIT);
444 
445 	if (nmount == 0) {
446 		plog(XLOG_FATAL, "No work to do - quitting");
447 		amd_state = Done;
448 		return 0;
449 	}
450 
451 #ifdef DEBUG
452 	Debug(D_AMQ) {
453 #endif /* DEBUG */
454 	/*
455 	 * Register with amq
456 	 */
457 	unregister_amq();
458 
459 	if (!svc_register(amqp, AMQ_PROGRAM, AMQ_VERSION, amq_program_1, IPPROTO_UDP)) {
460 		plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM, AMQ_VERSION, udp)");
461 		return 3;
462 	}
463 #ifdef DEBUG
464 	}
465 #endif /* DEBUG */
466 
467 	/*
468 	 * Start timeout_mp rolling
469 	 */
470 	reschedule_timeout_mp();
471 
472 	/*
473 	 * Start the server
474 	 */
475 	if (run_rpc() != Done) {
476 		plog(XLOG_FATAL, "run_rpc failed");
477 		amd_state = Done;
478 	}
479 
480 	return 0;
481 }
482