xref: /original-bsd/usr.sbin/amd/amd/nfs_start.c (revision 05cf3734)
1 /*
2  * $Id: nfs_start.c,v 5.2 90/06/23 22:19:48 jsp Rel $
3  *
4  * Copyright (c) 1990 Jan-Simon Pendry
5  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
6  * Copyright (c) 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * Jan-Simon Pendry at Imperial College, London.
11  *
12  * %sccs.include.redist.c%
13  *
14  *	@(#)nfs_start.c	5.1 (Berkeley) 06/29/90
15  */
16 
17 #include "am.h"
18 #include "amq.h"
19 #include <sys/signal.h>
20 #include <setjmp.h>
21 extern jmp_buf select_intr;
22 extern int select_intr_valid;
23 
24 #ifdef HAS_TFS
25 /*
26  * Use replacement for RPC/UDP transport
27  * so that we do NFS gatewaying.
28  */
29 #define	svcudp_create svcudp2_create
30 extern SVCXPRT *svcudp2_create P((int));
31 #endif /* HAS_TFS */
32 
33 extern void nfs_program_2();
34 extern void amq_program_1();
35 
36 unsigned short nfs_port;
37 SVCXPRT *nfsxprt;
38 
39 extern int fwd_sock;
40 int max_fds = -1;
41 
42 #define	MASKED_SIGS	(sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP))
43 
44 #ifdef DEBUG
45 /*
46  * Check that we are not burning resources
47  */
48 static void checkup(P_void)
49 {
50 
51 static int max_fd = 0;
52 static char *max_mem = 0;
53 
54 	int next_fd = dup(0);
55 	extern caddr_t sbrk P((int));
56 	caddr_t next_mem = sbrk(0);
57 	close(next_fd);
58 
59 	/*if (max_fd < 0) {
60 		max_fd = next_fd;
61 	} else*/ if (max_fd < next_fd) {
62 		dlog("%d new fds allocated; total is %d",
63 			next_fd - max_fd, next_fd);
64 		max_fd = next_fd;
65 	}
66 
67 	/*if (max_mem == 0) {
68 		max_mem = next_mem;
69 	} else*/ if (max_mem < next_mem) {
70 		dlog("%#x bytes of memory allocated; total is %#x (%d pages)",
71 			next_mem - max_mem,
72 			next_mem,
73 			((int)next_mem+getpagesize()-1)/getpagesize());
74 		max_mem = next_mem;
75 	}
76 }
77 #endif /* DEBUG */
78 
79 static int do_select(smask, fds, fdp, tvp)
80 int smask;
81 int fds;
82 int *fdp;
83 struct timeval *tvp;
84 {
85 	int sig;
86 	int nsel;
87 	if (sig = setjmp(select_intr)) {
88 		select_intr_valid = 0;
89 		/* Got a signal */
90 		switch (sig) {
91 		case SIGINT:
92 		case SIGTERM:
93 			amd_state = Finishing;
94 			reschedule_timeout_mp();
95 			break;
96 		}
97 		nsel = -1;
98 		errno = EINTR;
99 	} else {
100 		select_intr_valid = 1;
101 		/*
102 		 * Invalidate the current clock value
103 		 */
104 		clock_valid = 0;
105 		/*
106 		 * Allow interrupts.  If a signal
107 		 * occurs, then it will cause a longjmp
108 		 * up above.
109 		 */
110 		(void) sigsetmask(smask);
111 		/*
112 		 * Wait for input
113 		 */
114 		nsel = select(fds, fdp, (int *) 0, (int *) 0,
115 				tvp->tv_sec ? tvp : (struct timeval *) 0);
116 
117 	}
118 
119 	(void) sigblock(MASKED_SIGS);
120 
121 	/*
122 	 * Perhaps reload the cache?
123 	 */
124 	if (do_mapc_reload < clocktime()) {
125 		mapc_reload();
126 		do_mapc_reload = clocktime() + ONE_HOUR;
127 	}
128 	return nsel;
129 }
130 
131 static serv_state run_rpc(P_void)
132 {
133 	int dtbsz = max_fds + 1;
134 	int smask = sigblock(MASKED_SIGS);
135 
136 	next_softclock = clocktime();
137 
138 	amd_state = Run;
139 
140 	/*
141 	 * Keep on trucking while we are in Run mode.  This state
142 	 * is switched to Quit after all the file systems have
143 	 * been unmounted.
144 	 */
145 	while ((int)amd_state <= (int)Finishing) {
146 		struct timeval tvv;
147 		int nsel;
148 		time_t now;
149 #ifdef RPC_4
150 		fd_set readfds;
151 		readfds = svc_fdset;
152 		FD_SET(fwd_sock, &readfds);
153 #else
154 #ifdef FD_SET
155 		fd_set readfds;
156 		FD_ZERO(&readfds);
157 		readfds.fds_bits[0] = svc_fds;
158 		FD_SET(fwd_sock, &readfds);
159 #else
160 		int readfds = svc_fds | (1 << fwd_sock);
161 #endif /* FD_SET */
162 #endif /* RPC_4 */
163 
164 #ifdef DEBUG
165 		checkup();
166 #endif /* DEBUG */
167 
168 		/*
169 		 * If the full timeout code is not called,
170 		 * then recompute the time delta manually.
171 		 */
172 		now = clocktime();
173 
174 		if (next_softclock <= now) {
175 			if (amd_state == Finishing)
176 				umount_exported();
177 			tvv.tv_sec = softclock();
178 		} else {
179 			tvv.tv_sec = next_softclock - now;
180 		}
181 		tvv.tv_usec = 0;
182 
183 		if (amd_state == Finishing && last_used_map < 0) {
184 			flush_mntfs();
185 			amd_state = Quit;
186 			break;
187 		}
188 
189 #ifdef DEBUG
190 		if (tvv.tv_sec)
191 			dlog("Select waits for %ds", tvv.tv_sec);
192 		else
193 			dlog("Select waits for Godot");
194 #endif /* DEBUG */
195 
196 		nsel = do_select(smask, dtbsz, &readfds, &tvv);
197 
198 
199 		switch (nsel) {
200 		case -1:
201 			if (errno == EINTR) {
202 #ifdef DEBUG
203 				dlog("select interrupted");
204 #endif /* DEBUG */
205 				continue;
206 			}
207 			perror("select");
208 			break;
209 
210 		case 0:
211 #ifdef DEBUG
212 			/*dlog("select returned 0");*/
213 #endif /* DEBUG */
214 			break;
215 
216 		default:
217 #ifdef FD_SET
218 			if (FD_ISSET(fwd_sock, &readfds)) {
219 				FD_CLR(fwd_sock, &readfds);
220 				fwd_reply();
221 				--nsel;
222 			}
223 #else
224 			if (readfds & (1 << fwd_sock)) {
225 				readfds &= ~(1 << fwd_sock);
226 				fwd_reply();
227 				--nsel;
228 			}
229 #endif /* FD_SET */
230 
231 			if (nsel) {
232 				/*
233 				 * Anything left must be a normal
234 				 * RPC request.
235 				 */
236 #ifdef RPC_4
237 				svc_getreqset(&readfds);
238 #else
239 #ifdef FD_SET
240 				svc_getreq(readfds.fds_bits[0]);
241 #else
242 				svc_getreq(readfds);
243 #endif /* FD_SET */
244 #endif /* RPC_4 */
245 			}
246 			break;
247 		}
248 	}
249 
250 	(void) sigsetmask(smask);
251 
252 	if (amd_state == Quit)
253 		amd_state = Done;
254 
255 	return amd_state;
256 }
257 
258 static int bindnfs_port(so)
259 int so;
260 {
261 	unsigned short port;
262 	int error = bind_resv_port(so, &port);
263 	if (error == 0)
264 		nfs_port = port;
265 	return error;
266 }
267 
268 void unregister_amq(P_void)
269 {
270 #ifdef DEBUG
271 	Debug(D_AMQ)
272 #endif /* DEBUG */
273 	(void) pmap_unset(AMQ_PROGRAM, AMQ_VERSION);
274 }
275 
276 int mount_automounter(ppid)
277 int ppid;
278 {
279 	int so = socket(AF_INET, SOCK_DGRAM, 0);
280 	SVCXPRT *amqp;
281 	int nmount;
282 
283 	unregister_amq();
284 
285 	if (so < 0 || bindnfs_port(so) < 0) {
286 		perror("Can't create privileged nfs port");
287 		return 1;
288 	}
289 
290 	if ((nfsxprt = svcudp_create(so)) == NULL ||
291 			(amqp = svcudp_create(so)) == NULL) {
292 		plog(XLOG_FATAL, "cannot create rpc/udp service");
293 		return 2;
294 	}
295 
296 	if (!svc_register(nfsxprt, NFS_PROGRAM, NFS_VERSION, nfs_program_2, 0)) {
297 		plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)");
298 		return 3;
299 	}
300 
301 #ifdef DEBUG
302 	Debug(D_AMQ)
303 #endif /* DEBUG */
304 	if (!svc_register(amqp, AMQ_PROGRAM, AMQ_VERSION, amq_program_1, IPPROTO_UDP)) {
305 		plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM, AMQ_VERSION, udp)");
306 		return 3;
307 	}
308 
309 	/*
310 	 * Start RPC forwarding
311 	 */
312 	if (fwd_init() != 0)
313 		return 3;
314 
315 	/*
316 	 * One or other of so, fwd_sock
317 	 * must be the highest fd on
318 	 * which to select.
319 	 */
320 	if (so > max_fds)
321 		max_fds = so;
322 	if (fwd_sock > max_fds)
323 		max_fds = fwd_sock;
324 
325 	/*
326 	 * Construct the root automount node
327 	 */
328 	make_root_node();
329 
330 	/*
331 	 * Pick up the pieces from a previous run
332 	 * This is likely to (indirectly) need the rpc_fwd package
333 	 * so it *must* come after the call to fwd_init().
334 	 */
335 	if (restart_existing_mounts)
336 		restart();
337 
338 	/*
339 	 * Mount the top-level auto-mountpoints
340 	 */
341 	nmount = mount_exported();
342 
343 	/*
344 	 * Now safe to tell parent that we are up and running
345 	 */
346 	if (ppid)
347 		kill(ppid, SIGQUIT);
348 
349 	if (nmount == 0) {
350 		plog(XLOG_FATAL, "No work to do - quitting");
351 		amd_state = Done;
352 		return 0;
353 	}
354 
355 	/*
356 	 * Start timeout_mp rolling
357 	 */
358 	reschedule_timeout_mp();
359 
360 	/*
361 	 * Start the server
362 	 */
363 	if (run_rpc() != Done) {
364 		plog(XLOG_FATAL, "run_rpc failed");
365 		amd_state = Done;
366 	}
367 
368 	return 0;
369 }
370