xref: /original-bsd/usr.sbin/amd/amd/nfsx_ops.c (revision 95a66346)
1 /*
2  * $Id: nfsx_ops.c,v 5.2.1.5 91/03/17 17:46:15 jsp Alpha $
3  *
4  * Copyright (c) 1990 Jan-Simon Pendry
5  * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
6  * Copyright (c) 1990 The Regents of the University of California.
7  * 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  * %sccs.include.redist.c%
13  *
14  *	@(#)nfsx_ops.c	5.2 (Berkeley) 03/17/91
15  */
16 
17 #include "am.h"
18 
19 #ifdef HAS_NFSX
20 
21 /*
22  * NFS hierarchical mounts
23  *
24  * TODO: Re-implement.
25  */
26 
27 /*
28  * The rfs field contains a list of mounts to be done from
29  * the remote host.
30  */
31 typedef struct nfsx_mnt {
32 	mntfs *n_mnt;
33 	int n_error;
34 } nfsx_mnt;
35 
36 struct nfsx {
37 	int nx_c;		/* Number of elements in nx_v */
38 	nfsx_mnt *nx_v;		/* Underlying mounts */
39 	nfsx_mnt *nx_try;
40 };
41 
42 static int nfsx_fmount P((mntfs*));
43 
44 static char *nfsx_match(fo)
45 am_opts *fo;
46 {
47 	char *xmtab;
48 	char *ptr;
49 	int len;
50 
51 	if (!fo->opt_rfs) {
52 		plog(XLOG_USER, "nfsx: no remote filesystem specified");
53 		return FALSE;
54 	}
55 	if (!fo->opt_rhost) {
56 		plog(XLOG_USER, "nfsx: no remote host specified");
57 		return FALSE;
58 	}
59 
60 	/* fiddle sublink, must be last... */
61 	if (fo->opt_sublink) {
62 		plog(XLOG_WARNING, "nfsx: sublink %s ignored", fo->opt_sublink);
63 		free((voidp) fo->opt_sublink);
64 		fo->opt_sublink = 0;
65 	}
66 
67 	/*
68 	 * Remove trailing ",..." from ${fs}
69 	 * After deslashifying, overwrite the end of ${fs} with "/"
70 	 * to make sure it is unique.
71 	 */
72 	if (ptr = strchr(fo->opt_fs, ','))
73 		*ptr = '\0';
74 	deslashify(fo->opt_fs);
75 	len = strlen(fo->opt_fs);
76 	fo->opt_fs = xrealloc(fo->opt_fs, len + 1);
77 	ptr = fo->opt_fs + len;
78 	/*
79 	 * Make unique...
80 	 */
81 	*ptr++ = '/';
82 	*ptr = '\0';
83 
84 	/*
85 	 * Determine magic cookie to put in mtab
86 	 */
87 	xmtab = (char *) xmalloc(strlen(fo->opt_rhost) + strlen(fo->opt_rfs) + 2);
88 	sprintf(xmtab, "%s:%s", fo->opt_rhost, fo->opt_rfs);
89 #ifdef DEBUG
90 	dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
91 		fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
92 #endif /* DEBUG */
93 
94 	return xmtab;
95 }
96 
97 static void nfsx_prfree P((voidp vp));
98 static void nfsx_prfree(vp)
99 voidp vp;
100 {
101 	struct nfsx *nx = (struct nfsx *) vp;
102 	int i;
103 
104 	for (i = 0; i < nx->nx_c; i++) {
105 		mntfs *m = nx->nx_v[i].n_mnt;
106 		if (m)
107 			free_mntfs(m);
108 	}
109 
110 	free((voidp) nx->nx_v);
111 	free((voidp) nx);
112 }
113 
114 static int nfsx_init(mf)
115 mntfs *mf;
116 {
117 	/*
118 	 * mf_info has the form:
119 	 *   host:/prefix/path,sub,sub,sub
120 	 */
121 	int i;
122 	int glob_error;
123 	struct nfsx *nx;
124 
125 	nx = (struct nfsx *) mf->mf_private;
126 
127 	if (nx == 0) {
128 		char **ivec;
129 		char *info = 0;
130 		char *host;
131 		char *pref;
132 		int error = 0;
133 
134 		info = strdup(mf->mf_info);
135 		host = strchr(info, ':');
136 		if (!host) {
137 			error = EINVAL;
138 			goto errexit;
139 		}
140 
141 		pref = host+1;
142 		host = info;
143 
144 		/*
145 		 * Split the prefix off from the suffices
146 		 */
147 		ivec = strsplit(pref, ',', '\'');
148 
149 		/*
150 		 * Count array size
151 		 */
152 		for (i = 0; ivec[i]; i++)
153 			;
154 
155 		nx = ALLOC(nfsx);
156 		mf->mf_private = (voidp) nx;
157 		mf->mf_prfree = nfsx_prfree;
158 
159 		nx->nx_c = i - 1;	/* i-1 because we don't want the prefix */
160 		nx->nx_v = (nfsx_mnt *) xmalloc(nx->nx_c * sizeof(nfsx_mnt));
161 		{ char *mp = 0;
162 		  char *xinfo = 0;
163 		  char *fs = mf->mf_fo->opt_fs;
164 		  char *rfs = 0;
165 		  for (i = 0; i < nx->nx_c; i++) {
166 		  	char *path = ivec[i+1];
167 			rfs = str3cat(rfs, pref, "/", path);
168 		  	/*
169 			 * Determine the mount point.
170 			 * If this is the root, then don't remove
171 			 * the trailing slash to avoid mntfs name clashes.
172 			 */
173 			mp = str3cat(mp, fs, "/", rfs);
174 			normalize_slash(mp);
175 			deslashify(mp);
176 			/*
177 			 * Determine the mount info
178 			 */
179 			xinfo = str3cat(xinfo, host, *path == '/' ? "" : "/", path);
180 			normalize_slash(xinfo);
181 			if (pref[1] != '\0')
182 				deslashify(xinfo);
183 #ifdef DEBUG
184 			dlog("nfsx: init mount for %s on %s", xinfo, mp);
185 #endif
186 			nx->nx_v[i].n_error = -1;
187 			nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts);
188 		  }
189 		  if (rfs) free(rfs);
190 		  if (mp) free(mp);
191 		  if (xinfo) free(xinfo);
192 		}
193 
194 		free((voidp) ivec);
195 errexit:
196 		if (info)
197 			free(info);
198 		if (error)
199 			return error;
200 	}
201 
202 	/*
203 	 * Iterate through the mntfs's and call
204 	 * the underlying init routine on each
205 	 */
206 	glob_error = 0;
207 	for (i = 0; i < nx->nx_c; i++) {
208 		nfsx_mnt *n = &nx->nx_v[i];
209 		mntfs *m = n->n_mnt;
210 		int error = (*m->mf_ops->fs_init)(m);
211 		/*
212 		 * If HARD_NFSX_ERRORS is defined, make any
213 		 * initialisation failure a hard error and
214 		 * fail the entire group.  Otherwise only fail
215 		 * fail if none of the group is mountable (see
216 		 * nfsx_fmount).
217 		 */
218 #ifdef HARD_NFSX_ERRORS
219 		if (error > 0)
220 			return error;
221 #else
222 		if (error > 0)
223 			n->n_error = error;
224 #endif
225 		else if (error < 0)
226 			glob_error = -1;
227 	}
228 
229 	return glob_error;
230 }
231 
232 static void nfsx_cont P((int rc, int term, voidp closure));
233 static void nfsx_cont(rc, term, closure)
234 int rc;
235 int term;
236 voidp closure;
237 {
238 	mntfs *mf = (mntfs *) closure;
239 	struct nfsx *nx = (struct nfsx *) mf->mf_private;
240 	nfsx_mnt *n = nx->nx_try;
241 
242 	n->n_mnt->mf_flags &= ~(MFF_ERROR|MFF_MOUNTING);
243 	mf->mf_flags &= ~(MFF_ERROR|MFF_MOUNTING);
244 
245 	/*
246 	 * Wakeup anything waiting for this mount
247 	 */
248 	wakeup((voidp) mf);
249 
250 	if (rc || term) {
251 		if (term) {
252 			/*
253 			 * Not sure what to do for an error code.
254 			 */
255 			plog(XLOG_ERROR, "mount for %s got signal %d", n->n_mnt->mf_mount, term);
256 			n->n_error = EIO;
257 		} else {
258 			/*
259 			 * Check for exit status
260 			 */
261 			errno = rc;	/* XXX */
262 			plog(XLOG_ERROR, "%s: mount (nfsx_cont): %m", n->n_mnt->mf_mount);
263 			n->n_error = rc;
264 		}
265 		free_mntfs(n->n_mnt);
266 		n->n_mnt = new_mntfs();
267 		n->n_mnt->mf_error = n->n_error;
268 		n->n_mnt->mf_flags |= MFF_ERROR;
269 	} else {
270 		/*
271 		 * The mount worked.
272 		 */
273 		mf_mounted(n->n_mnt);
274 		n->n_error = 0;
275 		/*
276 		 * Do the remaining bits
277 		 */
278 		if (nfsx_fmount(mf) >= 0)
279 			mf_mounted(mf);
280 	}
281 }
282 
283 static int try_nfsx_mount P((voidp mv));
284 static int try_nfsx_mount(mv)
285 voidp mv;
286 {
287 	mntfs *mf = (mntfs *) mv;
288 	int error;
289 
290 	mf->mf_flags |= MFF_MOUNTING;
291 	error = (*mf->mf_ops->fmount_fs)(mf);
292 	mf->mf_flags &= ~MFF_MOUNTING;
293 	return error;
294 }
295 
296 static int nfsx_fmount P((mntfs *mf));
297 static int nfsx_fmount(mf)
298 mntfs *mf;
299 {
300 	struct nfsx *nx = (struct nfsx *) mf->mf_private;
301 	nfsx_mnt *n;
302 	int glob_error = -1;
303 
304 	for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
305 		mntfs *m = n->n_mnt;
306 		if (n->n_error < 0) {
307 			if (!(m->mf_flags & MFF_MKMNT) && m->mf_ops->fs_flags & FS_MKMNT) {
308 				int error = mkdirs(m->mf_mount, 0555);
309 				if (!error)
310 					m->mf_flags |= MFF_MKMNT;
311 			}
312 		}
313 	}
314 
315 	/*
316 	 * Iterate through the mntfs's and mount each filesystem
317 	 * which is not yet mounted.
318 	 */
319 	for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
320 		mntfs *m = n->n_mnt;
321 		if (n->n_error < 0) {
322 			/*
323 			 * Check fmount entry pt. exists
324 			 * and then mount...
325 			 */
326 			if (!m->mf_ops->fmount_fs) {
327 				n->n_error = EINVAL;
328 			} else {
329 #ifdef DEBUG
330 				dlog("calling underlying fmount on %s", m->mf_mount);
331 #endif
332 				if (foreground && (m->mf_ops->fs_flags & FS_MBACKGROUND)) {
333 					m->mf_flags |= MFF_MOUNTING;	/* XXX */
334 #ifdef DEBUG
335 					dlog("backgrounding mount of \"%s\"", m->mf_info);
336 #endif
337 					nx->nx_try = n;
338 					run_task(try_nfsx_mount, (voidp) m, nfsx_cont, (voidp) mf);
339 					n->n_error = -1;
340 					return -1;
341 				} else {
342 #ifdef DEBUG
343 					dlog("foreground mount of \"%s\" ...", mf->mf_info);
344 #endif /* DEBUG */
345 					n->n_error = (*m->mf_ops->fmount_fs)(m);
346 				}
347 			}
348 #ifdef DEBUG
349 			if (n->n_error > 0) {
350 				errno = n->n_error;	/* XXX */
351 				dlog("underlying fmount of %s failed: %m", m->mf_mount);
352 			}
353 #endif
354 			if (n->n_error == 0) {
355 				glob_error = 0;
356 			} else if (glob_error < 0) {
357 				glob_error = n->n_error;
358 			}
359 		}
360 	}
361 
362 	return glob_error < 0 ? 0 : glob_error;
363 }
364 
365 static int nfsx_fumount(mf)
366 mntfs *mf;
367 {
368 	struct nfsx *nx = (struct nfsx *) mf->mf_private;
369 	nfsx_mnt *n;
370 	int glob_error = 0;
371 
372 	/*
373 	 * Iterate in reverse through the mntfs's and unmount each filesystem
374 	 * which is mounted.
375 	 */
376 	for (n = nx->nx_v + nx->nx_c - 1; n >= nx->nx_v; --n) {
377 		mntfs *m = n->n_mnt;
378 		/*
379 		 * If this node has not been messed with
380 		 * and there has been no error so far
381 		 * then try and unmount.
382 		 * If an error had occured then zero
383 		 * the error code so that the remount
384 		 * only tries to unmount those nodes
385 		 * which had been successfully unmounted.
386 		 */
387 		if (n->n_error == 0) {
388 #ifdef DEBUG
389 			dlog("calling underlying fumount on %s", m->mf_mount);
390 #endif
391 			n->n_error = (*m->mf_ops->fumount_fs)(m);
392 			if (n->n_error) {
393 				glob_error = n->n_error;
394 			} else {
395 				/*
396 				 * Make sure remount gets this node
397 				 */
398 				n->n_error = -1;
399 			}
400 		}
401 	}
402 
403 	/*
404 	 * If any unmounts failed then remount the
405 	 * whole lot...
406 	 */
407 	if (glob_error) {
408 		glob_error = nfsx_fmount(mf);
409 		if (glob_error)
410 			plog(XLOG_USER, "nfsx: remount of %s failed: %m", mf->mf_mount);
411 		glob_error = EBUSY;
412 	} else {
413 		/*
414 		 * Remove all the mount points
415 		 */
416 		for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
417 			mntfs *m = n->n_mnt;
418 			if (n->n_error < 0) {
419 				if (m->mf_ops->fs_flags & FS_MKMNT)
420 					(void) rmdirs(m->mf_mount);
421 			}
422 			free_mntfs(m);
423 			n->n_mnt = 0;
424 		}
425 	}
426 
427 	return glob_error;
428 }
429 
430 /*
431  * Ops structure
432  */
433 am_ops nfsx_ops = {
434 	"nfsx",
435 	nfsx_match,
436 	nfsx_init,
437 	auto_fmount,
438 	nfsx_fmount,
439 	auto_fumount,
440 	nfsx_fumount,
441 	efs_lookuppn,
442 	efs_readdir,
443 	0, /* nfsx_readlink */
444 	0, /* nfsx_mounted */
445 	0, /* nfsx_umounted */
446 	find_nfs_srvr,			/* XXX */
447 	/*FS_UBACKGROUND|*/FS_AMQINFO
448 };
449 
450 #endif /* HAS_NFSX */
451