Home | History | Annotate | Line # | Download | only in amd
      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 (at) 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