GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/amd/amd/nfsx_ops.c Lines: 0 166 0.0 %
Date: 2016-12-06 Branches: 0 88 0.0 %

Line Branch Exec Source
1
/*
2
 * Copyright (c) 1990 Jan-Simon Pendry
3
 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
4
 * Copyright (c) 1990, 1993
5
 *	The Regents of the University of California.  All rights reserved.
6
 *
7
 * This code is derived from software contributed to Berkeley by
8
 * Jan-Simon Pendry at Imperial College, London.
9
 *
10
 * Redistribution and use in source and binary forms, with or without
11
 * modification, are permitted provided that the following conditions
12
 * are met:
13
 * 1. Redistributions of source code must retain the above copyright
14
 *    notice, this list of conditions and the following disclaimer.
15
 * 2. Redistributions in binary form must reproduce the above copyright
16
 *    notice, this list of conditions and the following disclaimer in the
17
 *    documentation and/or other materials provided with the distribution.
18
 * 3. Neither the name of the University nor the names of its contributors
19
 *    may be used to endorse or promote products derived from this software
20
 *    without specific prior written permission.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32
 * SUCH DAMAGE.
33
 *
34
 *	from: @(#)nfsx_ops.c	8.1 (Berkeley) 6/6/93
35
 *	$Id: nfsx_ops.c,v 1.10 2015/12/05 21:15:01 mmcc Exp $
36
 */
37
38
#include "am.h"
39
40
#ifdef HAS_NFSX
41
42
/*
43
 * NFS hierarchical mounts
44
 *
45
 * TODO: Re-implement.
46
 */
47
48
/*
49
 * The rfs field contains a list of mounts to be done from
50
 * the remote host.
51
 */
52
typedef struct nfsx_mnt {
53
	mntfs *n_mnt;
54
	int n_error;
55
} nfsx_mnt;
56
57
struct nfsx {
58
	int nx_c;		/* Number of elements in nx_v */
59
	nfsx_mnt *nx_v;		/* Underlying mounts */
60
	nfsx_mnt *nx_try;
61
};
62
63
static int nfsx_fmount(mntfs *);
64
65
static char *
66
nfsx_match(am_opts *fo)
67
{
68
	char *xmtab;
69
	char *ptr;
70
	int len;
71
72
	if (!fo->opt_rfs) {
73
		plog(XLOG_USER, "nfsx: no remote filesystem specified");
74
		return FALSE;
75
	}
76
	if (!fo->opt_rhost) {
77
		plog(XLOG_USER, "nfsx: no remote host specified");
78
		return FALSE;
79
	}
80
81
#ifdef notdef
82
	/* fiddle sublink, must be last... */
83
	if (fo->opt_sublink) {
84
		plog(XLOG_WARNING, "nfsx: sublink %s ignored", fo->opt_sublink);
85
		free(fo->opt_sublink);
86
		fo->opt_sublink = 0;
87
	}
88
#endif
89
90
	/* set default sublink */
91
	if (fo->opt_sublink == 0) {
92
		ptr = strchr(fo->opt_rfs, ',');
93
		if (ptr && ptr != (fo->opt_rfs + 1))
94
			fo->opt_sublink = strnsave(fo->opt_rfs + 1, ptr - fo->opt_rfs - 1);
95
	}
96
97
	/*
98
	 * Remove trailing ",..." from ${fs}
99
	 * After deslashifying, overwrite the end of ${fs} with "/"
100
	 * to make sure it is unique.
101
	 */
102
	if ((ptr = strchr(fo->opt_fs, ',')))
103
		*ptr = '\0';
104
	deslashify(fo->opt_fs);
105
	/*
106
	 * Bump string length to allow trailing /
107
	 */
108
	len = strlen(fo->opt_fs);
109
	if (len > SIZE_MAX - 2)
110
		 xmallocfailure();
111
	fo->opt_fs = xreallocarray(fo->opt_fs, len + 1 + 1, 1);
112
	ptr = fo->opt_fs + len;
113
	/*
114
	 * Make unique...
115
	 */
116
	*ptr++ = '/';
117
	*ptr = '\0';
118
119
	/*
120
	 * Determine magic cookie to put in mtab
121
	 */
122
	xmtab = str3cat((char *) 0, fo->opt_rhost, ":", fo->opt_rfs);
123
#ifdef DEBUG
124
	dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
125
		fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
126
#endif /* DEBUG */
127
128
	return xmtab;
129
}
130
131
static void
132
nfsx_prfree(void *vp)
133
{
134
	struct nfsx *nx = (struct nfsx *) vp;
135
	int i;
136
137
	for (i = 0; i < nx->nx_c; i++) {
138
		mntfs *m = nx->nx_v[i].n_mnt;
139
		if (m)
140
			free_mntfs(m);
141
	}
142
143
	free(nx->nx_v);
144
	free(nx);
145
}
146
147
static int
148
nfsx_init(mntfs *mf)
149
{
150
	/*
151
	 * mf_info has the form:
152
	 *   host:/prefix/path,sub,sub,sub
153
	 */
154
	int i;
155
	int glob_error;
156
	struct nfsx *nx;
157
	int asked_for_wakeup = 0;
158
159
	nx = (struct nfsx *) mf->mf_private;
160
161
	if (nx == 0) {
162
		char **ivec;
163
		char *info = 0;
164
		char *host;
165
		char *pref;
166
		int error = 0;
167
168
		info = strdup(mf->mf_info);
169
		host = strchr(info, ':');
170
		if (!host) {
171
			error = EINVAL;
172
			goto errexit;
173
		}
174
175
		pref = host+1;
176
		host = info;
177
178
		/*
179
		 * Split the prefix off from the suffices
180
		 */
181
		ivec = strsplit(pref, ',', '\'');
182
183
		/*
184
		 * Count array size
185
		 */
186
		for (i = 0; ivec[i]; i++)
187
			;
188
189
		nx = ALLOC(nfsx);
190
		mf->mf_private = nx;
191
		mf->mf_prfree = nfsx_prfree;
192
193
		nx->nx_c = i - 1;	/* i-1 because we don't want the prefix */
194
		nx->nx_v = xreallocarray(NULL, nx->nx_c, sizeof *nx->nx_v);
195
		{ char *mp = 0;
196
		  char *xinfo = 0;
197
		  char *fs = mf->mf_fo->opt_fs;
198
		  char *rfs = 0;
199
		  for (i = 0; i < nx->nx_c; i++) {
200
			char *path = ivec[i+1];
201
			rfs = str3cat(rfs, pref, "/", path);
202
			/*
203
			 * Determine the mount point.
204
			 * If this is the root, then don't remove
205
			 * the trailing slash to avoid mntfs name clashes.
206
			 */
207
			mp = str3cat(mp, fs, "/", rfs);
208
			normalize_slash(mp);
209
			deslashify(mp);
210
			/*
211
			 * Determine the mount info
212
			 */
213
			xinfo = str3cat(xinfo, host, *path == '/' ? "" : "/", path);
214
			normalize_slash(xinfo);
215
			if (pref[1] != '\0')
216
				deslashify(xinfo);
217
#ifdef DEBUG
218
			dlog("nfsx: init mount for %s on %s", xinfo, mp);
219
#endif
220
			nx->nx_v[i].n_error = -1;
221
			nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts, mf->mf_remopts);
222
		  }
223
		  free(rfs);
224
		  free(mp);
225
		  free(xinfo);
226
		}
227
228
		free(ivec);
229
errexit:
230
		free(info);
231
		if (error)
232
			return error;
233
	}
234
235
	/*
236
	 * Iterate through the mntfs's and call
237
	 * the underlying init routine on each
238
	 */
239
	glob_error = 0;
240
	for (i = 0; i < nx->nx_c; i++) {
241
		nfsx_mnt *n = &nx->nx_v[i];
242
		mntfs *m = n->n_mnt;
243
		int error = (*m->mf_ops->fs_init)(m);
244
		/*
245
		 * If HARD_NFSX_ERRORS is defined, make any
246
		 * initialisation failure a hard error and
247
		 * fail the entire group.  Otherwise only fail
248
		 * if none of the group is mountable (see nfsx_fmount).
249
		 */
250
#ifdef HARD_NFSX_ERRORS
251
		if (error > 0)
252
			return error;
253
#else
254
		if (error > 0)
255
			n->n_error = error;
256
#endif
257
		else if (error < 0) {
258
			glob_error = -1;
259
			if (!asked_for_wakeup) {
260
				asked_for_wakeup = 1;
261
				sched_task(wakeup_task, mf, m);
262
			}
263
		}
264
	}
265
266
	return glob_error;
267
}
268
269
static void
270
nfsx_cont(int rc, int term, void *closure)
271
{
272
	mntfs *mf = (mntfs *) closure;
273
	struct nfsx *nx = (struct nfsx *) mf->mf_private;
274
	nfsx_mnt *n = nx->nx_try;
275
276
	n->n_mnt->mf_flags &= ~(MFF_ERROR|MFF_MOUNTING);
277
	mf->mf_flags &= ~MFF_ERROR;
278
279
	/*
280
	 * Wakeup anything waiting for this mount
281
	 */
282
	wakeup(n->n_mnt);
283
284
	if (rc || term) {
285
		if (term) {
286
			/*
287
			 * Not sure what to do for an error code.
288
			 */
289
			plog(XLOG_ERROR, "mount for %s got signal %d", n->n_mnt->mf_mount, term);
290
			n->n_error = EIO;
291
		} else {
292
			/*
293
			 * Check for exit status
294
			 */
295
			errno = rc;	/* XXX */
296
			plog(XLOG_ERROR, "%s: mount (nfsx_cont): %m", n->n_mnt->mf_mount);
297
			n->n_error = rc;
298
		}
299
		free_mntfs(n->n_mnt);
300
		n->n_mnt = new_mntfs();
301
		n->n_mnt->mf_error = n->n_error;
302
		n->n_mnt->mf_flags |= MFF_ERROR;
303
	} else {
304
		/*
305
		 * The mount worked.
306
		 */
307
		mf_mounted(n->n_mnt);
308
		n->n_error = 0;
309
	}
310
311
	/*
312
	 * Do the remaining bits
313
	 */
314
	if (nfsx_fmount(mf) >= 0) {
315
		wakeup(mf);
316
		mf->mf_flags &= ~MFF_MOUNTING;
317
		mf_mounted(mf);
318
	}
319
}
320
321
static int
322
try_nfsx_mount(void *mv)
323
{
324
	mntfs *mf = (mntfs *) mv;
325
	int error;
326
327
	mf->mf_flags |= MFF_MOUNTING;
328
	error = (*mf->mf_ops->fmount_fs)(mf);
329
	mf->mf_flags &= ~MFF_MOUNTING;
330
	return error;
331
}
332
333
static int
334
nfsx_remount(mntfs *mf, int fg)
335
{
336
	struct nfsx *nx = (struct nfsx *) mf->mf_private;
337
	nfsx_mnt *n;
338
	int glob_error = -1;
339
340
	for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
341
		mntfs *m = n->n_mnt;
342
		if (n->n_error < 0) {
343
			if (!(m->mf_flags & MFF_MKMNT) && m->mf_ops->fs_flags & FS_MKMNT) {
344
				int error = mkdirs(m->mf_mount, 0555);
345
				if (!error)
346
					m->mf_flags |= MFF_MKMNT;
347
			}
348
		}
349
	}
350
351
	/*
352
	 * Iterate through the mntfs's and mount each filesystem
353
	 * which is not yet mounted.
354
	 */
355
	for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
356
		mntfs *m = n->n_mnt;
357
		if (n->n_error < 0) {
358
			/*
359
			 * Check fmount entry pt. exists
360
			 * and then mount...
361
			 */
362
			if (!m->mf_ops->fmount_fs) {
363
				n->n_error = EINVAL;
364
			} else {
365
#ifdef DEBUG
366
				dlog("calling underlying fmount on %s", m->mf_mount);
367
#endif
368
				if (!fg && foreground && (m->mf_ops->fs_flags & FS_MBACKGROUND)) {
369
					m->mf_flags |= MFF_MOUNTING;	/* XXX */
370
#ifdef DEBUG
371
					dlog("backgrounding mount of \"%s\"", m->mf_info);
372
#endif
373
					nx->nx_try = n;
374
					run_task(try_nfsx_mount, m,
375
					    nfsx_cont, mf);
376
					n->n_error = -1;
377
					return -1;
378
				} else {
379
#ifdef DEBUG
380
					dlog("foreground mount of \"%s\" ...", mf->mf_info);
381
#endif
382
					n->n_error = (*m->mf_ops->fmount_fs)(m);
383
				}
384
			}
385
#ifdef DEBUG
386
			if (n->n_error > 0) {
387
				errno = n->n_error;	/* XXX */
388
				dlog("underlying fmount of %s failed: %m", m->mf_mount);
389
			}
390
#endif
391
			if (n->n_error == 0) {
392
				glob_error = 0;
393
			} else if (glob_error < 0) {
394
				glob_error = n->n_error;
395
			}
396
		}
397
	}
398
399
	return glob_error < 0 ? 0 : glob_error;
400
}
401
402
static int
403
nfsx_fmount(mntfs *mf)
404
{
405
	return nfsx_remount(mf, FALSE);
406
}
407
408
/*
409
 * Unmount an NFS hierarchy.
410
 * Note that this is called in the foreground
411
 * and so may hang under extremely rare conditions.
412
 */
413
static int
414
nfsx_fumount(mntfs *mf)
415
{
416
	struct nfsx *nx = (struct nfsx *) mf->mf_private;
417
	nfsx_mnt *n;
418
	int glob_error = 0;
419
420
	/*
421
	 * Iterate in reverse through the mntfs's and unmount each filesystem
422
	 * which is mounted.
423
	 */
424
	for (n = nx->nx_v + nx->nx_c - 1; n >= nx->nx_v; --n) {
425
		mntfs *m = n->n_mnt;
426
		/*
427
		 * If this node has not been messed with
428
		 * and there has been no error so far
429
		 * then try and unmount.
430
		 * If an error had occured then zero
431
		 * the error code so that the remount
432
		 * only tries to unmount those nodes
433
		 * which had been successfully unmounted.
434
		 */
435
		if (n->n_error == 0) {
436
#ifdef DEBUG
437
			dlog("calling underlying fumount on %s", m->mf_mount);
438
#endif
439
			n->n_error = (*m->mf_ops->fumount_fs)(m);
440
			if (n->n_error) {
441
				glob_error = n->n_error;
442
				n->n_error = 0;
443
			} else {
444
				/*
445
				 * Make sure remount gets this node
446
				 */
447
				n->n_error = -1;
448
			}
449
		}
450
	}
451
452
	/*
453
	 * If any unmounts failed then remount the
454
	 * whole lot...
455
	 */
456
	if (glob_error) {
457
		glob_error = nfsx_remount(mf, TRUE);
458
		if (glob_error) {
459
			errno = glob_error; /* XXX */
460
			plog(XLOG_USER, "nfsx: remount of %s failed: %m", mf->mf_mount);
461
		}
462
		glob_error = EBUSY;
463
	} else {
464
		/*
465
		 * Remove all the mount points
466
		 */
467
		for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
468
			mntfs *m = n->n_mnt;
469
			if (n->n_error < 0) {
470
				if (m->mf_ops->fs_flags & FS_MKMNT) {
471
					(void) rmdirs(m->mf_mount);
472
					m->mf_flags &= ~MFF_MKMNT;
473
				}
474
			}
475
			free_mntfs(m);
476
			n->n_mnt = 0;
477
			n->n_error = -1;
478
		}
479
	}
480
481
	return glob_error;
482
}
483
484
/*
485
 * Ops structure
486
 */
487
am_ops nfsx_ops = {
488
	"nfsx",
489
	nfsx_match,
490
	nfsx_init,
491
	auto_fmount,
492
	nfsx_fmount,
493
	auto_fumount,
494
	nfsx_fumount,
495
	efs_lookuppn,
496
	efs_readdir,
497
	0, /* nfsx_readlink */
498
	0, /* nfsx_mounted */
499
	0, /* nfsx_umounted */
500
	find_nfs_srvr,			/* XXX */
501
	/*FS_UBACKGROUND|*/FS_AMQINFO
502
};
503
504
#endif /* HAS_NFSX */