diff options
author | obrien <obrien@FreeBSD.org> | 1998-08-23 22:07:21 +0000 |
---|---|---|
committer | obrien <obrien@FreeBSD.org> | 1998-08-23 22:07:21 +0000 |
commit | 663d5a0f32ed8dfc091ffb6153161591ac6ba563 (patch) | |
tree | 60b090a6cbdb64326bb128ea49a231d08eb2680e /contrib/amd/fixmount | |
download | FreeBSD-src-663d5a0f32ed8dfc091ffb6153161591ac6ba563.zip FreeBSD-src-663d5a0f32ed8dfc091ffb6153161591ac6ba563.tar.gz |
Virgin import of AMD (am-utils) v6.0a16
Diffstat (limited to 'contrib/amd/fixmount')
-rw-r--r-- | contrib/amd/fixmount/fixmount.8 | 159 | ||||
-rw-r--r-- | contrib/amd/fixmount/fixmount.c | 612 |
2 files changed, 771 insertions, 0 deletions
diff --git a/contrib/amd/fixmount/fixmount.8 b/contrib/amd/fixmount/fixmount.8 new file mode 100644 index 0000000..f9a87f0 --- /dev/null +++ b/contrib/amd/fixmount/fixmount.8 @@ -0,0 +1,159 @@ +.\" +.\" Copyright (c) 1997-1998 Erez Zadok +.\" 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. +.\" All rights reserved. +.\" +.\" 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 +.\" 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. +.\" 3. All advertising materials mentioning features or use of this software +.\" must display the following acknowledgment: +.\" 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 +.\" SUCH DAMAGE. +.\" +.\" %W% (Berkeley) %G% +.\" +.\" $Id: fixmount.8,v 5.2.2.1 1992/02/09 15:11:15 jsp beta $ +.\" +.TH FIXMOUNT 8L "26 Feb 1993" +.SH NAME +fixmount \- fix remote mount entries +.SH SYNOPSIS +.B fixmount +[ +.B \-adervq +] +[ +.B \-h +.I name +] +.I host +\&... +.SH DESCRIPTION +.IX "fixmount command" "" "\fLfixmount\fP \(em fix remote mount entries" +.LP +.B fixmount +is a variant of +.BR showmount (8) +that can delete bogus mount entries in remote +.BR mountd (8C) +daemons. +The actions specified by the options are performed for each +.I host +in turn. +.SH OPTIONS +.TP +.B \-a \-d \-e +These options work as in +.BR showmount (8) +except that only entries pertaining to the local host are printed. +.TP +.B \-r +Removes those remote mount entries on +.I host +that do not correspond to current mounts, i.e., which are left-over +from a crash or are the result of improper mount protocol. +The actuality of mounts is verified using the entries in +.BR /etc/mtab . +.TP +.B \-v +Verify remote mounts. Similar to +.B \-r +except that only a notification message is printed for each bogus entry +found. The remote mount table is not changed. +.TP +.B \-A +Issues a command to the remote mountd declaring that ALL of its filesystems +have been unmounted. This should be used with caution, as it removes all +remote mount entries pertaining to the local system, whether or not any +filesystems are still mounted locally. +.TP +.B \-q +Be quiet. +Suppresses error messages due to timeouts and "Program not registered", +i.e., due to remote hosts not supporting RPC or not running mountd. +.TP +.BI \-h \ name +Pretend the local hostname is +.IR name . +This is useful after the local hostname has been changed and rmtab entries +using the old name remain on a remote machine. +Unfortunately, most mountd's won't be able to successfully handle removal +of such entries, so this option is useful in combination with +.B \-v +only. +.br +This option also saves time as comparisons of remotely recorded and local +hostnames by address are avoided. +.SH FILES +.PD 0 +.TP 20 +.B /etc/mtab +List of current mounts. +.TP +.B /etc/rmtab +Backup file for remote mount entries on NFS server. +.PD +.SH "SEE ALSO" +.BR showmount (8), +.BR mtab (5), +.BR rmtab (5), +.BR mountd (8C). +.SH BUGS +No attempt is made to verify the information in +.B /etc/mtab +itself. +.PP +Since swap file mounts are not recorded in +.BR /etc/mtab , +a heuristic specific to SunOS is used to determine whether such a mount +is actual (replacing the string "swap" with "root" and verifying the resulting +path). +.PP +Symbolic links on the server will cause the path in the remote entry to differ +from the one in +.BR /etc/mtab . +To catch those cases, a filesystem is also deemed mounted if its +.I local +mount point is identical to the remote entry. +I.e., on a SunOS diskless client, +.B server:/export/share/sunos.4.1.1 +is actually +.BR /usr/share . +Since the local mount point is +.B /usr/share +as well this will be handled correctly. +.PP +There is no way to clear a stale entry in a remote mountd after the +local hostname (or whatever reverse name resolution returns for it) +has been changed. To take care of these cases, +the remote /etc/rmtab file has to be edited and mountd restarted. +.PP +The RPC timeouts for mountd calls can only be changed by recompiling. +The defaults are 2 seconds for client handle creation and 5 seconds for +RPC calls. diff --git a/contrib/amd/fixmount/fixmount.c b/contrib/amd/fixmount/fixmount.c new file mode 100644 index 0000000..9769a41 --- /dev/null +++ b/contrib/amd/fixmount/fixmount.c @@ -0,0 +1,612 @@ +/* + * Copyright (c) 1997-1998 Erez Zadok + * 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. + * All rights reserved. + * + * 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 + * 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. + * 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 + * SUCH DAMAGE. + * + * %W% (Berkeley) %G% + * + * $Id: fixmount.c,v 5.2.2.2 1992/05/31 16:35:45 jsp Exp $ + * + */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif /* HAVE_CONFIG_H */ +#include <am_defs.h> + +#define CREATE_TIMEOUT 2 /* seconds */ +#define CALL_TIMEOUT 5 /* seconds */ + +#ifndef INADDR_NONE +# define INADDR_NONE 0xffffffff +#endif /* not INADDR_NONE */ + +/* Constant defs */ +#define ALL 1 +#define DIRS 2 + +#define DODUMP 0x1 +#define DOEXPORTS 0x2 +#define DOREMOVE 0x4 +#define DOVERIFY 0x8 +#define DOREMALL 0x10 + +extern int fixmount_check_mount(char *host, struct in_addr hostaddr, char *path); + +static char dir_path[NFS_MAXPATHLEN]; +static char localhost[] = "localhost"; +static char thishost[MAXHOSTNAMELEN] = ""; +static exports mntexports; +static int quiet = 0; +static int type = 0; +static jmp_buf before_rpc; +static mountlist mntdump; +static struct in_addr thisaddr; +static CLIENT *clnt_create_timeout(char *, struct timeval *); + +RETSIGTYPE create_timeout(int); +int is_same_host(char *, char *, struct in_addr); +int main(int, char *[]); +int remove_all(CLIENT *, char *); +int remove_mount(CLIENT *, char *, mountlist, int); +void fix_rmtab(CLIENT *, char *, mountlist, int, int); +void print_dump(mountlist); +void usage(void); + +/* dummy variables */ +char *progname; +char hostname[MAXHOSTNAMELEN]; +int orig_umask, foreground, debug_flags; +pid_t mypid; +serv_state amd_state; + +void +usage(void) +{ + fprintf(stderr, "usage: fixmount [-adervAqf] [-h hostname] host ...\n"); + exit(1); +} + + +/* + * Check hostname against other name and its IP address + */ +int +is_same_host(char *name1, char *name2, struct in_addr addr2) +{ + if (strcasecmp(name1, name2) == 0) { + return 1; + } else if (addr2.s_addr == INADDR_NONE) { + return 0; + } else { + static char lasthost[MAXHOSTNAMELEN] = ""; + static struct in_addr addr1; + struct hostent *he; + + /* + * To save nameserver lookups, and because this function + * is typically called repeatedly on the same names, + * cache the last lookup result and reuse it if possible. + */ + if (strcasecmp(name1, lasthost) == 0) { + return (addr1.s_addr == addr2.s_addr); + } else if (!(he = gethostbyname(name1))) { + return 0; + } else { + strncpy(lasthost, name1, sizeof(lasthost) - 1); + memcpy(&addr1, he->h_addr, sizeof(addr1)); + return (addr1.s_addr == addr2.s_addr); + } + } +} + + +/* + * Print the binary tree in inorder so that output is sorted. + */ +void +print_dump(mountlist mp) +{ + if (mp == NULL) + return; + if (is_same_host(mp->ml_hostname, thishost, thisaddr)) { + switch (type) { + case ALL: + printf("%s:%s\n", mp->ml_hostname, mp->ml_directory); + break; + case DIRS: + printf("%s\n", mp->ml_directory); + break; + default: + printf("%s\n", mp->ml_hostname); + break; + }; + } + if (mp->ml_next) + print_dump(mp->ml_next); +} + + +/* + * remove entry from remote rmtab + */ +int +remove_mount(CLIENT *client, char *host, mountlist ml, int fixit) +{ + enum clnt_stat estat; + struct timeval tv; + char *pathp = dir_path; + + strncpy(dir_path, ml->ml_directory, sizeof(dir_path)); + + if (!fixit) { + printf("%s: bogus mount %s:%s\n", host, ml->ml_hostname, ml->ml_directory); + fflush(stdout); + } else { + printf("%s: removing %s:%s\n", host, ml->ml_hostname, ml->ml_directory); + fflush(stdout); + + tv.tv_sec = CALL_TIMEOUT; + tv.tv_usec = 0; + + if ((estat = clnt_call(client, + MOUNTPROC_UMNT, + (XDRPROC_T_TYPE) xdr_dirpath, + (char *) &pathp, + (XDRPROC_T_TYPE) xdr_void, + (char *) 0, + tv)) != RPC_SUCCESS) { + fprintf(stderr, "%s:%s MOUNTPROC_UMNT: ", + host, ml->ml_directory); + clnt_perrno(estat); + fflush(stderr); + return -1; + } + } + return 0; +} + + +/* + * fix mount list on remote host + */ +void +fix_rmtab(CLIENT *client, char *host, mountlist mp, int fixit, int force) +{ + mountlist p; + struct hostent *he; + struct in_addr hostaddr; + + /* + * Obtain remote address for comparisons + */ + if ((he = gethostbyname(host))) { + memcpy(&hostaddr, he->h_addr, sizeof(hostaddr)); + } else { + hostaddr.s_addr = INADDR_NONE; + } + + for (p = mp; p; p = p->ml_next) { + if (is_same_host(p->ml_hostname, thishost, thisaddr)) { + if (force || !fixmount_check_mount(host, hostaddr, p->ml_directory)) + remove_mount(client, host, p, fixit); + } + } +} + + +/* + * remove all entries from remote rmtab + */ +int +remove_all(CLIENT *client, char *host) +{ + enum clnt_stat estat; + struct timeval tv; + + printf("%s: removing ALL\n", host); + fflush(stdout); + + tv.tv_sec = CALL_TIMEOUT; + tv.tv_usec = 0; + + if ((estat = clnt_call(client, + MOUNTPROC_UMNTALL, + (XDRPROC_T_TYPE) xdr_void, + (char *) 0, + (XDRPROC_T_TYPE) xdr_void, + (char *) 0, + tv)) != RPC_SUCCESS) { + /* + * RPC_SYSTEMERROR is returned even if all went well + */ + if (estat != RPC_SYSTEMERROR) { + fprintf(stderr, "%s MOUNTPROC_UMNTALL: ", host); + clnt_perrno(estat); + fflush(stderr); + return -1; + } + } + + return 0; +} + + +/* + * This command queries the NFS mount daemon for it's mount list and/or + * it's exports list and prints them out. + * See "NFS: Network File System Protocol Specification, RFC1094, Appendix A" + * for detailed information on the protocol. + */ +int +main(int argc, char *argv[]) +{ + AUTH *auth; + CLIENT *client; + char *host; + enum clnt_stat estat; + exports exp; + extern char *optarg; + extern int optind; + groups grp; + int ch; + int force = 0; + int morethanone; + register int rpcs = 0; + struct timeval tv; + + while ((ch = getopt(argc, argv, "adervAqfh:")) != EOF) + switch ((char) ch) { + + case 'a': + if (type == 0) { + type = ALL; + rpcs |= DODUMP; + } else + usage(); + break; + + case 'd': + if (type == 0) { + type = DIRS; + rpcs |= DODUMP; + } else + usage(); + break; + + case 'e': + rpcs |= DOEXPORTS; + break; + + case 'r': + rpcs |= DOREMOVE; + break; + + case 'A': + rpcs |= DOREMALL; + break; + + case 'v': + rpcs |= DOVERIFY; + break; + + case 'q': + quiet = 1; + break; + + case 'f': + force = 1; + break; + + case 'h': + strncpy(thishost, optarg, sizeof(thishost)); + thishost[sizeof(thishost) - 1] = '\0'; + break; + + case '?': + default: + usage(); + } + + if (optind == argc) + usage(); + + if (rpcs == 0) + rpcs = DODUMP; + + if (!*thishost) { + struct hostent *he; + + if (gethostname(thishost, sizeof(thishost)) < 0) { + perror("gethostname"); + exit(1); + } + + /* + * We need the hostname as it appears to the other side's + * mountd, so get our own hostname by reverse address + * resolution. + */ + if (!(he = gethostbyname(thishost))) { + fprintf(stderr, "gethostbyname failed on %s\n", + thishost); + exit(1); + } + memcpy(&thisaddr, he->h_addr, sizeof(thisaddr)); + if (!(he = gethostbyaddr((char *) &thisaddr, sizeof(thisaddr), + he->h_addrtype))) { + fprintf(stderr, "gethostbyaddr failed on %s\n", + inet_ntoa(thisaddr)); + exit(1); + } + strncpy(thishost, he->h_name, sizeof(thishost)); + thishost[sizeof(thishost) - 1] = '\0'; + } else { + thisaddr.s_addr = INADDR_NONE; + } + + if (!(auth = authunix_create_default())) { + fprintf(stderr, "couldn't create authentication handle\n"); + exit(1); + } + morethanone = (optind + 1 < argc); + + for (; optind < argc; optind++) { + + host = argv[optind]; + tv.tv_sec = CREATE_TIMEOUT; + tv.tv_usec = 0; + + if (!(client = clnt_create_timeout(host, &tv))) + continue; + + client->cl_auth = auth; + tv.tv_sec = CALL_TIMEOUT; + tv.tv_usec = 0; + + if (rpcs & (DODUMP | DOREMOVE | DOVERIFY)) + if ((estat = clnt_call(client, + MOUNTPROC_DUMP, + (XDRPROC_T_TYPE) xdr_void, + (char *) 0, + (XDRPROC_T_TYPE) xdr_mountlist, + (char *) &mntdump, + tv)) != RPC_SUCCESS) { + fprintf(stderr, "%s: MOUNTPROC_DUMP: ", host); + clnt_perrno(estat); + fflush(stderr); + mntdump = NULL; + goto next; + } + if (rpcs & DOEXPORTS) + if ((estat = clnt_call(client, + MOUNTPROC_EXPORT, + (XDRPROC_T_TYPE) xdr_void, + (char *) 0, + (XDRPROC_T_TYPE) xdr_exports, + (char *) &mntexports, + tv)) != RPC_SUCCESS) { + fprintf(stderr, "%s: MOUNTPROC_EXPORT: ", host); + clnt_perrno(estat); + fflush(stderr); + mntexports = NULL; + goto next; + } + + /* Now just print out the results */ + if ((rpcs & (DODUMP | DOEXPORTS)) && + morethanone) { + printf(">>> %s <<<\n", host); + fflush(stdout); + } + + if (rpcs & DODUMP) { + print_dump(mntdump); + } + + if (rpcs & DOEXPORTS) { + exp = mntexports; + while (exp) { + printf("%-35s", exp->ex_dir); + grp = exp->ex_groups; + if (grp == NULL) { + printf("Everyone\n"); + } else { + while (grp) { + printf("%s ", grp->gr_name); + grp = grp->gr_next; + } + printf("\n"); + } + exp = exp->ex_next; + } + } + + if (rpcs & DOVERIFY) + fix_rmtab(client, host, mntdump, 0, force); + + if (rpcs & DOREMOVE) + fix_rmtab(client, host, mntdump, 1, force); + + if (rpcs & DOREMALL) + remove_all(client, host); + + next: + if (mntdump) + (void) clnt_freeres(client, + (XDRPROC_T_TYPE) xdr_mountlist, + (char *) &mntdump); + if (mntexports) + (void) clnt_freeres(client, + (XDRPROC_T_TYPE) xdr_exports, + (char *) &mntexports); + + clnt_destroy(client); + } + exit(0); + return 0; /* should never reach here */ +} + + +RETSIGTYPE +create_timeout(int sig) +{ + signal(SIGALRM, SIG_DFL); + longjmp(before_rpc, 1); +} + + +#ifndef HAVE_TRANSPORT_TYPE_TLI +/* + * inetresport creates a datagram socket and attempts to bind it to a + * secure port. + * returns: The bound socket, or -1 to indicate an error. + */ +static int +inetresport(int ty) +{ + int alport; + struct sockaddr_in addr; + int fd; + + /* Use internet address family */ + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + if ((fd = socket(AF_INET, ty, 0)) < 0) + return -1; + + for (alport = IPPORT_RESERVED - 1; alport > IPPORT_RESERVED / 2 + 1; alport--) { + addr.sin_port = htons((u_short) alport); + if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) >= 0) + return fd; + if (errno != EADDRINUSE) { + close(fd); + return -1; + } + } + close(fd); + errno = EAGAIN; + return -1; +} + + +/* + * Privsock() calls inetresport() to attempt to bind a socket to a secure + * port. If inetresport() fails, privsock returns a magic socket number which + * indicates to RPC that it should make its own socket. + * returns: A privileged socket # or RPC_ANYSOCK. + */ +static int +privsock(int ty) +{ + int sock = inetresport(ty); + + if (sock < 0) { + errno = 0; + /* Couldn't get a secure port, let RPC make an insecure one */ + sock = RPC_ANYSOCK; + } + return sock; +} +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + +static CLIENT * +clnt_create_timeout(char *host, struct timeval *tvp) +{ + CLIENT *clnt; + struct sockaddr_in host_addr; + struct hostent *hp; +#ifndef HAVE_TRANSPORT_TYPE_TLI + int s; +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + if (setjmp(before_rpc)) { + if (!quiet) { + fprintf(stderr, "%s: ", host); + clnt_perrno(RPC_TIMEDOUT); + fprintf(stderr, "\n"); + fflush(stderr); + } + return NULL; + } + signal(SIGALRM, create_timeout); + ualarm(tvp->tv_sec * 1000000 + tvp->tv_usec, 0); + + /* + * Get address of host + */ + if ((hp = gethostbyname(host)) == 0 && !STREQ(host, localhost)) { + fprintf(stderr, "can't get address of %s\n", host); + return NULL; + } + memset(&host_addr, 0, sizeof host_addr); + host_addr.sin_family = AF_INET; + if (hp) { + memmove((voidp) &host_addr.sin_addr, (voidp) hp->h_addr, + sizeof(host_addr.sin_addr)); + } else { + /* fake "localhost" */ + host_addr.sin_addr.s_addr = htonl(0x7f000001); + } + +#ifdef HAVE_TRANSPORT_TYPE_TLI + /* try TCP first (in case return data is large), then UDP */ + clnt = clnt_create(host, MOUNTPROG, MOUNTVERS, "tcp"); + if (!clnt) + clnt = clnt_create(host, MOUNTPROG, MOUNTVERS, "udp"); +#else /* not HAVE_TRANSPORT_TYPE_TLI */ + s = RPC_ANYSOCK; + clnt = clnttcp_create(&host_addr, MOUNTPROG, MOUNTVERS, &s, 0, 0); + if (!clnt) { + /* XXX: do we need to close(s) ? */ + s = privsock(SOCK_DGRAM); + clnt = clntudp_create(&host_addr, MOUNTPROG, MOUNTVERS, *tvp, &s); + } +#endif /* not HAVE_TRANSPORT_TYPE_TLI */ + + if (!clnt) { + ualarm(0, 0); + if (!quiet) { + clnt_pcreateerror(host); + fflush(stderr); + } + return NULL; + } + + ualarm(0, 0); + return clnt; +} |