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