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 50SVCXPRT *nfsxprt = NULL; 51u_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 */ 61static void 62checkup(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 94static int 95#ifdef HAVE_SIGACTION 96do_select(sigset_t smask, int fds, fd_set *fdp, struct timeval *tvp) 97#else /* not HAVE_SIGACTION */ 98do_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 */ 158static int 159rpc_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 179static serv_state 180run_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 315int 316mount_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} 458