1 /* $NetBSD: nfs_start.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $ */
2
3 /*
4 * Copyright (c) 1997-2014 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
8 * All rights reserved.
9 *
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
12 *
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. Neither the name of the University nor the names of its contributors
22 * may be used to endorse or promote products derived from this software
23 * without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 * SUCH DAMAGE.
36 *
37 *
38 * File: am-utils/amd/nfs_start.c
39 *
40 */
41
42 #ifdef HAVE_CONFIG_H
43 # include <config.h>
44 #endif /* HAVE_CONFIG_H */
45 #include <am_defs.h>
46 #include <amd.h>
47
48 #ifndef SELECT_MAXWAIT
49 # define SELECT_MAXWAIT 16
50 #endif /* not SELECT_MAXWAIT */
51
52 SVCXPRT *nfsxprt = NULL;
53 u_short nfs_port = 0;
54
55 #ifndef HAVE_SIGACTION
56 # define MASKED_SIGS (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP))
57 #endif /* not HAVE_SIGACTION */
58
59 #ifdef DEBUG
60 /*
61 * Check that we are not burning resources
62 */
63 static void
checkup(void)64 checkup(void)
65 {
66 static int max_fd = 0;
67 static char *max_mem = NULL;
68 int next_fd = dup(0);
69 caddr_t next_mem = sbrk(0);
70
71 close(next_fd);
72
73 if (max_fd < next_fd) {
74 dlog("%d new fds allocated; total is %d",
75 next_fd - max_fd, next_fd);
76 max_fd = next_fd;
77 }
78 if (max_mem < next_mem) {
79 #ifdef HAVE_GETPAGESIZE
80 dlog("%#lx bytes of memory allocated; total is %#lx (%ld pages)",
81 (long) (next_mem - max_mem), (unsigned long) next_mem,
82 ((long) next_mem + getpagesize() - 1) / (long) getpagesize());
83 #else /* not HAVE_GETPAGESIZE */
84 dlog("%#lx bytes of memory allocated; total is %#lx",
85 (long) (next_mem - max_mem), (unsigned long) next_mem);
86 #endif /* not HAVE_GETPAGESIZE */
87 max_mem = next_mem;
88
89 }
90 }
91 #else /* not DEBUG */
92 #define checkup()
93 #endif /* not DEBUG */
94
95
96 static int
97 #ifdef HAVE_SIGACTION
do_select(sigset_t smask,int fds,fd_set * fdp,struct timeval * tvp)98 do_select(sigset_t smask, int fds, fd_set *fdp, struct timeval *tvp)
99 #else /* not HAVE_SIGACTION */
100 do_select(int smask, int fds, fd_set *fdp, struct timeval *tvp)
101 #endif /* not HAVE_SIGACTION */
102 {
103
104 int sig;
105 int nsel;
106
107 if ((sig = setjmp(select_intr))) {
108 select_intr_valid = 0;
109 /* Got a signal */
110 switch (sig) {
111 case SIGINT:
112 case SIGTERM:
113 amd_state = Finishing;
114 reschedule_timeout_mp();
115 break;
116 }
117 nsel = -1;
118 errno = EINTR;
119 } else {
120 select_intr_valid = 1;
121 /*
122 * Allow interrupts. If a signal
123 * occurs, then it will cause a longjmp
124 * up above.
125 */
126 #ifdef HAVE_SIGACTION
127 sigprocmask(SIG_SETMASK, &smask, NULL);
128 #else /* not HAVE_SIGACTION */
129 (void) sigsetmask(smask);
130 #endif /* not HAVE_SIGACTION */
131
132 /*
133 * Wait for input
134 */
135 nsel = select(fds, fdp, (fd_set *) NULL, (fd_set *) NULL,
136 tvp->tv_sec ? tvp : (struct timeval *) NULL);
137 }
138
139 #ifdef HAVE_SIGACTION
140 sigprocmask(SIG_BLOCK, &masked_sigs, NULL);
141 #else /* not HAVE_SIGACTION */
142 (void) sigblock(MASKED_SIGS);
143 #endif /* not HAVE_SIGACTION */
144
145 /*
146 * Perhaps reload the cache?
147 */
148 if (do_mapc_reload < clocktime(NULL)) {
149 mapc_reload();
150 do_mapc_reload = clocktime(NULL) + gopt.map_reload_interval;
151 }
152 return nsel;
153 }
154
155
156 /*
157 * Determine whether anything is left in
158 * the RPC input queue.
159 */
160 static int
rpc_pending_now(void)161 rpc_pending_now(void)
162 {
163 struct timeval tvv;
164 int nsel;
165 fd_set readfds;
166
167 FD_ZERO(&readfds);
168 FD_SET(fwd_sock, &readfds);
169
170 tvv.tv_sec = tvv.tv_usec = 0;
171 nsel = select(FD_SETSIZE, &readfds, (fd_set *) NULL, (fd_set *) NULL, &tvv);
172 if (nsel < 1)
173 return (0);
174 if (FD_ISSET(fwd_sock, &readfds))
175 return (1);
176
177 return (0);
178 }
179
180
181 static serv_state
run_rpc(void)182 run_rpc(void)
183 {
184 #ifdef HAVE_SIGACTION
185 sigset_t smask;
186 sigprocmask(SIG_BLOCK, &masked_sigs, &smask);
187 #else /* not HAVE_SIGACTION */
188 int smask = sigblock(MASKED_SIGS);
189 #endif /* not HAVE_SIGACTION */
190
191 next_softclock = clocktime(NULL);
192
193 amd_state = Run;
194
195 /*
196 * Keep on trucking while we are in Run mode. This state
197 * is switched to Quit after all the file systems have
198 * been unmounted.
199 */
200 while ((int) amd_state <= (int) Finishing) {
201 struct timeval tvv;
202 int nsel;
203 time_t now;
204 fd_set readfds;
205
206 #ifdef HAVE_SVC_GETREQSET
207 memmove(&readfds, &svc_fdset, sizeof(svc_fdset));
208 #else /* not HAVE_SVC_GETREQSET */
209 FD_ZERO(&readfds);
210 # ifdef HAVE_FD_SET_FDS_BITS
211 readfds.fds_bits[0] = svc_fds;
212 # else /* not HAVE_FD_SET_FDS_BITS */
213 readfds = svc_fds;
214 # endif /* not HAVE_FD_SET_FDS_BITS */
215 #endif /* not HAVE_SVC_GETREQSET */
216 FD_SET(fwd_sock, &readfds);
217
218 checkup();
219
220 /*
221 * If the full timeout code is not called,
222 * then recompute the time delta manually.
223 */
224 now = clocktime(NULL);
225
226 if (next_softclock <= now) {
227 if (amd_state == Finishing)
228 umount_exported();
229 tvv.tv_sec = softclock();
230 } else {
231 tvv.tv_sec = next_softclock - now;
232 }
233 tvv.tv_usec = 0;
234
235 if (amd_state == Finishing && get_exported_ap(0) == NULL) {
236 flush_mntfs();
237 amd_state = Quit;
238 break;
239 }
240
241 #ifdef HAVE_FS_AUTOFS
242 autofs_add_fdset(&readfds);
243 #endif /* HAVE_FS_AUTOFS */
244
245 if (tvv.tv_sec <= 0)
246 tvv.tv_sec = SELECT_MAXWAIT;
247 if (tvv.tv_sec) {
248 dlog("Select waits for %ds", (int) tvv.tv_sec);
249 } else {
250 dlog("Select waits for Godot");
251 }
252
253 nsel = do_select(smask, FD_SETSIZE, &readfds, &tvv);
254
255 switch (nsel) {
256 case -1:
257 if (errno == EINTR) {
258 dlog("select interrupted");
259 continue;
260 }
261 plog(XLOG_ERROR, "select: %m");
262 break;
263
264 case 0:
265 break;
266
267 default:
268 /*
269 * Read all pending NFS responses at once to avoid having responses
270 * queue up as a consequence of retransmissions.
271 */
272 if (FD_ISSET(fwd_sock, &readfds)) {
273 FD_CLR(fwd_sock, &readfds);
274 --nsel;
275 do {
276 fwd_reply();
277 } while (rpc_pending_now() > 0);
278 }
279
280 #ifdef HAVE_FS_AUTOFS
281 if (nsel)
282 nsel = autofs_handle_fdset(&readfds, nsel);
283 #endif /* HAVE_FS_AUTOFS */
284
285 if (nsel) {
286 /*
287 * Anything left must be a normal
288 * RPC request.
289 */
290 #ifdef HAVE_SVC_GETREQSET
291 svc_getreqset(&readfds);
292 #else /* not HAVE_SVC_GETREQSET */
293 # ifdef HAVE_FD_SET_FDS_BITS
294 svc_getreq(readfds.fds_bits[0]);
295 # else /* not HAVE_FD_SET_FDS_BITS */
296 svc_getreq(readfds);
297 # endif /* not HAVE_FD_SET_FDS_BITS */
298 #endif /* not HAVE_SVC_GETREQSET */
299 }
300 break;
301 }
302 }
303
304 #ifdef HAVE_SIGACTION
305 sigprocmask(SIG_SETMASK, &smask, NULL);
306 #else /* not HAVE_SIGACTION */
307 (void) sigsetmask(smask);
308 #endif /* not HAVE_SIGACTION */
309
310 if (amd_state == Quit)
311 amd_state = Done;
312
313 return amd_state;
314 }
315
316
317 int
mount_automounter(int ppid)318 mount_automounter(int ppid)
319 {
320 /*
321 * Old code replaced by rpc-trash patch.
322 * Erez Zadok <ezk@cs.columbia.edu>
323 int so = socket(AF_INET, SOCK_DGRAM, 0);
324 */
325 SVCXPRT *udp_amqp = NULL, *tcp_amqp = NULL;
326 int nmount, ret;
327 int soNFS;
328 int udp_soAMQ, tcp_soAMQ;
329 struct netconfig *udp_amqncp, *tcp_amqncp;
330
331 /*
332 * This must be done first, because it attempts to bind
333 * to various UDP ports and we don't want anything else
334 * potentially taking over those ports before we get a chance
335 * to reserve them.
336 */
337 if (gopt.flags & CFM_RESTART_EXISTING_MOUNTS)
338 restart_automounter_nodes();
339
340 /*
341 * Start RPC forwarding
342 */
343 if (fwd_init() != 0)
344 return 3;
345
346 /*
347 * Construct the root automount node
348 */
349 make_root_node();
350
351 /*
352 * Pick up the pieces from a previous run
353 * This is likely to (indirectly) need the rpc_fwd package
354 * so it *must* come after the call to fwd_init().
355 */
356 if (gopt.flags & CFM_RESTART_EXISTING_MOUNTS)
357 restart();
358
359 /*
360 * Create the nfs service for amd
361 * If nfs_port is already initialized, it means we
362 * already created the service during restart_automounter_nodes().
363 */
364 if (nfs_port == 0) {
365 ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_dispatcher,
366 get_nfs_dispatcher_version(nfs_dispatcher));
367 if (ret != 0)
368 return ret;
369 }
370 xsnprintf(pid_fsname, sizeof(pid_fsname), "%s:(pid%ld,port%u)",
371 am_get_hostname(), (long) am_mypid, nfs_port);
372
373 /* security: if user sets -D noamq, don't even create listening socket */
374 if (amuDebug(D_AMQ)) {
375 ret = create_amq_service(&udp_soAMQ,
376 &udp_amqp,
377 &udp_amqncp,
378 &tcp_soAMQ,
379 &tcp_amqp,
380 &tcp_amqncp,
381 gopt.preferred_amq_port);
382 if (ret != 0)
383 return ret;
384 }
385
386 #ifdef HAVE_FS_AUTOFS
387 if (amd_use_autofs) {
388 /*
389 * Create the autofs service for amd.
390 */
391 ret = create_autofs_service();
392 /* if autofs service fails it is OK if using a test amd */
393 if (ret != 0) {
394 plog(XLOG_WARNING, "autofs service registration failed, turning off autofs support");
395 amd_use_autofs = 0;
396 }
397 }
398 #endif /* HAVE_FS_AUTOFS */
399
400 /*
401 * Mount the top-level auto-mountpoints
402 */
403 nmount = mount_exported();
404
405 /*
406 * Now safe to tell parent that we are up and running
407 */
408 if (ppid)
409 kill(ppid, SIGQUIT);
410
411 if (nmount == 0) {
412 plog(XLOG_FATAL, "No work to do - quitting");
413 amd_state = Done;
414 return 0;
415 }
416
417 if (amuDebug(D_AMQ)) {
418 /*
419 * Complete registration of amq (first TCP service then UDP)
420 */
421 int tcp_ok = 0, udp_ok = 0;
422
423 unregister_amq(); /* unregister leftover Amd, if any, just in case */
424
425 tcp_ok = amu_svc_register(tcp_amqp, get_amd_program_number(), AMQ_VERSION,
426 amq_program_1, IPPROTO_TCP, tcp_amqncp);
427 if (!tcp_ok)
428 plog(XLOG_FATAL,
429 "unable to register (AMQ_PROGRAM=%lu, AMQ_VERSION, tcp)",
430 get_amd_program_number());
431
432 udp_ok = amu_svc_register(udp_amqp, get_amd_program_number(), AMQ_VERSION,
433 amq_program_1, IPPROTO_UDP, udp_amqncp);
434 if (!udp_ok)
435 plog(XLOG_FATAL,
436 "unable to register (AMQ_PROGRAM=%lu, AMQ_VERSION, udp)",
437 get_amd_program_number());
438
439 /* return error only if both failed */
440 if (!tcp_ok && !udp_ok) {
441 amd_state = Done;
442 return 3;
443 }
444 }
445
446 /*
447 * Start timeout_mp rolling
448 */
449 reschedule_timeout_mp();
450
451 /*
452 * Start the server
453 */
454 if (run_rpc() != Done) {
455 plog(XLOG_FATAL, "run_rpc failed");
456 amd_state = Done;
457 }
458 return 0;
459 }
460