1/* $NetBSD$ */ 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 52SVCXPRT *nfsxprt = NULL; 53u_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 */ 63static void 64checkup(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 96static int 97#ifdef HAVE_SIGACTION 98do_select(sigset_t smask, int fds, fd_set *fdp, struct timeval *tvp) 99#else /* not HAVE_SIGACTION */ 100do_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 */ 160static int 161rpc_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 181static serv_state 182run_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 317int 318mount_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