No empty .Rs/.Re
[netbsd-mini2440.git] / external / bsd / am-utils / dist / amd / amfs_nfsx.c
blob3644f51eadc4169af28f2033f7bfddeb2500cd60
1 /* $NetBSD$ */
3 /*
4 * Copyright (c) 1997-2009 Erez Zadok
5 * Copyright (c) 1990 Jan-Simon Pendry
6 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
7 * Copyright (c) 1990 The Regents of the University of California.
8 * All rights reserved.
10 * This code is derived from software contributed to Berkeley by
11 * Jan-Simon Pendry at Imperial College, London.
13 * Redistribution and use in source and binary forms, with or without
14 * modification, are permitted provided that the following conditions
15 * are met:
16 * 1. Redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution.
21 * 3. All advertising materials mentioning features or use of this software
22 * must display the following acknowledgment:
23 * This product includes software developed by the University of
24 * California, Berkeley and its contributors.
25 * 4. Neither the name of the University nor the names of its contributors
26 * may be used to endorse or promote products derived from this software
27 * without specific prior written permission.
29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
39 * SUCH DAMAGE.
42 * File: am-utils/amd/amfs_nfsx.c
47 * NFS hierarchical mounts
49 * TODO: Re-implement.
52 #ifdef HAVE_CONFIG_H
53 # include <config.h>
54 #endif /* HAVE_CONFIG_H */
55 #include <am_defs.h>
56 #include <amd.h>
59 * The rfs field contains a list of mounts to be done from
60 * the remote host.
62 typedef struct amfs_nfsx_mnt {
63 mntfs *n_mnt;
64 int n_error;
65 } amfs_nfsx_mnt;
67 struct amfs_nfsx {
68 int nx_c; /* Number of elements in nx_v */
69 amfs_nfsx_mnt *nx_v; /* Underlying mounts */
70 amfs_nfsx_mnt *nx_try;
71 am_node *nx_mp;
74 /* forward definitions */
75 static char *amfs_nfsx_match(am_opts *fo);
76 static int amfs_nfsx_mount(am_node *am, mntfs *mf);
77 static int amfs_nfsx_umount(am_node *am, mntfs *mf);
78 static int amfs_nfsx_init(mntfs *mf);
81 * Ops structure
83 am_ops amfs_nfsx_ops =
85 "nfsx",
86 amfs_nfsx_match,
87 amfs_nfsx_init,
88 amfs_nfsx_mount,
89 amfs_nfsx_umount,
90 amfs_error_lookup_child,
91 amfs_error_mount_child,
92 amfs_error_readdir,
93 0, /* amfs_nfsx_readlink */
94 0, /* amfs_nfsx_mounted */
95 0, /* amfs_nfsx_umounted */
96 find_nfs_srvr, /* XXX */
97 0, /* amfs_nfsx_get_wchan */
98 /* FS_UBACKGROUND| */ FS_AMQINFO, /* nfs_fs_flags */
99 #ifdef HAVE_FS_AUTOFS
100 AUTOFS_NFSX_FS_FLAGS,
101 #endif /* HAVE_FS_AUTOFS */
105 static char *
106 amfs_nfsx_match(am_opts *fo)
108 char *xmtab;
109 char *ptr;
110 int len;
112 if (!fo->opt_rfs) {
113 plog(XLOG_USER, "amfs_nfsx: no remote filesystem specified");
114 return FALSE;
117 if (!fo->opt_rhost) {
118 plog(XLOG_USER, "amfs_nfsx: no remote host specified");
119 return FALSE;
122 /* set default sublink */
123 if (fo->opt_sublink == NULL || fo->opt_sublink[0] == '\0') {
124 ptr = strchr(fo->opt_rfs, ',');
125 if (ptr && ptr > (fo->opt_rfs + 1))
126 fo->opt_sublink = strnsave(fo->opt_rfs + 1, ptr - fo->opt_rfs - 1);
130 * Remove trailing ",..." from ${fs}
131 * After deslashifying, overwrite the end of ${fs} with "/"
132 * to make sure it is unique.
134 if ((ptr = strchr(fo->opt_fs, ',')))
135 *ptr = '\0';
136 deslashify(fo->opt_fs);
139 * Bump string length to allow trailing /
141 len = strlen(fo->opt_fs);
142 fo->opt_fs = xrealloc(fo->opt_fs, len + 1 + 1);
143 ptr = fo->opt_fs + len;
146 * Make unique...
148 *ptr++ = '/';
149 *ptr = '\0';
152 * Determine magic cookie to put in mtab
154 xmtab = str3cat((char *) NULL, fo->opt_rhost, ":", fo->opt_rfs);
155 dlog("NFSX: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
156 fo->opt_rhost, fo->opt_rfs, fo->opt_fs);
158 return xmtab;
162 static void
163 amfs_nfsx_prfree(opaque_t vp)
165 struct amfs_nfsx *nx = (struct amfs_nfsx *) vp;
166 int i;
168 for (i = 0; i < nx->nx_c; i++) {
169 mntfs *m = nx->nx_v[i].n_mnt;
170 if (m)
171 free_mntfs(m);
174 XFREE(nx->nx_v);
175 XFREE(nx);
179 static int
180 amfs_nfsx_init(mntfs *mf)
183 * mf_info has the form:
184 * host:/prefix/path,sub,sub,sub
186 int i;
187 int glob_error;
188 struct amfs_nfsx *nx;
189 int asked_for_wakeup = 0;
191 nx = (struct amfs_nfsx *) mf->mf_private;
193 if (nx == 0) {
194 char **ivec;
195 char *info = NULL;
196 char *host;
197 char *pref;
198 int error = 0;
200 info = strdup(mf->mf_info);
201 host = strchr(info, ':');
202 if (!host) {
203 error = EINVAL;
204 goto errexit;
206 pref = host + 1;
207 host = info;
210 * Split the prefix off from the suffices
212 ivec = strsplit(pref, ',', '\'');
215 * Count array size
217 for (i = 0; ivec[i]; i++)
218 /* nothing */;
220 nx = ALLOC(struct amfs_nfsx);
221 mf->mf_private = (opaque_t) nx;
222 mf->mf_prfree = amfs_nfsx_prfree;
224 nx->nx_c = i - 1; /* i-1 because we don't want the prefix */
225 nx->nx_v = (amfs_nfsx_mnt *) xmalloc(nx->nx_c * sizeof(amfs_nfsx_mnt));
226 nx->nx_mp = NULL;
228 char *mp = NULL;
229 char *xinfo = NULL;
230 char *fs = mf->mf_fo->opt_fs;
231 char *rfs = NULL;
232 for (i = 0; i < nx->nx_c; i++) {
233 char *path = ivec[i + 1];
234 rfs = str3cat(rfs, pref, "/", path);
236 * Determine the mount point.
237 * If this is the root, then don't remove
238 * the trailing slash to avoid mntfs name clashes.
240 mp = str3cat(mp, fs, "/", rfs);
241 normalize_slash(mp);
242 deslashify(mp);
244 * Determine the mount info
246 xinfo = str3cat(xinfo, host, *path == '/' ? "" : "/", path);
247 normalize_slash(xinfo);
248 if (pref[1] != '\0')
249 deslashify(xinfo);
250 dlog("amfs_nfsx: init mount for %s on %s", xinfo, mp);
251 nx->nx_v[i].n_error = -1;
252 nx->nx_v[i].n_mnt = find_mntfs(&nfs_ops, mf->mf_fo, mp, xinfo, "", mf->mf_mopts, mf->mf_remopts);
253 /* propagate the on_autofs flag */
254 nx->nx_v[i].n_mnt->mf_flags |= mf->mf_flags & MFF_ON_AUTOFS;
256 if (rfs)
257 XFREE(rfs);
258 if (mp)
259 XFREE(mp);
260 if (xinfo)
261 XFREE(xinfo);
264 XFREE(ivec);
265 errexit:
266 if (info)
267 XFREE(info);
268 if (error)
269 return error;
273 * Iterate through the mntfs's and call
274 * the underlying init routine on each
276 glob_error = 0;
278 for (i = 0; i < nx->nx_c; i++) {
279 amfs_nfsx_mnt *n = &nx->nx_v[i];
280 mntfs *m = n->n_mnt;
281 int error = 0;
282 if (m->mf_ops->fs_init && !(mf->mf_flags & MFF_RESTART))
283 error = m->mf_ops->fs_init(m);
285 * if you just "return error" here, you will have made a failure
286 * in any submounts to fail the whole group. There was old unused code
287 * here before.
289 if (error > 0)
290 n->n_error = error;
292 else if (error < 0) {
293 glob_error = -1;
294 if (!asked_for_wakeup) {
295 asked_for_wakeup = 1;
296 sched_task(wakeup_task, (opaque_t) mf, get_mntfs_wchan(m));
301 return glob_error;
305 static void
306 amfs_nfsx_cont(int rc, int term, opaque_t arg)
308 mntfs *mf = (mntfs *) arg;
309 struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private;
310 am_node *mp = nx->nx_mp;
311 amfs_nfsx_mnt *n = nx->nx_try;
313 n->n_mnt->mf_flags &= ~(MFF_ERROR | MFF_MOUNTING);
314 mf->mf_flags &= ~MFF_ERROR;
317 * Wakeup anything waiting for this mount
319 wakeup(get_mntfs_wchan(n->n_mnt));
321 if (rc || term) {
322 if (term) {
324 * Not sure what to do for an error code.
326 plog(XLOG_ERROR, "mount for %s got signal %d", n->n_mnt->mf_mount, term);
327 n->n_error = EIO;
328 } else {
330 * Check for exit status
332 errno = rc; /* XXX */
333 plog(XLOG_ERROR, "%s: mount (amfs_nfsx_cont): %m", n->n_mnt->mf_mount);
334 n->n_error = rc;
336 free_mntfs(n->n_mnt);
337 n->n_mnt = new_mntfs();
338 n->n_mnt->mf_error = n->n_error;
339 n->n_mnt->mf_flags |= MFF_ERROR;
340 } else {
342 * The mount worked.
344 mf_mounted(n->n_mnt, FALSE); /* FALSE => don't free the n_mnt->am_opts */
345 n->n_error = 0;
349 * Do the remaining bits
351 if (amfs_nfsx_mount(mp, mf) >= 0)
352 wakeup(get_mntfs_wchan(mf));
356 static int
357 try_amfs_nfsx_mount(opaque_t mv)
359 mntfs *mf = (mntfs *) mv;
360 struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private;
361 am_node *mp = nx->nx_mp;
362 int error;
364 error = mf->mf_ops->mount_fs(mp, mf);
366 return error;
370 static int
371 amfs_nfsx_remount(am_node *am, mntfs *mf, int fg)
373 struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private;
374 amfs_nfsx_mnt *n;
375 int glob_error = -1;
377 /* Save the am_node pointer for later use */
378 nx->nx_mp = am;
381 * Iterate through the mntfs's and mount each filesystem
382 * which is not yet mounted.
384 for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
385 mntfs *m = n->n_mnt;
387 if (m->mf_flags & MFF_MOUNTING)
388 break;
390 if (m->mf_flags & MFF_MOUNTED) {
391 mf_mounted(m, FALSE); /* FALSE => don't free the m->am_opts */
392 n->n_error = glob_error = 0;
393 continue;
396 if (n->n_error < 0) {
397 /* Create the mountpoint, if and as required */
398 if (!(m->mf_flags & MFF_MKMNT) && m->mf_fsflags & FS_MKMNT) {
399 if (!mkdirs(m->mf_mount, 0555))
400 m->mf_flags |= MFF_MKMNT;
403 dlog("calling underlying mount on %s", m->mf_mount);
404 if (!fg && foreground && (m->mf_fsflags & FS_MBACKGROUND)) {
405 m->mf_flags |= MFF_MOUNTING;
406 dlog("backgrounding mount of \"%s\"", m->mf_info);
407 nx->nx_try = n;
408 run_task(try_amfs_nfsx_mount, (opaque_t) m, amfs_nfsx_cont, (opaque_t) mf);
409 n->n_error = -1;
410 return -1;
411 } else {
412 dlog("foreground mount of \"%s\" ...", mf->mf_info);
413 n->n_error = m->mf_ops->mount_fs(am, m);
416 if (n->n_error > 0)
417 dlog("underlying fmount of %s failed: %s", m->mf_mount, strerror(n->n_error));
419 if (n->n_error == 0) {
420 glob_error = 0;
421 } else if (glob_error < 0) {
422 glob_error = n->n_error;
427 return glob_error < 0 ? 0 : glob_error;
431 static int
432 amfs_nfsx_mount(am_node *am, mntfs *mf)
434 return amfs_nfsx_remount(am, mf, FALSE);
439 * Unmount an NFS hierarchy.
440 * Note that this is called in the foreground
441 * and so may hang under extremely rare conditions.
443 static int
444 amfs_nfsx_umount(am_node *am, mntfs *mf)
446 struct amfs_nfsx *nx = (struct amfs_nfsx *) mf->mf_private;
447 amfs_nfsx_mnt *n;
448 int glob_error = 0;
451 * Iterate in reverse through the mntfs's and unmount each filesystem
452 * which is mounted.
454 for (n = nx->nx_v + nx->nx_c - 1; n >= nx->nx_v; --n) {
455 mntfs *m = n->n_mnt;
457 * If this node has not been messed with
458 * and there has been no error so far
459 * then try and unmount.
460 * If an error had occurred then zero
461 * the error code so that the remount
462 * only tries to unmount those nodes
463 * which had been successfully unmounted.
465 if (n->n_error == 0) {
466 dlog("calling underlying fumount on %s", m->mf_mount);
467 n->n_error = m->mf_ops->umount_fs(am, m);
468 if (n->n_error) {
469 glob_error = n->n_error;
470 n->n_error = 0;
471 } else {
473 * Make sure remount gets this node
475 n->n_error = -1;
481 * If any unmounts failed then remount the
482 * whole lot...
484 if (glob_error) {
485 glob_error = amfs_nfsx_remount(am, mf, TRUE);
486 if (glob_error) {
487 errno = glob_error; /* XXX */
488 plog(XLOG_USER, "amfs_nfsx: remount of %s failed: %m", mf->mf_mount);
490 glob_error = EBUSY;
491 } else {
493 * Remove all the mount points
495 for (n = nx->nx_v; n < nx->nx_v + nx->nx_c; n++) {
496 mntfs *m = n->n_mnt;
497 dlog("calling underlying umounted on %s", m->mf_mount);
498 if (m->mf_ops->umounted)
499 m->mf_ops->umounted(m);
501 if (n->n_error < 0) {
502 if (m->mf_fsflags & FS_MKMNT) {
503 (void) rmdirs(m->mf_mount);
504 m->mf_flags &= ~MFF_MKMNT;
507 free_mntfs(m);
508 n->n_mnt = NULL;
509 n->n_error = -1;
513 return glob_error;