Add rpc.umntall utility, to be used by startup and shutdown scripts

to replace (broken) umntall signal code previously in mountd.

Submitted by:	Martin Blapp <mb@imp.ch>
This commit is contained in:
Matthew Dillon 1999-11-21 08:06:00 +00:00
parent b3be35ee5e
commit c69a34d486
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=53494
6 changed files with 681 additions and 0 deletions

View File

@ -73,6 +73,7 @@ SUBDIR= IPXrouted \
rmt \
rpc.lockd \
rpc.statd \
rpc.umntall \
rpc.yppasswdd \
rpc.ypupdated \
rpc.ypxfrd \

View File

@ -0,0 +1,8 @@
# @(#)Makefile 8.4 (Berkeley) 6/22/95
# $FreeBSD$
PROG= rpc.umntall
SRCS= rpc.umntall.c mounttab.c
MAN8= rpc.umntall.8
.include <bsd.prog.mk>

View File

@ -0,0 +1,221 @@
/*
* Copyright (c) 1999 Martin Blapp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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
* SUCH DAMAGE.
*
*/
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/syslog.h>
#include <rpc/rpc.h>
#include <nfs/rpcv2.h>
#include <err.h>
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mounttab.h"
int verbose;
struct mtablist *mtabhead;
/*
* Add an entry to PATH_MOUNTTAB for each mounted NFS filesystem,
* so the client can notify the NFS server even after reboot.
*/
int
add_mtab(char *hostp, char *dirp) {
FILE *mtabfile;
time_t *now;
now = NULL;
if ((mtabfile = fopen(PATH_MOUNTTAB, "a")) == NULL)
return (0);
else {
fprintf(mtabfile, "%ld\t%s\t%s\n", time(now), hostp, dirp);
fclose(mtabfile);
return (1);
}
}
/*
* Read mounttab line for line and return struct mtablist.
*/
int
read_mtab(struct mtablist *mtabp) {
struct mtablist **mtabpp;
char *hostp, *dirp, *cp;
char str[STRSIZ];
char *timep;
time_t time;
FILE *mtabfile;
if ((mtabfile = fopen(PATH_MOUNTTAB, "r")) == NULL) {
if (errno == ENOENT)
return (0);
else {
syslog(LOG_ERR, "can't open %s", PATH_MOUNTTAB);
return (0);
}
}
time = 0;
mtabpp = &mtabhead;
while (fgets(str, STRSIZ, mtabfile) != NULL) {
cp = str;
errno = 0;
if (*cp == '#' || *cp == ' ' || *cp == '\n')
continue;
timep = strsep(&cp, " \t\n");
if (timep == NULL || *timep == ' ' || *timep == '\n') {
badline(timep);
continue;
}
hostp = strsep(&cp, " \t\n");
if (hostp == NULL || *hostp == ' ' || *hostp == '\n') {
badline(hostp);
continue;
}
dirp = strsep(&cp, " \t\n");
if (dirp == NULL || *dirp == ' ' || *dirp == '\n') {
badline(dirp);
continue;
}
time = strtoul(timep, (char **)NULL, 10);
if (errno == ERANGE) {
badline(timep);
continue;
}
if ((mtabp = malloc(sizeof (struct mtablist))) == NULL) {
syslog(LOG_ERR, "malloc");
fclose(mtabfile);
return (0);
}
mtabp->mtab_time = time;
memmove(mtabp->mtab_host, hostp, RPCMNT_NAMELEN);
mtabp->mtab_host[RPCMNT_NAMELEN - 1] = '\0';
memmove(mtabp->mtab_dirp, dirp, RPCMNT_PATHLEN);
mtabp->mtab_dirp[RPCMNT_PATHLEN - 1] = '\0';
mtabp->mtab_next = (struct mtablist *)NULL;
*mtabpp = mtabp;
mtabpp = &mtabp->mtab_next;
}
fclose(mtabfile);
return (1);
}
/*
* Rewrite PATH_MOUNTTAB from scratch and skip bad entries.
* Unlink PATH_MOUNTAB if no entry is left.
*/
int
write_mtab() {
struct mtablist *mtabp;
FILE *mtabfile;
int line;
if ((mtabfile = fopen(PATH_MOUNTTAB, "w")) == NULL) {
syslog(LOG_ERR, "can't write to %s", PATH_MOUNTTAB);
return (0);
}
line = 0;
for (mtabp = mtabhead; mtabp != NULL; mtabp = mtabp->mtab_next) {
if (mtabp->mtab_host != NULL &&
strlen(mtabp->mtab_host) > 0) {
fprintf(mtabfile, "%ld\t%s\t%s\n", mtabp->mtab_time,
mtabp->mtab_host, mtabp->mtab_dirp);
line++;
}
}
fclose(mtabfile);
if (line == 0) {
if (unlink(PATH_MOUNTTAB) == -1) {
syslog(LOG_ERR, "can't remove %s", PATH_MOUNTTAB);
return (0);
}
}
return (1);
}
/*
* Mark the entries as clean where RPC calls have been done successfully.
*/
void
clean_mtab(char *hostp, char *dirp) {
struct mtablist *mtabp;
char *host;
host = strdup(hostp);
for (mtabp = mtabhead; mtabp != NULL; mtabp = mtabp->mtab_next) {
if (mtabp->mtab_host != NULL &&
strcmp(mtabp->mtab_host, host) == 0) {
if (dirp == NULL) {
if (verbose) {
warnx("entries deleted for "
"host %s", host);
}
bzero(mtabp->mtab_host, RPCMNT_NAMELEN);
} else {
if (strcmp(mtabp->mtab_dirp, dirp) == 0) {
if (verbose) {
warnx("entry deleted for "
"%s:%s", host, dirp);
}
bzero(mtabp->mtab_host, RPCMNT_NAMELEN);
}
}
}
}
free(host);
}
/*
* Free struct mtablist mtab.
*/
void
free_mtab() {
struct mtablist *mtabp;
struct mtablist *mtab_next;
for (mtabp = mtabhead; mtabp != NULL; mtabp = mtab_next) {
mtab_next = mtabp->mtab_next;
free(mtabp);
mtabp = mtab_next;
}
}
/*
* Print bad lines to syslog.
*/
void
badline(char *bad) {
syslog(LOG_ERR, "skipped bad line in mounttab with entry %s", bad);
}

View File

@ -0,0 +1,45 @@
/*
* Copyright (c) 1999 Martin Blapp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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
* SUCH DAMAGE.
*
* $FreeBSD$
*/
#define STRSIZ (RPCMNT_NAMELEN+RPCMNT_PATHLEN+100)
#define PATH_MOUNTTAB "/var/db/mounttab"
/* Structure for /var/db/mounttab */
struct mtablist {
time_t mtab_time;
char mtab_host[RPCMNT_NAMELEN];
char mtab_dirp[RPCMNT_PATHLEN];
struct mtablist *mtab_next;
};
int add_mtab(char *, char *);
void badline (char *);
void clean_mtab (char *, char *);
int read_mtab (struct mtablist *);
int write_mtab (void);
void free_mtab (void);

View File

@ -0,0 +1,111 @@
.\"
.\" Copyright (c) 1999 Martin Blapp
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 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.
.\"
.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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
.\" SUCH DAMAGE.
.\"
.\" $FreeBSD$
.\"
.Dd November 17, 1999
.Dt RPC.UMNTALL 8
.Os
.Sh NAME
.Nm rpc.umntall
.Nd Notify NFS servers about unmounted NFS filesystems
.Sh SYNOPSIS
.Nm rpc.umntall
.Op Fl e Ar expire
.Op Fl h Ar host
.Op Fl k
.Op Fl p Ar remotepath
.Op Fl v
.Sh DESCRIPTION
.Nm
is as command as proposed in the
.Tn NFS
RPC specification; see
.%T "NFS Version 3 Protocol Specification",
RFC 1813, Appendix I. It uses remote procedure calls
to remove mount entries from
.Pa /var/db/mountdtab
on the remote NFS server. It is called automatically
without any parameters during startup and shutdown of
the system. This ensures that
.Xr showmount 8
does not display old and expired entries. The
.Nm
command
is only needed on client side, where
.Xr mount_nfs 8
adds a mount entry with the current date to
.Pa /var/db/mounttab,
and
.Xr umount 8
removes the entry again. The
.Nm
command
cares about all remaining entries in this table which result from crashes
or unproper shutdowns.
.Pp
The options are as follows:
.Bl -tag -width indent
.It Fl e Ar expire
All entries which are not actually mounted or older than
.Ar expire
(seconds) are removed from /var/db/mounttab. This may be the case
for DNS changes or long out of service periods. Default expire time
is 172800 seconds (2 days).
.It Fl h Ar host
Only remove the specific hostname. Send a UMNTALL RPC to the NFS server.
.It Fl k
Keep entries for existing NFS filesystems. Compare the NFS filesystems from
the mounttab against the kernel mountlist and do not send the RPC to
existing mount entries. Useful during startup of the system. It may be
possible that there are already mounted NFS filesystems, so calling
RPC UMNTALL isn't a good idea. This is the case if the user has rebooted
to 'single user mode' and starts up the system again.
.It Fl p Ar path
Only remove the specific mount-path. Send a UMOUNT RPC to the NFS server.
This option implies the
.Fl host
option.
.It Fl v
Verbose, additional information is printed for each processed mounttab
entry.
.El
.Sh FILES
.Bl -tag -width /var/db/mounttab -compact
.It Pa /var/db/mounttab
mounted nfs-filesystems
.El
.Sh HISTORY
The
.Nm
command first appeared in
.Fx 4.0 .
.El
.Sh SEE ALSO
.Xr mountd 8 ,
.Xr umount 8 ,
.Xr mount_nfs 8
.Sh AUTHORS
.An Martin Blapp Aq mb@imp.ch

View File

@ -0,0 +1,295 @@
/*
* Copyright (c) 1999 Martin Blapp
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 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.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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
* SUCH DAMAGE.
*
*/
#ifndef lint
static const char rcsid[] =
"$FreeBSD$";
#endif /* not lint */
#include <sys/param.h>
#include <sys/ucred.h>
#include <sys/mount.h>
#include <rpc/rpc.h>
#include <nfs/rpcv2.h>
#include <err.h>
#include <netdb.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "mounttab.h"
int verbose;
static int do_umount (char *, char *);
static int do_umntall (char *);
static int is_mounted (char *, char *);
static void usage (void);
int xdr_dir (XDR *, char *);
struct mtablist *mtabhead;
int
main(int argc, char **argv) {
int ch, keep, success, pathlen;
time_t expire, *now;
char *host, *path;
struct mtablist *mtab;
mtab = NULL;
now = NULL;
expire = 0;
host = path = '\0';
success = keep = verbose = 0;
while ((ch = getopt(argc, argv, "h:kp:ve:")) != -1)
switch (ch) {
case 'h':
host = optarg;
break;
case 'e':
expire = (time_t)optarg;
break;
case 'k':
keep = 1;
break;
case 'p':
path = optarg;
break;
case 'v':
verbose = 1;
break;
case '?':
usage();
default:
}
argc -= optind;
argv += optind;
/* Ignore SIGINT and SIGQUIT during shutdown */
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
/* Default expiretime is two days */
if (expire == 0)
expire = 172800;
/*
* Read PATH_MOUNTTAB and check each entry
* and do finally the unmounts.
*/
if (host == NULL && path == NULL) {
if (!read_mtab(mtab)) {
if (verbose)
warnx("nothing to do, remove %s",
PATH_MOUNTTAB);
}
for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) {
if (*mtab->mtab_host != '\0' &&
(do_umntall(mtab->mtab_host) ||
mtab->mtab_time <= (time(now) - expire))) {
if (keep && is_mounted(mtab->mtab_host,
mtab->mtab_dirp)) {
if (verbose) {
warnx("skipping entry %s:%s",
mtab->mtab_host,
mtab->mtab_dirp);
}
} else
clean_mtab(mtab->mtab_host, NULL);
}
}
/* Only do a RPC UMNTALL for this specific host */
} else if (host != NULL && path == NULL) {
if (!do_umntall(host))
exit(1);
else
success = 1;
/* Someone forgot to enter a hostname */
} else if (host == NULL && path != NULL)
usage();
/* Only do a RPC UMOUNT for this specific mount */
else {
for (pathlen = strlen(path);
pathlen > 1 && path[pathlen - 1] == '/'; pathlen--)
path[pathlen - 1] = '\0';
if (!do_umount(host, path))
exit(1);
else
success = 1;
}
/* Write and unlink PATH_MOUNTTAB if necessary */
if (success) {
if (verbose)
warnx("UMOUNT RPC successfully sent to %s", host);
if (read_mtab(mtab)) {
mtab = mtabhead;
clean_mtab(host, path);
}
}
if (!write_mtab()) {
free_mtab();
exit(1);
}
free_mtab();
exit(0);
}
/*
* Send a RPC_MNT UMNTALL request to hostname.
*/
int
do_umntall(char *hostname) {
enum clnt_stat clnt_stat;
struct hostent *hp;
struct sockaddr_in saddr;
struct timeval pertry, try;
int so;
CLIENT *clp;
if ((hp = gethostbyname(hostname)) == NULL) {
warnx("gethostbyname(%s) failed", hostname);
return (0);
}
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = 0;
memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length,
sizeof(saddr.sin_addr)));
pertry.tv_sec = 3;
pertry.tv_usec = 0;
so = RPC_ANYSOCK;
if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
pertry, &so)) == NULL) {
clnt_pcreateerror("Cannot send MNT PRC");
return (0);
}
clp->cl_auth = authunix_create_default();
try.tv_sec = 3;
try.tv_usec = 0;
clnt_stat = clnt_call(clp, RPCMNT_UMNTALL, xdr_void, (caddr_t)0,
xdr_void, (caddr_t)0, try);
if (clnt_stat != RPC_SUCCESS) {
clnt_perror(clp, "Bad MNT RPC");
return (0);
} else
return (1);
}
/*
* Send a RPC_MNT UMOUNT request for dirp to hostname.
*/
int
do_umount(char *hostname, char *dirp) {
enum clnt_stat clnt_stat;
struct hostent *hp;
struct sockaddr_in saddr;
struct timeval pertry, try;
CLIENT *clp;
int so;
if ((hp = gethostbyname(hostname)) == NULL) {
warnx("gethostbyname(%s) failed", hostname);
return (0);
}
memset(&saddr, 0, sizeof(saddr));
saddr.sin_family = AF_INET;
saddr.sin_port = 0;
memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length,
sizeof(saddr.sin_addr)));
pertry.tv_sec = 3;
pertry.tv_usec = 0;
so = RPC_ANYSOCK;
if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
pertry, &so)) == NULL) {
clnt_pcreateerror("Cannot send MNT PRC");
return (0);
}
clp->cl_auth = authunix_create_default();
try.tv_sec = 3;
try.tv_usec = 0;
clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp,
xdr_void, (caddr_t)0, try);
if (clnt_stat != RPC_SUCCESS) {
clnt_perror(clp, "Bad MNT RPC");
return (0);
}
return (1);
}
/*
* Check if the entry is still/already mounted.
*/
int
is_mounted(char *hostname, char *dirp) {
struct statfs *mntbuf;
char name[MNAMELEN + 1];
size_t bufsize, hostlen, dirlen;
int mntsize, i;
hostlen = strlen(hostname);
dirlen = strlen(dirp);
if ((hostlen + dirlen) >= MNAMELEN)
return (0);
memmove(name, hostname, hostlen);
name[hostlen] = ':';
memmove(name + hostlen + 1, dirp, dirlen);
name[hostlen + dirlen + 1] = '\0';
mntsize = getfsstat(NULL, 0, MNT_NOWAIT);
if (mntsize <= 0)
return (0);
bufsize = (mntsize + 1) * sizeof(struct statfs);
if ((mntbuf = malloc(bufsize)) == NULL)
err(1, "malloc");
mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT);
for (i = mntsize - 1; i >= 0; i--) {
if (strcmp(mntbuf[i].f_mntfromname, name) == 0) {
free(mntbuf);
return (1);
}
}
free(mntbuf);
return (0);
}
/*
* xdr routines for mount rpc's
*/
int
xdr_dir(XDR *xdrsp, char *dirp) {
return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
}
static void
usage() {
(void)fprintf(stderr, "%s\n",
"usage: rpc.umntall [-h host] [-k] [-p path] [-t expire] [-v]");
exit(1);
}