1/* 2 * Copyright (c) 1997-2006 Erez Zadok 3 * Copyright (c) 1990 Jan-Simon Pendry 4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine 5 * Copyright (c) 1990 The Regents of the University of California. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * Jan-Simon Pendry at Imperial College, London. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgment: 21 * This product includes software developed by the University of 22 * California, Berkeley and its contributors. 23 * 4. Neither the name of the University nor the names of its contributors 24 * may be used to endorse or promote products derived from this software 25 * without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 37 * SUCH DAMAGE. 38 * 39 * 40 * File: am-utils/amd/autil.c 41 * 42 */ 43 44/* 45 * utilities specified to amd, taken out of the older amd/util.c. 46 */ 47 48#ifdef HAVE_CONFIG_H 49# include <config.h> 50#endif /* HAVE_CONFIG_H */ 51#include <am_defs.h> 52#include <amd.h> 53 54int NumChildren = 0; /* number of children of primary amd */ 55static char invalid_keys[] = "\"'!;@ \t\n"; 56 57/**************************************************************************** 58 *** MACROS *** 59 ****************************************************************************/ 60 61#ifdef HAVE_TRANSPORT_TYPE_TLI 62# define PARENT_USLEEP_TIME 100000 /* 0.1 seconds */ 63#endif /* HAVE_TRANSPORT_TYPE_TLI */ 64 65 66/**************************************************************************** 67 *** FORWARD DEFINITIONS *** 68 ****************************************************************************/ 69static void domain_strip(char *otherdom, char *localdom); 70static int dofork(void); 71 72 73/**************************************************************************** 74 *** FUNCTIONS *** 75 ****************************************************************************/ 76 77/* 78 * Copy s into p, reallocating p if necessary 79 */ 80char * 81strealloc(char *p, char *s) 82{ 83 size_t len = strlen(s) + 1; 84 85 p = (char *) xrealloc((voidp) p, len); 86 87 xstrlcpy(p, s, len); 88#ifdef DEBUG_MEM 89# if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) 90 malloc_verify(); 91# endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */ 92#endif /* DEBUG_MEM */ 93 return p; 94} 95 96 97/* 98 * Strip off the trailing part of a domain 99 * to produce a short-form domain relative 100 * to the local host domain. 101 * Note that this has no effect if the domain 102 * names do not have the same number of 103 * components. If that restriction proves 104 * to be a problem then the loop needs recoding 105 * to skip from right to left and do partial 106 * matches along the way -- ie more expensive. 107 */ 108static void 109domain_strip(char *otherdom, char *localdom) 110{ 111 char *p1, *p2; 112 113 if ((p1 = strchr(otherdom, '.')) && 114 (p2 = strchr(localdom, '.')) && 115 STREQ(p1 + 1, p2 + 1)) 116 *p1 = '\0'; 117} 118 119 120/* 121 * Normalize a host name: replace cnames with real names, and decide if to 122 * strip domain name or not. 123 */ 124void 125host_normalize(char **chp) 126{ 127 /* 128 * Normalize hosts is used to resolve host name aliases 129 * and replace them with the standard-form name. 130 * Invoked with "-n" command line option. 131 */ 132 if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) { 133 struct hostent *hp; 134 hp = gethostbyname(*chp); 135 if (hp && hp->h_addrtype == AF_INET) { 136 dlog("Hostname %s normalized to %s", *chp, hp->h_name); 137 *chp = strealloc(*chp, (char *) hp->h_name); 138 } 139 } 140 if (gopt.flags & CFM_DOMAIN_STRIP) { 141 domain_strip(*chp, hostd); 142 } 143} 144 145 146/* 147 * Keys are not allowed to contain " ' ! or ; to avoid 148 * problems with macro expansions. 149 */ 150int 151valid_key(char *key) 152{ 153 while (*key) 154 if (strchr(invalid_keys, *key++)) 155 return FALSE; 156 return TRUE; 157} 158 159 160void 161forcibly_timeout_mp(am_node *mp) 162{ 163 mntfs *mf = mp->am_mnt; 164 /* 165 * Arrange to timeout this node 166 */ 167 if (mf && ((mp->am_flags & AMF_ROOT) || 168 (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)))) { 169 if (mf->mf_flags & MFF_UNMOUNTING) 170 plog(XLOG_WARNING, "node %s is currently being unmounted, ignoring timeout request", mp->am_path); 171 else 172 plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path); 173 } else { 174 plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path); 175 mp->am_flags &= ~AMF_NOTIMEOUT; 176 mp->am_ttl = clocktime(NULL); 177 /* 178 * Force mtime update of parent dir, to prevent DNLC/dcache from caching 179 * the old entry, which could result in ESTALE errors, bad symlinks, and 180 * more. 181 */ 182 clocktime(&mp->am_parent->am_fattr.na_mtime); 183 reschedule_timeout_mp(); 184 } 185} 186 187 188void 189mf_mounted(mntfs *mf, bool_t call_free_opts) 190{ 191 int quoted; 192 int wasmounted = mf->mf_flags & MFF_MOUNTED; 193 194 if (!wasmounted) { 195 /* 196 * If this is a freshly mounted 197 * filesystem then update the 198 * mntfs structure... 199 */ 200 mf->mf_flags |= MFF_MOUNTED; 201 mf->mf_error = 0; 202 203 /* 204 * Do mounted callback 205 */ 206 if (mf->mf_ops->mounted) 207 mf->mf_ops->mounted(mf); 208 209 /* 210 * Be careful when calling free_ops and XFREE here. Some pseudo file 211 * systems like nfsx call this function (mf_mounted), even though it 212 * would be called by the lower-level amd file system functions. nfsx 213 * needs to call this function because of the other actions it takes. 214 * So we pass a boolean from the caller (yes, not so clean workaround) 215 * to determine if we should free or not. If we're not freeing (often 216 * because we're called from a callback function), then just to be sure, 217 * we'll zero out the am_opts structure and set the pointer to NULL. 218 * The parent mntfs node owns this memory and is going to free it with a 219 * call to mf_mounted(mntfs,TRUE) (see comment in the am_mounted code). 220 */ 221 if (call_free_opts) { 222 free_opts(mf->mf_fo); /* this free is needed to prevent leaks */ 223 XFREE(mf->mf_fo); /* (also this one) */ 224 } else { 225 memset(mf->mf_fo, 0, sizeof(am_opts)); 226 mf->mf_fo = NULL; 227 } 228 } 229 230 if (mf->mf_flags & MFF_RESTART) { 231 mf->mf_flags &= ~MFF_RESTART; 232 dlog("Restarted filesystem %s, flags 0x%x", mf->mf_mount, mf->mf_flags); 233 } 234 235 /* 236 * Log message 237 */ 238 quoted = strchr(mf->mf_info, ' ') != 0; 239 plog(XLOG_INFO, "%s%s%s %s fstype %s on %s", 240 quoted ? "\"" : "", 241 mf->mf_info, 242 quoted ? "\"" : "", 243 wasmounted ? "referenced" : "mounted", 244 mf->mf_ops->fs_type, mf->mf_mount); 245} 246 247 248void 249am_mounted(am_node *mp) 250{ 251 int notimeout = 0; /* assume normal timeouts initially */ 252 mntfs *mf = mp->am_mnt; 253 254 /* 255 * This is the parent mntfs which does the mf->mf_fo (am_opts type), and 256 * we're passing TRUE here to tell mf_mounted to actually free the 257 * am_opts. See a related comment in mf_mounted(). 258 */ 259 mf_mounted(mf, TRUE); 260 261#ifdef HAVE_FS_AUTOFS 262 if (mf->mf_flags & MFF_IS_AUTOFS) 263 autofs_mounted(mp); 264#endif /* HAVE_FS_AUTOFS */ 265 266 /* 267 * Patch up path for direct mounts 268 */ 269 if (mp->am_parent && mp->am_parent->am_mnt->mf_fsflags & FS_DIRECT) 270 mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", "."); 271 272 /* 273 * Check whether this mount should be cached permanently or not, 274 * and handle user-requested timeouts. 275 */ 276 /* first check if file system was set to never timeout */ 277 if (mf->mf_fsflags & FS_NOTIMEOUT) 278 notimeout = 1; 279 /* next, alter that decision by map flags */ 280 if (mf->mf_mopts) { 281 mntent_t mnt; 282 mnt.mnt_opts = mf->mf_mopts; 283 284 /* umount option: user wants to unmount this entry */ 285 if (amu_hasmntopt(&mnt, "unmount") || amu_hasmntopt(&mnt, "umount")) 286 notimeout = 0; 287 /* noumount option: user does NOT want to unmount this entry */ 288 if (amu_hasmntopt(&mnt, "nounmount") || amu_hasmntopt(&mnt, "noumount")) 289 notimeout = 1; 290 /* utimeout=N option: user wants to unmount this option AND set timeout */ 291 if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0) 292 mp->am_timeo = gopt.am_timeo; /* otherwise use default timeout */ 293 else 294 notimeout = 0; 295 /* special case: don't try to unmount "/" (it can never succeed) */ 296 if (mf->mf_mount[0] == '/' && mf->mf_mount[1] == '\0') 297 notimeout = 1; 298 } 299 /* finally set actual flags */ 300 if (notimeout) { 301 mp->am_flags |= AMF_NOTIMEOUT; 302 plog(XLOG_INFO, "%s set to never timeout", mp->am_path); 303 } else { 304 mp->am_flags &= ~AMF_NOTIMEOUT; 305 plog(XLOG_INFO, "%s set to timeout in %d seconds", mp->am_path, mp->am_timeo); 306 } 307 308 /* 309 * If this node is a symlink then 310 * compute the length of the returned string. 311 */ 312 if (mp->am_fattr.na_type == NFLNK) 313 mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mf->mf_mount); 314 315 /* 316 * Record mount time, and update am_stats at the same time. 317 */ 318 mp->am_stats.s_mtime = clocktime(&mp->am_fattr.na_mtime); 319 new_ttl(mp); 320 321 /* 322 * Update mtime of parent node (copying "struct nfstime" in '=' below) 323 */ 324 if (mp->am_parent && mp->am_parent->am_mnt) 325 mp->am_parent->am_fattr.na_mtime = mp->am_fattr.na_mtime; 326 327 /* 328 * This is ugly, but essentially unavoidable 329 * Sublinks must be treated separately as type==link 330 * when the base type is different. 331 */ 332 if (mp->am_link && mf->mf_ops != &amfs_link_ops) 333 amfs_link_ops.mount_fs(mp, mf); 334 335 /* 336 * Now, if we can, do a reply to our client here 337 * to speed things up. 338 */ 339#ifdef HAVE_FS_AUTOFS 340 if (mp->am_flags & AMF_AUTOFS) 341 autofs_mount_succeeded(mp); 342 else 343#endif /* HAVE_FS_AUTOFS */ 344 nfs_quick_reply(mp, 0); 345 346 /* 347 * Update stats 348 */ 349 amd_stats.d_mok++; 350} 351 352 353/* 354 * Replace mount point with a reference to an error filesystem. 355 * The mount point (struct mntfs) is NOT discarded, 356 * the caller must do it if it wants to _before_ calling this function. 357 */ 358void 359assign_error_mntfs(am_node *mp) 360{ 361 int error; 362 dlog("assign_error_mntfs"); 363 /* 364 * Save the old error code 365 */ 366 error = mp->am_error; 367 if (error <= 0) 368 error = mp->am_mnt->mf_error; 369 /* 370 * Allocate a new error reference 371 */ 372 mp->am_mnt = new_mntfs(); 373 /* 374 * Put back the error code 375 */ 376 mp->am_mnt->mf_error = error; 377 mp->am_mnt->mf_flags |= MFF_ERROR; 378 /* 379 * Zero the error in the mount point 380 */ 381 mp->am_error = 0; 382} 383 384 385/* 386 * Build a new map cache for this node, or re-use 387 * an existing cache for the same map. 388 */ 389void 390amfs_mkcacheref(mntfs *mf) 391{ 392 char *cache; 393 394 if (mf->mf_fo && mf->mf_fo->opt_cache) 395 cache = mf->mf_fo->opt_cache; 396 else 397 cache = "none"; 398 mf->mf_private = (opaque_t) mapc_find(mf->mf_info, 399 cache, 400 (mf->mf_fo ? mf->mf_fo->opt_maptype : NULL)); 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 */ 409am_node * 410next_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_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 */ 446int 447amfs_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 457 memset((voidp) &mnt, 0, sizeof(mnt)); 458 mnt.mnt_dir = dir; 459 mnt.mnt_fsname = pid_fsname; 460 mnt.mnt_opts = opts; 461 462#ifdef HAVE_FS_AUTOFS 463 if (mf->mf_flags & MFF_IS_AUTOFS) { 464 type = MOUNT_TYPE_AUTOFS; 465 /* 466 * Make sure that amd's top-level autofs mounts are hidden by default 467 * from df. 468 * XXX: It works ok on Linux, might not work on other systems. 469 */ 470 mnt.mnt_type = "autofs"; 471 } else 472#endif /* HAVE_FS_AUTOFS */ 473 { 474 type = MOUNT_TYPE_NFS; 475 /* 476 * Make sure that amd's top-level NFS mounts are hidden by default 477 * from df. 478 * If they don't appear to support the either the "ignore" mnttab 479 * option entry, or the "auto" one, set the mount type to "nfs". 480 */ 481 mnt.mnt_type = HIDE_MOUNT_TYPE; 482 } 483 484 retry = hasmntval(&mnt, MNTTAB_OPT_RETRY); 485 if (retry <= 0) 486 retry = 2; /* XXX: default to 2 retries */ 487 488 /* 489 * SET MOUNT ARGS 490 */ 491 492 /* 493 * Make a ``hostname'' string for the kernel 494 */ 495 xsnprintf(fs_hostname, sizeof(fs_hostname), "pid%ld@%s:%s", 496 get_server_pid(), am_get_hostname(), dir); 497 /* 498 * Most kernels have a name length restriction (64 bytes)... 499 */ 500 if (strlen(fs_hostname) >= MAXHOSTNAMELEN) 501 xstrlcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..", 502 sizeof(fs_hostname) - MAXHOSTNAMELEN + 3); 503#ifdef HOSTNAMESZ 504 /* 505 * ... and some of these restrictions are 32 bytes (HOSTNAMESZ) 506 * If you need to get the definition for HOSTNAMESZ found, you may 507 * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file. 508 */ 509 if (strlen(fs_hostname) >= HOSTNAMESZ) 510 xstrlcpy(fs_hostname + HOSTNAMESZ - 3, "..", 511 sizeof(fs_hostname) - HOSTNAMESZ + 3); 512#endif /* HOSTNAMESZ */ 513 514 /* 515 * Finally we can compute the mount genflags set above, 516 * and add any automounter specific flags. 517 */ 518 genflags = compute_mount_flags(&mnt); 519#ifdef HAVE_FS_AUTOFS 520 if (on_autofs) 521 genflags |= autofs_compute_mount_flags(&mnt); 522#endif /* HAVE_FS_AUTOFS */ 523 genflags |= compute_automounter_mount_flags(&mnt); 524 525again: 526 if (!(mf->mf_flags & MFF_IS_AUTOFS)) { 527 nfs_args_t nfs_args; 528 am_nfs_fh *fhp; 529 am_nfs_handle_t 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); 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((voidp) &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 memmove(&anh.v2, fhp, sizeof(*fhp)); 563#ifdef HAVE_TRANSPORT_TYPE_TLI 564 compute_nfs_args(&nfs_args, 565 &mnt, 566 genflags, 567 nfsncp, 568 NULL, /* remote host IP addr is set below */ 569 NFS_VERSION, /* version 2 */ 570 "udp", 571 &anh, 572 fs_hostname, 573 pid_fsname); 574 /* 575 * IMPORTANT: set the correct IP address AFTERWARDS. It cannot 576 * be done using the normal mechanism of compute_nfs_args(), because 577 * that one will allocate a new address and use NFS_SA_DREF() to copy 578 * parts to it, while assuming that the ip_addr passed is always 579 * a "struct sockaddr_in". That assumption is incorrect on TLI systems, 580 * because they define a special macro HOST_SELF which is DIFFERENT 581 * than localhost (127.0.0.1)! 582 */ 583 nfs_args.addr = &nfsxprt->xp_ltaddr; 584#else /* not HAVE_TRANSPORT_TYPE_TLI */ 585 compute_nfs_args(&nfs_args, 586 &mnt, 587 genflags, 588 NULL, 589 &sin, 590 NFS_VERSION, /* version 2 */ 591 "udp", 592 &anh, 593 fs_hostname, 594 pid_fsname); 595#endif /* not HAVE_TRANSPORT_TYPE_TLI */ 596 597 /************************************************************************* 598 * NOTE: while compute_nfs_args() works ok for regular NFS mounts * 599 * the toplvl one is not quite regular, and so some options must be * 600 * corrected by hand more carefully, *after* compute_nfs_args() runs. * 601 *************************************************************************/ 602 compute_automounter_nfs_args(&nfs_args, &mnt); 603 604 if (amuDebug(D_TRACE)) { 605 print_nfs_args(&nfs_args, 0); 606 plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags); 607 } 608 609 /* This is it! Here we try to mount amd on its mount points */ 610 error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args, 611 retry, type, 0, NULL, mnttab_file_name, on_autofs); 612 613#ifdef HAVE_TRANSPORT_TYPE_TLI 614 free_knetconfig(nfs_args.knconf); 615 /* 616 * local automounter mounts do not allocate a special address, so 617 * no need to XFREE(nfs_args.addr) under TLI. 618 */ 619#endif /* HAVE_TRANSPORT_TYPE_TLI */ 620 621#ifdef HAVE_FS_AUTOFS 622 } else { 623 /* This is it! Here we try to mount amd on its mount points */ 624 error = mount_fs(&mnt, genflags, (caddr_t) mp->am_autofs_fh, 625 retry, type, 0, NULL, mnttab_file_name, on_autofs); 626#endif /* HAVE_FS_AUTOFS */ 627 } 628 if (error == 0 || forced_unmount) 629 return error; 630 631 /* 632 * If user wants forced/lazy unmount semantics, then try it iff the 633 * current mount failed with EIO or ESTALE. 634 */ 635 if (gopt.flags & CFM_FORCED_UNMOUNTS) { 636 switch (errno) { 637 case ESTALE: 638 case EIO: 639 forced_unmount = errno; 640 plog(XLOG_WARNING, "Mount %s failed (%m); force unmount.", mp->am_path); 641 if ((error = UMOUNT_FS(mp->am_path, mnttab_file_name, 642 AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH)) < 0) { 643 plog(XLOG_WARNING, "Forced umount %s failed: %m.", mp->am_path); 644 errno = forced_unmount; 645 } else 646 goto again; 647 default: 648 break; 649 } 650 } 651 652 return error; 653} 654 655 656void 657am_unmounted(am_node *mp) 658{ 659 mntfs *mf = mp->am_mnt; 660 661 if (!foreground) /* firewall - should never happen */ 662 return; 663 664 /* 665 * Do unmounted callback 666 */ 667 if (mf->mf_ops->umounted) 668 mf->mf_ops->umounted(mf); 669 670 /* 671 * This is ugly, but essentially unavoidable. 672 * Sublinks must be treated separately as type==link 673 * when the base type is different. 674 */ 675 if (mp->am_link && mf->mf_ops != &amfs_link_ops) 676 amfs_link_ops.umount_fs(mp, mf); 677 678#ifdef HAVE_FS_AUTOFS 679 if (mf->mf_flags & MFF_IS_AUTOFS) 680 autofs_release_fh(mp); 681 if (mp->am_flags & AMF_AUTOFS) 682 autofs_umount_succeeded(mp); 683#endif /* HAVE_FS_AUTOFS */ 684 685 /* 686 * Clean up any directories that were made 687 * 688 * If we remove the mount point of a pending mount, any queued access 689 * to it will fail. So don't do it in that case. 690 * Also don't do it if the refcount is > 1. 691 */ 692 if (mf->mf_flags & MFF_MKMNT && 693 mf->mf_refc == 1 && 694 !(mp->am_flags & AMF_REMOUNT)) { 695 plog(XLOG_INFO, "removing mountpoint directory '%s'", mf->mf_mount); 696 rmdirs(mf->mf_mount); 697 mf->mf_flags &= ~MFF_MKMNT; 698 } 699 700 /* 701 * If this is a pseudo-directory then adjust the link count 702 * in the parent 703 */ 704 if (mp->am_parent && mp->am_fattr.na_type == NFDIR) 705 --mp->am_parent->am_fattr.na_nlink; 706 707 /* 708 * Update mtime of parent node 709 */ 710 if (mp->am_parent && mp->am_parent->am_mnt) 711 clocktime(&mp->am_parent->am_fattr.na_mtime); 712 713 if (mp->am_parent && (mp->am_flags & AMF_REMOUNT)) { 714 char *fname = strdup(mp->am_name); 715 am_node *mp_parent = mp->am_parent; 716 mntfs *mf_parent = mp_parent->am_mnt; 717 int error = 0; 718 719 free_map(mp); 720 plog(XLOG_INFO, "am_unmounted: remounting %s", fname); 721 mp = mf_parent->mf_ops->lookup_child(mp_parent, fname, &error, VLOOK_CREATE); 722 if (mp && error < 0) 723 mp = mf_parent->mf_ops->mount_child(mp, &error); 724 if (error > 0) { 725 errno = error; 726 plog(XLOG_ERROR, "am_unmounted: could not remount %s: %m", fname); 727 } 728 XFREE(fname); 729 } else 730 /* 731 * We have a race here. 732 * If this node has a pending mount and amd is going down (unmounting 733 * everything in the process), then we could potentially free it here 734 * while a struct continuation still has a reference to it. So when 735 * amfs_cont is called, it blows up. 736 * We avoid the race by refusing to free any nodes that have 737 * pending mounts (defined as having a non-NULL am_mfarray). 738 */ 739 if (!mp->am_mfarray) 740 free_map(mp); 741} 742 743 744/* 745 * Fork the automounter 746 * 747 * TODO: Need a better strategy for handling errors 748 */ 749static int 750dofork(void) 751{ 752 int pid; 753 754top: 755 pid = fork(); 756 757 if (pid < 0) { /* fork error, retry in 1 second */ 758 sleep(1); 759 goto top; 760 } 761 if (pid == 0) { /* child process (foreground==false) */ 762 am_set_mypid(); 763 foreground = 0; 764 } else { /* parent process, has one more child */ 765 NumChildren++; 766 } 767 768 return pid; 769} 770 771 772int 773background(void) 774{ 775 int pid = dofork(); 776 777 if (pid == 0) { 778 dlog("backgrounded"); 779 foreground = 0; 780 } else 781 dlog("forked process %d", pid); 782 return pid; 783} 784