* Copyright (c) 1990 Jan-Simon Pendry
* Copyright (c) 1990 Imperial College of Science, Technology & Medicine
* Copyright (c) 1990 The Regents of the University of California.
* This code is derived from software contributed to Berkeley by
* Jan-Simon Pendry at Imperial College, London.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* @(#)host_ops.c 5.3 (Berkeley) 5/12/91
* $Id: host_ops.c,v 5.2.1.6 91/05/07 22:17:53 jsp Alpha $
* Mounts all exported filesystems from a given host.
* This has now degenerated into a mess but will not
* be rewritten. Amd 6 will support the abstractions
* needed to make this work correctly.
* Define HOST_RPC_UDP to use dgram instead of stream RPC.
* Datagrams are generally much faster.
* Define HOST_MKDIRS to make Amd automatically try
* to create the mount points.
* Determine the mount point
#define MAKE_MNTPT(mntpt, ex, mf) { \
if (strcmp((ex)->ex_dir, "/") == 0) \
strcpy((mntpt), (mf)->mf_mount); \
sprintf((mntpt), "%s%s", (mf)->mf_mount, (ex)->ex_dir); \
* Execute needs the same as NFS plus a helper command
static char *host_match
P((am_opts
*fo
));
static char *host_match(fo
)
plog(XLOG_USER
, "No host helper command given");
* Make sure rfs is specified to keep nfs_match happy...
return (*nfs_ops
.fs_match
)(fo
);
if (strchr(mf
->mf_info
, ':') == 0)
* HOST_EXEC gets you the external version. The program specified with
* the -h option is called. The external program is not published...
* Otherwise you get the native version. Faster but makes the program
xdr_pri_free(xdr_args
, args_ptr
)
return ((*xdr_args
)(&xdr
, args_ptr
));
static int do_mount
P((fhstatus
*fhp
, char *dir
, char *fs_name
, char *opts
, mntfs
*mf
));
static int do_mount(fhp
, dir
, fs_name
, opts
, mf
)
dlog("host: mounting fs %s on %s\n", fs_name
, dir
);
(void) mkdirs(dir
, 0555);
if (stat(dir
, &stb
) < 0 || (stb
.st_mode
& S_IFMT
) != S_IFDIR
) {
plog(XLOG_ERROR
, "No mount point for %s - skipping", dir
);
return mount_nfs_fh(fhp
, dir
, fs_name
, opts
, mf
);
static int sortfun
P((exports
*a
, exports
*b
));
return strcmp((*a
)->ex_dir
, (*b
)->ex_dir
);
static int fetch_fhandle
P((CLIENT
*client
, char *dir
, fhstatus
*fhp
));
static int fetch_fhandle(client
, dir
, fhp
)
enum clnt_stat clnt_stat
;
* Pick a number, any number...
dlog("Fetching fhandle for %s", dir
);
* Call the mount daemon on the remote host to
clnt_stat
= clnt_call(client
, MOUNTPROC_MNT
, xdr_dirpath
, &dir
, xdr_fhstatus
, fhp
, tv
);
if (clnt_stat
!= RPC_SUCCESS
) {
extern char *clnt_sperrno();
char *msg
= clnt_sperrno(clnt_stat
);
plog(XLOG_ERROR
, "mountd rpc failed: %s", msg
);
* Check status of filehandle
dlog("fhandle fetch failed: %m");
* Scan mount table to see if something already mounted
static int already_mounted
P((mntlist
*mlist
, char*dir
));
static int already_mounted(mlist
, dir
)
for (ml
= mlist
; ml
; ml
= ml
->mnext
)
if (strcmp(ml
->mnt
->mnt_dir
, dir
) == 0)
* Mount the export tree from a host
static int host_fmount
P((mntfs
*mf
));
static int host_fmount(mf
)
enum clnt_stat clnt_stat
;
char *host
= mf
->mf_server
->fs_host
;
char fs_name
[MAXPATHLEN
], *rfs_dir
;
tv
.tv_sec
= 10; tv
.tv_usec
= 0;
#endif /* HOST_RPC_UDP */
mlist
= read_mtab(mf
->mf_mount
);
* Take a copy of the server address
sin
= *mf
->mf_server
->fs_ip
;
* Zero out the port - make sure we recompute
* Make a client end-point
if ((client
= clntudp_create(&sin
, MOUNTPROG
, MOUNTVERS
, tv
, &sock
)) == NULL
)
if ((client
= clnttcp_create(&sin
, MOUNTPROG
, MOUNTVERS
, &sock
, 0, 0)) == NULL
)
#endif /* HOST_RPC_UDP */
plog(XLOG_ERROR
, "Failed to make rpc connection to mountd on %s", host
);
client
->cl_auth
= nfs_auth
;
dlog("Fetching export list from %s", host
);
tv2
.tv_sec
= 10; tv2
.tv_usec
= 0;
clnt_stat
= clnt_call(client
, MOUNTPROC_EXPORT
, xdr_void
, 0, xdr_exports
, &exlist
, tv2
);
if (clnt_stat
!= RPC_SUCCESS
) {
/*clnt_perror(client, "rpc");*/
* Figure out how many exports were returned
for (n_export
= 0, ex
= exlist
; ex
; ex
= ex
->ex_next
) {
/*printf("export %s\n", ex->ex_dir);*/
/*dlog("%d exports returned\n", n_export);*/
* Allocate an array of pointers into the list
* so that they can be sorted. If the filesystem
* is already mounted then ignore it.
ep
= (exports
*) xmalloc(n_export
* sizeof(exports
));
for (j
= 0, ex
= exlist
; ex
; ex
= ex
->ex_next
) {
MAKE_MNTPT(mntpt
, ex
, mf
);
if (!already_mounted(mlist
, mntpt
))
* This way the mounts are done in order down the tree,
* instead of any random order returned by the mount
* daemon (the protocol doesn't specify...).
qsort(ep
, n_export
, sizeof(exports
), sortfun
);
* Allocate an array of filehandles
fp
= (fhstatus
*) xmalloc(n_export
* sizeof(fhstatus
));
* Try to obtain filehandles for each directory.
* If a fetch fails then just zero out the array
* reference but discard the error.
for (j
= k
= 0; j
< n_export
; j
++) {
/* Check and avoid a duplicated export entry */
if (j
> k
&& ep
[k
] && strcmp(ep
[j
]->ex_dir
, ep
[k
]->ex_dir
) == 0) {
dlog("avoiding dup fhandle requested for %s", ep
[j
]->ex_dir
);
if (error
= fetch_fhandle(client
, ep
[j
]->ex_dir
, &fp
[j
]))
* Mount each filesystem for which we have a filehandle.
* If any of the mounts succeed then mark "ok" and return
* error code 0 at the end. If they all fail then return
strncpy(fs_name
, mf
->mf_info
, sizeof(fs_name
));
if ((rfs_dir
= strchr(fs_name
, ':')) == (char *) 0) {
plog(XLOG_FATAL
, "host_fmount: mf_info has no colon");
for (j
= 0; j
< n_export
; j
++) {
strcpy(rfs_dir
, ex
->ex_dir
);
MAKE_MNTPT(mntpt
, ex
, mf
);
if (do_mount(&fp
[j
], mntpt
, fs_name
, mf
->mf_mopts
, mf
) == 0)
xdr_pri_free(xdr_exports
, &exlist
);
* Return true if pref is a directory prefix of dir.
* Does not work if pref is "/".
static int directory_prefix
P((char *pref
, char *dir
));
static int directory_prefix(pref
, dir
)
if (strncmp(pref
, dir
, len
) != 0)
if (dir
[len
] == '/' || dir
[len
] == '\0')
static int host_fumount
P((mntfs
*mf
));
static int host_fumount(mf
)
mntlist
*mlist
= read_mtab(mf
->mf_mount
);
mntlist
*ml2
= ml
->mnext
;
* Unmount all filesystems...
for (ml
= mlist
; ml
&& !xerror
; ml
= ml
->mnext
) {
char *dir
= ml
->mnt
->mnt_dir
;
if (directory_prefix(mf
->mf_mount
, dir
)) {
dlog("host: unmounts %s", dir
);
plog("Tree unmount of %s failed: %m", ml
->mnt
->mnt_dir
);
* Try to remount, except when we are shutting down.
if (xerror
&& amd_state
!= Finishing
) {
xerror
= host_fmount(mf
);
* Don't log this - it's usually too verbose
plog(XLOG_INFO, "Remounted host %s", mf->mf_info);
static int host_exec
P((char*op
, char*host
, char*fs
, char*opts
));
static int host_exec(op
, host
, fs
, opts
)
argv
[5] = opts
&& *opts
? opts
: "rw,default";
(void) dup(fileno(logfp
));
if (fileno(logfp
) != fileno(stderr
)) {
(void) dup(fileno(logfp
));
plog(XLOG_DEBUG
, "executing (un)mount command...");
plog(XLOG_DEBUG
, "arg[%d] = '%s'", cp
-argv
, *cp
);
if (argv
[0] == 0 || argv
[1] == 0) {
plog(XLOG_USER
, "1st/2nd args missing to (un)mount program");
(void) execv(argv
[0], argv
+1);
plog(XLOG_ERROR
, "exec %s failed: %m", argv
[0]);
static int host_mount
P((am_node
*mp
));
static int host_mount(mp
)
return host_exec("mount", mf
->mf_server
->fs_host
, mf
->mf_mount
, mf
->mf_opts
);
static int host_umount
P((am_node
*mp
));
static int host_umount(mp
)
return host_exec("unmount", mf
->mf_server
->fs_host
, mf
->mf_mount
, "xxx");
FS_MKMNT
|FS_BACKGROUND
|FS_AMQINFO