GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/amd/amd/afs_ops.c Lines: 0 479 0.0 %
Date: 2017-11-13 Branches: 0 316 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: afs_ops.c,v 1.19 2014/10/26 03:28:41 guenther 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 *
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
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[MAXHOSTNAMELEN+MAXPATHLEN+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
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
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
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
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
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
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
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
424
afs_umount(am_node *mp)
425
{
426
	return 0;
427
}
428
429
/*
430
 * Unmount a top-level automount node
431
 */
432
static int
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
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
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
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
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
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
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 backgroun 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
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 *
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[MAXPATHLEN];	/* 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 *
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
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 *
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 */