Sync usage with man page.
[netbsd-mini2440.git] / external / bsd / am-utils / dist / amd / autil.c
blob8e4155bc8b0466f4281e861c75021023ffb8fa11
1 /* $NetBSD$ */
3 /*
4 * Copyright (c) 1997-2009 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.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
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. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
42 * File: am-utils/amd/autil.c
47 * utilities specified to amd, taken out of the older amd/util.c.
50 #ifdef HAVE_CONFIG_H
51 # include <config.h>
52 #endif /* HAVE_CONFIG_H */
53 #include <am_defs.h>
54 #include <amd.h>
56 int NumChildren = 0; /* number of children of primary amd */
57 static char invalid_keys[] = "\"'!;@ \t\n";
59 /****************************************************************************
60 *** MACROS ***
61 ****************************************************************************/
63 #ifdef HAVE_TRANSPORT_TYPE_TLI
64 # define PARENT_USLEEP_TIME 100000 /* 0.1 seconds */
65 #endif /* HAVE_TRANSPORT_TYPE_TLI */
68 /****************************************************************************
69 *** FORWARD DEFINITIONS ***
70 ****************************************************************************/
71 static void domain_strip(char *otherdom, char *localdom);
72 static int dofork(void);
75 /****************************************************************************
76 *** FUNCTIONS ***
77 ****************************************************************************/
80 * Copy s into p, reallocating p if necessary
82 char *
83 strealloc(char *p, char *s)
85 size_t len = strlen(s) + 1;
87 p = (char *) xrealloc((voidp) p, len);
89 xstrlcpy(p, s, len);
90 #ifdef DEBUG_MEM
91 # if defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY)
92 malloc_verify();
93 # endif /* not defined(HAVE_MALLINFO) && defined(HAVE_MALLOC_VERIFY) */
94 #endif /* DEBUG_MEM */
95 return p;
100 * Strip off the trailing part of a domain
101 * to produce a short-form domain relative
102 * to the local host domain.
103 * Note that this has no effect if the domain
104 * names do not have the same number of
105 * components. If that restriction proves
106 * to be a problem then the loop needs recoding
107 * to skip from right to left and do partial
108 * matches along the way -- ie more expensive.
110 static void
111 domain_strip(char *otherdom, char *localdom)
113 char *p1, *p2;
115 if ((p1 = strchr(otherdom, '.')) &&
116 (p2 = strchr(localdom, '.')) &&
117 STREQ(p1 + 1, p2 + 1))
118 *p1 = '\0';
123 * Normalize a host name: replace cnames with real names, and decide if to
124 * strip domain name or not.
126 void
127 host_normalize(char **chp)
130 * Normalize hosts is used to resolve host name aliases
131 * and replace them with the standard-form name.
132 * Invoked with "-n" command line option.
134 if (gopt.flags & CFM_NORMALIZE_HOSTNAMES) {
135 struct hostent *hp;
136 hp = gethostbyname(*chp);
137 if (hp && hp->h_addrtype == AF_INET) {
138 dlog("Hostname %s normalized to %s", *chp, hp->h_name);
139 *chp = strealloc(*chp, (char *) hp->h_name);
142 if (gopt.flags & CFM_DOMAIN_STRIP) {
143 domain_strip(*chp, hostd);
149 * Keys are not allowed to contain " ' ! or ; to avoid
150 * problems with macro expansions.
153 valid_key(char *key)
155 while (*key)
156 if (strchr(invalid_keys, *key++))
157 return FALSE;
158 return TRUE;
162 void
163 forcibly_timeout_mp(am_node *mp)
165 mntfs *mf = mp->am_mnt;
167 * Arrange to timeout this node
169 if (mf && ((mp->am_flags & AMF_ROOT) ||
170 (mf->mf_flags & (MFF_MOUNTING | MFF_UNMOUNTING)))) {
172 * We aren't going to schedule a timeout, so we need to notify the
173 * child here unless we are already unmounting, in which case that
174 * process is responsible for notifying the child.
176 if (mf->mf_flags & MFF_UNMOUNTING)
177 plog(XLOG_WARNING, "node %s is currently being unmounted, ignoring timeout request", mp->am_path);
178 else {
179 plog(XLOG_WARNING, "ignoring timeout request for active node %s", mp->am_path);
180 notify_child(mp, AMQ_UMNT_FAILED, EBUSY, 0);
182 } else {
183 plog(XLOG_INFO, "\"%s\" forcibly timed out", mp->am_path);
184 mp->am_flags &= ~AMF_NOTIMEOUT;
185 mp->am_ttl = clocktime(NULL);
187 * Force mtime update of parent dir, to prevent DNLC/dcache from caching
188 * the old entry, which could result in ESTALE errors, bad symlinks, and
189 * more.
191 clocktime(&mp->am_parent->am_fattr.na_mtime);
192 reschedule_timeout_mp();
197 void
198 mf_mounted(mntfs *mf, bool_t call_free_opts)
200 int quoted;
201 int wasmounted = mf->mf_flags & MFF_MOUNTED;
203 if (!wasmounted) {
205 * If this is a freshly mounted
206 * filesystem then update the
207 * mntfs structure...
209 mf->mf_flags |= MFF_MOUNTED;
210 mf->mf_error = 0;
213 * Do mounted callback
215 if (mf->mf_ops->mounted)
216 mf->mf_ops->mounted(mf);
219 * Be careful when calling free_ops and XFREE here. Some pseudo file
220 * systems like nfsx call this function (mf_mounted), even though it
221 * would be called by the lower-level amd file system functions. nfsx
222 * needs to call this function because of the other actions it takes.
223 * So we pass a boolean from the caller (yes, not so clean workaround)
224 * to determine if we should free or not. If we're not freeing (often
225 * because we're called from a callback function), then just to be sure,
226 * we'll zero out the am_opts structure and set the pointer to NULL.
227 * The parent mntfs node owns this memory and is going to free it with a
228 * call to mf_mounted(mntfs,TRUE) (see comment in the am_mounted code).
230 if (call_free_opts) {
231 free_opts(mf->mf_fo); /* this free is needed to prevent leaks */
232 XFREE(mf->mf_fo); /* (also this one) */
233 } else {
234 memset(mf->mf_fo, 0, sizeof(am_opts));
235 mf->mf_fo = NULL;
239 if (mf->mf_flags & MFF_RESTART) {
240 mf->mf_flags &= ~MFF_RESTART;
241 dlog("Restarted filesystem %s, flags 0x%x", mf->mf_mount, mf->mf_flags);
245 * Log message
247 quoted = strchr(mf->mf_info, ' ') != 0;
248 plog(XLOG_INFO, "%s%s%s %s fstype %s on %s",
249 quoted ? "\"" : "",
250 mf->mf_info,
251 quoted ? "\"" : "",
252 wasmounted ? "referenced" : "mounted",
253 mf->mf_ops->fs_type, mf->mf_mount);
257 void
258 am_mounted(am_node *mp)
260 int notimeout = 0; /* assume normal timeouts initially */
261 mntfs *mf = mp->am_mnt;
264 * This is the parent mntfs which does the mf->mf_fo (am_opts type), and
265 * we're passing TRUE here to tell mf_mounted to actually free the
266 * am_opts. See a related comment in mf_mounted().
268 mf_mounted(mf, TRUE);
270 #ifdef HAVE_FS_AUTOFS
271 if (mf->mf_flags & MFF_IS_AUTOFS)
272 autofs_mounted(mp);
273 #endif /* HAVE_FS_AUTOFS */
276 * Patch up path for direct mounts
278 if (mp->am_parent && mp->am_parent->am_mnt->mf_fsflags & FS_DIRECT)
279 mp->am_path = str3cat(mp->am_path, mp->am_parent->am_path, "/", ".");
282 * Check whether this mount should be cached permanently or not,
283 * and handle user-requested timeouts.
285 /* first check if file system was set to never timeout */
286 if (mf->mf_fsflags & FS_NOTIMEOUT)
287 notimeout = 1;
288 /* next, alter that decision by map flags */
289 if (mf->mf_mopts) {
290 mntent_t mnt;
291 mnt.mnt_opts = mf->mf_mopts;
293 /* umount option: user wants to unmount this entry */
294 if (amu_hasmntopt(&mnt, "unmount") || amu_hasmntopt(&mnt, "umount"))
295 notimeout = 0;
296 /* noumount option: user does NOT want to unmount this entry */
297 if (amu_hasmntopt(&mnt, "nounmount") || amu_hasmntopt(&mnt, "noumount"))
298 notimeout = 1;
299 /* utimeout=N option: user wants to unmount this option AND set timeout */
300 if ((mp->am_timeo = hasmntval(&mnt, "utimeout")) == 0)
301 mp->am_timeo = gopt.am_timeo; /* otherwise use default timeout */
302 else
303 notimeout = 0;
304 /* special case: don't try to unmount "/" (it can never succeed) */
305 if (mf->mf_mount[0] == '/' && mf->mf_mount[1] == '\0')
306 notimeout = 1;
308 /* finally set actual flags */
309 if (notimeout) {
310 mp->am_flags |= AMF_NOTIMEOUT;
311 plog(XLOG_INFO, "%s set to never timeout", mp->am_path);
312 } else {
313 mp->am_flags &= ~AMF_NOTIMEOUT;
314 plog(XLOG_INFO, "%s set to timeout in %d seconds", mp->am_path, mp->am_timeo);
318 * If this node is a symlink then
319 * compute the length of the returned string.
321 if (mp->am_fattr.na_type == NFLNK)
322 mp->am_fattr.na_size = strlen(mp->am_link ? mp->am_link : mf->mf_mount);
325 * Record mount time, and update am_stats at the same time.
327 mp->am_stats.s_mtime = clocktime(&mp->am_fattr.na_mtime);
328 new_ttl(mp);
331 * Update mtime of parent node (copying "struct nfstime" in '=' below)
333 if (mp->am_parent && mp->am_parent->am_mnt)
334 mp->am_parent->am_fattr.na_mtime = mp->am_fattr.na_mtime;
337 * This is ugly, but essentially unavoidable
338 * Sublinks must be treated separately as type==link
339 * when the base type is different.
341 if (mp->am_link && mf->mf_ops != &amfs_link_ops)
342 amfs_link_ops.mount_fs(mp, mf);
345 * Now, if we can, do a reply to our client here
346 * to speed things up.
348 #ifdef HAVE_FS_AUTOFS
349 if (mp->am_flags & AMF_AUTOFS)
350 autofs_mount_succeeded(mp);
351 else
352 #endif /* HAVE_FS_AUTOFS */
353 nfs_quick_reply(mp, 0);
356 * Update stats
358 amd_stats.d_mok++;
363 * Replace mount point with a reference to an error filesystem.
364 * The mount point (struct mntfs) is NOT discarded,
365 * the caller must do it if it wants to _before_ calling this function.
367 void
368 assign_error_mntfs(am_node *mp)
370 int error;
371 dlog("assign_error_mntfs");
373 * Save the old error code
375 error = mp->am_error;
376 if (error <= 0)
377 error = mp->am_mnt->mf_error;
379 * Allocate a new error reference
381 mp->am_mnt = new_mntfs();
383 * Put back the error code
385 mp->am_mnt->mf_error = error;
386 mp->am_mnt->mf_flags |= MFF_ERROR;
388 * Zero the error in the mount point
390 mp->am_error = 0;
395 * Build a new map cache for this node, or re-use
396 * an existing cache for the same map.
398 void
399 amfs_mkcacheref(mntfs *mf)
401 char *cache;
403 if (mf->mf_fo && mf->mf_fo->opt_cache)
404 cache = mf->mf_fo->opt_cache;
405 else
406 cache = "none";
407 mf->mf_private = (opaque_t) mapc_find(mf->mf_info,
408 cache,
409 (mf->mf_fo ? mf->mf_fo->opt_maptype : NULL),
410 mf->mf_mount);
411 mf->mf_prfree = mapc_free;
416 * Locate next node in sibling list which is mounted
417 * and is not an error node.
419 am_node *
420 next_nonerror_node(am_node *xp)
422 mntfs *mf;
425 * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
426 * Fixes a race condition when mounting direct automounts.
427 * Also fixes a problem when doing a readdir on a directory
428 * containing hung automounts.
430 while (xp &&
431 (!(mf = xp->am_mnt) || /* No mounted filesystem */
432 mf->mf_error != 0 || /* There was a mntfs error */
433 xp->am_error != 0 || /* There was a mount error */
434 !(mf->mf_flags & MFF_MOUNTED) || /* The fs is not mounted */
435 (mf->mf_server->fs_flags & FSF_DOWN)) /* The fs may be down */
437 xp = xp->am_osib;
439 return xp;
444 * Mount an automounter directory.
445 * The automounter is connected into the system
446 * as a user-level NFS server. amfs_mount constructs
447 * the necessary NFS parameters to be given to the
448 * kernel so that it will talk back to us.
450 * NOTE: automounter mounts in themselves are using NFS Version 2 (UDP).
452 * NEW: on certain systems, mounting can be done using the
453 * kernel-level automount (autofs) support. In that case,
454 * we don't need NFS at all here.
457 amfs_mount(am_node *mp, mntfs *mf, char *opts)
459 char fs_hostname[MAXHOSTNAMELEN + MAXPATHLEN + 1];
460 int retry, error = 0, genflags;
461 int on_autofs = mf->mf_flags & MFF_ON_AUTOFS;
462 char *dir = mf->mf_mount;
463 mntent_t mnt;
464 MTYPE_TYPE type;
465 int forced_unmount = 0; /* are we using forced unmounts? */
467 memset((voidp) &mnt, 0, sizeof(mnt));
468 mnt.mnt_dir = dir;
469 mnt.mnt_fsname = pid_fsname;
470 mnt.mnt_opts = opts;
472 #ifdef HAVE_FS_AUTOFS
473 if (mf->mf_flags & MFF_IS_AUTOFS) {
474 type = MOUNT_TYPE_AUTOFS;
476 * Make sure that amd's top-level autofs mounts are hidden by default
477 * from df.
478 * XXX: It works ok on Linux, might not work on other systems.
480 mnt.mnt_type = "autofs";
481 } else
482 #endif /* HAVE_FS_AUTOFS */
484 type = MOUNT_TYPE_NFS;
486 * Make sure that amd's top-level NFS mounts are hidden by default
487 * from df.
488 * If they don't appear to support the either the "ignore" mnttab
489 * option entry, or the "auto" one, set the mount type to "nfs".
491 mnt.mnt_type = HIDE_MOUNT_TYPE;
494 retry = hasmntval(&mnt, MNTTAB_OPT_RETRY);
495 if (retry <= 0)
496 retry = 2; /* XXX: default to 2 retries */
499 * SET MOUNT ARGS
503 * Make a ``hostname'' string for the kernel
505 xsnprintf(fs_hostname, sizeof(fs_hostname), "pid%ld@%s:%s",
506 get_server_pid(), am_get_hostname(), dir);
508 * Most kernels have a name length restriction (64 bytes)...
510 if (strlen(fs_hostname) >= MAXHOSTNAMELEN)
511 xstrlcpy(fs_hostname + MAXHOSTNAMELEN - 3, "..",
512 sizeof(fs_hostname) - MAXHOSTNAMELEN + 3);
513 #ifdef HOSTNAMESZ
515 * ... and some of these restrictions are 32 bytes (HOSTNAMESZ)
516 * If you need to get the definition for HOSTNAMESZ found, you may
517 * add the proper header file to the conf/nfs_prot/nfs_prot_*.h file.
519 if (strlen(fs_hostname) >= HOSTNAMESZ)
520 xstrlcpy(fs_hostname + HOSTNAMESZ - 3, "..",
521 sizeof(fs_hostname) - HOSTNAMESZ + 3);
522 #endif /* HOSTNAMESZ */
525 * Finally we can compute the mount genflags set above,
526 * and add any automounter specific flags.
528 genflags = compute_mount_flags(&mnt);
529 #ifdef HAVE_FS_AUTOFS
530 if (on_autofs)
531 genflags |= autofs_compute_mount_flags(&mnt);
532 #endif /* HAVE_FS_AUTOFS */
533 genflags |= compute_automounter_mount_flags(&mnt);
535 again:
536 if (!(mf->mf_flags & MFF_IS_AUTOFS)) {
537 nfs_args_t nfs_args;
538 am_nfs_fh *fhp;
539 am_nfs_handle_t anh;
540 #ifndef HAVE_TRANSPORT_TYPE_TLI
541 u_short port;
542 struct sockaddr_in sin;
543 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
546 * get fhandle of remote path for automount point
548 fhp = get_root_nfs_fh(dir);
549 if (!fhp) {
550 plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
551 return EINVAL;
554 #ifndef HAVE_TRANSPORT_TYPE_TLI
556 * Create sockaddr to point to the local machine.
558 memset((voidp) &sin, 0, sizeof(sin));
559 /* as per POSIX, sin_len need not be set (used internally by kernel) */
560 sin.sin_family = AF_INET;
561 sin.sin_addr = myipaddr;
562 port = hasmntval(&mnt, MNTTAB_OPT_PORT);
563 if (port) {
564 sin.sin_port = htons(port);
565 } else {
566 plog(XLOG_ERROR, "no port number specified for %s", dir);
567 return EINVAL;
569 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
571 /* setup the many fields and flags within nfs_args */
572 memmove(&anh.v2, fhp, sizeof(*fhp));
573 #ifdef HAVE_TRANSPORT_TYPE_TLI
574 compute_nfs_args(&nfs_args,
575 &mnt,
576 genflags,
577 nfsncp,
578 NULL, /* remote host IP addr is set below */
579 NFS_VERSION, /* version 2 */
580 "udp",
581 &anh,
582 fs_hostname,
583 pid_fsname);
585 * IMPORTANT: set the correct IP address AFTERWARDS. It cannot
586 * be done using the normal mechanism of compute_nfs_args(), because
587 * that one will allocate a new address and use NFS_SA_DREF() to copy
588 * parts to it, while assuming that the ip_addr passed is always
589 * a "struct sockaddr_in". That assumption is incorrect on TLI systems,
590 * because they define a special macro HOST_SELF which is DIFFERENT
591 * than localhost (127.0.0.1)!
593 nfs_args.addr = &nfsxprt->xp_ltaddr;
594 #else /* not HAVE_TRANSPORT_TYPE_TLI */
595 compute_nfs_args(&nfs_args,
596 &mnt,
597 genflags,
598 NULL,
599 &sin,
600 NFS_VERSION, /* version 2 */
601 "udp",
602 &anh,
603 fs_hostname,
604 pid_fsname);
605 #endif /* not HAVE_TRANSPORT_TYPE_TLI */
607 /*************************************************************************
608 * NOTE: while compute_nfs_args() works ok for regular NFS mounts *
609 * the toplvl one is not quite regular, and so some options must be *
610 * corrected by hand more carefully, *after* compute_nfs_args() runs. *
611 *************************************************************************/
612 compute_automounter_nfs_args(&nfs_args, &mnt);
614 if (amuDebug(D_TRACE)) {
615 print_nfs_args(&nfs_args, 0);
616 plog(XLOG_DEBUG, "Generic mount flags 0x%x", genflags);
619 /* This is it! Here we try to mount amd on its mount points */
620 error = mount_fs(&mnt, genflags, (caddr_t) &nfs_args,
621 retry, type, 0, NULL, mnttab_file_name, on_autofs);
623 #ifdef HAVE_TRANSPORT_TYPE_TLI
624 free_knetconfig(nfs_args.knconf);
626 * local automounter mounts do not allocate a special address, so
627 * no need to XFREE(nfs_args.addr) under TLI.
629 #endif /* HAVE_TRANSPORT_TYPE_TLI */
631 #ifdef HAVE_FS_AUTOFS
632 } else {
633 /* This is it! Here we try to mount amd on its mount points */
634 error = mount_fs(&mnt, genflags, (caddr_t) mp->am_autofs_fh,
635 retry, type, 0, NULL, mnttab_file_name, on_autofs);
636 #endif /* HAVE_FS_AUTOFS */
638 if (error == 0 || forced_unmount)
639 return error;
642 * If user wants forced/lazy unmount semantics, then try it iff the
643 * current mount failed with EIO or ESTALE.
645 if (gopt.flags & CFM_FORCED_UNMOUNTS) {
646 switch (errno) {
647 case ESTALE:
648 case EIO:
649 forced_unmount = errno;
650 plog(XLOG_WARNING, "Mount %s failed (%m); force unmount.", mp->am_path);
651 if ((error = UMOUNT_FS(mp->am_path, mnttab_file_name,
652 AMU_UMOUNT_FORCE | AMU_UMOUNT_DETACH)) < 0) {
653 plog(XLOG_WARNING, "Forced umount %s failed: %m.", mp->am_path);
654 errno = forced_unmount;
655 } else
656 goto again;
657 default:
658 break;
662 return error;
666 void
667 am_unmounted(am_node *mp)
669 mntfs *mf = mp->am_mnt;
671 if (!foreground) { /* firewall - should never happen */
673 * This is a coding error. Make sure we hear about it!
675 plog(XLOG_FATAL, "am_unmounted: illegal use in background (%s)",
676 mp->am_name);
677 notify_child(mp, AMQ_UMNT_OK, 0, 0); /* XXX - be safe? */
678 return;
682 * Do unmounted callback
684 if (mf->mf_ops->umounted)
685 mf->mf_ops->umounted(mf);
688 * This is ugly, but essentially unavoidable.
689 * Sublinks must be treated separately as type==link
690 * when the base type is different.
692 if (mp->am_link && mf->mf_ops != &amfs_link_ops)
693 amfs_link_ops.umount_fs(mp, mf);
695 #ifdef HAVE_FS_AUTOFS
696 if (mf->mf_flags & MFF_IS_AUTOFS)
697 autofs_release_fh(mp);
698 if (mp->am_flags & AMF_AUTOFS)
699 autofs_umount_succeeded(mp);
700 #endif /* HAVE_FS_AUTOFS */
703 * Clean up any directories that were made
705 * If we remove the mount point of a pending mount, any queued access
706 * to it will fail. So don't do it in that case.
707 * Also don't do it if the refcount is > 1.
709 if (mf->mf_flags & MFF_MKMNT &&
710 mf->mf_refc == 1 &&
711 !(mp->am_flags & AMF_REMOUNT)) {
712 plog(XLOG_INFO, "removing mountpoint directory '%s'", mf->mf_mount);
713 rmdirs(mf->mf_mount);
714 mf->mf_flags &= ~MFF_MKMNT;
718 * If this is a pseudo-directory then adjust the link count
719 * in the parent
721 if (mp->am_parent && mp->am_fattr.na_type == NFDIR)
722 --mp->am_parent->am_fattr.na_nlink;
725 * Update mtime of parent node
727 if (mp->am_parent && mp->am_parent->am_mnt)
728 clocktime(&mp->am_parent->am_fattr.na_mtime);
730 if (mp->am_parent && (mp->am_flags & AMF_REMOUNT)) {
731 char *fname = strdup(mp->am_name);
732 am_node *mp_parent = mp->am_parent;
733 mntfs *mf_parent = mp_parent->am_mnt;
734 am_node fake_mp;
735 int error = 0;
738 * We need to use notify_child() after free_map(), so save enough
739 * to do that in fake_mp.
741 fake_mp.am_fd[1] = mp->am_fd[1];
742 mp->am_fd[1] = -1;
744 free_map(mp);
745 plog(XLOG_INFO, "am_unmounted: remounting %s", fname);
746 mp = mf_parent->mf_ops->lookup_child(mp_parent, fname, &error, VLOOK_CREATE);
747 if (mp && error < 0)
748 mp = mf_parent->mf_ops->mount_child(mp, &error);
749 if (error > 0) {
750 errno = error;
751 plog(XLOG_ERROR, "am_unmounted: could not remount %s: %m", fname);
752 notify_child(&fake_mp, AMQ_UMNT_OK, 0, 0);
753 } else {
754 notify_child(&fake_mp, AMQ_UMNT_FAILED, EBUSY, 0);
756 XFREE(fname);
757 } else {
759 * We have a race here.
760 * If this node has a pending mount and amd is going down (unmounting
761 * everything in the process), then we could potentially free it here
762 * while a struct continuation still has a reference to it. So when
763 * amfs_cont is called, it blows up.
764 * We avoid the race by refusing to free any nodes that have
765 * pending mounts (defined as having a non-NULL am_mfarray).
767 notify_child(mp, AMQ_UMNT_OK, 0, 0); /* do this regardless */
768 if (!mp->am_mfarray)
769 free_map(mp);
775 * Fork the automounter
777 * TODO: Need a better strategy for handling errors
779 static int
780 dofork(void)
782 int pid;
784 top:
785 pid = fork();
787 if (pid < 0) { /* fork error, retry in 1 second */
788 sleep(1);
789 goto top;
791 if (pid == 0) { /* child process (foreground==false) */
792 am_set_mypid();
793 foreground = 0;
794 } else { /* parent process, has one more child */
795 NumChildren++;
798 return pid;
803 background(void)
805 int pid = dofork();
807 if (pid == 0) {
808 dlog("backgrounded");
809 foreground = 0;
810 } else
811 dlog("forked process %d", pid);
812 return pid;