1 /* 2 * $Id: nfs_start.c,v 5.2 90/06/23 22:19:48 jsp Rel $ 3 * 4 * Copyright (c) 1990 Jan-Simon Pendry 5 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 6 * Copyright (c) 1990 The Regents of the University of California. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to Berkeley by 10 * Jan-Simon Pendry at Imperial College, London. 11 * 12 * %sccs.include.redist.c% 13 * 14 * @(#)nfs_start.c 5.1 (Berkeley) 06/29/90 15 */ 16 17 #include "am.h" 18 #include "amq.h" 19 #include <sys/signal.h> 20 #include <setjmp.h> 21 extern jmp_buf select_intr; 22 extern int select_intr_valid; 23 24 #ifdef HAS_TFS 25 /* 26 * Use replacement for RPC/UDP transport 27 * so that we do NFS gatewaying. 28 */ 29 #define svcudp_create svcudp2_create 30 extern SVCXPRT *svcudp2_create P((int)); 31 #endif /* HAS_TFS */ 32 33 extern void nfs_program_2(); 34 extern void amq_program_1(); 35 36 unsigned short nfs_port; 37 SVCXPRT *nfsxprt; 38 39 extern int fwd_sock; 40 int max_fds = -1; 41 42 #define MASKED_SIGS (sigmask(SIGINT)|sigmask(SIGTERM)|sigmask(SIGCHLD)|sigmask(SIGHUP)) 43 44 #ifdef DEBUG 45 /* 46 * Check that we are not burning resources 47 */ 48 static void checkup(P_void) 49 { 50 51 static int max_fd = 0; 52 static char *max_mem = 0; 53 54 int next_fd = dup(0); 55 extern caddr_t sbrk P((int)); 56 caddr_t next_mem = sbrk(0); 57 close(next_fd); 58 59 /*if (max_fd < 0) { 60 max_fd = next_fd; 61 } else*/ if (max_fd < next_fd) { 62 dlog("%d new fds allocated; total is %d", 63 next_fd - max_fd, next_fd); 64 max_fd = next_fd; 65 } 66 67 /*if (max_mem == 0) { 68 max_mem = next_mem; 69 } else*/ if (max_mem < next_mem) { 70 dlog("%#x bytes of memory allocated; total is %#x (%d pages)", 71 next_mem - max_mem, 72 next_mem, 73 ((int)next_mem+getpagesize()-1)/getpagesize()); 74 max_mem = next_mem; 75 } 76 } 77 #endif /* DEBUG */ 78 79 static int do_select(smask, fds, fdp, tvp) 80 int smask; 81 int fds; 82 int *fdp; 83 struct timeval *tvp; 84 { 85 int sig; 86 int nsel; 87 if (sig = setjmp(select_intr)) { 88 select_intr_valid = 0; 89 /* Got a signal */ 90 switch (sig) { 91 case SIGINT: 92 case SIGTERM: 93 amd_state = Finishing; 94 reschedule_timeout_mp(); 95 break; 96 } 97 nsel = -1; 98 errno = EINTR; 99 } else { 100 select_intr_valid = 1; 101 /* 102 * Invalidate the current clock value 103 */ 104 clock_valid = 0; 105 /* 106 * Allow interrupts. If a signal 107 * occurs, then it will cause a longjmp 108 * up above. 109 */ 110 (void) sigsetmask(smask); 111 /* 112 * Wait for input 113 */ 114 nsel = select(fds, fdp, (int *) 0, (int *) 0, 115 tvp->tv_sec ? tvp : (struct timeval *) 0); 116 117 } 118 119 (void) sigblock(MASKED_SIGS); 120 121 /* 122 * Perhaps reload the cache? 123 */ 124 if (do_mapc_reload < clocktime()) { 125 mapc_reload(); 126 do_mapc_reload = clocktime() + ONE_HOUR; 127 } 128 return nsel; 129 } 130 131 static serv_state run_rpc(P_void) 132 { 133 int dtbsz = max_fds + 1; 134 int smask = sigblock(MASKED_SIGS); 135 136 next_softclock = clocktime(); 137 138 amd_state = Run; 139 140 /* 141 * Keep on trucking while we are in Run mode. This state 142 * is switched to Quit after all the file systems have 143 * been unmounted. 144 */ 145 while ((int)amd_state <= (int)Finishing) { 146 struct timeval tvv; 147 int nsel; 148 time_t now; 149 #ifdef RPC_4 150 fd_set readfds; 151 readfds = svc_fdset; 152 FD_SET(fwd_sock, &readfds); 153 #else 154 #ifdef FD_SET 155 fd_set readfds; 156 FD_ZERO(&readfds); 157 readfds.fds_bits[0] = svc_fds; 158 FD_SET(fwd_sock, &readfds); 159 #else 160 int readfds = svc_fds | (1 << fwd_sock); 161 #endif /* FD_SET */ 162 #endif /* RPC_4 */ 163 164 #ifdef DEBUG 165 checkup(); 166 #endif /* DEBUG */ 167 168 /* 169 * If the full timeout code is not called, 170 * then recompute the time delta manually. 171 */ 172 now = clocktime(); 173 174 if (next_softclock <= now) { 175 if (amd_state == Finishing) 176 umount_exported(); 177 tvv.tv_sec = softclock(); 178 } else { 179 tvv.tv_sec = next_softclock - now; 180 } 181 tvv.tv_usec = 0; 182 183 if (amd_state == Finishing && last_used_map < 0) { 184 flush_mntfs(); 185 amd_state = Quit; 186 break; 187 } 188 189 #ifdef DEBUG 190 if (tvv.tv_sec) 191 dlog("Select waits for %ds", tvv.tv_sec); 192 else 193 dlog("Select waits for Godot"); 194 #endif /* DEBUG */ 195 196 nsel = do_select(smask, dtbsz, &readfds, &tvv); 197 198 199 switch (nsel) { 200 case -1: 201 if (errno == EINTR) { 202 #ifdef DEBUG 203 dlog("select interrupted"); 204 #endif /* DEBUG */ 205 continue; 206 } 207 perror("select"); 208 break; 209 210 case 0: 211 #ifdef DEBUG 212 /*dlog("select returned 0");*/ 213 #endif /* DEBUG */ 214 break; 215 216 default: 217 #ifdef FD_SET 218 if (FD_ISSET(fwd_sock, &readfds)) { 219 FD_CLR(fwd_sock, &readfds); 220 fwd_reply(); 221 --nsel; 222 } 223 #else 224 if (readfds & (1 << fwd_sock)) { 225 readfds &= ~(1 << fwd_sock); 226 fwd_reply(); 227 --nsel; 228 } 229 #endif /* FD_SET */ 230 231 if (nsel) { 232 /* 233 * Anything left must be a normal 234 * RPC request. 235 */ 236 #ifdef RPC_4 237 svc_getreqset(&readfds); 238 #else 239 #ifdef FD_SET 240 svc_getreq(readfds.fds_bits[0]); 241 #else 242 svc_getreq(readfds); 243 #endif /* FD_SET */ 244 #endif /* RPC_4 */ 245 } 246 break; 247 } 248 } 249 250 (void) sigsetmask(smask); 251 252 if (amd_state == Quit) 253 amd_state = Done; 254 255 return amd_state; 256 } 257 258 static int bindnfs_port(so) 259 int so; 260 { 261 unsigned short port; 262 int error = bind_resv_port(so, &port); 263 if (error == 0) 264 nfs_port = port; 265 return error; 266 } 267 268 void unregister_amq(P_void) 269 { 270 #ifdef DEBUG 271 Debug(D_AMQ) 272 #endif /* DEBUG */ 273 (void) pmap_unset(AMQ_PROGRAM, AMQ_VERSION); 274 } 275 276 int mount_automounter(ppid) 277 int ppid; 278 { 279 int so = socket(AF_INET, SOCK_DGRAM, 0); 280 SVCXPRT *amqp; 281 int nmount; 282 283 unregister_amq(); 284 285 if (so < 0 || bindnfs_port(so) < 0) { 286 perror("Can't create privileged nfs port"); 287 return 1; 288 } 289 290 if ((nfsxprt = svcudp_create(so)) == NULL || 291 (amqp = svcudp_create(so)) == NULL) { 292 plog(XLOG_FATAL, "cannot create rpc/udp service"); 293 return 2; 294 } 295 296 if (!svc_register(nfsxprt, NFS_PROGRAM, NFS_VERSION, nfs_program_2, 0)) { 297 plog(XLOG_FATAL, "unable to register (NFS_PROGRAM, NFS_VERSION, 0)"); 298 return 3; 299 } 300 301 #ifdef DEBUG 302 Debug(D_AMQ) 303 #endif /* DEBUG */ 304 if (!svc_register(amqp, AMQ_PROGRAM, AMQ_VERSION, amq_program_1, IPPROTO_UDP)) { 305 plog(XLOG_FATAL, "unable to register (AMQ_PROGRAM, AMQ_VERSION, udp)"); 306 return 3; 307 } 308 309 /* 310 * Start RPC forwarding 311 */ 312 if (fwd_init() != 0) 313 return 3; 314 315 /* 316 * One or other of so, fwd_sock 317 * must be the highest fd on 318 * which to select. 319 */ 320 if (so > max_fds) 321 max_fds = so; 322 if (fwd_sock > max_fds) 323 max_fds = fwd_sock; 324 325 /* 326 * Construct the root automount node 327 */ 328 make_root_node(); 329 330 /* 331 * Pick up the pieces from a previous run 332 * This is likely to (indirectly) need the rpc_fwd package 333 * so it *must* come after the call to fwd_init(). 334 */ 335 if (restart_existing_mounts) 336 restart(); 337 338 /* 339 * Mount the top-level auto-mountpoints 340 */ 341 nmount = mount_exported(); 342 343 /* 344 * Now safe to tell parent that we are up and running 345 */ 346 if (ppid) 347 kill(ppid, SIGQUIT); 348 349 if (nmount == 0) { 350 plog(XLOG_FATAL, "No work to do - quitting"); 351 amd_state = Done; 352 return 0; 353 } 354 355 /* 356 * Start timeout_mp rolling 357 */ 358 reschedule_timeout_mp(); 359 360 /* 361 * Start the server 362 */ 363 if (run_rpc() != Done) { 364 plog(XLOG_FATAL, "run_rpc failed"); 365 amd_state = Done; 366 } 367 368 return 0; 369 } 370