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