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