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