138494Sobrien/* 2174294Sobrien * Copyright (c) 1997-2006 Erez Zadok 338494Sobrien * Copyright (c) 1990 Jan-Simon Pendry 438494Sobrien * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 538494Sobrien * Copyright (c) 1990 The Regents of the University of California. 638494Sobrien * All rights reserved. 738494Sobrien * 838494Sobrien * This code is derived from software contributed to Berkeley by 938494Sobrien * Jan-Simon Pendry at Imperial College, London. 1038494Sobrien * 1138494Sobrien * Redistribution and use in source and binary forms, with or without 1238494Sobrien * modification, are permitted provided that the following conditions 1338494Sobrien * are met: 1438494Sobrien * 1. Redistributions of source code must retain the above copyright 1538494Sobrien * notice, this list of conditions and the following disclaimer. 1638494Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1738494Sobrien * notice, this list of conditions and the following disclaimer in the 1838494Sobrien * documentation and/or other materials provided with the distribution. 1938494Sobrien * 3. All advertising materials mentioning features or use of this software 2042629Sobrien * must display the following acknowledgment: 2138494Sobrien * This product includes software developed by the University of 2238494Sobrien * California, Berkeley and its contributors. 2338494Sobrien * 4. Neither the name of the University nor the names of its contributors 2438494Sobrien * may be used to endorse or promote products derived from this software 2538494Sobrien * without specific prior written permission. 2638494Sobrien * 2738494Sobrien * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2838494Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2938494Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 3038494Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 3138494Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 3238494Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3338494Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3438494Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3538494Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3638494Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3738494Sobrien * SUCH DAMAGE. 3838494Sobrien * 3938494Sobrien * 40174294Sobrien * File: am-utils/amd/nfs_start.c 4138494Sobrien * 4238494Sobrien */ 4338494Sobrien 4438494Sobrien#ifdef HAVE_CONFIG_H 4538494Sobrien# include <config.h> 4638494Sobrien#endif /* HAVE_CONFIG_H */ 4738494Sobrien#include <am_defs.h> 4838494Sobrien#include <amd.h> 4938494Sobrien 5038494Sobrien#ifndef SELECT_MAXWAIT 5138494Sobrien# define SELECT_MAXWAIT 16 5238494Sobrien#endif /* not SELECT_MAXWAIT */ 5338494Sobrien 54174294SobrienSVCXPRT *nfsxprt = NULL; 55174294Sobrienu_short nfs_port = 0; 5638494Sobrien 5738494Sobrien#ifndef HAVE_SIGACTION 5838494Sobrien# define MASKED_SIGS (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP)) 5938494Sobrien#endif /* not HAVE_SIGACTION */ 6038494Sobrien 6138494Sobrien#ifdef DEBUG 6238494Sobrien/* 6338494Sobrien * Check that we are not burning resources 6438494Sobrien */ 6538494Sobrienstatic void 6638494Sobriencheckup(void) 6738494Sobrien{ 6838494Sobrien 6938494Sobrien static int max_fd = 0; 7038494Sobrien static char *max_mem = 0; 7138494Sobrien 7238494Sobrien int next_fd = dup(0); 7338494Sobrien caddr_t next_mem = sbrk(0); 7438494Sobrien close(next_fd); 7538494Sobrien 7638494Sobrien if (max_fd < next_fd) { 7738494Sobrien dlog("%d new fds allocated; total is %d", 7838494Sobrien next_fd - max_fd, next_fd); 7938494Sobrien max_fd = next_fd; 8038494Sobrien } 8138494Sobrien if (max_mem < next_mem) { 8238494Sobrien#ifdef HAVE_GETPAGESIZE 8351292Sobrien dlog("%#lx bytes of memory allocated; total is %#lx (%ld pages)", 8451292Sobrien (long) (next_mem - max_mem), (unsigned long) next_mem, 85119679Smbr ((long) next_mem + getpagesize() - 1) / (long) getpagesize()); 8638494Sobrien#else /* not HAVE_GETPAGESIZE */ 8751292Sobrien dlog("%#lx bytes of memory allocated; total is %#lx", 8851292Sobrien (long) (next_mem - max_mem), (unsigned long) next_mem); 8938494Sobrien#endif /* not HAVE_GETPAGESIZE */ 9038494Sobrien max_mem = next_mem; 9138494Sobrien 9238494Sobrien } 9338494Sobrien} 94174294Sobrien#else /* not DEBUG */ 95174294Sobrien#define checkup() 96174294Sobrien#endif /* not DEBUG */ 9738494Sobrien 9838494Sobrien 9938494Sobrienstatic int 10038494Sobrien#ifdef HAVE_SIGACTION 10138494Sobriendo_select(sigset_t smask, int fds, fd_set *fdp, struct timeval *tvp) 10238494Sobrien#else /* not HAVE_SIGACTION */ 10338494Sobriendo_select(int smask, int fds, fd_set *fdp, struct timeval *tvp) 10438494Sobrien#endif /* not HAVE_SIGACTION */ 10538494Sobrien{ 10638494Sobrien 10738494Sobrien int sig; 10838494Sobrien int nsel; 10938494Sobrien 11038494Sobrien if ((sig = setjmp(select_intr))) { 11138494Sobrien select_intr_valid = 0; 11238494Sobrien /* Got a signal */ 11338494Sobrien switch (sig) { 11438494Sobrien case SIGINT: 11538494Sobrien case SIGTERM: 11638494Sobrien amd_state = Finishing; 11738494Sobrien reschedule_timeout_mp(); 11838494Sobrien break; 11938494Sobrien } 12038494Sobrien nsel = -1; 12138494Sobrien errno = EINTR; 12238494Sobrien } else { 12338494Sobrien select_intr_valid = 1; 12438494Sobrien /* 12538494Sobrien * Allow interrupts. If a signal 12638494Sobrien * occurs, then it will cause a longjmp 12738494Sobrien * up above. 12838494Sobrien */ 12938494Sobrien#ifdef HAVE_SIGACTION 13038494Sobrien sigprocmask(SIG_SETMASK, &smask, NULL); 13138494Sobrien#else /* not HAVE_SIGACTION */ 13238494Sobrien (void) sigsetmask(smask); 13338494Sobrien#endif /* not HAVE_SIGACTION */ 13438494Sobrien 13538494Sobrien /* 13638494Sobrien * Wait for input 13738494Sobrien */ 13838494Sobrien nsel = select(fds, fdp, (fd_set *) 0, (fd_set *) 0, 13938494Sobrien tvp->tv_sec ? tvp : (struct timeval *) 0); 14038494Sobrien } 14138494Sobrien 14238494Sobrien#ifdef HAVE_SIGACTION 14338494Sobrien sigprocmask(SIG_BLOCK, &masked_sigs, NULL); 14438494Sobrien#else /* not HAVE_SIGACTION */ 14538494Sobrien (void) sigblock(MASKED_SIGS); 14638494Sobrien#endif /* not HAVE_SIGACTION */ 14738494Sobrien 14838494Sobrien /* 14938494Sobrien * Perhaps reload the cache? 15038494Sobrien */ 151174294Sobrien if (do_mapc_reload < clocktime(NULL)) { 15238494Sobrien mapc_reload(); 153174294Sobrien do_mapc_reload = clocktime(NULL) + gopt.map_reload_interval; 15438494Sobrien } 15538494Sobrien return nsel; 15638494Sobrien} 15738494Sobrien 15838494Sobrien 15938494Sobrien/* 16038494Sobrien * Determine whether anything is left in 16138494Sobrien * the RPC input queue. 16238494Sobrien */ 16338494Sobrienstatic int 16438494Sobrienrpc_pending_now(void) 16538494Sobrien{ 16638494Sobrien struct timeval tvv; 16738494Sobrien int nsel; 16838494Sobrien fd_set readfds; 16938494Sobrien 17038494Sobrien FD_ZERO(&readfds); 17138494Sobrien FD_SET(fwd_sock, &readfds); 17238494Sobrien 17338494Sobrien tvv.tv_sec = tvv.tv_usec = 0; 17438494Sobrien nsel = select(FD_SETSIZE, &readfds, (fd_set *) 0, (fd_set *) 0, &tvv); 17538494Sobrien if (nsel < 1) 17638494Sobrien return (0); 17738494Sobrien if (FD_ISSET(fwd_sock, &readfds)) 17838494Sobrien return (1); 17938494Sobrien 18038494Sobrien return (0); 18138494Sobrien} 18238494Sobrien 18338494Sobrien 18438494Sobrienstatic serv_state 18538494Sobrienrun_rpc(void) 18638494Sobrien{ 18738494Sobrien#ifdef HAVE_SIGACTION 18838494Sobrien sigset_t smask; 18938494Sobrien sigprocmask(SIG_BLOCK, &masked_sigs, &smask); 19038494Sobrien#else /* not HAVE_SIGACTION */ 19138494Sobrien int smask = sigblock(MASKED_SIGS); 19238494Sobrien#endif /* not HAVE_SIGACTION */ 19338494Sobrien 194174294Sobrien next_softclock = clocktime(NULL); 19538494Sobrien 19638494Sobrien amd_state = Run; 19738494Sobrien 19838494Sobrien /* 19938494Sobrien * Keep on trucking while we are in Run mode. This state 20038494Sobrien * is switched to Quit after all the file systems have 20138494Sobrien * been unmounted. 20238494Sobrien */ 20338494Sobrien while ((int) amd_state <= (int) Finishing) { 20438494Sobrien struct timeval tvv; 20538494Sobrien int nsel; 20638494Sobrien time_t now; 20738494Sobrien fd_set readfds; 20838494Sobrien 209174294Sobrien#ifdef HAVE_SVC_GETREQSET 21038494Sobrien memmove(&readfds, &svc_fdset, sizeof(svc_fdset)); 21138494Sobrien#else /* not HAVE_SVC_GETREQSET */ 21238494Sobrien FD_ZERO(&readfds); 213174294Sobrien# ifdef HAVE_FD_SET_FDS_BITS 21438494Sobrien readfds.fds_bits[0] = svc_fds; 215174294Sobrien# else /* not HAVE_FD_SET_FDS_BITS */ 216174294Sobrien readfds = svc_fds; 217174294Sobrien# endif /* not HAVE_FD_SET_FDS_BITS */ 218174294Sobrien#endif /* not HAVE_SVC_GETREQSET */ 21938494Sobrien FD_SET(fwd_sock, &readfds); 22038494Sobrien 22138494Sobrien checkup(); 22238494Sobrien 22338494Sobrien /* 22438494Sobrien * If the full timeout code is not called, 22538494Sobrien * then recompute the time delta manually. 22638494Sobrien */ 227174294Sobrien now = clocktime(NULL); 22838494Sobrien 22938494Sobrien if (next_softclock <= now) { 23038494Sobrien if (amd_state == Finishing) 23138494Sobrien umount_exported(); 23238494Sobrien tvv.tv_sec = softclock(); 23338494Sobrien } else { 23438494Sobrien tvv.tv_sec = next_softclock - now; 23538494Sobrien } 23638494Sobrien tvv.tv_usec = 0; 23738494Sobrien 238174294Sobrien if (amd_state == Finishing && get_exported_ap(0) == NULL) { 23938494Sobrien flush_mntfs(); 24038494Sobrien amd_state = Quit; 24138494Sobrien break; 24238494Sobrien } 243174294Sobrien 244174294Sobrien#ifdef HAVE_FS_AUTOFS 245174294Sobrien autofs_add_fdset(&readfds); 246174294Sobrien#endif /* HAVE_FS_AUTOFS */ 247174294Sobrien 24838494Sobrien if (tvv.tv_sec <= 0) 24938494Sobrien tvv.tv_sec = SELECT_MAXWAIT; 25038494Sobrien if (tvv.tv_sec) { 25151292Sobrien dlog("Select waits for %ds", (int) tvv.tv_sec); 25238494Sobrien } else { 25338494Sobrien dlog("Select waits for Godot"); 25438494Sobrien } 25538494Sobrien 25638494Sobrien nsel = do_select(smask, FD_SETSIZE, &readfds, &tvv); 25738494Sobrien 25838494Sobrien switch (nsel) { 25938494Sobrien case -1: 26038494Sobrien if (errno == EINTR) { 26138494Sobrien dlog("select interrupted"); 26238494Sobrien continue; 26338494Sobrien } 264119679Smbr plog(XLOG_ERROR, "select: %m"); 26538494Sobrien break; 26638494Sobrien 26738494Sobrien case 0: 26838494Sobrien break; 26938494Sobrien 27038494Sobrien default: 27138494Sobrien /* 272174294Sobrien * Read all pending NFS responses at once to avoid having responses 27338494Sobrien * queue up as a consequence of retransmissions. 27438494Sobrien */ 27538494Sobrien if (FD_ISSET(fwd_sock, &readfds)) { 27638494Sobrien FD_CLR(fwd_sock, &readfds); 27738494Sobrien --nsel; 27838494Sobrien do { 27938494Sobrien fwd_reply(); 28038494Sobrien } while (rpc_pending_now() > 0); 28138494Sobrien } 28238494Sobrien 283174294Sobrien#ifdef HAVE_FS_AUTOFS 284174294Sobrien if (nsel) 285174294Sobrien nsel = autofs_handle_fdset(&readfds, nsel); 286174294Sobrien#endif /* HAVE_FS_AUTOFS */ 287174294Sobrien 28838494Sobrien if (nsel) { 28938494Sobrien /* 29038494Sobrien * Anything left must be a normal 29138494Sobrien * RPC request. 29238494Sobrien */ 29338494Sobrien#ifdef HAVE_SVC_GETREQSET 29438494Sobrien svc_getreqset(&readfds); 29538494Sobrien#else /* not HAVE_SVC_GETREQSET */ 296174294Sobrien# ifdef HAVE_FD_SET_FDS_BITS 29738494Sobrien svc_getreq(readfds.fds_bits[0]); 298174294Sobrien# else /* not HAVE_FD_SET_FDS_BITS */ 29938494Sobrien svc_getreq(readfds); 300174294Sobrien# endif /* not HAVE_FD_SET_FDS_BITS */ 30138494Sobrien#endif /* not HAVE_SVC_GETREQSET */ 30238494Sobrien } 30338494Sobrien break; 30438494Sobrien } 30538494Sobrien } 30638494Sobrien 30738494Sobrien#ifdef HAVE_SIGACTION 30838494Sobrien sigprocmask(SIG_SETMASK, &smask, NULL); 30938494Sobrien#else /* not HAVE_SIGACTION */ 31038494Sobrien (void) sigsetmask(smask); 31138494Sobrien#endif /* not HAVE_SIGACTION */ 31238494Sobrien 31338494Sobrien if (amd_state == Quit) 31438494Sobrien amd_state = Done; 31538494Sobrien 31638494Sobrien return amd_state; 31738494Sobrien} 31838494Sobrien 31938494Sobrien 32038494Sobrienint 32138494Sobrienmount_automounter(int ppid) 32238494Sobrien{ 32338494Sobrien /* 32438494Sobrien * Old code replaced by rpc-trash patch. 32538494Sobrien * Erez Zadok <ezk@cs.columbia.edu> 32638494Sobrien int so = socket(AF_INET, SOCK_DGRAM, 0); 32738494Sobrien */ 32838494Sobrien SVCXPRT *udp_amqp = NULL, *tcp_amqp = NULL; 32938494Sobrien int nmount, ret; 33038494Sobrien int soNFS; 33138494Sobrien int udp_soAMQ, tcp_soAMQ; 33238494Sobrien struct netconfig *udp_amqncp, *tcp_amqncp; 33338494Sobrien 33438494Sobrien /* 335174294Sobrien * This must be done first, because it attempts to bind 336174294Sobrien * to various UDP ports and we don't want anything else 337174294Sobrien * potentially taking over those ports before we get a chance 338174294Sobrien * to reserve them. 33938494Sobrien */ 340174294Sobrien if (gopt.flags & CFM_RESTART_EXISTING_MOUNTS) 341174294Sobrien restart_automounter_nodes(); 34238494Sobrien 34338494Sobrien /* 34438494Sobrien * Start RPC forwarding 34538494Sobrien */ 34638494Sobrien if (fwd_init() != 0) 34738494Sobrien return 3; 34838494Sobrien 34938494Sobrien /* 35038494Sobrien * Construct the root automount node 35138494Sobrien */ 35238494Sobrien make_root_node(); 35338494Sobrien 35438494Sobrien /* 35538494Sobrien * Pick up the pieces from a previous run 35638494Sobrien * This is likely to (indirectly) need the rpc_fwd package 35738494Sobrien * so it *must* come after the call to fwd_init(). 35838494Sobrien */ 35938494Sobrien if (gopt.flags & CFM_RESTART_EXISTING_MOUNTS) 36038494Sobrien restart(); 36138494Sobrien 36238494Sobrien /* 363174294Sobrien * Create the nfs service for amd 364174294Sobrien * If nfs_port is already initialized, it means we 365174294Sobrien * already created the service during restart_automounter_nodes(). 366174294Sobrien */ 367174294Sobrien if (nfs_port == 0) { 368174294Sobrien ret = create_nfs_service(&soNFS, &nfs_port, &nfsxprt, nfs_program_2); 369174294Sobrien if (ret != 0) 370174294Sobrien return ret; 371174294Sobrien } 372174294Sobrien xsnprintf(pid_fsname, sizeof(pid_fsname), "%s:(pid%ld,port%u)", 373174294Sobrien am_get_hostname(), (long) am_mypid, nfs_port); 374174294Sobrien 375174294Sobrien /* security: if user sets -D amq, don't even create listening socket */ 376174294Sobrien if (!amuDebug(D_AMQ)) { 377174294Sobrien ret = create_amq_service(&udp_soAMQ, 378174294Sobrien &udp_amqp, 379174294Sobrien &udp_amqncp, 380174294Sobrien &tcp_soAMQ, 381174294Sobrien &tcp_amqp, 382174294Sobrien &tcp_amqncp, 383174294Sobrien gopt.preferred_amq_port); 384174294Sobrien if (ret != 0) 385174294Sobrien return ret; 386174294Sobrien } 387174294Sobrien 388174294Sobrien#ifdef HAVE_FS_AUTOFS 389174294Sobrien if (amd_use_autofs) { 390174294Sobrien /* 391174294Sobrien * Create the autofs service for amd. 392174294Sobrien */ 393174294Sobrien ret = create_autofs_service(); 394174294Sobrien /* if autofs service fails it is OK if using a test amd */ 395174294Sobrien if (ret != 0) { 396174294Sobrien plog(XLOG_WARNING, "autofs service registration failed, turning off autofs support"); 397174294Sobrien amd_use_autofs = 0; 398174294Sobrien } 399174294Sobrien } 400174294Sobrien#endif /* HAVE_FS_AUTOFS */ 401174294Sobrien 402174294Sobrien /* 40338494Sobrien * Mount the top-level auto-mountpoints 40438494Sobrien */ 40538494Sobrien nmount = mount_exported(); 40638494Sobrien 40738494Sobrien /* 40838494Sobrien * Now safe to tell parent that we are up and running 40938494Sobrien */ 41038494Sobrien if (ppid) 41138494Sobrien kill(ppid, SIGQUIT); 41238494Sobrien 41338494Sobrien if (nmount == 0) { 41438494Sobrien plog(XLOG_FATAL, "No work to do - quitting"); 41538494Sobrien amd_state = Done; 41638494Sobrien return 0; 41738494Sobrien } 41838494Sobrien 419174294Sobrien if (!amuDebug(D_AMQ)) { 42038494Sobrien /* 42138494Sobrien * Complete registration of amq (first TCP service then UDP) 42238494Sobrien */ 42338494Sobrien unregister_amq(); 42438494Sobrien 425174294Sobrien ret = amu_svc_register(tcp_amqp, get_amd_program_number(), AMQ_VERSION, 426174294Sobrien amq_program_1, IPPROTO_TCP, tcp_amqncp); 42738494Sobrien if (ret != 1) { 42838494Sobrien plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%d, AMQ_VERSION, tcp)", get_amd_program_number()); 42938494Sobrien return 3; 43038494Sobrien } 43138494Sobrien 432174294Sobrien ret = amu_svc_register(udp_amqp, get_amd_program_number(), AMQ_VERSION, 433174294Sobrien amq_program_1, IPPROTO_UDP, udp_amqncp); 43438494Sobrien if (ret != 1) { 43538494Sobrien plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM=%d, AMQ_VERSION, udp)", get_amd_program_number()); 43638494Sobrien return 4; 43738494Sobrien } 43838494Sobrien } 43938494Sobrien 44038494Sobrien /* 44138494Sobrien * Start timeout_mp rolling 44238494Sobrien */ 44338494Sobrien reschedule_timeout_mp(); 44438494Sobrien 44538494Sobrien /* 44638494Sobrien * Start the server 44738494Sobrien */ 44838494Sobrien if (run_rpc() != Done) { 44938494Sobrien plog(XLOG_FATAL, "run_rpc failed"); 45038494Sobrien amd_state = Done; 45138494Sobrien } 45238494Sobrien return 0; 45338494Sobrien} 454