2 * Copyright (c) 1997-1999 Erez Zadok
3 * Copyright (c) 1990 Jan-Simon Pendry
4 * Copyright (c) 1990 Imperial College of Science, Technology & Medicine
5 * Copyright (c) 1990 The Regents of the University of California.
8 * This code is derived from software contributed to Berkeley by
9 * Jan-Simon Pendry at Imperial College, London.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgment:
21 * This product includes software developed by the University of
22 * California, Berkeley and its contributors.
23 * 4. Neither the name of the University nor the names of its contributors
24 * may be used to endorse or promote products derived from this software
25 * without specific prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
28 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
31 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
32 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
33 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
34 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
35 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
36 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
41 * $Id: amfs_nfsx.c,v 1.2 1999/01/10 21:53:42 ezk Exp $
46 * NFS hierarchical mounts
53 #endif /* HAVE_CONFIG_H */
58 * The rfs field contains a list of mounts to be done from
61 typedef struct amfs_nfsx_mnt
{
67 int nx_c
; /* Number of elements in nx_v */
68 amfs_nfsx_mnt
*nx_v
; /* Underlying mounts */
69 amfs_nfsx_mnt
*nx_try
;
72 /* forward definitions */
73 static char *amfs_nfsx_match(am_opts
*fo
);
74 static int amfs_nfsx_fmount (mntfs
*);
75 static int amfs_nfsx_fmount(mntfs
*mf
);
76 static int amfs_nfsx_fumount(mntfs
*mf
);
77 static int amfs_nfsx_init(mntfs
*mf
);
82 am_ops amfs_nfsx_ops
=
93 0, /* amfs_nfsx_readlink */
94 0, /* amfs_nfsx_mounted */
95 0, /* amfs_nfsx_umounted */
96 find_nfs_srvr
, /* XXX */
97 /* FS_UBACKGROUND| */ FS_AMQINFO
102 amfs_nfsx_match(am_opts
*fo
)
109 plog(XLOG_USER
, "amfs_nfsx: no remote filesystem specified");
113 if (!fo
->opt_rhost
) {
114 plog(XLOG_USER
, "amfs_nfsx: no remote host specified");
118 /* set default sublink */
119 if (fo
->opt_sublink
== 0) {
120 ptr
= strchr(fo
->opt_rfs
, ',');
121 if (ptr
&& ptr
!= (fo
->opt_rfs
+ 1))
122 fo
->opt_sublink
= strnsave(fo
->opt_rfs
+ 1, ptr
- fo
->opt_rfs
- 1);
126 * Remove trailing ",..." from ${fs}
127 * After deslashifying, overwrite the end of ${fs} with "/"
128 * to make sure it is unique.
130 if ((ptr
= strchr(fo
->opt_fs
, ',')))
132 deslashify(fo
->opt_fs
);
135 * Bump string length to allow trailing /
137 len
= strlen(fo
->opt_fs
);
138 fo
->opt_fs
= xrealloc(fo
->opt_fs
, len
+ 1 + 1);
139 ptr
= fo
->opt_fs
+ len
;
148 * Determine magic cookie to put in mtab
150 xmtab
= str3cat((char *) 0, fo
->opt_rhost
, ":", fo
->opt_rfs
);
152 dlog("NFS: mounting remote server \"%s\", remote fs \"%s\" on \"%s\"",
153 fo
->opt_rhost
, fo
->opt_rfs
, fo
->opt_fs
);
161 amfs_nfsx_prfree(voidp vp
)
163 struct amfs_nfsx
*nx
= (struct amfs_nfsx
*) vp
;
166 for (i
= 0; i
< nx
->nx_c
; i
++) {
167 mntfs
*m
= nx
->nx_v
[i
].n_mnt
;
178 amfs_nfsx_init(mntfs
*mf
)
181 * mf_info has the form:
182 * host:/prefix/path,sub,sub,sub
186 struct amfs_nfsx
*nx
;
187 int asked_for_wakeup
= 0;
189 nx
= (struct amfs_nfsx
*) mf
->mf_private
;
198 info
= strdup(mf
->mf_info
);
199 host
= strchr(info
, ':');
208 * Split the prefix off from the suffices
210 ivec
= strsplit(pref
, ',', '\'');
215 for (i
= 0; ivec
[i
]; i
++) ;
217 nx
= ALLOC(struct amfs_nfsx
);
218 mf
->mf_private
= (voidp
) nx
;
219 mf
->mf_prfree
= amfs_nfsx_prfree
;
221 nx
->nx_c
= i
- 1; /* i-1 because we don't want the prefix */
222 nx
->nx_v
= (amfs_nfsx_mnt
*) xmalloc(nx
->nx_c
* sizeof(amfs_nfsx_mnt
));
226 char *fs
= mf
->mf_fo
->opt_fs
;
228 for (i
= 0; i
< nx
->nx_c
; i
++) {
229 char *path
= ivec
[i
+ 1];
230 rfs
= str3cat(rfs
, pref
, "/", path
);
232 * Determine the mount point.
233 * If this is the root, then don't remove
234 * the trailing slash to avoid mntfs name clashes.
236 mp
= str3cat(mp
, fs
, "/", rfs
);
240 * Determine the mount info
242 xinfo
= str3cat(xinfo
, host
, *path
== '/' ? "" : "/", path
);
243 normalize_slash(xinfo
);
247 dlog("amfs_nfsx: init mount for %s on %s", xinfo
, mp
);
249 nx
->nx_v
[i
].n_error
= -1;
250 nx
->nx_v
[i
].n_mnt
= find_mntfs(&nfs_ops
, mf
->mf_fo
, mp
, xinfo
, "", mf
->mf_mopts
, mf
->mf_remopts
);
269 * Iterate through the mntfs's and call
270 * the underlying init routine on each
274 for (i
= 0; i
< nx
->nx_c
; i
++) {
275 amfs_nfsx_mnt
*n
= &nx
->nx_v
[i
];
277 int error
= (*m
->mf_ops
->fs_init
) (m
);
279 * if you just "return error" here, you will have made a failure
280 * in any submounts to fail the whole group. There was old unused code
286 else if (error
< 0) {
288 if (!asked_for_wakeup
) {
289 asked_for_wakeup
= 1;
290 sched_task(wakeup_task
, (voidp
) mf
, (voidp
) m
);
300 amfs_nfsx_cont(int rc
, int term
, voidp closure
)
302 mntfs
*mf
= (mntfs
*) closure
;
303 struct amfs_nfsx
*nx
= (struct amfs_nfsx
*) mf
->mf_private
;
304 amfs_nfsx_mnt
*n
= nx
->nx_try
;
306 n
->n_mnt
->mf_flags
&= ~(MFF_ERROR
| MFF_MOUNTING
);
307 mf
->mf_flags
&= ~MFF_ERROR
;
310 * Wakeup anything waiting for this mount
312 wakeup((voidp
) n
->n_mnt
);
317 * Not sure what to do for an error code.
319 plog(XLOG_ERROR
, "mount for %s got signal %d", n
->n_mnt
->mf_mount
, term
);
323 * Check for exit status
325 errno
= rc
; /* XXX */
326 plog(XLOG_ERROR
, "%s: mount (amfs_nfsx_cont): %m", n
->n_mnt
->mf_mount
);
329 free_mntfs(n
->n_mnt
);
330 n
->n_mnt
= new_mntfs();
331 n
->n_mnt
->mf_error
= n
->n_error
;
332 n
->n_mnt
->mf_flags
|= MFF_ERROR
;
337 mf_mounted(n
->n_mnt
);
342 * Do the remaining bits
344 if (amfs_nfsx_fmount(mf
) >= 0) {
346 mf
->mf_flags
&= ~MFF_MOUNTING
;
353 try_amfs_nfsx_mount(voidp mv
)
355 mntfs
*mf
= (mntfs
*) mv
;
358 mf
->mf_flags
|= MFF_MOUNTING
;
359 error
= (*mf
->mf_ops
->fmount_fs
) (mf
);
360 mf
->mf_flags
&= ~MFF_MOUNTING
;
367 amfs_nfsx_remount(mntfs
*mf
, int fg
)
369 struct amfs_nfsx
*nx
= (struct amfs_nfsx
*) mf
->mf_private
;
373 for (n
= nx
->nx_v
; n
< nx
->nx_v
+ nx
->nx_c
; n
++) {
375 if (n
->n_error
< 0) {
376 if (!(m
->mf_flags
& MFF_MKMNT
) && m
->mf_ops
->fs_flags
& FS_MKMNT
) {
377 int error
= mkdirs(m
->mf_mount
, 0555);
379 m
->mf_flags
|= MFF_MKMNT
;
385 * Iterate through the mntfs's and mount each filesystem
386 * which is not yet mounted.
388 for (n
= nx
->nx_v
; n
< nx
->nx_v
+ nx
->nx_c
; n
++) {
390 if (n
->n_error
< 0) {
392 * Check fmount entry pt. exists
395 if (!m
->mf_ops
->fmount_fs
) {
399 dlog("calling underlying fmount on %s", m
->mf_mount
);
401 if (!fg
&& foreground
&& (m
->mf_ops
->fs_flags
& FS_MBACKGROUND
)) {
402 m
->mf_flags
|= MFF_MOUNTING
; /* XXX */
404 dlog("backgrounding mount of \"%s\"", m
->mf_info
);
407 run_task(try_amfs_nfsx_mount
, (voidp
) m
, amfs_nfsx_cont
, (voidp
) mf
);
412 dlog("foreground mount of \"%s\" ...", mf
->mf_info
);
414 n
->n_error
= (*m
->mf_ops
->fmount_fs
) (m
);
419 if (n
->n_error
> 0) {
420 errno
= n
->n_error
; /* XXX */
421 dlog("underlying fmount of %s failed: %m", m
->mf_mount
);
425 if (n
->n_error
== 0) {
427 } else if (glob_error
< 0) {
428 glob_error
= n
->n_error
;
433 return glob_error
< 0 ? 0 : glob_error
;
438 amfs_nfsx_fmount(mntfs
*mf
)
440 return amfs_nfsx_remount(mf
, FALSE
);
445 * Unmount an NFS hierarchy.
446 * Note that this is called in the foreground
447 * and so may hang under extremely rare conditions.
450 amfs_nfsx_fumount(mntfs
*mf
)
452 struct amfs_nfsx
*nx
= (struct amfs_nfsx
*) mf
->mf_private
;
457 * Iterate in reverse through the mntfs's and unmount each filesystem
460 for (n
= nx
->nx_v
+ nx
->nx_c
- 1; n
>= nx
->nx_v
; --n
) {
463 * If this node has not been messed with
464 * and there has been no error so far
465 * then try and unmount.
466 * If an error had occurred then zero
467 * the error code so that the remount
468 * only tries to unmount those nodes
469 * which had been successfully unmounted.
471 if (n
->n_error
== 0) {
473 dlog("calling underlying fumount on %s", m
->mf_mount
);
475 n
->n_error
= (*m
->mf_ops
->fumount_fs
) (m
);
477 glob_error
= n
->n_error
;
481 * Make sure remount gets this node
489 * If any unmounts failed then remount the
493 glob_error
= amfs_nfsx_remount(mf
, TRUE
);
495 errno
= glob_error
; /* XXX */
496 plog(XLOG_USER
, "amfs_nfsx: remount of %s failed: %m", mf
->mf_mount
);
501 * Remove all the mount points
503 for (n
= nx
->nx_v
; n
< nx
->nx_v
+ nx
->nx_c
; n
++) {
508 * XXX: all the umounted handler needs is a
509 * mntfs pointer, so pass an am_node with the right
512 memset((voidp
) &am
, 0, sizeof(am
));
515 dlog("calling underlying umounted on %s", m
->mf_mount
);
517 (*m
->mf_ops
->umounted
) (&am
);
519 if (n
->n_error
< 0) {
520 if (m
->mf_ops
->fs_flags
& FS_MKMNT
) {
521 (void) rmdirs(m
->mf_mount
);
522 m
->mf_flags
&= ~MFF_MKMNT
;