xref: /original-bsd/usr.sbin/amd/amd/afs_ops.c (revision 68d9582f)
1 /*
2  * Copyright (c) 1990 Jan-Simon Pendry
3  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4  * Copyright (c) 1990 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Jan-Simon Pendry at Imperial College, London.
9  *
10  * %sccs.include.redist.c%
11  *
12  *	@(#)afs_ops.c	5.5 (Berkeley) 05/31/92
13  *
14  * $Id: afs_ops.c,v 5.2.2.4 1992/05/31 16:36:36 jsp Exp $
15  *
16  */
17 
18 #include "am.h"
19 
20 #define NFS
21 #define NFSCLIENT
22 
23 #include <sys/stat.h>
24 #ifdef NFS_3
25 typedef nfs_fh fhandle_t;
26 #endif /* NFS_3 */
27 #ifdef NFS_HDR
28 #include NFS_HDR
29 #endif /* NFS_HDR */
30 #include <sys/mount.h>
31 #include "mount.h"
32 
33 /*
34  * Automount file system
35  * Direct file system
36  * Root file system
37  * Top-level file system
38  */
39 
40 /*
41  * Interval between forced retries of a mount.
42  */
43 #define RETRY_INTERVAL	2
44 
45 /*
46  * AFS needs nothing in particular.
47  */
48 static char *afs_match P((am_opts *fo));
49 static char *afs_match(fo)
50 am_opts *fo;
51 {
52 	char *p = fo->opt_rfs;
53 	if (!fo->opt_rfs) {
54 		plog(XLOG_USER, "auto: no mount point named (rfs:=)");
55 		return 0;
56 	}
57 	if (!fo->opt_fs) {
58 		plog(XLOG_USER, "auto: no map named (fs:=)");
59 		return 0;
60 	}
61 	/*
62 	 * Swap round fs:= and rfs:= options
63 	 * ... historical (jsp)
64 	 */
65 	fo->opt_rfs = fo->opt_fs;
66 	fo->opt_fs = p;
67 	/*
68 	 * mtab entry turns out to be the name of the mount map
69 	 */
70 	return strdup(fo->opt_rfs ? fo->opt_rfs : ".");
71 }
72 
73 /*
74  * Mount an automounter directory.
75  * The automounter is connected into the system
76  * as a user-level NFS server.  mount_toplvl constructs
77  * the necessary NFS parameters to be given to the
78  * kernel so that it will talk back to us.
79  */
80 static int mount_toplvl P((char *dir, char *opts));
81 static int mount_toplvl(dir, opts)
82 char *dir;
83 char *opts;
84 {
85 	struct nfs_args nfs_args;
86 	struct mntent mnt;
87 	int retry;
88 	struct sockaddr_in sin;
89 	unsigned short port;
90 	int flags;
91 	extern nfs_fh *root_fh();
92 	nfs_fh *fhp;
93 	char fs_hostname[MAXHOSTNAMELEN+MAXPATHLEN+1];
94 
95 	MTYPE_TYPE type = MOUNT_TYPE_NFS;
96 
97 	bzero((voidp) &nfs_args, sizeof(nfs_args));	/* Paranoid */
98 
99 	mnt.mnt_dir = dir;
100 	mnt.mnt_fsname = pid_fsname;
101 	mnt.mnt_type = MNTTYPE_AUTO;
102 	mnt.mnt_opts = opts;
103 	mnt.mnt_freq = 0;
104 	mnt.mnt_passno = 0;
105 
106 	retry = hasmntval(&mnt, "retry");
107 	if (retry <= 0)
108 		retry = 2;	/* XXX */
109 
110 	/*
111 	 * get fhandle of remote path for automount point
112 	 */
113 
114 	fhp = root_fh(dir);
115 	if (!fhp) {
116 		plog(XLOG_FATAL, "Can't find root file handle for %s", dir);
117 		return EINVAL;
118 	}
119 
120 	NFS_FH_DREF(nfs_args.fh, (NFS_FH_TYPE) fhp);
121 
122 	/*
123 	 * Create sockaddr to point to the local machine.  127.0.0.1
124 	 * is not used since that will not work in HP-UX clusters and
125 	 * this is no more expensive.
126 	 */
127 	bzero((voidp) &sin, sizeof(sin));
128 	sin.sin_family = AF_INET;
129 	sin.sin_addr = myipaddr;
130 	if (port = hasmntval(&mnt, "port")) {
131 		sin.sin_port = htons(port);
132 	} else {
133 		plog(XLOG_ERROR, "no port number specified for %s", dir);
134 		return EINVAL;
135 	}
136 
137 	/*
138 	 * set mount args
139 	 */
140 	NFS_SA_DREF(nfs_args, &sin);
141 
142 	/*
143 	 * Make a ``hostname'' string for the kernel
144 	 */
145 #ifndef HOSTNAMESZ
146 #define	SHORT_MOUNT_NAME
147 #endif /* HOSTNAMESZ */
148 #ifdef SHORT_MOUNT_NAME
149 	sprintf(fs_hostname, "amd:%d", foreground ? mypid : getppid());
150 #else
151 	sprintf(fs_hostname, "pid%d@%s:%s", foreground ? mypid : getppid(), hostname, dir);
152 #endif /* SHORT_MOUNT_NAME */
153 	nfs_args.hostname = fs_hostname;
154 	nfs_args.flags |= NFSMNT_HOSTNAME;
155 #ifdef HOSTNAMESZ
156 	/*
157 	 * Most kernels have a name length restriction.
158 	 */
159 	if (strlen(fs_hostname) >= HOSTNAMESZ)
160 		strcpy(fs_hostname + HOSTNAMESZ - 3, "..");
161 #endif /* HOSTNAMESZ */
162 
163 	/*
164 	 * Parse a subset of the standard nfs options.  The
165 	 * others are probably irrelevant for this application
166 	 */
167 	if (nfs_args.timeo = hasmntval(&mnt, "timeo"))
168 		nfs_args.flags |= NFSMNT_TIMEO;
169 
170 	if (nfs_args.retrans = hasmntval(&mnt, "retrans"))
171 		nfs_args.flags |= NFSMNT_RETRANS;
172 
173 #ifdef NFSMNT_BIODS
174 	if (nfs_args.biods = hasmntval(&mnt, "biods"))
175 		nfs_args.flags |= NFSMNT_BIODS;
176 
177 #endif /* NFSMNT_BIODS */
178 
179 #if defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX)
180 	/*
181 	 * Don't cache attributes - they are changing under
182 	 * the kernel's feet...
183 	 */
184 	nfs_args.acregmin = nfs_args.acregmax = 1;
185 	nfs_args.flags |= NFSMNT_ACREGMIN|NFSMNT_ACREGMAX;
186 #endif /* defined(NFSMNT_ACREGMIN) && defined(NFSMNT_ACREGMAX) */
187 	/*
188 	 * These two are constructed internally by the calling routine
189 	 */
190 	if (hasmntopt(&mnt, MNTOPT_SOFT) != NULL)
191 		nfs_args.flags |= NFSMNT_SOFT;
192 
193 #ifdef MNTOPT_INTR
194 	if (hasmntopt(&mnt, MNTOPT_INTR) != NULL)
195 		nfs_args.flags |= NFSMNT_INT;
196 #endif /* MNTOPT_INTR */
197 
198 	flags = compute_mount_flags(&mnt);
199 #ifdef ULTRIX_HACK
200 	nfs_args.gfs_flags = flags;
201 	flags &= M_RDONLY;
202 	if (flags & M_RDONLY)
203 		nfs_args.flags |= NFSMNT_RONLY;
204 #endif /* ULTRIX_HACK */
205 	return mount_fs(&mnt, flags, (caddr_t) &nfs_args, retry, type);
206 }
207 
208 static void afs_mkcacheref P((mntfs *mf));
209 static void afs_mkcacheref(mf)
210 mntfs *mf;
211 {
212 	/*
213 	 * Build a new map cache for this node, or re-use
214 	 * an existing cache for the same map.
215 	 */
216 	char *cache;
217 	if (mf->mf_fo && mf->mf_fo->opt_cache)
218 	  	cache = mf->mf_fo->opt_cache;
219 	else
220 	  	cache = "none";
221 	mf->mf_private = (voidp) mapc_find(mf->mf_info, cache);
222 	mf->mf_prfree = mapc_free;
223 }
224 
225 /*
226  * Mount the root...
227  */
228 static int root_mount P((am_node *mp));
229 static int root_mount(mp)
230 am_node *mp;
231 {
232 	mntfs *mf = mp->am_mnt;
233 
234 	mf->mf_mount = strealloc(mf->mf_mount, pid_fsname);
235 	mf->mf_private = (voidp) mapc_find(mf->mf_info, "");
236 	mf->mf_prfree = mapc_free;
237 
238 	return 0;
239 }
240 
241 /*
242  * Mount a sub-mount
243  */
244 static int afs_mount P((am_node *mp));
245 static int afs_mount(mp)
246 am_node *mp;
247 {
248 	mntfs *mf = mp->am_mnt;
249 
250 	/*
251 	 * Pseudo-directories are used to provide some structure
252 	 * to the automounted directories instead
253 	 * of putting them all in the top-level automount directory.
254 	 *
255 	 * Here, just increment the parent's link count.
256 	 */
257 	mp->am_parent->am_fattr.nlink++;
258 	/*
259 	 * Info field of . means use parent's info field.
260 	 * Historical - not documented.
261 	 */
262 	if (mf->mf_info[0] == '.' && mf->mf_info[1] == '\0')
263 		mf->mf_info = strealloc(mf->mf_info, mp->am_parent->am_mnt->mf_info);
264 	/*
265 	 * Compute prefix:
266 	 *
267 	 * If there is an option prefix then use that else
268 	 * If the parent had a prefix then use that with name
269 	 *	of this node appended else
270 	 * Use the name of this node.
271 	 *
272 	 * That means if you want no prefix you must say so
273 	 * in the map.
274 	 */
275 	if (mf->mf_fo->opt_pref) {
276 		/*
277 		 * the prefix specified as an option
278 		 */
279 		mp->am_pref = strdup(mf->mf_fo->opt_pref);
280 	} else {
281 		/*
282 		 * else the parent's prefix
283 		 * followed by the name
284 		 * followed by /
285 		 */
286 		char *ppref = mp->am_parent->am_pref;
287 		if (ppref == 0)
288 			ppref = "";
289 		mp->am_pref = str3cat((char *) 0, ppref, mp->am_name, "/");
290 	}
291 
292 	/*
293 	 * Attach a map cache
294 	 */
295 	afs_mkcacheref(mf);
296 
297 	return 0;
298 }
299 
300 /*
301  * Mount the top-level
302  */
303 static int toplvl_mount P((am_node *mp));
304 static int toplvl_mount(mp)
305 am_node *mp;
306 {
307 	mntfs *mf = mp->am_mnt;
308 	struct stat stb;
309 	char opts[256];
310 	int error;
311 	char *mnttype;
312 
313 	/*
314 	 * Mounting the automounter.
315 	 * Make sure the mount directory exists, construct
316 	 * the mount options and call the mount_toplvl routine.
317 	 */
318 
319 	if (stat(mp->am_path, &stb) < 0) {
320 		return errno;
321 	} else if ((stb.st_mode & S_IFMT) != S_IFDIR) {
322 		plog(XLOG_WARNING, "%s is not a directory", mp->am_path);
323 		return ENOTDIR;
324 	}
325 
326 	if (mf->mf_ops == &toplvl_ops) mnttype = "indirect";
327 	else if (mf->mf_ops == &dfs_ops) mnttype = "direct";
328 #ifdef HAS_UNION_FS
329 	else if (mf->mf_ops == &union_ops) mnttype = "union";
330 #endif
331 	else mnttype = "auto";
332 
333 	/*
334 	 * Construct some mount options
335 	 */
336 	sprintf(opts,
337 #ifdef MNTOPT_INTR
338 		"%s,%s,%s=%d,%s=%d,%s=%d,%s",
339 		MNTOPT_INTR,
340 #else
341 		"%s,%s=%d,%s=%d,%s=%d,%s",
342 #endif /* MNTOPT_INTR */
343 		"rw",
344 		"port", nfs_port,
345 		"timeo", afs_timeo,
346 		"retrans", afs_retrans,
347 		mnttype);
348 
349 	error = mount_toplvl(mf->mf_mount, opts);
350 	if (error) {
351 		errno = error;
352 		plog(XLOG_FATAL, "mount_toplvl: %m");
353 		return error;
354 	}
355 
356 	return 0;
357 }
358 
359 static void toplvl_mounted P((mntfs *mf));
360 static void toplvl_mounted(mf)
361 mntfs *mf;
362 {
363 	afs_mkcacheref(mf);
364 }
365 
366 #ifdef HAS_UNION_FS
367 /*
368  * Create a reference to a union'ed entry
369  */
370 static int create_union_node P((char *dir, voidp arg));
371 static int create_union_node(dir, arg)
372 char *dir;
373 voidp arg;
374 {
375 	if (strcmp(dir, "/defaults") != 0) {
376 		int error = 0;
377 		(void) toplvl_ops.lookuppn(arg, dir, &error, VLOOK_CREATE);
378 		if (error > 0) {
379 			errno = error; /* XXX */
380 			plog(XLOG_ERROR, "Could not mount %s: %m", dir);
381 		}
382 		return error;
383 	}
384 	return 0;
385 }
386 
387 static void union_mounted P((mntfs *mf));
388 static void union_mounted(mf)
389 mntfs *mf;
390 {
391 	int i;
392 
393 	afs_mkcacheref(mf);
394 
395 	/*
396 	 * Having made the union mount point,
397 	 * populate all the entries...
398 	 */
399 	for (i = 0; i <= last_used_map; i++) {
400 		am_node *mp = exported_ap[i];
401 		if (mp && mp->am_mnt == mf) {
402 			/* return value from create_union_node is ignored by mapc_keyiter */
403 			(void) mapc_keyiter((mnt_map *) mp->am_mnt->mf_private,
404 				(void (*)P((char*,void*))) create_union_node, mp);
405 			break;
406 		}
407 	}
408 
409 #ifdef notdef
410 	/*
411 	 * would be nice to flush most of the cache, but we need to
412 	 * keep the wildcard and /defaults entries...
413 	 */
414 	mapc_free(mf->mf_private);
415 	mf->mf_private = (voidp) mapc_find(mf->mf_info, "inc");
416 /*	mapc_add_kv(mf->mf_private, strdup("/defaults"),
417 		strdup("type:=link;opts:=nounmount;sublink:=${key}")); */
418 #endif
419 }
420 #endif /* HAS_UNION_FS */
421 
422 /*
423  * Unmount an automount sub-node
424  */
425 static int afs_umount P((am_node *mp));
426 static int afs_umount(mp)
427 am_node *mp;
428 {
429 	return 0;
430 }
431 
432 /*
433  * Unmount a top-level automount node
434  */
435 static int toplvl_umount P((am_node *mp));
436 static int toplvl_umount(mp)
437 am_node *mp;
438 {
439 	int error;
440 
441 	struct stat stb;
442 again:
443 	/*
444 	 * The lstat is needed if this mount is type=direct.
445 	 * When that happens, the kernel cache gets confused
446 	 * between the underlying type (dir) and the mounted
447 	 * type (link) and so needs to be re-synced before
448 	 * the unmount.  This is all because the unmount system
449 	 * call follows links and so can't actually unmount
450 	 * a link (stupid!).  It was noted that doing an ls -ld
451 	 * of the mount point to see why things were not working
452 	 * actually fixed the problem - so simulate an ls -ld here.
453 	 */
454 	if (lstat(mp->am_path, &stb) < 0) {
455 #ifdef DEBUG
456 		dlog("lstat(%s): %m", mp->am_path);
457 #endif /* DEBUG */
458 	}
459 	error = UMOUNT_FS(mp->am_path);
460 	if (error == EBUSY) {
461 		plog(XLOG_WARNING, "afs_unmount retrying %s in 1s", mp->am_path);
462 		sleep(1);	/* XXX */
463 		goto again;
464 	}
465 
466 	return error;
467 }
468 
469 /*
470  * Unmount an automount node
471  */
472 static void afs_umounted P((am_node *mp));
473 static void afs_umounted(mp)
474 am_node *mp;
475 {
476 	/*
477 	 * If this is a pseudo-directory then just adjust the link count
478 	 * in the parent, otherwise call the generic unmount routine
479 	 */
480 	if (mp->am_parent && mp->am_parent->am_parent)
481 		--mp->am_parent->am_fattr.nlink;
482 }
483 
484 /*
485  * Mounting a file system may take a significant period of time.  The
486  * problem is that if this is done in the main process thread then
487  * the entire automounter could be blocked, possibly hanging lots of
488  * processes on the system.  Instead we use a continuation scheme to
489  * allow mounts to be attempted in a sub-process.  When the sub-process
490  * exits we pick up the exit status (by convention a UN*X error number)
491  * and continue in a notifier.  The notifier gets handed a data structure
492  * and can then determine whether the mount was successful or not.  If
493  * not, it updates the data structure and tries again until there are no
494  * more ways to try the mount, or some other permanent error occurs.
495  * In the mean time no RPC reply is sent, even after the mount is succesful.
496  * We rely on the RPC retry mechanism to resend the lookup request which
497  * can then be handled.
498  */
499 
500 
501 struct continuation {
502 	char **ivec;		/* Current mount info */
503 	am_node *mp;		/* Node we are trying to mount */
504 	char *key;		/* Map key */
505 	char *info;		/* Info string */
506 	char **xivec;		/* Saved strsplit vector */
507 	char *auto_opts;	/* Automount options */
508 	am_opts fs_opts;	/* Filesystem options */
509 	char *def_opts;		/* Default automount options */
510 	int retry;		/* Try again? */
511 	int tried;		/* Have we tried any yet? */
512 	time_t start;		/* Time we started this mount */
513 	int callout;		/* Callout identifier */
514 };
515 
516 #define	IN_PROGRESS(cp) ((cp)->mp->am_mnt->mf_flags & MFF_MOUNTING)
517 
518 /*
519  * Discard an old continuation
520  */
521 static void free_continuation P((struct continuation *cp));
522 static void free_continuation(cp)
523 struct continuation *cp;
524 {
525 	if (cp->callout)
526 		untimeout(cp->callout);
527 	free((voidp) cp->key);
528 	free((voidp) cp->xivec);
529 	free((voidp) cp->info);
530 	free((voidp) cp->auto_opts);
531 	free((voidp) cp->def_opts);
532 	free_opts(&cp->fs_opts);
533 	free((voidp) cp);
534 }
535 
536 static int afs_bgmount P((struct continuation*, int));
537 
538 /*
539  * Discard the underlying mount point and replace
540  * with a reference to an error filesystem.
541  */
542 static void assign_error_mntfs P((am_node *mp));
543 static void assign_error_mntfs(mp)
544 am_node *mp;
545 {
546 	if (mp->am_error > 0) {
547 		/*
548 		 * Save the old error code
549 		 */
550 		int error = mp->am_error;
551 		if (error <= 0)
552 			error = mp->am_mnt->mf_error;
553 		/*
554 		 * Discard the old filesystem
555 		 */
556 		free_mntfs(mp->am_mnt);
557 		/*
558 		 * Allocate a new error reference
559 		 */
560 		mp->am_mnt = new_mntfs();
561 		/*
562 		 * Put back the error code
563 		 */
564 		mp->am_mnt->mf_error = error;
565 		mp->am_mnt->mf_flags |= MFF_ERROR;
566 		/*
567 		 * Zero the error in the mount point
568 		 */
569 		mp->am_error = 0;
570 	}
571 }
572 
573 /*
574  * The continuation function.  This is called by
575  * the task notifier when a background mount attempt
576  * completes.
577  */
578 static void afs_cont P((int rc, int term, voidp closure));
579 static void afs_cont(rc, term, closure)
580 int rc;
581 int term;
582 voidp closure;
583 {
584 	struct continuation *cp = (struct continuation *) closure;
585 	mntfs *mf = cp->mp->am_mnt;
586 
587 	/*
588 	 * Definitely not trying to mount at the moment
589 	 */
590 	mf->mf_flags &= ~MFF_MOUNTING;
591 	/*
592 	 * While we are mounting - try to avoid race conditions
593 	 */
594 	new_ttl(cp->mp);
595 
596 	/*
597 	 * Wakeup anything waiting for this mount
598 	 */
599 	wakeup((voidp) mf);
600 
601 	/*
602 	 * Check for termination signal or exit status...
603 	 */
604 	if (rc || term) {
605 		am_node *xmp;
606 
607 		if (term) {
608 			/*
609 			 * Not sure what to do for an error code.
610 			 */
611 			mf->mf_error = EIO;	/* XXX ? */
612 			mf->mf_flags |= MFF_ERROR;
613 			plog(XLOG_ERROR, "mount for %s got signal %d", cp->mp->am_path, term);
614 		} else {
615 			/*
616 			 * Check for exit status...
617 			 */
618 			mf->mf_error = rc;
619 			mf->mf_flags |= MFF_ERROR;
620 			errno = rc;	/* XXX */
621 			plog(XLOG_ERROR, "%s: mount (afs_cont): %m", cp->mp->am_path);
622 		}
623 
624 		/*
625 		 * If we get here then that attempt didn't work, so
626 		 * move the info vector pointer along by one and
627 		 * call the background mount routine again
628 		 */
629 		amd_stats.d_merr++;
630 		cp->ivec++;
631 		xmp = cp->mp;
632 		(void) afs_bgmount(cp, 0);
633 		assign_error_mntfs(xmp);
634 	} else {
635 		/*
636 		 * The mount worked.
637 		 */
638 		am_mounted(cp->mp);
639 		free_continuation(cp);
640 	}
641 
642 	reschedule_timeout_mp();
643 }
644 
645 /*
646  * Retry a mount
647  */
648 /*ARGSUSED*/
649 static void afs_retry P((int rc, int term, voidp closure));
650 static void afs_retry(rc, term, closure)
651 int rc;
652 int term;
653 voidp closure;
654 {
655 	struct continuation *cp = (struct continuation *) closure;
656 	int error = 0;
657 
658 #ifdef DEBUG
659 	dlog("Commencing retry for mount of %s", cp->mp->am_path);
660 #endif /* DEBUG */
661 
662 	new_ttl(cp->mp);
663 
664 	if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime()) {
665 		/*
666 		 * The entire mount has timed out.
667 		 * Set the error code and skip past
668 		 * all the info vectors so that
669 		 * afs_bgmount will not have any more
670 		 * ways to try the mount, so causing
671 		 * an error.
672 		 */
673 		plog(XLOG_INFO, "mount of \"%s\" has timed out", cp->mp->am_path);
674 		error = ETIMEDOUT;
675 		while (*cp->ivec)
676 			cp->ivec++;
677 	}
678 
679 	if (error || !IN_PROGRESS(cp)) {
680 		(void) afs_bgmount(cp, error);
681 	}
682 	reschedule_timeout_mp();
683 }
684 
685 /*
686  * Try to mount a file system.  Can be called
687  * directly or in a sub-process by run_task
688  */
689 static int try_mount P((voidp mvp));
690 static int try_mount(mvp)
691 voidp mvp;
692 {
693 	/*
694 	 * Mount it!
695 	 */
696 	int error;
697 	am_node *mp = (am_node *) mvp;
698 	mntfs *mf = mp->am_mnt;
699 
700 	/*
701 	 * If the directory is not yet made and
702 	 * it needs to be made, then make it!
703 	 * This may be run in a backgroun process
704 	 * in which case the flag setting won't be
705 	 * noticed later - but it is set anyway
706 	 * just after run_task is called.  It
707 	 * should probably go away totally...
708 	 */
709 	if (!(mf->mf_flags & MFF_MKMNT) && mf->mf_ops->fs_flags & FS_MKMNT) {
710 		error = mkdirs(mf->mf_mount, 0555);
711 		if (!error)
712 			mf->mf_flags |= MFF_MKMNT;
713 	}
714 
715 	error = mount_node(mp);
716 #ifdef DEBUG
717 	if (error > 0) {
718 		errno = error;
719 		dlog("afs call to mount_node failed: %m");
720 	}
721 #endif /* DEBUG */
722 	return error;
723 }
724 
725 /*
726  * Pick a file system to try mounting and
727  * do that in the background if necessary
728  *
729 For each location:
730 	if it is new -defaults then
731 		extract and process
732 		continue;
733 	fi
734 	if it is a cut then
735 		if a location has been tried then
736 			break;
737 		fi
738 		continue;
739 	fi
740 	parse mount location
741 	discard previous mount location if required
742 	find matching mounted filesystem
743 	if not applicable then
744 		this_error = No such file or directory
745 		continue
746 	fi
747 	if the filesystem failed to be mounted then
748 		this_error = error from filesystem
749 	elif the filesystem is mounting or unmounting then
750 		this_error = -1
751 	elif the fileserver is down then
752 		this_error = -1
753 	elif the filesystem is already mounted
754 		this_error = 0
755 		break
756 	fi
757 	if no error on this mount then
758 		this_error = initialise mount point
759 	fi
760 	if no error on this mount and mount is delayed then
761 		this_error = -1
762 	fi
763 	if this_error < 0 then
764 		retry = true
765 	fi
766 	if no error on this mount then
767 		make mount point if required
768 	fi
769 	if no error on this mount then
770 		if mount in background then
771 			run mount in background
772 			return -1
773 		else
774 			this_error = mount in foreground
775 		fi
776 	fi
777 	if an error occured on this mount then
778 		update stats
779 		save error in mount point
780 	fi
781 endfor
782  */
783 
784 static int afs_bgmount P((struct continuation *cp, int mpe));
785 static int afs_bgmount(cp, mpe)
786 struct continuation *cp;
787 int mpe;
788 {
789 	mntfs *mf = cp->mp->am_mnt;	/* Current mntfs */
790 	mntfs *mf_retry = 0;		/* First mntfs which needed retrying */
791 	int this_error = -1;		/* Per-mount error */
792 	int hard_error = -1;
793 	int mp_error = mpe;
794 
795 	/*
796 	 * Try to mount each location.
797 	 * At the end:
798 	 * hard_error == 0 indicates something was mounted.
799 	 * hard_error > 0 indicates everything failed with a hard error
800 	 * hard_error < 0 indicates nothing could be mounted now
801 	 */
802 	for (; this_error && *cp->ivec; cp->ivec++) {
803 		am_ops *p;
804 		am_node *mp = cp->mp;
805 		char *link_dir;
806 		int dont_retry;
807 
808 		if (hard_error < 0)
809 			hard_error = this_error;
810 
811 		this_error = -1;
812 
813 		if (**cp->ivec == '-') {
814 			/*
815 			 * Pick up new defaults
816 			 */
817 			if (cp->auto_opts && *cp->auto_opts)
818 				cp->def_opts = str3cat(cp->def_opts, cp->auto_opts, ";", *cp->ivec+1);
819 			else
820 				cp->def_opts = strealloc(cp->def_opts, *cp->ivec+1);
821 #ifdef DEBUG
822 			dlog("Setting def_opts to \"%s\"", cp->def_opts);
823 #endif /* DEBUG */
824 			continue;
825 		}
826 
827 		/*
828 		 * If a mount has been attempted, and we find
829 		 * a cut then don't try any more locations.
830 		 */
831 		if (strcmp(*cp->ivec, "/") == 0 || strcmp(*cp->ivec, "||") == 0) {
832 			if (cp->tried) {
833 #ifdef DEBUG
834 				dlog("Cut: not trying any more locations for %s",
835 					mp->am_path);
836 #endif /* DEBUG */
837 				break;
838 			}
839 			continue;
840 		}
841 
842 #ifdef SUNOS4_COMPAT
843 #ifdef nomore
844 		/*
845 		 * By default, you only get this bit on SunOS4.
846 		 * If you want this anyway, then define SUNOS4_COMPAT
847 		 * in the relevant "os-blah.h" file.
848 		 *
849 		 * We make the observation that if the local key line contains
850 		 * no '=' signs then either it is sick, or it is a SunOS4-style
851 		 * "host:fs[:link]" line.  In the latter case the am_opts field
852 		 * is also assumed to be in old-style, so you can't mix & match.
853 		 * You can use ${} expansions for the fs and link bits though...
854 		 *
855 		 * Actually, this doesn't really cover all the possibilities for
856 		 * the latest SunOS automounter and it is debatable whether there
857 		 * is any point bothering.
858 		 */
859 		if (strchr(*cp->ivec, '=') == 0)
860 			p = sunos4_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
861 		else
862 #endif
863 #endif /* SUNOS4_COMPAT */
864 			p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
865 
866 		/*
867 		 * Find a mounted filesystem for this node.
868 		 */
869 		mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, cp->fs_opts.opt_fs,
870 			cp->fs_opts.fs_mtab, cp->auto_opts, cp->fs_opts.opt_opts, cp->fs_opts.opt_remopts);
871 
872 		p = mf->mf_ops;
873 #ifdef DEBUG
874 		dlog("Got a hit with %s", p->fs_type);
875 #endif /* DEBUG */
876 		/*
877 		 * Note whether this is a real mount attempt
878 		 */
879 		if (p == &efs_ops) {
880 			plog(XLOG_MAP, "Map entry %s for %s failed to match", *cp->ivec, mp->am_path);
881 			if (this_error <= 0)
882 				this_error = ENOENT;
883 			continue;
884 		} else {
885 			if (cp->fs_opts.fs_mtab) {
886 				plog(XLOG_MAP, "Trying mount of %s on %s fstype %s",
887 					cp->fs_opts.fs_mtab, mp->am_path, p->fs_type);
888 			}
889 			cp->tried = TRUE;
890 		}
891 
892 		this_error = 0;
893 		dont_retry = FALSE;
894 
895 		if (mp->am_link) {
896 			free(mp->am_link);
897 			mp->am_link = 0;
898 		}
899 
900 		link_dir = mf->mf_fo->opt_sublink;
901 
902 		if (link_dir && *link_dir) {
903 			if (*link_dir == '/') {
904 				mp->am_link = strdup(link_dir);
905 			} else {
906 				mp->am_link = str3cat((char *) 0,
907 					mf->mf_fo->opt_fs, "/", link_dir);
908 				normalize_slash(mp->am_link);
909 			}
910 		}
911 
912 		if (mf->mf_error > 0) {
913 			this_error = mf->mf_error;
914 		} else if (mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)) {
915 			/*
916 			 * Still mounting - retry later
917 			 */
918 #ifdef DEBUG
919 			dlog("Duplicate pending mount fstype %s", p->fs_type);
920 #endif /* DEBUG */
921 			this_error = -1;
922 		} else if (FSRV_ISDOWN(mf->mf_server)) {
923 			/*
924 			 * Would just mount from the same place
925 			 * as a hung mount - so give up
926 			 */
927 #ifdef DEBUG
928 			dlog("%s is already hung - giving up", mf->mf_mount);
929 #endif /* DEBUG */
930 			mp_error = EWOULDBLOCK;
931 			dont_retry = TRUE;
932 			this_error = -1;
933 		} else if (mf->mf_flags & MFF_MOUNTED) {
934 #ifdef DEBUG
935 			dlog("duplicate mount of \"%s\" ...", mf->mf_info);
936 #endif /* DEBUG */
937 			/*
938 			 * Just call mounted()
939 			 */
940 			am_mounted(mp);
941 
942 			this_error = 0;
943 			break;
944 		}
945 
946 		/*
947 		 * Will usually need to play around with the mount nodes
948 		 * file attribute structure.  This must be done here.
949 		 * Try and get things initialised, even if the fileserver
950 		 * is not known to be up.  In the common case this will
951 		 * progress things faster.
952 		 */
953 		if (!this_error) {
954 			/*
955 			 * Fill in attribute fields.
956 			 */
957 			if (mf->mf_ops->fs_flags & FS_DIRECTORY)
958 				mk_fattr(mp, NFDIR);
959 			else
960 				mk_fattr(mp, NFLNK);
961 
962 			mp->am_fattr.fileid = mp->am_gen;
963 
964 			if (p->fs_init)
965 				this_error = (*p->fs_init)(mf);
966 		}
967 
968 		/*
969 		 * Make sure the fileserver is UP before doing any more work
970 		 */
971 		if (!FSRV_ISUP(mf->mf_server)) {
972 #ifdef DEBUG
973 			dlog("waiting for server %s to become available", mf->mf_server->fs_host);
974 #endif
975 			this_error =  -1;
976 		}
977 
978 		if (!this_error && mf->mf_fo->opt_delay) {
979 			/*
980 			 * If there is a delay timer on the mount
981 			 * then don't try to mount if the timer
982 			 * has not expired.
983 			 */
984 			int i = atoi(mf->mf_fo->opt_delay);
985 			if (i > 0 && clocktime() < (cp->start + i)) {
986 #ifdef DEBUG
987 				dlog("Mount of %s delayed by %ds", mf->mf_mount, i - clocktime() + cp->start);
988 #endif /* DEBUG */
989 				this_error = -1;
990 			}
991 		}
992 
993 		if (this_error < 0 && !dont_retry) {
994 			if (!mf_retry)
995 				mf_retry = dup_mntfs(mf);
996 			cp->retry = TRUE;
997 		}
998 
999 		if (!this_error)
1000 		if (p->fs_flags & FS_MBACKGROUND) {
1001 			mf->mf_flags |= MFF_MOUNTING;	/*XXX*/
1002 #ifdef DEBUG
1003 			dlog("backgrounding mount of \"%s\"", mf->mf_mount);
1004 #endif /* DEBUG */
1005 			if (cp->callout) {
1006 				untimeout(cp->callout);
1007 				cp->callout = 0;
1008 			}
1009 			run_task(try_mount, (voidp) mp, afs_cont, (voidp) cp);
1010 			mf->mf_flags |= MFF_MKMNT;	/* XXX */
1011 			if (mf_retry) free_mntfs(mf_retry);
1012 			return -1;
1013 		} else {
1014 #ifdef DEBUG
1015 			dlog("foreground mount of \"%s\" ...", mf->mf_info);
1016 #endif /* DEBUG */
1017 			this_error = try_mount((voidp) mp);
1018 			if (this_error < 0) {
1019 				if (!mf_retry)
1020 					mf_retry = dup_mntfs(mf);
1021 				cp->retry = TRUE;
1022 			}
1023 		}
1024 
1025 		if (this_error >= 0) {
1026 			if (this_error > 0) {
1027 				amd_stats.d_merr++;
1028 				if (mf != mf_retry) {
1029 					mf->mf_error = this_error;
1030 					mf->mf_flags |= MFF_ERROR;
1031 				}
1032 			}
1033 			/*
1034 			 * Wakeup anything waiting for this mount
1035 			 */
1036 			wakeup((voidp) mf);
1037 		}
1038 	}
1039 
1040 	if (this_error && cp->retry) {
1041 		free_mntfs(mf);
1042 		mf = cp->mp->am_mnt = mf_retry;
1043 		/*
1044 		 * Not retrying again (so far)
1045 		 */
1046 		cp->retry = FALSE;
1047 		cp->tried = FALSE;
1048 		/*
1049 		 * Start at the beginning.
1050 		 * Rewind the location vector and
1051 		 * reset the default options.
1052 		 */
1053 		cp->ivec = cp->xivec;
1054 		cp->def_opts = strealloc(cp->def_opts, cp->auto_opts);
1055 		/*
1056 		 * Arrange that afs_bgmount is called
1057 		 * after anything else happens.
1058 		 */
1059 #ifdef DEBUG
1060 		dlog("Arranging to retry mount of %s", cp->mp->am_path);
1061 #endif /* DEBUG */
1062 		sched_task(afs_retry, (voidp) cp, (voidp) mf);
1063 		if (cp->callout)
1064 			untimeout(cp->callout);
1065 		cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf);
1066 
1067 		cp->mp->am_ttl = clocktime() + RETRY_INTERVAL;
1068 
1069 		/*
1070 		 * Not done yet - so don't return anything
1071 		 */
1072 		return -1;
1073 	}
1074 
1075 	if (hard_error < 0 || this_error == 0)
1076 		hard_error = this_error;
1077 
1078 	/*
1079 	 * Discard handle on duff filesystem.
1080 	 * This should never happen since it
1081 	 * should be caught by the case above.
1082 	 */
1083 	if (mf_retry) {
1084 		if (hard_error)
1085 			plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount);
1086 		free_mntfs(mf_retry);
1087 	}
1088 
1089 	/*
1090 	 * If we get here, then either the mount succeeded or
1091 	 * there is no more mount information available.
1092 	 */
1093 	if (hard_error < 0 && mp_error)
1094 		hard_error = cp->mp->am_error = mp_error;
1095 	if (hard_error > 0) {
1096 		/*
1097 		 * Set a small(ish) timeout on an error node if
1098 		 * the error was not a time out.
1099 		 */
1100 		switch (hard_error) {
1101 		case ETIMEDOUT:
1102 		case EWOULDBLOCK:
1103 			cp->mp->am_timeo = 5;
1104 			break;
1105 		default:
1106 			cp->mp->am_timeo = 17;
1107 			break;
1108 		}
1109 		new_ttl(cp->mp);
1110 	}
1111 
1112 	/*
1113 	 * Make sure that the error value in the mntfs has a
1114 	 * reasonable value.
1115 	 */
1116 	if (mf->mf_error < 0) {
1117 		mf->mf_error = hard_error;
1118 		if (hard_error)
1119 			mf->mf_flags |= MFF_ERROR;
1120 	}
1121 
1122 	/*
1123 	 * In any case we don't need the continuation any more
1124 	 */
1125 	free_continuation(cp);
1126 
1127 	return hard_error;
1128 }
1129 
1130 /*
1131  * Automount interface to RPC lookup routine
1132  */
1133 static am_node *afs_lookuppn P((am_node *mp, char *fname, int *error_return, int op));
1134 static am_node *afs_lookuppn(mp, fname, error_return, op)
1135 am_node *mp;
1136 char *fname;
1137 int *error_return;
1138 int op;
1139 {
1140 #define ereturn(x) { *error_return = x; return 0; }
1141 
1142 	/*
1143 	 * Find the corresponding entry and return
1144 	 * the file handle for it.
1145 	 */
1146 	am_node *ap, *new_mp, *ap_hung;
1147 	char *info;			/* Mount info - where to get the file system */
1148 	char **ivec, **xivec;		/* Split version of info */
1149 	char *auto_opts;		/* Automount options */
1150 	int error = 0;			/* Error so far */
1151 	char path_name[MAXPATHLEN];	/* General path name buffer */
1152 	char *pfname;			/* Path for database lookup */
1153 	struct continuation *cp;	/* Continuation structure if we need to mount */
1154 	int in_progress = 0;		/* # of (un)mount in progress */
1155 	char *dflts;
1156 	mntfs *mf;
1157 
1158 #ifdef DEBUG
1159 	dlog("in afs_lookuppn");
1160 #endif /* DEBUG */
1161 
1162 	/*
1163 	 * If the server is shutting down
1164 	 * then don't return information
1165 	 * about the mount point.
1166 	 */
1167 	if (amd_state == Finishing) {
1168 #ifdef DEBUG
1169 		if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &dfs_ops)
1170 			dlog("%s mount ignored - going down", fname);
1171 		else
1172 			dlog("%s/%s mount ignored - going down", mp->am_path, fname);
1173 #endif /* DEBUG */
1174 		ereturn(ENOENT);
1175 	}
1176 
1177 	/*
1178 	 * Handle special case of "." and ".."
1179 	 */
1180 	if (fname[0] == '.') {
1181 		if (fname[1] == '\0')
1182 			return mp;	/* "." is the current node */
1183 		if (fname[1] == '.' && fname[2] == '\0') {
1184 			if (mp->am_parent) {
1185 #ifdef DEBUG
1186 				dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path);
1187 #endif /* DEBUG */
1188 				return mp->am_parent;	/* ".." is the parent node */
1189 			}
1190 			ereturn(ESTALE);
1191 		}
1192 	}
1193 
1194 	/*
1195 	 * Check for valid key name.
1196 	 * If it is invalid then pretend it doesn't exist.
1197 	 */
1198 	if (!valid_key(fname)) {
1199 		plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname);
1200 		ereturn(ENOENT);
1201 	}
1202 
1203 	/*
1204 	 * Expand key name.
1205 	 * fname is now a private copy.
1206 	 */
1207 	fname = expand_key(fname);
1208 
1209 	for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) {
1210 		/*
1211 		 * Otherwise search children of this node
1212 		 */
1213 		if (FSTREQ(ap->am_name, fname)) {
1214 			mf = ap->am_mnt;
1215 			if (ap->am_error) {
1216 				error = ap->am_error;
1217 				continue;
1218 			}
1219 
1220 			/*
1221 			 * If the error code is undefined then it must be
1222 			 * in progress.
1223 			 */
1224 			if (mf->mf_error < 0)
1225 				goto in_progrss;
1226 
1227 			/*
1228 			 * Check for a hung node
1229 			 */
1230 			if (FSRV_ISDOWN(mf->mf_server)) {
1231 #ifdef DEBUG
1232 				dlog("server hung");
1233 #endif /* DEBUG */
1234 				error = ap->am_error;
1235 				ap_hung = ap;
1236 				continue;
1237 			}
1238 
1239 			/*
1240 			 * If there was a previous error with this node
1241 			 * then return that error code.
1242 			 */
1243 			if (mf->mf_flags & MFF_ERROR) {
1244 				error = mf->mf_error;
1245 				continue;
1246 			}
1247 
1248 			if (!(mf->mf_flags & MFF_MOUNTED) /*|| (mf->mf_flags & MFF_UNMOUNTING)*/) {
1249 in_progrss:
1250 				/*
1251 				 * If the fs is not mounted or it is unmounting then there
1252 				 * is a background (un)mount in progress.  In this case
1253 				 * we just drop the RPC request (return nil) and
1254 				 * wait for a retry, by which time the (un)mount may
1255 				 * have completed.
1256 				 */
1257 #ifdef DEBUG
1258 				dlog("ignoring mount of %s in %s -- in progress",
1259 					fname, mf->mf_mount);
1260 #endif /* DEBUG */
1261 				in_progress++;
1262 				continue;
1263 			}
1264 
1265 			/*
1266 			 * Otherwise we have a hit: return the current mount point.
1267 			 */
1268 #ifdef DEBUG
1269 			dlog("matched %s in %s", fname, ap->am_path);
1270 #endif /* DEBUG */
1271 			free(fname);
1272 			return ap;
1273 		}
1274 	}
1275 
1276 	if (in_progress) {
1277 #ifdef DEBUG
1278 		dlog("Waiting while %d mount(s) in progress", in_progress);
1279 #endif /* DEBUG */
1280 		free(fname);
1281 		ereturn(-1);
1282 	}
1283 
1284 	/*
1285 	 * If an error occured then return it.
1286 	 */
1287 	if (error) {
1288 #ifdef DEBUG
1289 		errno = error; /* XXX */
1290 		dlog("Returning error: %m", error);
1291 #endif /* DEBUG */
1292 		free(fname);
1293 		ereturn(error);
1294 	}
1295 
1296 	/*
1297 	 * If doing a delete then don't create again!
1298 	 */
1299 	switch (op) {
1300 	case VLOOK_DELETE:
1301 		ereturn(ENOENT);
1302 		break;
1303 
1304 	case VLOOK_CREATE:
1305 		break;
1306 
1307 	default:
1308 		plog(XLOG_FATAL, "Unknown op to afs_lookuppn: 0x%x", op);
1309 		ereturn(EINVAL);
1310 		break;
1311 	}
1312 
1313 	/*
1314 	 * If the server is going down then just return,
1315 	 * don't try to mount any more file systems
1316 	 */
1317 	if ((int)amd_state >= (int)Finishing) {
1318 #ifdef DEBUG
1319 		dlog("not found - server going down anyway");
1320 #endif /* DEBUG */
1321 		free(fname);
1322 		ereturn(ENOENT);
1323 	}
1324 
1325 	/*
1326 	 * If we get there then this is a reference to an,
1327 	 * as yet, unknown name so we need to search the mount
1328 	 * map for it.
1329 	 */
1330 	if (mp->am_pref) {
1331 		sprintf(path_name, "%s%s", mp->am_pref, fname);
1332 		pfname = path_name;
1333 	} else {
1334 		pfname = fname;
1335 	}
1336 
1337 	mf = mp->am_mnt;
1338 
1339 #ifdef DEBUG
1340 	dlog("will search map info in %s to find %s", mf->mf_info, pfname);
1341 #endif /* DEBUG */
1342 	/*
1343 	 * Consult the oracle for some mount information.
1344 	 * info is malloc'ed and belongs to this routine.
1345 	 * It ends up being free'd in free_continuation().
1346 	 *
1347 	 * Note that this may return -1 indicating that information
1348 	 * is not yet available.
1349 	 */
1350 	error = mapc_search((mnt_map*) mf->mf_private, pfname, &info);
1351 	if (error) {
1352 		if (error > 0)
1353 			plog(XLOG_MAP, "No map entry for %s", pfname);
1354 		else
1355 			plog(XLOG_MAP, "Waiting on map entry for %s", pfname);
1356 		free(fname);
1357 		ereturn(error);
1358 	}
1359 
1360 #ifdef DEBUG
1361 	dlog("mount info is %s", info);
1362 #endif /* DEBUG */
1363 
1364 	/*
1365 	 * Split info into an argument vector.
1366 	 * The vector is malloc'ed and belongs to
1367 	 * this routine.  It is free'd in free_continuation()
1368 	 */
1369 	xivec = ivec = strsplit(info, ' ', '\"');
1370 
1371 	/*
1372 	 * Default error code...
1373 	 */
1374 	if (ap_hung)
1375 		error = EWOULDBLOCK;
1376 	else
1377 		error = ENOENT;
1378 
1379 	/*
1380 	 * Allocate a new map
1381 	 */
1382 	new_mp = exported_ap_alloc();
1383 	if (new_mp == 0) {
1384 		free((voidp) xivec);
1385 		free((voidp) info);
1386 		free((voidp) fname);
1387 		ereturn(ENOSPC);
1388 	}
1389 
1390 	if (mf->mf_auto)
1391 		auto_opts = mf->mf_auto;
1392 	else
1393 		auto_opts = "";
1394 
1395 	auto_opts = strdup(auto_opts);
1396 
1397 #ifdef DEBUG
1398 	dlog("searching for /defaults entry");
1399 #endif /* DEBUG */
1400 	if (mapc_search((mnt_map*) mf->mf_private, "/defaults", &dflts) == 0) {
1401 	  	char *dfl;
1402 		char **rvec;
1403 #ifdef DEBUG
1404 		dlog("/defaults gave %s", dflts);
1405 #endif /* DEBUG */
1406 		if (*dflts == '-')
1407 			dfl = dflts+1;
1408 		else
1409 			dfl = dflts;
1410 
1411 		/*
1412 		 * Chop the defaults up
1413 		 */
1414 		rvec = strsplit(dfl, ' ', '\"');
1415 		/*
1416 		 * Extract first value
1417 		 */
1418 		dfl = rvec[0];
1419 
1420 		/*
1421 		 * If there were any values at all...
1422 		 */
1423 		if (dfl) {
1424 			/*
1425 			 * Log error if there were other values
1426 			 */
1427 			if (rvec[1]) {
1428 #ifdef DEBUG
1429 				dlog("/defaults chopped into %s", dfl);
1430 #endif /* DEBUG */
1431 				plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info);
1432 			}
1433 
1434 			/*
1435 			 * Prepend to existing defaults if they exist,
1436 			 * otherwise just use these defaults.
1437 			 */
1438 			if (*auto_opts && *dfl) {
1439 				char *nopts = (char *) xmalloc(strlen(auto_opts)+strlen(dfl)+2);
1440 				sprintf(nopts, "%s;%s", dfl, auto_opts);
1441 				free(auto_opts);
1442 				auto_opts = nopts;
1443 			} else if (*dfl) {
1444 				auto_opts = strealloc(auto_opts, dfl);
1445 			}
1446 		}
1447 		free(dflts);
1448 		/*
1449 		 * Don't need info vector any more
1450 		 */
1451 		free((voidp) rvec);
1452 	}
1453 
1454 	/*
1455 	 * Fill it in
1456 	 */
1457 	init_map(new_mp, fname);
1458 
1459 	/*
1460 	 * Put it in the table
1461 	 */
1462 	insert_am(new_mp, mp);
1463 
1464 	/*
1465 	 * Fill in some other fields,
1466 	 * path and mount point.
1467 	 *
1468 	 * bugfix: do not prepend old am_path if direct map
1469 	 *         <wls@astro.umd.edu> William Sebok
1470 	 */
1471 	new_mp->am_path = str3cat(new_mp->am_path,
1472 		mf->mf_ops == &dfs_ops ? "" : mp->am_path,
1473 		*fname == '/' ? "" : "/", fname);
1474 
1475 #ifdef DEBUG
1476 	dlog("setting path to %s", new_mp->am_path);
1477 #endif /* DEBUG */
1478 
1479 	/*
1480 	 * Take private copy of pfname
1481 	 */
1482 	pfname = strdup(pfname);
1483 
1484 	/*
1485 	 * Construct a continuation
1486 	 */
1487 	cp = ALLOC(continuation);
1488 	cp->mp = new_mp;
1489 	cp->xivec = xivec;
1490 	cp->ivec = ivec;
1491 	cp->info = info;
1492 	cp->key = pfname;
1493 	cp->auto_opts = auto_opts;
1494 	cp->retry = FALSE;
1495 	cp->tried = FALSE;
1496 	cp->start = clocktime();
1497 	cp->def_opts = strdup(auto_opts);
1498 	bzero((voidp) &cp->fs_opts, sizeof(cp->fs_opts));
1499 
1500 	/*
1501 	 * Try and mount the file system
1502 	 * If this succeeds immediately (possible
1503 	 * for a ufs file system) then return
1504 	 * the attributes, otherwise just
1505 	 * return an error.
1506 	 */
1507 	error = afs_bgmount(cp, error);
1508 	reschedule_timeout_mp();
1509 	if (!error) {
1510 		free(fname);
1511 		return new_mp;
1512 	}
1513 
1514 	if (error && (cp->mp->am_mnt->mf_ops == &efs_ops))
1515 		cp->mp->am_error = error;
1516 
1517 	assign_error_mntfs(new_mp);
1518 
1519 	free(fname);
1520 
1521 	ereturn(error);
1522 #undef ereturn
1523 }
1524 
1525 /*
1526  * Locate next node in sibling list which is mounted
1527  * and is not an error node.
1528  */
1529 static am_node *next_nonerror_node P((am_node *xp));
1530 static am_node *next_nonerror_node(xp)
1531 am_node *xp;
1532 {
1533 	mntfs *mf;
1534 
1535 	/*
1536 	 * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
1537 	 * Fixes a race condition when mounting direct automounts.
1538 	 * Also fixes a problem when doing a readdir on a directory
1539 	 * containing hung automounts.
1540 	 */
1541 	while (xp &&
1542 	       (!(mf = xp->am_mnt) ||			/* No mounted filesystem */
1543 	        mf->mf_error != 0 ||			/* There was a mntfs error */
1544 	        xp->am_error != 0 ||			/* There was a mount error */
1545 	        !(mf->mf_flags & MFF_MOUNTED) ||	/* The fs is not mounted */
1546 	        (mf->mf_server->fs_flags & FSF_DOWN))	/* The fs may be down */
1547 		)
1548 		xp = xp->am_osib;
1549 
1550 	return xp;
1551 }
1552 
1553 static int afs_readdir P((am_node *mp, nfscookie cookie, struct dirlist *dp, struct entry *ep, int count));
1554 static int afs_readdir(mp, cookie, dp, ep, count)
1555 am_node *mp;
1556 nfscookie cookie;
1557 struct dirlist *dp;
1558 struct entry *ep;
1559 int count;
1560 {
1561 	unsigned int gen = *(unsigned int*) cookie;
1562 	am_node *xp;
1563 
1564 	dp->eof = FALSE;
1565 
1566 	if (gen == 0) {
1567 		/*
1568 		 * In the default instance (which is used to
1569 		 * start a search) we return "." and "..".
1570 		 *
1571 		 * This assumes that the count is big enough
1572 		 * to allow both "." and ".." to be returned in
1573 		 * a single packet.  If it isn't (which would
1574 		 * be fairly unbelievable) then tough.
1575 		 */
1576 #ifdef DEBUG
1577 		dlog("default search");
1578 #endif /* DEBUG */
1579 		/*
1580 		 * Check for enough room.  This is extremely
1581 		 * approximate but is more than enough space.
1582 		 * Really need 2 times:
1583 		 * 	4byte fileid
1584 		 * 	4byte cookie
1585 		 * 	4byte name length
1586 		 * 	4byte name
1587 		 * plus the dirlist structure
1588 		 */
1589 		if (count <
1590 			(2 * (2 * (sizeof(*ep) + sizeof("..") + 4)
1591 					+ sizeof(*dp))))
1592 			return EINVAL;
1593 
1594 		xp = next_nonerror_node(mp->am_child);
1595 		dp->entries = ep;
1596 
1597 		/* construct "." */
1598 		ep[0].fileid = mp->am_gen;
1599 		ep[0].name = ".";
1600 		ep[0].nextentry = &ep[1];
1601 		*(unsigned int *) ep[0].cookie = 0;
1602 
1603 		/* construct ".." */
1604 		if (mp->am_parent)
1605 			ep[1].fileid = mp->am_parent->am_gen;
1606 		else
1607 			ep[1].fileid = mp->am_gen;
1608 		ep[1].name = "..";
1609 		ep[1].nextentry = 0;
1610 		*(unsigned int *) ep[1].cookie =
1611 			xp ? xp->am_gen : ~(unsigned int)0;
1612 
1613 		if (!xp) dp->eof = TRUE;
1614 		return 0;
1615 	}
1616 
1617 #ifdef DEBUG
1618 	dlog("real child");
1619 #endif /* DEBUG */
1620 
1621 	if (gen == ~(unsigned int)0) {
1622 #ifdef DEBUG
1623 		dlog("End of readdir in %s", mp->am_path);
1624 #endif /* DEBUG */
1625 		dp->eof = TRUE;
1626 		dp->entries = 0;
1627 		return 0;
1628 	}
1629 
1630 	xp = mp->am_child;
1631 	while (xp && xp->am_gen != gen)
1632 		xp = xp->am_osib;
1633 
1634 	if (xp) {
1635 		int nbytes = count / 2;		/* conservative */
1636 		int todo = MAX_READDIR_ENTRIES;
1637 		dp->entries = ep;
1638 		do {
1639 			am_node *xp_next = next_nonerror_node(xp->am_osib);
1640 
1641 			if (xp_next) {
1642 				*(unsigned int *) ep->cookie = xp_next->am_gen;
1643 			} else {
1644 				*(unsigned int *) ep->cookie = ~(unsigned int)0;
1645 				dp->eof = TRUE;
1646 			}
1647 
1648 			ep->fileid = xp->am_gen;
1649 			ep->name = xp->am_name;
1650 			nbytes -= sizeof(*ep) + strlen(xp->am_name) + 1;
1651 
1652 			xp = xp_next;
1653 
1654 			if (nbytes > 0 && !dp->eof && todo > 1) {
1655 				ep->nextentry = ep + 1;
1656 				ep++;
1657 				--todo;
1658 			} else {
1659 				todo = 0;
1660 			}
1661 		} while (todo > 0);
1662 
1663 		ep->nextentry = 0;
1664 
1665 		return 0;
1666 	}
1667 
1668 	return ESTALE;
1669 
1670 }
1671 
1672 static am_node *dfs_readlink P((am_node *mp, int *error_return));
1673 static am_node *dfs_readlink(mp, error_return)
1674 am_node *mp;
1675 int *error_return;
1676 {
1677 	am_node *xp;
1678 	int rc = 0;
1679 
1680 	xp = next_nonerror_node(mp->am_child);
1681 	if (!xp) {
1682 		if (!mp->am_mnt->mf_private)
1683 			afs_mkcacheref(mp->am_mnt);	/* XXX */
1684 		xp = afs_lookuppn(mp, mp->am_path+1, &rc, VLOOK_CREATE);
1685 	}
1686 
1687 	if (xp) {
1688 		new_ttl(xp);	/* (7/12/89) from Rein Tollevik */
1689 		return xp;
1690 	}
1691 	if (amd_state == Finishing)
1692 		rc = ENOENT;
1693 	*error_return = rc;
1694 	return 0;
1695 }
1696 
1697 /*
1698  * Ops structure
1699  */
1700 am_ops root_ops = {
1701 	"root",
1702 	0, /* root_match */
1703 	0, /* root_init */
1704 	root_mount,
1705 	0,
1706 	afs_umount,
1707 	0,
1708 	afs_lookuppn,
1709 	afs_readdir,
1710 	0, /* root_readlink */
1711 	0, /* root_mounted */
1712 	0, /* root_umounted */
1713 	find_afs_srvr,
1714 	FS_NOTIMEOUT|FS_AMQINFO|FS_DIRECTORY
1715 };
1716 
1717 am_ops afs_ops = {
1718 	"auto",
1719 	afs_match,
1720 	0, /* afs_init */
1721 	afs_mount,
1722 	0,
1723 	afs_umount,
1724 	0,
1725 	afs_lookuppn,
1726 	afs_readdir,
1727 	0, /* afs_readlink */
1728 	0, /* afs_mounted */
1729 	afs_umounted,
1730 	find_afs_srvr,
1731 	FS_AMQINFO|FS_DIRECTORY
1732 };
1733 
1734 am_ops toplvl_ops = {
1735 	"toplvl",
1736 	afs_match,
1737 	0, /* afs_init */
1738 	toplvl_mount,
1739 	0,
1740 	toplvl_umount,
1741 	0,
1742 	afs_lookuppn,
1743 	afs_readdir,
1744 	0, /* toplvl_readlink */
1745 	toplvl_mounted,
1746 	0, /* toplvl_umounted */
1747 	find_afs_srvr,
1748 	FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY
1749 };
1750 
1751 am_ops dfs_ops = {
1752 	"direct",
1753 	afs_match,
1754 	0, /* dfs_init */
1755 	toplvl_mount,
1756 	0,
1757 	toplvl_umount,
1758 	0,
1759 	efs_lookuppn,
1760 	efs_readdir,
1761 	dfs_readlink,
1762 	toplvl_mounted,
1763 	0, /* afs_umounted */
1764 	find_afs_srvr,
1765 	FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO
1766 };
1767 
1768 #ifdef HAS_UNION_FS
1769 am_ops union_ops = {
1770 	"union",
1771 	afs_match,
1772 	0, /* afs_init */
1773 	toplvl_mount,
1774 	0,
1775 	toplvl_umount,
1776 	0,
1777 	afs_lookuppn,
1778 	afs_readdir,
1779 	0, /* toplvl_readlink */
1780 	union_mounted,
1781 	0, /* toplvl_umounted */
1782 	find_afs_srvr,
1783 	FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY
1784 };
1785 #endif /* HAS_UNION_FS */
1786