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