xref: /original-bsd/usr.sbin/amd/amd/afs_ops.c (revision ff9931ee)
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.3 (Berkeley) 05/12/91
13  *
14  * $Id: afs_ops.c,v 5.2.1.9 91/05/07 22:17:40 jsp Alpha $
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 		if (term) {
606 			/*
607 			 * Not sure what to do for an error code.
608 			 */
609 			mf->mf_error = EIO;	/* XXX ? */
610 			mf->mf_flags |= MFF_ERROR;
611 			plog(XLOG_ERROR, "mount for %s got signal %d", cp->mp->am_path, term);
612 		} else {
613 			/*
614 			 * Check for exit status...
615 			 */
616 			mf->mf_error = rc;
617 			mf->mf_flags |= MFF_ERROR;
618 			errno = rc;	/* XXX */
619 			plog(XLOG_ERROR, "%s: mount (afs_cont): %m", cp->mp->am_path);
620 		}
621 
622 		/*
623 		 * If we get here then that attempt didn't work, so
624 		 * move the info vector pointer along by one and
625 		 * call the background mount routine again
626 		 */
627 		amd_stats.d_merr++;
628 		cp->ivec++;
629 		(void) afs_bgmount(cp, 0);
630 		assign_error_mntfs(cp->mp);
631 	} else {
632 		/*
633 		 * The mount worked.
634 		 */
635 		am_mounted(cp->mp);
636 		free_continuation(cp);
637 	}
638 
639 	reschedule_timeout_mp();
640 }
641 
642 /*
643  * Retry a mount
644  */
645 /*ARGSUSED*/
646 static void afs_retry P((int rc, int term, voidp closure));
647 static void afs_retry(rc, term, closure)
648 int rc;
649 int term;
650 voidp closure;
651 {
652 	struct continuation *cp = (struct continuation *) closure;
653 	int error = 0;
654 
655 #ifdef DEBUG
656 	dlog("Commencing retry for mount of %s", cp->mp->am_path);
657 #endif /* DEBUG */
658 
659 	new_ttl(cp->mp);
660 
661 	if ((cp->start + ALLOWED_MOUNT_TIME) < clocktime()) {
662 		/*
663 		 * The entire mount has timed out.
664 		 * Set the error code and skip past
665 		 * all the info vectors so that
666 		 * afs_bgmount will not have any more
667 		 * ways to try the mount, so causing
668 		 * an error.
669 		 */
670 		plog(XLOG_INFO, "mount of \"%s\" has timed out", cp->mp->am_path);
671 		error = ETIMEDOUT;
672 		while (*cp->ivec)
673 			cp->ivec++;
674 	}
675 
676 	if (error || !IN_PROGRESS(cp)) {
677 		(void) afs_bgmount(cp, error);
678 	}
679 	reschedule_timeout_mp();
680 }
681 
682 /*
683  * Try to mount a file system.  Can be called
684  * directly or in a sub-process by run_task
685  */
686 static int try_mount P((voidp mvp));
687 static int try_mount(mvp)
688 voidp mvp;
689 {
690 	/*
691 	 * Mount it!
692 	 */
693 	int error;
694 	am_node *mp = (am_node *) mvp;
695 	mntfs *mf = mp->am_mnt;
696 
697 	/*
698 	 * If the directory is not yet made and
699 	 * it needs to be made, then make it!
700 	 * This may be run in a backgroun process
701 	 * in which case the flag setting won't be
702 	 * noticed later - but it is set anyway
703 	 * just after run_task is called.  It
704 	 * should probably go away totally...
705 	 */
706 	if (!(mf->mf_flags & MFF_MKMNT) && mf->mf_ops->fs_flags & FS_MKMNT) {
707 		error = mkdirs(mf->mf_mount, 0555);
708 		if (!error)
709 			mf->mf_flags |= MFF_MKMNT;
710 	}
711 
712 	error = mount_node(mp);
713 #ifdef DEBUG
714 	if (error > 0) {
715 		errno = error;
716 		dlog("afs call to mount_node failed: %m");
717 	}
718 #endif /* DEBUG */
719 	return error;
720 }
721 
722 /*
723  * Pick a file system to try mounting and
724  * do that in the background if necessary
725  *
726 For each location:
727 	if it is new -defaults then
728 		extract and process
729 		continue;
730 	fi
731 	if it is a cut then
732 		if a location has been tried then
733 			break;
734 		fi
735 		continue;
736 	fi
737 	parse mount location
738 	discard previous mount location if required
739 	find matching mounted filesystem
740 	if not applicable then
741 		this_error = No such file or directory
742 		continue
743 	fi
744 	if the filesystem failed to be mounted then
745 		this_error = error from filesystem
746 	elif the filesystem is mounting or unmounting then
747 		this_error = -1
748 	elif the fileserver is down then
749 		this_error = -1
750 	elif the filesystem is already mounted
751 		this_error = 0
752 		break
753 	fi
754 	if no error on this mount then
755 		this_error = initialise mount point
756 	fi
757 	if no error on this mount and mount is delayed then
758 		this_error = -1
759 	fi
760 	if this_error < 0 then
761 		retry = true
762 	fi
763 	if no error on this mount then
764 		make mount point if required
765 	fi
766 	if no error on this mount then
767 		if mount in background then
768 			run mount in background
769 			return -1
770 		else
771 			this_error = mount in foreground
772 		fi
773 	fi
774 	if an error occured on this mount then
775 		update stats
776 		save error in mount point
777 	fi
778 endfor
779  */
780 
781 static int afs_bgmount P((struct continuation *cp, int mpe));
782 static int afs_bgmount(cp, mpe)
783 struct continuation *cp;
784 int mpe;
785 {
786 	mntfs *mf = cp->mp->am_mnt;	/* Current mntfs */
787 	mntfs *mf_retry = 0;		/* First mntfs which needed retrying */
788 	int this_error = -1;		/* Per-mount error */
789 	int hard_error = -1;
790 	int mp_error = mpe;
791 
792 	/*
793 	 * Try to mount each location.
794 	 * At the end:
795 	 * hard_error == 0 indicates something was mounted.
796 	 * hard_error > 0 indicates everything failed with a hard error
797 	 * hard_error < 0 indicates nothing could be mounted now
798 	 */
799 	for (; this_error && *cp->ivec; cp->ivec++) {
800 		am_ops *p;
801 		am_node *mp = cp->mp;
802 		char *link_dir;
803 		int dont_retry;
804 
805 		if (hard_error < 0)
806 			hard_error = this_error;
807 
808 		this_error = -1;
809 
810 		if (**cp->ivec == '-') {
811 			/*
812 			 * Pick up new defaults
813 			 */
814 			if (cp->auto_opts && *cp->auto_opts)
815 				cp->def_opts = str3cat(cp->def_opts, cp->auto_opts, ";", *cp->ivec+1);
816 			else
817 				cp->def_opts = strealloc(cp->def_opts, *cp->ivec+1);
818 #ifdef DEBUG
819 			dlog("Setting def_opts to \"%s\"", cp->def_opts);
820 #endif /* DEBUG */
821 			continue;
822 		}
823 
824 		/*
825 		 * If a mount has been attempted, and we find
826 		 * a cut then don't try any more locations.
827 		 */
828 		if (strcmp(*cp->ivec, "/") == 0 || strcmp(*cp->ivec, "||") == 0) {
829 			if (cp->tried) {
830 #ifdef DEBUG
831 				dlog("Cut: not trying any more locations for %s",
832 					mp->am_path);
833 #endif /* DEBUG */
834 				break;
835 			}
836 			continue;
837 		}
838 
839 #ifdef SUNOS4_COMPAT
840 #ifdef nomore
841 		/*
842 		 * By default, you only get this bit on SunOS4.
843 		 * If you want this anyway, then define SUNOS4_COMPAT
844 		 * in the relevant "os-blah.h" file.
845 		 *
846 		 * We make the observation that if the local key line contains
847 		 * no '=' signs then either it is sick, or it is a SunOS4-style
848 		 * "host:fs[:link]" line.  In the latter case the am_opts field
849 		 * is also assumed to be in old-style, so you can't mix & match.
850 		 * You can use ${} expansions for the fs and link bits though...
851 		 *
852 		 * Actually, this doesn't really cover all the possibilities for
853 		 * the latest SunOS automounter and it is debatable whether there
854 		 * is any point bothering.
855 		 */
856 		if (strchr(*cp->ivec, '=') == 0)
857 			p = sunos4_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
858 		else
859 #endif
860 #endif /* SUNOS4_COMPAT */
861 			p = ops_match(&cp->fs_opts, *cp->ivec, cp->def_opts, mp->am_path, cp->key, mp->am_parent->am_mnt->mf_info);
862 
863 		/*
864 		 * Find a mounted filesystem for this node.
865 		 */
866 		mp->am_mnt = mf = realloc_mntfs(mf, p, &cp->fs_opts, cp->fs_opts.opt_fs,
867 						cp->fs_opts.fs_mtab, cp->auto_opts, cp->fs_opts.opt_opts);
868 
869 		p = mf->mf_ops;
870 #ifdef DEBUG
871 		dlog("Got a hit with %s", p->fs_type);
872 #endif /* DEBUG */
873 		/*
874 		 * Note whether this is a real mount attempt
875 		 */
876 		if (p == &efs_ops) {
877 			plog(XLOG_MAP, "Map entry %s for %s failed to match", *cp->ivec, mp->am_path);
878 			if (this_error <= 0)
879 				this_error = ENOENT;
880 			continue;
881 		} else {
882 			if (cp->fs_opts.fs_mtab) {
883 				plog(XLOG_MAP, "Trying mount of %s on %s fstype %s",
884 					cp->fs_opts.fs_mtab, mp->am_path, p->fs_type);
885 			}
886 			cp->tried = TRUE;
887 		}
888 
889 		this_error = 0;
890 		dont_retry = FALSE;
891 
892 		if (mp->am_link) {
893 			free(mp->am_link);
894 			mp->am_link = 0;
895 		}
896 
897 		link_dir = mf->mf_fo->opt_sublink;
898 
899 		if (link_dir && *link_dir) {
900 			if (*link_dir == '/') {
901 				mp->am_link = strdup(link_dir);
902 			} else {
903 				mp->am_link = str3cat((char *) 0,
904 					mf->mf_fo->opt_fs, "/", link_dir);
905 				normalize_slash(mp->am_link);
906 			}
907 		}
908 
909 		if (mf->mf_error > 0) {
910 			this_error = mf->mf_error;
911 		} else if (mf->mf_flags & (MFF_MOUNTING|MFF_UNMOUNTING)) {
912 			/*
913 			 * Still mounting - retry later
914 			 */
915 #ifdef DEBUG
916 			dlog("Duplicate pending mount fstype %s", p->fs_type);
917 #endif /* DEBUG */
918 			this_error = -1;
919 		} else if (FSRV_ISDOWN(mf->mf_server)) {
920 			/*
921 			 * Would just mount from the same place
922 			 * as a hung mount - so give up
923 			 */
924 #ifdef DEBUG
925 			dlog("%s is already hung - giving up", mf->mf_mount);
926 #endif /* DEBUG */
927 			mp_error = EWOULDBLOCK;
928 			dont_retry = TRUE;
929 			this_error = -1;
930 		} else if (mf->mf_flags & MFF_MOUNTED) {
931 #ifdef DEBUG
932 			dlog("duplicate mount of \"%s\" ...", mf->mf_info);
933 #endif /* DEBUG */
934 			/*
935 			 * Just call mounted()
936 			 */
937 			am_mounted(mp);
938 
939 			this_error = 0;
940 			break;
941 		}
942 
943 		/*
944 		 * Will usually need to play around with the mount nodes
945 		 * file attribute structure.  This must be done here.
946 		 * Try and get things initialised, even if the fileserver
947 		 * is not known to be up.  In the common case this will
948 		 * progress things faster.
949 		 */
950 		if (!this_error) {
951 			/*
952 			 * Fill in attribute fields.
953 			 */
954 			if (mf->mf_ops->fs_flags & FS_DIRECTORY)
955 				mk_fattr(mp, NFDIR);
956 			else
957 				mk_fattr(mp, NFLNK);
958 
959 			mp->am_fattr.fileid = mp->am_gen;
960 
961 			if (p->fs_init)
962 				this_error = (*p->fs_init)(mf);
963 		}
964 
965 		/*
966 		 * Make sure the fileserver is UP before doing any more work
967 		 */
968 		if (!FSRV_ISUP(mf->mf_server)) {
969 #ifdef DEBUG
970 			dlog("waiting for server %s to become available", mf->mf_server->fs_host);
971 #endif
972 			this_error =  -1;
973 		}
974 
975 		if (!this_error && mf->mf_fo->opt_delay) {
976 			/*
977 			 * If there is a delay timer on the mount
978 			 * then don't try to mount if the timer
979 			 * has not expired.
980 			 */
981 			int i = atoi(mf->mf_fo->opt_delay);
982 			if (i > 0 && clocktime() < (cp->start + i)) {
983 #ifdef DEBUG
984 				dlog("Mount of %s delayed by %ds", mf->mf_mount, i - clocktime() + cp->start);
985 #endif /* DEBUG */
986 				this_error = -1;
987 			}
988 		}
989 
990 		if (this_error < 0 && !dont_retry) {
991 			if (!mf_retry)
992 				mf_retry = dup_mntfs(mf);
993 			cp->retry = TRUE;
994 		}
995 
996 		if (!this_error)
997 		if (p->fs_flags & FS_MBACKGROUND) {
998 			mf->mf_flags |= MFF_MOUNTING;	/*XXX*/
999 #ifdef DEBUG
1000 			dlog("backgrounding mount of \"%s\"", mf->mf_mount);
1001 #endif /* DEBUG */
1002 			if (cp->callout) {
1003 				untimeout(cp->callout);
1004 				cp->callout = 0;
1005 			}
1006 			run_task(try_mount, (voidp) mp, afs_cont, (voidp) cp);
1007 			mf->mf_flags |= MFF_MKMNT;	/* XXX */
1008 			if (mf_retry) free_mntfs(mf_retry);
1009 			return -1;
1010 		} else {
1011 #ifdef DEBUG
1012 			dlog("foreground mount of \"%s\" ...", mf->mf_info);
1013 #endif /* DEBUG */
1014 			this_error = try_mount((voidp) mp);
1015 			if (this_error < 0) {
1016 				if (!mf_retry)
1017 					mf_retry = dup_mntfs(mf);
1018 				cp->retry = TRUE;
1019 			}
1020 		}
1021 
1022 		if (this_error >= 0) {
1023 			if (this_error > 0) {
1024 				amd_stats.d_merr++;
1025 				if (mf != mf_retry) {
1026 					mf->mf_error = this_error;
1027 					mf->mf_flags |= MFF_ERROR;
1028 				}
1029 			}
1030 			/*
1031 			 * Wakeup anything waiting for this mount
1032 			 */
1033 			wakeup((voidp) mf);
1034 		}
1035 	}
1036 
1037 	if (this_error && cp->retry) {
1038 		free_mntfs(mf);
1039 		mf = cp->mp->am_mnt = mf_retry;
1040 		/*
1041 		 * Not retrying again (so far)
1042 		 */
1043 		cp->retry = FALSE;
1044 		cp->tried = FALSE;
1045 		/*
1046 		 * Start at the beginning.
1047 		 * Rewind the location vector and
1048 		 * reset the default options.
1049 		 */
1050 		cp->ivec = cp->xivec;
1051 		cp->def_opts = strealloc(cp->def_opts, cp->auto_opts);
1052 		/*
1053 		 * Arrange that afs_bgmount is called
1054 		 * after anything else happens.
1055 		 */
1056 #ifdef DEBUG
1057 		dlog("Arranging to retry mount of %s", cp->mp->am_path);
1058 #endif /* DEBUG */
1059 		sched_task(afs_retry, (voidp) cp, (voidp) mf);
1060 		if (cp->callout)
1061 			untimeout(cp->callout);
1062 		cp->callout = timeout(RETRY_INTERVAL, wakeup, (voidp) mf);
1063 
1064 		cp->mp->am_ttl = clocktime() + RETRY_INTERVAL;
1065 
1066 		/*
1067 		 * Not done yet - so don't return anything
1068 		 */
1069 		return -1;
1070 	}
1071 
1072 	if (hard_error < 0 || this_error == 0)
1073 		hard_error = this_error;
1074 
1075 	/*
1076 	 * Discard handle on duff filesystem.
1077 	 * This should never happen since it
1078 	 * should be caught by the case above.
1079 	 */
1080 	if (mf_retry) {
1081 		if (hard_error)
1082 			plog(XLOG_ERROR, "discarding a retry mntfs for %s", mf_retry->mf_mount);
1083 		free_mntfs(mf_retry);
1084 	}
1085 
1086 	/*
1087 	 * If we get here, then either the mount succeeded or
1088 	 * there is no more mount information available.
1089 	 */
1090 	if (hard_error < 0 && mp_error)
1091 		hard_error = cp->mp->am_error = mp_error;
1092 	if (hard_error > 0) {
1093 		/*
1094 		 * Set a small(ish) timeout on an error node if
1095 		 * the error was not a time out.
1096 		 */
1097 		switch (hard_error) {
1098 		case ETIMEDOUT:
1099 		case EWOULDBLOCK:
1100 			cp->mp->am_timeo = 5;
1101 			break;
1102 		default:
1103 			cp->mp->am_timeo = 17;
1104 			break;
1105 		}
1106 		cp->mp->am_timeo_w = 0;
1107 	}
1108 
1109 	/*
1110 	 * Make sure that the error value in the mntfs has a
1111 	 * reasonable value.
1112 	 */
1113 	if (mf->mf_error < 0) {
1114 		mf->mf_error = hard_error;
1115 		if (hard_error)
1116 			mf->mf_flags |= MFF_ERROR;
1117 	}
1118 
1119 	/*
1120 	 * In any case we don't need the continuation any more
1121 	 */
1122 	free_continuation(cp);
1123 
1124 	return hard_error;
1125 }
1126 
1127 /*
1128  * Automount interface to RPC lookup routine
1129  */
1130 static am_node *afs_lookuppn P((am_node *mp, char *fname, int *error_return, int op));
1131 static am_node *afs_lookuppn(mp, fname, error_return, op)
1132 am_node *mp;
1133 char *fname;
1134 int *error_return;
1135 int op;
1136 {
1137 #define ereturn(x) { *error_return = x; return 0; }
1138 
1139 	/*
1140 	 * Find the corresponding entry and return
1141 	 * the file handle for it.
1142 	 */
1143 	am_node *ap, *new_mp, *ap_hung;
1144 	char *info;			/* Mount info - where to get the file system */
1145 	char **ivec, **xivec;		/* Split version of info */
1146 	char *auto_opts;		/* Automount options */
1147 	int error = 0;			/* Error so far */
1148 	char path_name[MAXPATHLEN];	/* General path name buffer */
1149 	char *pfname;			/* Path for database lookup */
1150 	struct continuation *cp;	/* Continuation structure if we need to mount */
1151 	int in_progress = 0;		/* # of (un)mount in progress */
1152 	char *dflts;
1153 	mntfs *mf;
1154 
1155 #ifdef DEBUG
1156 	dlog("in afs_lookuppn");
1157 #endif /* DEBUG */
1158 
1159 	/*
1160 	 * If the server is shutting down
1161 	 * then don't return information
1162 	 * about the mount point.
1163 	 */
1164 	if (amd_state == Finishing) {
1165 #ifdef DEBUG
1166 		if ((mf = mp->am_mnt) == 0 || mf->mf_ops == &dfs_ops)
1167 			dlog("%s mount ignored - going down", fname);
1168 		else
1169 			dlog("%s/%s mount ignored - going down", mp->am_path, fname);
1170 #endif /* DEBUG */
1171 		ereturn(ENOENT);
1172 	}
1173 
1174 	/*
1175 	 * Handle special case of "." and ".."
1176 	 */
1177 	if (fname[0] == '.') {
1178 		if (fname[1] == '\0')
1179 			return mp;	/* "." is the current node */
1180 		if (fname[1] == '.' && fname[2] == '\0') {
1181 			if (mp->am_parent) {
1182 #ifdef DEBUG
1183 				dlog(".. in %s gives %s", mp->am_path, mp->am_parent->am_path);
1184 #endif /* DEBUG */
1185 				return mp->am_parent;	/* ".." is the parent node */
1186 			}
1187 			ereturn(ESTALE);
1188 		}
1189 	}
1190 
1191 	/*
1192 	 * Check for valid key name.
1193 	 * If it is invalid then pretend it doesn't exist.
1194 	 */
1195 	if (!valid_key(fname)) {
1196 		plog(XLOG_WARNING, "Key \"%s\" contains a disallowed character", fname);
1197 		ereturn(ENOENT);
1198 	}
1199 
1200 	/*
1201 	 * Expand key name.
1202 	 * fname is now a private copy.
1203 	 */
1204 	fname = expand_key(fname);
1205 
1206 	for (ap_hung = 0, ap = mp->am_child; ap; ap = ap->am_osib) {
1207 		/*
1208 		 * Otherwise search children of this node
1209 		 */
1210 		if (FSTREQ(ap->am_name, fname)) {
1211 			mf = ap->am_mnt;
1212 			if (ap->am_error) {
1213 				error = ap->am_error;
1214 				continue;
1215 			}
1216 
1217 			/*
1218 			 * If the error code is undefined then it must be
1219 			 * in progress.
1220 			 */
1221 			if (mf->mf_error < 0)
1222 				goto in_progrss;
1223 
1224 			/*
1225 			 * Check for a hung node
1226 			 */
1227 			if (FSRV_ISDOWN(mf->mf_server)) {
1228 				ap_hung = ap;
1229 				continue;
1230 			}
1231 
1232 			/*
1233 			 * If there was a previous error with this node
1234 			 * then return that error code.
1235 			 */
1236 			if (mf->mf_flags & MFF_ERROR) {
1237 				error = mf->mf_error;
1238 				continue;
1239 			}
1240 
1241 			if (!(mf->mf_flags & MFF_MOUNTED) /*|| (mf->mf_flags & MFF_UNMOUNTING)*/) {
1242 in_progrss:
1243 				/*
1244 				 * If the fs is not mounted or it is unmounting then there
1245 				 * is a background (un)mount in progress.  In this case
1246 				 * we just drop the RPC request (return nil) and
1247 				 * wait for a retry, by which time the (un)mount may
1248 				 * have completed.
1249 				 */
1250 #ifdef DEBUG
1251 				dlog("ignoring mount of %s in %s -- in progress",
1252 					fname, mf->mf_mount);
1253 #endif /* DEBUG */
1254 				in_progress++;
1255 				continue;
1256 			}
1257 
1258 			/*
1259 			 * Otherwise we have a hit: return the current mount point.
1260 			 */
1261 #ifdef DEBUG
1262 			dlog("matched %s in %s", fname, ap->am_path);
1263 #endif /* DEBUG */
1264 			free(fname);
1265 			return ap;
1266 		}
1267 	}
1268 
1269 	if (in_progress) {
1270 #ifdef DEBUG
1271 		dlog("Waiting while %d mount(s) in progress", in_progress);
1272 #endif /* DEBUG */
1273 		free(fname);
1274 		ereturn(-1);
1275 	}
1276 
1277 	/*
1278 	 * If an error occured then return it.
1279 	 */
1280 	if (error) {
1281 #ifdef DEBUG
1282 		errno = error; /* XXX */
1283 		dlog("Returning error: %m", error);
1284 #endif /* DEBUG */
1285 		free(fname);
1286 		ereturn(error);
1287 	}
1288 
1289 	/*
1290 	 * If doing a delete then don't create again!
1291 	 */
1292 	switch (op) {
1293 	case VLOOK_DELETE:
1294 		ereturn(ENOENT);
1295 		break;
1296 
1297 	case VLOOK_CREATE:
1298 		break;
1299 
1300 	default:
1301 		plog(XLOG_FATAL, "Unknown op to afs_lookuppn: 0x%x", op);
1302 		ereturn(EINVAL);
1303 		break;
1304 	}
1305 
1306 	/*
1307 	 * If the server is going down then just return,
1308 	 * don't try to mount any more file systems
1309 	 */
1310 	if ((int)amd_state >= (int)Finishing) {
1311 #ifdef DEBUG
1312 		dlog("not found - server going down anyway");
1313 #endif /* DEBUG */
1314 		free(fname);
1315 		ereturn(ENOENT);
1316 	}
1317 
1318 	/*
1319 	 * If we get there then this is a reference to an,
1320 	 * as yet, unknown name so we need to search the mount
1321 	 * map for it.
1322 	 */
1323 	if (mp->am_pref) {
1324 		sprintf(path_name, "%s%s", mp->am_pref, fname);
1325 		pfname = path_name;
1326 	} else {
1327 		pfname = fname;
1328 	}
1329 
1330 	mf = mp->am_mnt;
1331 
1332 #ifdef DEBUG
1333 	dlog("will search map info in %s to find %s", mf->mf_info, pfname);
1334 #endif /* DEBUG */
1335 	/*
1336 	 * Consult the oracle for some mount information.
1337 	 * info is malloc'ed and belongs to this routine.
1338 	 * It ends up being free'd in free_continuation().
1339 	 *
1340 	 * Note that this may return -1 indicating that information
1341 	 * is not yet available.
1342 	 */
1343 	error = mapc_search((mnt_map*) mf->mf_private, pfname, &info);
1344 	if (error) {
1345 		if (error > 0)
1346 			plog(XLOG_MAP, "No map entry for %s", pfname);
1347 		else
1348 			plog(XLOG_MAP, "Waiting on map entry for %s", pfname);
1349 		free(fname);
1350 		ereturn(error);
1351 	}
1352 
1353 #ifdef DEBUG
1354 	dlog("mount info is %s", info);
1355 #endif /* DEBUG */
1356 
1357 	/*
1358 	 * Split info into an argument vector.
1359 	 * The vector is malloc'ed and belongs to
1360 	 * this routine.  It is free'd in free_continuation()
1361 	 */
1362 	xivec = ivec = strsplit(info, ' ', '\"');
1363 
1364 	/*
1365 	 * Default error code...
1366 	 */
1367 	if (ap_hung)
1368 		error = EWOULDBLOCK;
1369 	else
1370 		error = ENOENT;
1371 
1372 	/*
1373 	 * Allocate a new map
1374 	 */
1375 	new_mp = exported_ap_alloc();
1376 	if (new_mp == 0) {
1377 		free((voidp) xivec);
1378 		free((voidp) info);
1379 		free((voidp) fname);
1380 		ereturn(ENOSPC);
1381 	}
1382 
1383 	if (mf->mf_auto)
1384 		auto_opts = mf->mf_auto;
1385 	else
1386 		auto_opts = "";
1387 
1388 	auto_opts = strdup(auto_opts);
1389 
1390 #ifdef DEBUG
1391 	dlog("searching for /defaults entry");
1392 #endif /* DEBUG */
1393 	if (mapc_search((mnt_map*) mf->mf_private, "/defaults", &dflts) == 0) {
1394 	  	char *dfl;
1395 		char **rvec;
1396 #ifdef DEBUG
1397 		dlog("/defaults gave %s", dflts);
1398 #endif /* DEBUG */
1399 		if (*dflts == '-')
1400 			dfl = dflts+1;
1401 		else
1402 			dfl = dflts;
1403 
1404 		/*
1405 		 * Chop the defaults up
1406 		 */
1407 		rvec = strsplit(dfl, ' ', '\"');
1408 		/*
1409 		 * Extract first value
1410 		 */
1411 		dfl = rvec[0];
1412 
1413 		/*
1414 		 * Log error if there were other values
1415 		 */
1416 		if (rvec[1]) {
1417 #ifdef DEBUG
1418 			dlog("/defaults chopped into %s", dfl);
1419 #endif /* DEBUG */
1420 			plog(XLOG_USER, "More than a single value for /defaults in %s", mf->mf_info);
1421 		}
1422 
1423 		/*
1424 		 * Don't need info vector any more
1425 		 */
1426 		free((voidp) rvec);
1427 
1428 		/*
1429 		 * If there were any values at all...
1430 		 */
1431 		if (dfl) {
1432 			/*
1433 			 * Prepend to existing defaults if they exist,
1434 			 * otherwise just use these defaults.
1435 			 */
1436 			if (*auto_opts && *dfl) {
1437 				char *nopts = (char *) xmalloc(strlen(auto_opts)+strlen(dfl)+2);
1438 				sprintf(nopts, "%s;%s", dfl, auto_opts);
1439 				free(auto_opts);
1440 				auto_opts = nopts;
1441 			} else if (*dfl) {
1442 				auto_opts = strealloc(auto_opts, dfl);
1443 			}
1444 		}
1445 		free(dflts);
1446 	}
1447 
1448 	/*
1449 	 * Fill it in
1450 	 */
1451 	init_map(new_mp, fname);
1452 
1453 	/*
1454 	 * Put it in the table
1455 	 */
1456 	insert_am(new_mp, mp);
1457 
1458 	/*
1459 	 * Fill in some other fields,
1460 	 * path and mount point.
1461 	 *
1462 	 * bugfix: do not prepend old am_path if direct map
1463 	 *         <wls@astro.umd.edu> William Sebok
1464 	 */
1465 	new_mp->am_path = str3cat(new_mp->am_path,
1466 		mf->mf_ops == &dfs_ops ? "" : mp->am_path,
1467 		*fname == '/' ? "" : "/", fname);
1468 
1469 #ifdef DEBUG
1470 	dlog("setting path to %s", new_mp->am_path);
1471 #endif /* DEBUG */
1472 
1473 	/*
1474 	 * Take private copy of pfname
1475 	 */
1476 	pfname = strdup(pfname);
1477 
1478 	/*
1479 	 * Construct a continuation
1480 	 */
1481 	cp = ALLOC(continuation);
1482 	cp->mp = new_mp;
1483 	cp->xivec = xivec;
1484 	cp->ivec = ivec;
1485 	cp->info = info;
1486 	cp->key = pfname;
1487 	cp->auto_opts = auto_opts;
1488 	cp->retry = FALSE;
1489 	cp->tried = FALSE;
1490 	cp->start = clocktime();
1491 	cp->def_opts = strdup(auto_opts);
1492 	bzero((voidp) &cp->fs_opts, sizeof(cp->fs_opts));
1493 
1494 	/*
1495 	 * Try and mount the file system
1496 	 * If this succeeds immediately (possible
1497 	 * for a ufs file system) then return
1498 	 * the attributes, otherwise just
1499 	 * return an error.
1500 	 */
1501 	error = afs_bgmount(cp, error);
1502 	reschedule_timeout_mp();
1503 	if (!error) {
1504 		free(fname);
1505 		return new_mp;
1506 	}
1507 
1508 	assign_error_mntfs(cp->mp);
1509 
1510 	free(fname);
1511 
1512 	ereturn(error);
1513 #undef ereturn
1514 }
1515 
1516 /*
1517  * Locate next node in sibling list which is mounted
1518  * and is not an error node.
1519  */
1520 static am_node *next_nonerror_node P((am_node *xp));
1521 static am_node *next_nonerror_node(xp)
1522 am_node *xp;
1523 {
1524 	mntfs *mf;
1525 
1526 	/*
1527 	 * Bug report (7/12/89) from Rein Tollevik <rein@ifi.uio.no>
1528 	 * Fixes a race condition when mounting direct automounts.
1529 	 * Also fixes a problem when doing a readdir on a directory
1530 	 * containing hung automounts.
1531 	 */
1532 	while (xp &&
1533 	       (!(mf = xp->am_mnt) ||			/* No mounted filesystem */
1534 	        mf->mf_error != 0 ||			/* There was a mntfs error */
1535 	        xp->am_error != 0 ||			/* There was a mount error */
1536 	        !(mf->mf_flags & MFF_MOUNTED) ||	/* The fs is not mounted */
1537 	        (mf->mf_server->fs_flags & FSF_DOWN))	/* The fs may be down */
1538 		)
1539 		xp = xp->am_osib;
1540 
1541 	return xp;
1542 }
1543 
1544 static int afs_readdir P((am_node *mp, nfscookie cookie, struct dirlist *dp, struct entry *ep, int count));
1545 static int afs_readdir(mp, cookie, dp, ep, count)
1546 am_node *mp;
1547 nfscookie cookie;
1548 struct dirlist *dp;
1549 struct entry *ep;
1550 int count;
1551 {
1552 	unsigned int gen = *(unsigned int*) cookie;
1553 	am_node *xp;
1554 
1555 	dp->eof = FALSE;
1556 
1557 	if (gen == 0) {
1558 		/*
1559 		 * In the default instance (which is used to
1560 		 * start a search) we return "." and "..".
1561 		 *
1562 		 * This assumes that the count is big enough
1563 		 * to allow both "." and ".." to be returned in
1564 		 * a single packet.  If it isn't (which would
1565 		 * be fairly unbelievable) then tough.
1566 		 */
1567 #ifdef DEBUG
1568 		dlog("default search");
1569 #endif /* DEBUG */
1570 		xp = next_nonerror_node(mp->am_child);
1571 		dp->entries = ep;
1572 
1573 		/* construct "." */
1574 		ep[0].fileid = mp->am_gen;
1575 		ep[0].name = ".";
1576 		ep[0].nextentry = &ep[1];
1577 		*(unsigned int *) ep[0].cookie = 0;
1578 
1579 		/* construct ".." */
1580 		if (mp->am_parent)
1581 			ep[1].fileid = mp->am_parent->am_gen;
1582 		else
1583 			ep[1].fileid = mp->am_gen;
1584 		ep[1].name = "..";
1585 		ep[1].nextentry = 0;
1586 		*(unsigned int *) ep[1].cookie =
1587 			xp ? xp->am_gen : ~(unsigned int)0;
1588 
1589 		if (!xp) dp->eof = TRUE;
1590 		return 0;
1591 	}
1592 
1593 #ifdef DEBUG
1594 	dlog("real child");
1595 #endif /* DEBUG */
1596 
1597 	if (gen == ~(unsigned int)0) {
1598 #ifdef DEBUG
1599 		dlog("End of readdir in %s", mp->am_path);
1600 #endif /* DEBUG */
1601 		dp->eof = TRUE;
1602 		dp->entries = 0;
1603 		return 0;
1604 	}
1605 
1606 	xp = mp->am_child;
1607 	while (xp && xp->am_gen != gen)
1608 		xp = xp->am_osib;
1609 
1610 	if (xp) {
1611 		int nbytes = count / 2;		/* conservative */
1612 		int todo = MAX_READDIR_ENTRIES;
1613 		dp->entries = ep;
1614 		do {
1615 			am_node *xp_next = next_nonerror_node(xp->am_osib);
1616 
1617 			if (xp_next) {
1618 				*(unsigned int *) ep->cookie = xp_next->am_gen;
1619 			} else {
1620 				*(unsigned int *) ep->cookie = ~(unsigned int)0;
1621 				dp->eof = TRUE;
1622 			}
1623 
1624 			ep->fileid = xp->am_gen;
1625 			ep->name = xp->am_name;
1626 			nbytes -= sizeof(*ep) + strlen(xp->am_name) + 1;
1627 
1628 			xp = xp_next;
1629 
1630 			if (nbytes > 0 && !dp->eof && todo > 1) {
1631 				ep->nextentry = ep + 1;
1632 				ep++;
1633 				--todo;
1634 			} else {
1635 				todo = 0;
1636 			}
1637 		} while (todo > 0);
1638 
1639 		ep->nextentry = 0;
1640 
1641 		return 0;
1642 	}
1643 
1644 	return ESTALE;
1645 
1646 }
1647 
1648 static am_node *dfs_readlink P((am_node *mp, int *error_return));
1649 static am_node *dfs_readlink(mp, error_return)
1650 am_node *mp;
1651 int *error_return;
1652 {
1653 	am_node *xp;
1654 	int rc = 0;
1655 
1656 	xp = next_nonerror_node(mp->am_child);
1657 	if (!xp) {
1658 		if (!mp->am_mnt->mf_private)
1659 			afs_mkcacheref(mp->am_mnt);	/* XXX */
1660 		xp = afs_lookuppn(mp, mp->am_path+1, &rc, VLOOK_CREATE);
1661 	}
1662 
1663 	if (xp) {
1664 		new_ttl(xp);	/* (7/12/89) from Rein Tollevik */
1665 		return xp;
1666 	}
1667 	if (amd_state == Finishing)
1668 		rc = ENOENT;
1669 	*error_return = rc;
1670 	return 0;
1671 }
1672 
1673 /*
1674  * Ops structure
1675  */
1676 am_ops root_ops = {
1677 	"root",
1678 	0, /* root_match */
1679 	0, /* root_init */
1680 	root_mount,
1681 	0,
1682 	afs_umount,
1683 	0,
1684 	afs_lookuppn,
1685 	afs_readdir,
1686 	0, /* root_readlink */
1687 	0, /* root_mounted */
1688 	0, /* root_umounted */
1689 	find_afs_srvr,
1690 	FS_NOTIMEOUT|FS_AMQINFO|FS_DIRECTORY
1691 };
1692 
1693 am_ops afs_ops = {
1694 	"auto",
1695 	afs_match,
1696 	0, /* afs_init */
1697 	afs_mount,
1698 	0,
1699 	afs_umount,
1700 	0,
1701 	afs_lookuppn,
1702 	afs_readdir,
1703 	0, /* afs_readlink */
1704 	0, /* afs_mounted */
1705 	afs_umounted,
1706 	find_afs_srvr,
1707 	FS_AMQINFO|FS_DIRECTORY
1708 };
1709 
1710 am_ops toplvl_ops = {
1711 	"toplvl",
1712 	afs_match,
1713 	0, /* afs_init */
1714 	toplvl_mount,
1715 	0,
1716 	toplvl_umount,
1717 	0,
1718 	afs_lookuppn,
1719 	afs_readdir,
1720 	0, /* toplvl_readlink */
1721 	toplvl_mounted,
1722 	0, /* toplvl_umounted */
1723 	find_afs_srvr,
1724 	FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY
1725 };
1726 
1727 am_ops dfs_ops = {
1728 	"direct",
1729 	afs_match,
1730 	0, /* dfs_init */
1731 	toplvl_mount,
1732 	0,
1733 	toplvl_umount,
1734 	0,
1735 	efs_lookuppn,
1736 	efs_readdir,
1737 	dfs_readlink,
1738 	toplvl_mounted,
1739 	0, /* afs_umounted */
1740 	find_afs_srvr,
1741 	FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO
1742 };
1743 
1744 #ifdef HAS_UNION_FS
1745 am_ops union_ops = {
1746 	"union",
1747 	afs_match,
1748 	0, /* afs_init */
1749 	toplvl_mount,
1750 	0,
1751 	toplvl_umount,
1752 	0,
1753 	afs_lookuppn,
1754 	afs_readdir,
1755 	0, /* toplvl_readlink */
1756 	union_mounted,
1757 	0, /* toplvl_umounted */
1758 	find_afs_srvr,
1759 	FS_MKMNT|FS_NOTIMEOUT|FS_BACKGROUND|FS_AMQINFO|FS_DIRECTORY
1760 };
1761 #endif /* HAS_UNION_FS */
1762