1 /* 2 * Copyright (c) 1990 Jan-Simon Pendry 3 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 4 * Copyright (c) 1990, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Jan-Simon Pendry at Imperial College, London. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 * 34 * from: @(#)nfs_start.c 8.1 (Berkeley) 6/6/93 35 * $Id: nfs_start.c,v 1.15 2004/10/21 20:57:08 millert Exp $ 36 */ 37 38 #include "am.h" 39 #include "amq.h" 40 #include <signal.h> 41 #include <unistd.h> 42 #include <setjmp.h> 43 44 extern jmp_buf select_intr; 45 extern int select_intr_valid; 46 47 #ifdef HAS_TFS 48 /* 49 * Use replacement for RPC/UDP transport 50 * so that we do NFS gatewaying. 51 */ 52 #define svcudp_create svcudp2_create 53 extern SVCXPRT *svcudp2_create(int); 54 #endif /* HAS_TFS */ 55 56 extern void nfs_program_2(); 57 extern void amq_program_1(); 58 59 unsigned short nfs_port; 60 SVCXPRT *nfsxprt, *lnfsxprt; 61 SVCXPRT *amqp, *lamqp; 62 63 extern int fwd_sock; 64 int max_fds = -1; 65 66 #ifdef DEBUG 67 /* 68 * Check that we are not burning resources 69 */ 70 static void 71 checkup(void) 72 { 73 static int max_fd = 0; 74 static char *max_mem = 0; 75 76 int next_fd = dup(0); 77 extern caddr_t sbrk(int); 78 caddr_t next_mem = sbrk(0); 79 close(next_fd); 80 81 /*if (max_fd < 0) { 82 max_fd = next_fd; 83 } else*/ if (max_fd < next_fd) { 84 dlog("%d new fds allocated; total is %d", 85 next_fd - max_fd, next_fd); 86 max_fd = next_fd; 87 } 88 89 /*if (max_mem == 0) { 90 max_mem = next_mem; 91 } else*/ if (max_mem < next_mem) { 92 dlog("%#lx bytes of memory allocated; total is %#lx (%ld pages)", 93 (unsigned long)(next_mem - max_mem), 94 (unsigned long)next_mem, 95 ((unsigned long)next_mem+getpagesize()-1)/getpagesize()); 96 max_mem = next_mem; 97 } 98 } 99 #endif /* DEBUG */ 100 101 static int 102 do_select(sigset_t *mask, sigset_t *omask, int fds, fd_set *fdp, 103 struct timeval *tvp) 104 { 105 int sig; 106 int nsel; 107 108 if ((sig = setjmp(select_intr))) { 109 select_intr_valid = 0; 110 /* Got a signal */ 111 switch (sig) { 112 case SIGINT: 113 case SIGTERM: 114 amd_state = Finishing; 115 reschedule_timeout_mp(); 116 break; 117 } 118 nsel = -1; 119 errno = EINTR; 120 } else { 121 select_intr_valid = 1; 122 /* 123 * Invalidate the current clock value 124 */ 125 clock_valid = 0; 126 /* 127 * Allow interrupts. If a signal 128 * occurs, then it will cause a longjmp 129 * up above. 130 */ 131 sigprocmask(SIG_SETMASK, omask, NULL); 132 /* 133 * Wait for input 134 */ 135 nsel = select(fds, fdp, NULL, NULL, 136 tvp->tv_sec ? tvp : (struct timeval *) 0); 137 138 } 139 140 sigprocmask(SIG_BLOCK, mask, NULL); 141 142 /* 143 * Perhaps reload the cache? 144 */ 145 if (do_mapc_reload < clocktime()) { 146 mapc_reload(); 147 do_mapc_reload = clocktime() + ONE_HOUR; 148 } 149 return nsel; 150 } 151 152 /* 153 * Determine whether anything is left in 154 * the RPC input queue. 155 */ 156 static int 157 rpc_pending_now() 158 { 159 struct timeval tvv; 160 int nsel; 161 fd_set *fdsp; 162 int fdsn; 163 164 fdsn = howmany(max_fds+1, NFDBITS) * sizeof(fd_mask); 165 if ((fdsp = (fd_set *)malloc(fdsn)) == NULL) 166 return(0); 167 memset(fdsp, 0, fdsn); 168 FD_SET(fwd_sock, fdsp); 169 170 tvv.tv_sec = tvv.tv_usec = 0; 171 nsel = select(max_fds+1, fdsp, NULL, NULL, &tvv); 172 if (nsel < 1) { 173 free(fdsp); 174 return(0); 175 } 176 if (FD_ISSET(fwd_sock, fdsp)) { 177 free(fdsp); 178 return(1); 179 } 180 free(fdsp); 181 return(0); 182 } 183 184 static serv_state 185 run_rpc(void) 186 { 187 sigset_t mask, omask; 188 189 sigemptyset(&mask); 190 sigaddset(&mask, SIGINT); 191 sigaddset(&mask, SIGTERM); 192 sigaddset(&mask, SIGCHLD); 193 sigaddset(&mask, SIGHUP); 194 sigprocmask(SIG_BLOCK, &mask, &omask); 195 196 next_softclock = clocktime(); 197 198 amd_state = Run; 199 200 /* 201 * Keep on trucking while we are in Run mode. This state 202 * is switched to Quit after all the file systems have 203 * been unmounted. 204 */ 205 while ((int)amd_state <= (int)Finishing) { 206 struct timeval tvv; 207 int nsel; 208 time_t now; 209 #ifdef RPC_4 210 #ifdef __OpenBSD__ 211 extern int __svc_fdsetsize; 212 extern fd_set *__svc_fdset; 213 fd_set *fdsp; 214 int fdsn = __svc_fdsetsize; 215 int bytes; 216 217 if (fwd_sock > fdsn) 218 fdsn = fwd_sock; 219 bytes = howmany(fdsn, NFDBITS) * sizeof(fd_mask); 220 221 fdsp = malloc(bytes); 222 memset(fdsp, 0, bytes); 223 memcpy(fdsp, __svc_fdset, bytes); 224 FD_SET(fwd_sock, fdsp); 225 #else 226 fd_set *fdsp; 227 int fdsn = FDSETSIZE; 228 bytes = howmany(fdsn, NFDBITS) * sizeof(fd_mask); 229 fdsp = malloc(bytes); 230 memcpy(fdsp, &svc_fdset, bytes); 231 FD_SET(fwd_sock, fdsp); 232 #endif 233 #else 234 fd_set readfds; 235 FD_ZERO(&readfds); 236 readfds.fds_bits[0] = svc_fds; 237 FD_SET(fwd_sock, &readfds); 238 #endif /* RPC_4 */ 239 240 #ifdef DEBUG 241 checkup(); 242 #endif /* DEBUG */ 243 244 /* 245 * If the full timeout code is not called, 246 * then recompute the time delta manually. 247 */ 248 now = clocktime(); 249 250 if (next_softclock <= now) { 251 if (amd_state == Finishing) 252 umount_exported(); 253 tvv.tv_sec = softclock(); 254 } else { 255 tvv.tv_sec = next_softclock - now; 256 } 257 tvv.tv_usec = 0; 258 259 if (amd_state == Finishing && last_used_map < 0) { 260 flush_mntfs(); 261 amd_state = Quit; 262 break; 263 } 264 265 #ifdef DEBUG 266 if (tvv.tv_sec) 267 dlog("Select waits for %ds", tvv.tv_sec); 268 else 269 dlog("Select waits for Godot"); 270 #endif /* DEBUG */ 271 272 nsel = do_select(&mask, &omask, fdsn + 1, fdsp, &tvv); 273 274 275 switch (nsel) { 276 case -1: 277 if (errno == EINTR) { 278 #ifdef DEBUG 279 dlog("select interrupted"); 280 #endif /* DEBUG */ 281 continue; 282 } 283 perror("select"); 284 break; 285 286 case 0: 287 #ifdef DEBUG 288 /*dlog("select returned 0");*/ 289 #endif /* DEBUG */ 290 break; 291 292 default: 293 /* Read all pending NFS responses at once to avoid 294 having responses queue up as a consequence of 295 retransmissions. */ 296 if (FD_ISSET(fwd_sock, fdsp)) { 297 FD_CLR(fwd_sock, fdsp); 298 --nsel; 299 do { 300 fwd_reply(); 301 } while (rpc_pending_now() > 0); 302 } 303 304 if (nsel) { 305 /* 306 * Anything left must be a normal 307 * RPC request. 308 */ 309 #ifdef RPC_4 310 #ifdef __OpenBSD__ 311 svc_getreqset2(fdsp, fdsn); 312 #else 313 svc_getreqset(fdsp); 314 #endif 315 #else 316 svc_getreq(readfds.fds_bits[0]); 317 #endif /* RPC_4 */ 318 } 319 break; 320 } 321 free(fdsp); 322 } 323 324 sigprocmask(SIG_SETMASK, &omask, NULL); 325 326 if (amd_state == Quit) 327 amd_state = Done; 328 329 return amd_state; 330 } 331 332 static int 333 bindnfs_port(int so) 334 { 335 unsigned short port; 336 int error = bind_resv_port(so, &port); 337 if (error == 0) 338 nfs_port = port; 339 return error; 340 } 341 342 void 343 unregister_amq(void) 344 { 345 #ifdef DEBUG 346 Debug(D_AMQ) 347 #endif /* DEBUG */ 348 (void) pmap_unset(AMQ_PROGRAM, AMQ_VERSION); 349 } 350 351 int 352 mount_automounter(pid_t ppid) 353 { 354 struct sockaddr_in sin; 355 int so, so2, nmount; 356 int sinlen; 357 int on = 1; 358 359 so = socket(AF_INET, SOCK_DGRAM, 0); 360 361 if (so < 0 || bindnfs_port(so) < 0) { 362 perror("Can't create privileged nfs port"); 363 return 1; 364 } 365 366 if ((nfsxprt = svcudp_create(so)) == NULL || 367 (amqp = svcudp_create(so)) == NULL) { 368 plog(XLOG_FATAL, "cannot create rpc/udp service"); 369 return 2; 370 } 371 372 sinlen = sizeof sin; 373 if (getsockname(so, (struct sockaddr *)&sin, &sinlen) == -1) { 374 perror("Can't get information on socket"); 375 return 1; 376 } 377 378 so2 = socket(AF_INET, SOCK_DGRAM, 0); 379 if (so2 < 0) { 380 perror("Can't create 2nd socket"); 381 return 1; 382 } 383 384 setsockopt(so2, SOL_SOCKET, SO_REUSEADDR, &on, sizeof on); 385 386 sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 387 if (bind(so2, (struct sockaddr *)&sin, sizeof sin) == -1) { 388 perror("Can't bind 2nd socket"); 389 return 1; 390 } 391 392 if ((lnfsxprt = svcudp_create(so2)) == NULL || 393 (lamqp = svcudp_create(so2)) == NULL) { 394 plog(XLOG_FATAL, "cannot create rpc/udp service"); 395 return 2; 396 } 397 398 if (!svc_register(nfsxprt, NFS_PROGRAM, NFS_VERSION, nfs_program_2, 0)) { 399 plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)"); 400 return 3; 401 } 402 403 /* 404 * Start RPC forwarding 405 */ 406 if (fwd_init() != 0) 407 return 3; 408 409 /* 410 * One or other of so, fwd_sock 411 * must be the highest fd on 412 * which to select. 413 */ 414 if (so > max_fds) 415 max_fds = so; 416 if (so2 > max_fds) 417 max_fds = so2; 418 if (fwd_sock > max_fds) 419 max_fds = fwd_sock; 420 421 /* 422 * Construct the root automount node 423 */ 424 make_root_node(); 425 426 /* 427 * Pick up the pieces from a previous run 428 * This is likely to (indirectly) need the rpc_fwd package 429 * so it *must* come after the call to fwd_init(). 430 */ 431 if (restart_existing_mounts) 432 restart(); 433 434 /* 435 * Mount the top-level auto-mountpoints 436 */ 437 nmount = mount_exported(); 438 439 /* 440 * Now safe to tell parent that we are up and running 441 */ 442 if (ppid) 443 kill(ppid, SIGQUIT); 444 445 if (nmount == 0) { 446 plog(XLOG_FATAL, "No work to do - quitting"); 447 amd_state = Done; 448 return 0; 449 } 450 451 #ifdef DEBUG 452 Debug(D_AMQ) { 453 #endif /* DEBUG */ 454 /* 455 * Register with amq 456 */ 457 unregister_amq(); 458 459 if (!svc_register(amqp, AMQ_PROGRAM, AMQ_VERSION, amq_program_1, IPPROTO_UDP)) { 460 plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM, AMQ_VERSION, udp)"); 461 return 3; 462 } 463 #ifdef DEBUG 464 } 465 #endif /* DEBUG */ 466 467 /* 468 * Start timeout_mp rolling 469 */ 470 reschedule_timeout_mp(); 471 472 /* 473 * Start the server 474 */ 475 if (run_rpc() != Done) { 476 plog(XLOG_FATAL, "run_rpc failed"); 477 amd_state = Done; 478 } 479 480 return 0; 481 } 482