1 /* $NetBSD: autil.c,v 1.1.1.3 2015/01/17 16:34:15 christos Exp $ */ 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/autil.c 39 * 40 */ 41 42 /* 43 * utilities specified to amd, taken out of the older amd/util.c. 44 */ 45 46 #ifdef HAVE_CONFIG_H 47 # include <config.h> 48 #endif /* HAVE_CONFIG_H */ 49 #include <am_defs.h> 50 #include <amd.h> 51 52 int NumChildren = 0; /* number of children of primary amd */ 53 static char invalid_keys[] = "\"'!;@ \t\n"; 54 55 /**************************************************************************** 56 *** MACROS *** 57 ****************************************************************************/ 58 59 #ifdef HAVE_TRANSPORT_TYPE_TLI 60 # define PARENT_USLEEP_TIME 100000 /* 0.1 seconds */ 61 #endif /* HAVE_TRANSPORT_TYPE_TLI */ 62 63 64 /**************************************************************************** 65 *** FORWARD DEFINITIONS *** 66 ****************************************************************************/ 67 static void domain_strip(char *otherdom, char *localdom); 68 static int dofork(void); 69 70 71 /**************************************************************************** 72 *** FUNCTIONS *** 73 ****************************************************************************/ 74 75 /* 76 * Copy s into p, reallocating p if necessary 77 */ 78 char * 79 strealloc(char *p, char *s) 80 { 81 size_t len = strlen(s) + 1; 82 83 p = (char *) xrealloc((voidp) p, len); 84 85 xstrlcpy(p, s, len); 86 #ifdef DEBUG_MEM 87 # if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) 88 malloc_verify(); 89 # endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */ 90 #endif /* DEBUG_MEM */ 91 return p; 92 } 93 94 95 /* 96 * Strip off the trailing part of a domain 97 * to produce a short-form domain relative 98 * to the local host domain. 99 * Note that this has no effect if the domain 100 * names do not have the same number of 101 * components. If that restriction proves 102 * to be a problem then the loop needs recoding 103 * to skip from right to left and do partial 104 * matches along the way -- ie more expensive. 105 */ 106 static void 107 domain_strip(char *otherdom, char *localdom) 108 { 109 char *p1, *p2; 110 111 if ((p1 = strchr(otherdom, '.')) && 112 (p2 = strchr(localdom, '.')) && 113 STREQ(p1 + 1, p2 + 1)) 114 *p1 = '\0'; 115 } 116 117 118 /* 119 * Normalize a host name: replace cnames with real names, and decide if to 120 * strip domain name or not. 121 */ 122 void 123 host_normalize(char **chp) 124 { 125 /* 126 * Normalize hosts is used to resolve host name aliases 127 * and replace them with the standard-form name. 128 * Invoked with "-n" command line option. 129 */ 130 if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) { 131 struct hostent *hp; 132 hp = gethostbyname(*chp); 133 if (hp && hp->h_addrtype == AF_INET) { 134 dlog("Hostname %s normalized to %s", *chp, hp->h_name); 135 *chp = strealloc(*chp, (char *) hp->h_name); 136 } 137 } 138 if (gopt.flags & CFM_DOMAIN_STRIP) { 139 domain_strip(*chp, hostd); 140 } 141 } 142 143 144 /* 145 * Keys are not allowed to contain " ' ! or ; to avoid 146 * problems with macro expansions. 147 */ 148 int 149 valid_key(char *key) 150 { 151 while (*key) 152 if (strchr(invalid_keys, *key++)) 153 return FALSE; 154 return TRUE; 155 } 156 157 158 void 159 forcibly_timeout_mp(am_node *mp) 160 { 161 mntfs *mf = mp->am_al->al_mnt; 162 /* 163 * Arrange to timeout this node 164 */ 165 if (mf && ((mp->am_flags & AMF_ROOT) || 166 (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)))) { 167 /* 168 * We aren't going to schedule a timeout, so we need to notify the 169 * child here unless we are already unmounting, in which case that 170 * process is responsible for notifying the child. 171 */ 172 if (mf->mf_flags & MFF_UNMOUNTING) 173 plog(XLOG_WARNING, "node %s is currently being unmounted, ignoring timeout request", mp->am_path); 174 else { 175 plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path); 176 notify_child(mp, AMQ_UMNT_FAILED, EBUSY, 0); 177 } 178 } else { 179 plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path); 180 mp->am_flags &= ~AMF_NOTIMEOUT; 181 mp->am_ttl = clocktime(NULL); 182 /* 183 * Force mtime update of parent dir, to prevent DNLC/dcache from caching 184 * the old entry, which could result in ESTALE errors, bad symlinks, and 185 * more. 186 */ 187 clocktime(&mp->am_parent->am_fattr.na_mtime); 188 reschedule_timeout_mp(); 189 } 190 } 191 192 193 void 194 mf_mounted(mntfs *mf, bool_t call_free_opts) 195 { 196 int quoted; 197 int wasmounted = mf->mf_flags & MFF_MOUNTED; 198 199 if (!wasmounted) { 200 /* 201 * If this is a freshly mounted 202 * filesystem then update the 203 * mntfs structure... 204 */ 205 mf->mf_flags |= MFF_MOUNTED; 206 mf->mf_error = 0; 207 208 /* 209 * Do mounted callback 210 */ 211 if (mf->mf_ops->mounted) 212 mf->mf_ops->mounted(mf); 213 214 /* 215 * We used to free the mf_mo (options) here, however they're now stored 216 * and managed with the mntfs and do not need to be free'd here (this ensures 217 * that we use the same options to monitor/unmount the system as we used 218 * to mount it). 219 */ 220 } 221 222 if (mf->mf_flags & MFF_RESTART) { 223 mf->mf_flags &= ~MFF_RESTART; 224 dlog("Restarted filesystem %s, flags 0x%x", mf->mf_mount, mf->mf_flags); 225 } 226 227 /* 228 * Log message 229 */ 230 quoted = strchr(mf->mf_info, ' ') != 0; 231 plog(XLOG_INFO, "%s%s%s %s fstype %s on %s", 232 quoted ? "\"" : "", 233 mf->mf_info, 234 quoted ? "\"" : "", 235 wasmounted ? "referenced" : "mounted", 236 mf->mf_ops->fs_type, mf->mf_mount); 237 } 238 239 240 void 241 am_mounted(am_node *mp) 242 { 243 int notimeout = 0; /* assume normal timeouts initially */ 244 mntfs *mf = mp->am_al->al_mnt; 245 246 /* 247 * This is the parent mntfs which does the mf->mf_fo (am_opts type), and 248 * we're passing TRUE here to tell mf_mounted to actually free the 249 * am_opts. See a related comment in mf_mounted(). 250 */ 251 mf_mounted(mf, TRUE); 252 253 #ifdef HAVE_FS_AUTOFS 254 if (mf->mf_flags & MFF_IS_AUTOFS) 255 autofs_mounted(mp); 256 #endif /* HAVE_FS_AUTOFS */ 257 258 /* 259 * Patch up path for direct mounts 260 */ 261 if (mp->am_parent && mp->am_parent->am_al->al_mnt->mf_fsflags & FS_DIRECT) 262 mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", "."); 263 264 /* 265 * Check whether this mount should be cached permanently or not, 266 * and handle user-requested timeouts. 267 */ 268 /* first check if file system was set to never timeout */ 269 if (mf->mf_fsflags & FS_NOTIMEOUT) 270 notimeout = 1; 271 /* next, alter that decision by map flags */ 272 273 if (mf->mf_mopts) { 274 mntent_t mnt; 275 mnt.mnt_opts = mf->mf_mopts; 276 277 /* umount option: user wants to unmount this entry */ 278 if (amu_hasmntopt(&mnt, "unmount") || amu_hasmntopt(&mnt, "umount")) 279 notimeout = 0; 280 /* noumount option: user does NOT want to unmount this entry */ 281 if (amu_hasmntopt(&mnt, "nounmount") || amu_hasmntopt(&mnt, "noumount")) 282 notimeout = 1; 283 /* utimeout=N option: user wants to unmount this option AND set timeout */ 284 if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0) 285 mp->am_timeo = gopt.am_timeo; /* otherwise use default timeout */ 286 else 287 notimeout = 0; 288 /* special case: don't try to unmount "/" (it can never succeed) */ 289 if (mf->mf_mount[0] == '/' && mf->mf_mount[1] == '\0') 290 notimeout = 1; 291 } 292 /* finally set actual flags */ 293 if (notimeout) { 294 mp->am_flags |= AMF_NOTIMEOUT; 295 plog(XLOG_INFO, "%s set to never timeout", mp->am_path); 296 } else { 297 mp->am_flags &= ~AMF_NOTIMEOUT; 298 plog(XLOG_INFO, "%s set to timeout in %d seconds", mp->am_path, mp->am_timeo); 299 } 300 301 /* 302 * If this node is a symlink then 303 * compute the length of the returned string. 304 */ 305 if (mp->am_fattr.na_type == NFLNK) 306 mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mf->mf_mount); 307 308 /* 309 * Record mount time, and update am_stats at the same time. 310 */ 311 mp->am_stats.s_mtime = clocktime(&mp->am_fattr.na_mtime); 312 new_ttl(mp); 313 314 /* 315 * Update mtime of parent node (copying "struct nfstime" in '=' below) 316 */ 317 if (mp->am_parent && mp->am_parent->am_al->al_mnt) 318 mp->am_parent->am_fattr.na_mtime = mp->am_fattr.na_mtime; 319 320 /* 321 * This is ugly, but essentially unavoidable 322 * Sublinks must be treated separately as type==link 323 * when the base type is different. 324 */ 325 if (mp->am_link && mf->mf_ops != &amfs_link_ops) 326 amfs_link_ops.mount_fs(mp, mf); 327 328 /* 329 * Now, if we can, do a reply to our client here 330 * to speed things up. 331 */ 332 #ifdef HAVE_FS_AUTOFS 333 if (mp->am_flags & AMF_AUTOFS) 334 autofs_mount_succeeded(mp); 335 else 336 #endif /* HAVE_FS_AUTOFS */ 337 nfs_quick_reply(mp, 0); 338 339 /* 340 * Update stats 341 */ 342 amd_stats.d_mok++; 343 } 344 345 346 /* 347 * Replace mount point with a reference to an error filesystem. 348 * The mount point (struct mntfs) is NOT discarded, 349 * the caller must do it if it wants to _before_ calling this function. 350 */ 351 void 352 assign_error_mntfs(am_node *mp) 353 { 354 int error; 355 dlog("assign_error_mntfs"); 356 357 if (mp->am_al == NULL) { 358 plog(XLOG_ERROR, "%s: Can't assign error", __func__); 359 return; 360 } 361 /* 362 * Save the old error code 363 */ 364 error = mp->am_error; 365 if (error <= 0) 366 error = mp->am_al->al_mnt->mf_error; 367 /* 368 * Allocate a new error reference 369 */ 370 free_loc(mp->am_al); 371 mp->am_al = new_loc(); 372 /* 373 * Put back the error code 374 */ 375 mp->am_al->al_mnt->mf_error = error; 376 mp->am_al->al_mnt->mf_flags |= MFF_ERROR; 377 /* 378 * Zero the error in the mount point 379 */ 380 mp->am_error = 0; 381 } 382 383 384 /* 385 * Build a new map cache for this node, or re-use 386 * an existing cache for the same map. 387 */ 388 void 389 amfs_mkcacheref(mntfs *mf) 390 { 391 char *cache; 392 393 if (mf->mf_fo && mf->mf_fo->opt_cache) 394 cache = mf->mf_fo->opt_cache; 395 else 396 cache = "none"; 397 mf->mf_private = (opaque_t) mapc_find(mf->mf_info, 398 cache, 399 (mf->mf_fo ? mf->mf_fo->opt_maptype : NULL), 400 mf->mf_mount); 401 mf->mf_prfree = mapc_free; 402 } 403 404 405 /* 406 * Locate next node in sibling list which is mounted 407 * and is not an error node. 408 */ 409 am_node * 410 next_nonerror_node(am_node *xp) 411 { 412 mntfs *mf; 413 414 /* 415 * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no> 416 * Fixes a race condition when mounting direct automounts. 417 * Also fixes a problem when doing a readdir on a directory 418 * containing hung automounts. 419 */ 420 while (xp && 421 (!(mf = xp->am_al->al_mnt) || /* No mounted filesystem */ 422 mf->mf_error != 0 || /* There was a mntfs error */ 423 xp->am_error != 0 || /* There was a mount error */ 424 !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */ 425 (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */ 426 ) 427 xp = xp->am_osib; 428 429 return xp; 430 } 431 432 433 /* 434 * Mount an automounter directory. 435 * The automounter is connected into the system 436 * as a user-level NFS server. amfs_mount constructs 437 * the necessary NFS parameters to be given to the 438 * kernel so that it will talk back to us. 439 * 440 * NOTE: automounter mounts in themselves are using NFS Version 2 (UDP). 441 * 442 * NEW: on certain systems, mounting can be done using the 443 * kernel-level automount (autofs) support. In that case, 444 * we don't need NFS at all here. 445 */ 446 int 447 amfs_mount(am_node *mp, mntfs *mf, char *opts) 448 { 449 char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1]; 450 int retry, error = 0, genflags; 451 int on_autofs = mf->mf_flags & MFF_ON_AUTOFS; 452 char *dir = mf->mf_mount; 453 mntent_t mnt; 454 MTYPE_TYPE type; 455 int forced_unmount = 0; /* are we using forced unmounts? */ 456 u_long nfs_version = get_nfs_dispatcher_version(nfs_dispatcher); 457 458 memset(&mnt, 0, sizeof(mnt)); 459 mnt.mnt_dir = dir; 460 mnt.mnt_fsname = pid_fsname; 461 mnt.mnt_opts = opts; 462 463 #ifdef HAVE_FS_AUTOFS 464 if (mf->mf_flags & MFF_IS_AUTOFS) { 465 type = MOUNT_TYPE_AUTOFS; 466 /* 467 * Make sure that amd's top-level autofs mounts are hidden by default 468 * from df. 469 * XXX: It works ok on Linux, might not work on other systems. 470 */ 471 mnt.mnt_type = "autofs"; 472 } else 473 #endif /* HAVE_FS_AUTOFS */ 474 { 475 type = MOUNT_TYPE_NFS; 476 /* 477 * Make sure that amd's top-level NFS mounts are hidden by default 478 * from df. 479 * If they don't appear to support the either the "ignore" mnttab 480 * option entry, or the "auto" one, set the mount type to "nfs". 481 */ 482 mnt.mnt_type = HIDE_MOUNT_TYPE; 483 } 484 485 retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); 486 if (retry <= 0) 487 retry = 2; /* XXX: default to 2 retries */ 488 489 /* 490 * SET MOUNT ARGS 491 */ 492 493 /* 494 * Make a ``hostname'' string for the kernel 495 */ 496 xsnprintf(fs_hostname, sizeof(fs_hostname), "pid%ld@%s:%s", 497 get_server_pid(), am_get_hostname(), dir); 498 /* 499 * Most kernels have a name length restriction (64 bytes)... 500 */ 501 if (strlen(fs_hostname) >= MAXHOSTNAMELEN) 502 xstrlcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..", 503 sizeof(fs_hostname) - MAXHOSTNAMELEN + 3); 504 #ifdef HOSTNAMESZ 505 /* 506 * ... and some of these restrictions are 32 bytes (HOSTNAMESZ) 507 * If you need to get the definition for HOSTNAMESZ found, you may 508 * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file. 509 */ 510 if (strlen(fs_hostname) >= HOSTNAMESZ) 511 xstrlcpy(fs_hostname + HOSTNAMESZ - 3, "..", 512 sizeof(fs_hostname) - HOSTNAMESZ + 3); 513 #endif /* HOSTNAMESZ */ 514 515 /* 516 * Finally we can compute the mount genflags set above, 517 * and add any automounter specific flags. 518 */ 519 genflags = compute_mount_flags(&mnt); 520 #ifdef HAVE_FS_AUTOFS 521 if (on_autofs) 522 genflags |= autofs_compute_mount_flags(&mnt); 523 #endif /* HAVE_FS_AUTOFS */ 524 genflags |= compute_automounter_mount_flags(&mnt); 525 526 again: 527 if (!(mf->mf_flags & MFF_IS_AUTOFS)) { 528 nfs_args_t nfs_args; 529 am_nfs_handle_t *fhp, anh; 530 #ifndef HAVE_TRANSPORT_TYPE_TLI 531 u_short port; 532 struct sockaddr_in sin; 533 #endif /* not HAVE_TRANSPORT_TYPE_TLI */ 534 535 /* 536 * get fhandle of remote path for automount point 537 */ 538 fhp = get_root_nfs_fh(dir, &anh); 539 if (!fhp) { 540 plog(XLOG_FATAL, "Can't find root file handle for %s", dir); 541 return EINVAL; 542 } 543 544 #ifndef HAVE_TRANSPORT_TYPE_TLI 545 /* 546 * Create sockaddr to point to the local machine. 547 */ 548 memset(&sin, 0, sizeof(sin)); 549 /* as per POSIX, sin_len need not be set (used internally by kernel) */ 550 sin.sin_family = AF_INET; 551 sin.sin_addr = myipaddr; 552 port = hasmntval(&mnt, MNTTAB_OPT_PORT); 553 if (port) { 554 sin.sin_port = htons(port); 555 } else { 556 plog(XLOG_ERROR, "no port number specified for %s", dir); 557 return EINVAL; 558 } 559 #endif /* not HAVE_TRANSPORT_TYPE_TLI */ 560 561 /* setup the many fields and flags within nfs_args */ 562 #ifdef HAVE_TRANSPORT_TYPE_TLI 563 compute_nfs_args(&nfs_args, 564 &mnt, 565 genflags, 566 nfsncp, 567 NULL, /* remote host IP addr is set below */ 568 nfs_version, 569 "udp", 570 fhp, 571 fs_hostname, 572 pid_fsname); 573 /* 574 * IMPORTANT: set the correct IP address AFTERWARDS. It cannot 575 * be done using the normal mechanism of compute_nfs_args(), because 576 * that one will allocate a new address and use NFS_SA_DREF() to copy 577 * parts to it, while assuming that the ip_addr passed is always 578 * a "struct sockaddr_in". That assumption is incorrect on TLI systems, 579 * because they define a special macro HOST_SELF which is DIFFERENT 580 * than localhost (127.0.0.1)! 581 */ 582 nfs_args.addr = &nfsxprt->xp_ltaddr; 583 #else /* not HAVE_TRANSPORT_TYPE_TLI */ 584 compute_nfs_args(&nfs_args, 585 &mnt, 586 genflags, 587 NULL, 588 &sin, 589 nfs_version, 590 "udp", 591 fhp, 592 fs_hostname, 593 pid_fsname); 594 #endif /* not HAVE_TRANSPORT_TYPE_TLI */ 595 596 /************************************************************************* 597 * NOTE: while compute_nfs_args() works ok for regular NFS mounts * 598 * the toplvl one is not quite regular, and so some options must be * 599 * corrected by hand more carefully, *after* compute_nfs_args() runs. * 600 *************************************************************************/ 601 compute_automounter_nfs_args(&nfs_args, &mnt); 602 603 if (amuDebug(D_TRACE)) { 604 print_nfs_args(&nfs_args, 0); 605 plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags); 606 } 607 608 /* This is it! Here we try to mount amd on its mount points */ 609 error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, 610 retry, type, 0, NULL, mnttab_file_name, on_autofs); 611 612 #ifdef HAVE_TRANSPORT_TYPE_TLI 613 free_knetconfig(nfs_args.knconf); 614 /* 615 * local automounter mounts do not allocate a special address, so 616 * no need to XFREE(nfs_args.addr) under TLI. 617 */ 618 #endif /* HAVE_TRANSPORT_TYPE_TLI */ 619 620 #ifdef HAVE_FS_AUTOFS 621 } else { 622 /* This is it! Here we try to mount amd on its mount points */ 623 error = mount_fs(&mnt, genflags, (caddr_t) mp->am_autofs_fh, 624 retry, type, 0, NULL, mnttab_file_name, on_autofs); 625 #endif /* HAVE_FS_AUTOFS */ 626 } 627 if (error == 0 || forced_unmount) 628 return error; 629 630 /* 631 * If user wants forced/lazy unmount semantics, then try it iff the 632 * current mount failed with EIO or ESTALE. 633 */ 634 if (gopt.flags & CFM_FORCED_UNMOUNTS) { 635 switch (errno) { 636 case ESTALE: 637 case EIO: 638 forced_unmount = errno; 639 plog(XLOG_WARNING, "Mount %s failed (%m); force unmount.", mp->am_path); 640 if ((error = UMOUNT_FS(mp->am_path, mnttab_file_name, 641 AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH)) < 0) { 642 plog(XLOG_WARNING, "Forced umount %s failed: %m.", mp->am_path); 643 errno = forced_unmount; 644 } else 645 goto again; 646 default: 647 break; 648 } 649 } 650 651 return error; 652 } 653 654 655 void 656 am_unmounted(am_node *mp) 657 { 658 mntfs *mf = mp->am_al->al_mnt; 659 660 if (!foreground) { /* firewall - should never happen */ 661 /* 662 * This is a coding error. Make sure we hear about it! 663 */ 664 plog(XLOG_FATAL, "am_unmounted: illegal use in background (%s)", 665 mp->am_name); 666 notify_child(mp, AMQ_UMNT_OK, 0, 0); /* XXX - be safe? */ 667 return; 668 } 669 670 /* 671 * Do unmounted callback 672 */ 673 if (mf->mf_ops->umounted) 674 mf->mf_ops->umounted(mf); 675 676 /* 677 * This is ugly, but essentially unavoidable. 678 * Sublinks must be treated separately as type==link 679 * when the base type is different. 680 */ 681 if (mp->am_link && mf->mf_ops != &amfs_link_ops) 682 amfs_link_ops.umount_fs(mp, mf); 683 684 #ifdef HAVE_FS_AUTOFS 685 if (mf->mf_flags & MFF_IS_AUTOFS) 686 autofs_release_fh(mp); 687 if (mp->am_flags & AMF_AUTOFS) 688 autofs_umount_succeeded(mp); 689 #endif /* HAVE_FS_AUTOFS */ 690 691 /* 692 * Clean up any directories that were made 693 * 694 * If we remove the mount point of a pending mount, any queued access 695 * to it will fail. So don't do it in that case. 696 * Also don't do it if the refcount is > 1. 697 */ 698 if (mf->mf_flags & MFF_MKMNT && 699 mf->mf_refc == 1 && 700 !(mp->am_flags & AMF_REMOUNT)) { 701 plog(XLOG_INFO, "removing mountpoint directory '%s'", mf->mf_mount); 702 rmdirs(mf->mf_mount); 703 mf->mf_flags &= ~MFF_MKMNT; 704 } 705 706 /* 707 * If this is a pseudo-directory then adjust the link count 708 * in the parent 709 */ 710 if (mp->am_parent && mp->am_fattr.na_type == NFDIR) 711 --mp->am_parent->am_fattr.na_nlink; 712 713 /* 714 * Update mtime of parent node 715 */ 716 if (mp->am_parent && mp->am_parent->am_al->al_mnt) 717 clocktime(&mp->am_parent->am_fattr.na_mtime); 718 719 if (mp->am_parent && (mp->am_flags & AMF_REMOUNT)) { 720 char *fname = xstrdup(mp->am_name); 721 am_node *mp_parent = mp->am_parent; 722 mntfs *mf_parent = mp_parent->am_al->al_mnt; 723 am_node fake_mp; 724 int error = 0; 725 726 /* 727 * We need to use notify_child() after free_map(), so save enough 728 * to do that in fake_mp. 729 */ 730 fake_mp.am_fd[1] = mp->am_fd[1]; 731 mp->am_fd[1] = -1; 732 733 free_map(mp); 734 plog(XLOG_INFO, "am_unmounted: remounting %s", fname); 735 mp = mf_parent->mf_ops->lookup_child(mp_parent, fname, &error, VLOOK_CREATE); 736 if (mp && error < 0) 737 (void)mf_parent->mf_ops->mount_child(mp, &error); 738 if (error > 0) { 739 errno = error; 740 plog(XLOG_ERROR, "am_unmounted: could not remount %s: %m", fname); 741 notify_child(&fake_mp, AMQ_UMNT_OK, 0, 0); 742 } else { 743 notify_child(&fake_mp, AMQ_UMNT_FAILED, EBUSY, 0); 744 } 745 XFREE(fname); 746 } else { 747 /* 748 * We have a race here. 749 * If this node has a pending mount and amd is going down (unmounting 750 * everything in the process), then we could potentially free it here 751 * while a struct continuation still has a reference to it. So when 752 * amfs_cont is called, it blows up. 753 * We avoid the race by refusing to free any nodes that have 754 * pending mounts (defined as having a non-NULL am_alarray). 755 */ 756 notify_child(mp, AMQ_UMNT_OK, 0, 0); /* do this regardless */ 757 if (!mp->am_alarray) 758 free_map(mp); 759 } 760 } 761 762 763 /* 764 * Fork the automounter 765 * 766 * TODO: Need a better strategy for handling errors 767 */ 768 static int 769 dofork(void) 770 { 771 int pid; 772 773 top: 774 pid = fork(); 775 776 if (pid < 0) { /* fork error, retry in 1 second */ 777 sleep(1); 778 goto top; 779 } 780 if (pid == 0) { /* child process (foreground==false) */ 781 am_set_mypid(); 782 foreground = 0; 783 } else { /* parent process, has one more child */ 784 NumChildren++; 785 } 786 787 return pid; 788 } 789 790 791 int 792 background(void) 793 { 794 int pid = dofork(); 795 796 if (pid == 0) { 797 dlog("backgrounded"); 798 foreground = 0; 799 } else 800 dlog("forked process %d", pid); 801 return pid; 802 } 803