1c69a34d4SMatthew Dillon /* 2c69a34d4SMatthew Dillon * Copyright (c) 1999 Martin Blapp 3c69a34d4SMatthew Dillon * All rights reserved. 4c69a34d4SMatthew Dillon * 5c69a34d4SMatthew Dillon * Redistribution and use in source and binary forms, with or without 6c69a34d4SMatthew Dillon * modification, are permitted provided that the following conditions 7c69a34d4SMatthew Dillon * are met: 8c69a34d4SMatthew Dillon * 1. Redistributions of source code must retain the above copyright 9c69a34d4SMatthew Dillon * notice, this list of conditions and the following disclaimer. 10c69a34d4SMatthew Dillon * 2. Redistributions in binary form must reproduce the above copyright 11c69a34d4SMatthew Dillon * notice, this list of conditions and the following disclaimer in the 12c69a34d4SMatthew Dillon * documentation and/or other materials provided with the distribution. 13c69a34d4SMatthew Dillon * 14c69a34d4SMatthew Dillon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15c69a34d4SMatthew Dillon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16c69a34d4SMatthew Dillon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17c69a34d4SMatthew Dillon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18c69a34d4SMatthew Dillon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19c69a34d4SMatthew Dillon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20c69a34d4SMatthew Dillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21c69a34d4SMatthew Dillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22c69a34d4SMatthew Dillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23c69a34d4SMatthew Dillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24c69a34d4SMatthew Dillon * SUCH DAMAGE. 25c69a34d4SMatthew Dillon * 26c69a34d4SMatthew Dillon */ 27c69a34d4SMatthew Dillon 28c69a34d4SMatthew Dillon #ifndef lint 29c69a34d4SMatthew Dillon static const char rcsid[] = 30c69a34d4SMatthew Dillon "$FreeBSD$"; 31c69a34d4SMatthew Dillon #endif /* not lint */ 32c69a34d4SMatthew Dillon 33c69a34d4SMatthew Dillon #include <sys/param.h> 34c69a34d4SMatthew Dillon #include <sys/ucred.h> 35c69a34d4SMatthew Dillon #include <sys/mount.h> 36c69a34d4SMatthew Dillon 37c69a34d4SMatthew Dillon #include <rpc/rpc.h> 38c69a34d4SMatthew Dillon #include <nfs/rpcv2.h> 39c69a34d4SMatthew Dillon 40c69a34d4SMatthew Dillon #include <err.h> 41c69a34d4SMatthew Dillon #include <netdb.h> 42c69a34d4SMatthew Dillon #include <stdio.h> 43c69a34d4SMatthew Dillon #include <stdlib.h> 44c69a34d4SMatthew Dillon #include <string.h> 45c69a34d4SMatthew Dillon #include <unistd.h> 46c69a34d4SMatthew Dillon 47c69a34d4SMatthew Dillon #include "mounttab.h" 48c69a34d4SMatthew Dillon 49c69a34d4SMatthew Dillon int verbose; 50c69a34d4SMatthew Dillon 51c69a34d4SMatthew Dillon static int do_umount (char *, char *); 52c69a34d4SMatthew Dillon static int do_umntall (char *); 53c69a34d4SMatthew Dillon static int is_mounted (char *, char *); 54c69a34d4SMatthew Dillon static void usage (void); 55c69a34d4SMatthew Dillon int xdr_dir (XDR *, char *); 56c69a34d4SMatthew Dillon 57c69a34d4SMatthew Dillon int 58c69a34d4SMatthew Dillon main(int argc, char **argv) { 59c69a34d4SMatthew Dillon int ch, keep, success, pathlen; 60d730d3b4SIan Dowse time_t expire, now; 61c69a34d4SMatthew Dillon char *host, *path; 62c69a34d4SMatthew Dillon struct mtablist *mtab; 63c69a34d4SMatthew Dillon 64c69a34d4SMatthew Dillon expire = 0; 65d730d3b4SIan Dowse host = path = NULL; 66c69a34d4SMatthew Dillon success = keep = verbose = 0; 67c69a34d4SMatthew Dillon while ((ch = getopt(argc, argv, "h:kp:ve:")) != -1) 68c69a34d4SMatthew Dillon switch (ch) { 69c69a34d4SMatthew Dillon case 'h': 70c69a34d4SMatthew Dillon host = optarg; 71c69a34d4SMatthew Dillon break; 72c69a34d4SMatthew Dillon case 'e': 737b2df384SJonathan Lemon expire = atoi(optarg); 74c69a34d4SMatthew Dillon break; 75c69a34d4SMatthew Dillon case 'k': 76c69a34d4SMatthew Dillon keep = 1; 77c69a34d4SMatthew Dillon break; 78c69a34d4SMatthew Dillon case 'p': 79c69a34d4SMatthew Dillon path = optarg; 80c69a34d4SMatthew Dillon break; 81c69a34d4SMatthew Dillon case 'v': 82c69a34d4SMatthew Dillon verbose = 1; 83c69a34d4SMatthew Dillon break; 84c69a34d4SMatthew Dillon case '?': 85c69a34d4SMatthew Dillon usage(); 86c69a34d4SMatthew Dillon default: 87891c2f9eSWarner Losh break; 88c69a34d4SMatthew Dillon } 89c69a34d4SMatthew Dillon argc -= optind; 90c69a34d4SMatthew Dillon argv += optind; 91c69a34d4SMatthew Dillon 92ab80d6faSBrian Feldman /* Default expiretime is one day */ 93c69a34d4SMatthew Dillon if (expire == 0) 94ab80d6faSBrian Feldman expire = 86400; 95d730d3b4SIan Dowse time(&now); 96d730d3b4SIan Dowse 97d730d3b4SIan Dowse /* Read PATH_MOUNTTAB. */ 98afe1ef24SIan Dowse if (!read_mtab()) { 99c69a34d4SMatthew Dillon if (verbose) 100d730d3b4SIan Dowse warnx("no mounttab entries (%s does not exist)", 101c69a34d4SMatthew Dillon PATH_MOUNTTAB); 102d730d3b4SIan Dowse mtabhead = NULL; 103c69a34d4SMatthew Dillon } 104d730d3b4SIan Dowse 105d730d3b4SIan Dowse if (host == NULL && path == NULL) { 106d730d3b4SIan Dowse /* Check each entry and do any necessary unmount RPCs. */ 107c69a34d4SMatthew Dillon for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) { 108d730d3b4SIan Dowse if (*mtab->mtab_host == '\0') 109d730d3b4SIan Dowse continue; 110d730d3b4SIan Dowse if (mtab->mtab_time + expire < now) { 111d730d3b4SIan Dowse /* Clear expired entry. */ 112d730d3b4SIan Dowse if (verbose) 113d730d3b4SIan Dowse warnx("remove expired entry %s:%s", 114d730d3b4SIan Dowse mtab->mtab_host, mtab->mtab_dirp); 115d730d3b4SIan Dowse bzero(mtab->mtab_host, 116d730d3b4SIan Dowse sizeof(mtab->mtab_host)); 117d730d3b4SIan Dowse continue; 118d730d3b4SIan Dowse } 119c69a34d4SMatthew Dillon if (keep && is_mounted(mtab->mtab_host, 120c69a34d4SMatthew Dillon mtab->mtab_dirp)) { 121d730d3b4SIan Dowse if (verbose) 122ab80d6faSBrian Feldman warnx("skip entry %s:%s", 123d730d3b4SIan Dowse mtab->mtab_host, mtab->mtab_dirp); 124d730d3b4SIan Dowse continue; 125c69a34d4SMatthew Dillon } 126d730d3b4SIan Dowse if (do_umount(mtab->mtab_host, mtab->mtab_dirp)) { 127d730d3b4SIan Dowse if (verbose) 128d730d3b4SIan Dowse warnx("umount RPC for %s:%s succeeded", 129d730d3b4SIan Dowse mtab->mtab_host, mtab->mtab_dirp); 130d730d3b4SIan Dowse /* Remove all entries for this host + path. */ 131afe1ef24SIan Dowse clean_mtab(mtab->mtab_host, mtab->mtab_dirp, 132afe1ef24SIan Dowse verbose); 13310cb4f4aSGreg Lehey } 134c69a34d4SMatthew Dillon } 135c69a34d4SMatthew Dillon success = 1; 136d730d3b4SIan Dowse } else { 137d730d3b4SIan Dowse if (host == NULL && path != NULL) 138d730d3b4SIan Dowse /* Missing hostname. */ 139c69a34d4SMatthew Dillon usage(); 140d730d3b4SIan Dowse if (path == NULL) { 141d730d3b4SIan Dowse /* Do a RPC UMNTALL for this specific host */ 142d730d3b4SIan Dowse success = do_umntall(host); 143d730d3b4SIan Dowse if (verbose && success) 144d730d3b4SIan Dowse warnx("umntall RPC for %s succeeded", host); 145d730d3b4SIan Dowse } else { 146d730d3b4SIan Dowse /* Do a RPC UMNTALL for this specific mount */ 147c69a34d4SMatthew Dillon for (pathlen = strlen(path); 148c69a34d4SMatthew Dillon pathlen > 1 && path[pathlen - 1] == '/'; pathlen--) 149c69a34d4SMatthew Dillon path[pathlen - 1] = '\0'; 150d730d3b4SIan Dowse success = do_umount(host, path); 151d730d3b4SIan Dowse if (verbose && success) 152d730d3b4SIan Dowse warnx("umount RPC for %s:%s succeeded", host, 153d730d3b4SIan Dowse path); 154c69a34d4SMatthew Dillon } 155d730d3b4SIan Dowse /* If successful, remove any corresponding mounttab entries. */ 156d730d3b4SIan Dowse if (success) 157afe1ef24SIan Dowse clean_mtab(host, path, verbose); 158c69a34d4SMatthew Dillon } 159d730d3b4SIan Dowse /* Write and unlink PATH_MOUNTTAB if necessary */ 160d730d3b4SIan Dowse if (success) 161afe1ef24SIan Dowse success = write_mtab(verbose); 162c69a34d4SMatthew Dillon free_mtab(); 163d730d3b4SIan Dowse exit (success ? 0 : 1); 164c69a34d4SMatthew Dillon } 165c69a34d4SMatthew Dillon 166c69a34d4SMatthew Dillon /* 167c69a34d4SMatthew Dillon * Send a RPC_MNT UMNTALL request to hostname. 16810cb4f4aSGreg Lehey * XXX This works for all mountd implementations, 16910cb4f4aSGreg Lehey * but produces a RPC IOERR on non FreeBSD systems. 170c69a34d4SMatthew Dillon */ 171c69a34d4SMatthew Dillon int 172c69a34d4SMatthew Dillon do_umntall(char *hostname) { 173c69a34d4SMatthew Dillon enum clnt_stat clnt_stat; 1748360efbdSAlfred Perlstein struct timeval try; 175c69a34d4SMatthew Dillon CLIENT *clp; 176c69a34d4SMatthew Dillon 177b4bb2bf4SMaxime Henrion try.tv_sec = 3; 178b4bb2bf4SMaxime Henrion try.tv_usec = 0; 179b4bb2bf4SMaxime Henrion clp = clnt_create_timed(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp", 180b4bb2bf4SMaxime Henrion &try); 1818360efbdSAlfred Perlstein if (clp == NULL) { 182d730d3b4SIan Dowse warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT")); 183146e669bSIan Dowse return (0); 184c69a34d4SMatthew Dillon } 185c69a34d4SMatthew Dillon clp->cl_auth = authunix_create_default(); 186422e293cSPeter Wemm clnt_stat = clnt_call(clp, RPCMNT_UMNTALL, 187422e293cSPeter Wemm (xdrproc_t)xdr_void, (caddr_t)0, 188422e293cSPeter Wemm (xdrproc_t)xdr_void, (caddr_t)0, try); 189146e669bSIan Dowse if (clnt_stat != RPC_SUCCESS) 190d730d3b4SIan Dowse warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMNTALL")); 191146e669bSIan Dowse auth_destroy(clp->cl_auth); 192146e669bSIan Dowse clnt_destroy(clp); 193146e669bSIan Dowse return (clnt_stat == RPC_SUCCESS); 194c69a34d4SMatthew Dillon } 195c69a34d4SMatthew Dillon 196c69a34d4SMatthew Dillon /* 197c69a34d4SMatthew Dillon * Send a RPC_MNT UMOUNT request for dirp to hostname. 198c69a34d4SMatthew Dillon */ 199c69a34d4SMatthew Dillon int 200c69a34d4SMatthew Dillon do_umount(char *hostname, char *dirp) { 201c69a34d4SMatthew Dillon enum clnt_stat clnt_stat; 2028360efbdSAlfred Perlstein struct timeval try; 203c69a34d4SMatthew Dillon CLIENT *clp; 204c69a34d4SMatthew Dillon 205b4bb2bf4SMaxime Henrion try.tv_sec = 3; 206b4bb2bf4SMaxime Henrion try.tv_usec = 0; 207b4bb2bf4SMaxime Henrion clp = clnt_create_timed(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp", 208b4bb2bf4SMaxime Henrion &try); 2098360efbdSAlfred Perlstein if (clp == NULL) { 210d730d3b4SIan Dowse warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT")); 211146e669bSIan Dowse return (0); 212c69a34d4SMatthew Dillon } 2138360efbdSAlfred Perlstein clp->cl_auth = authsys_create_default(); 214422e293cSPeter Wemm clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, (xdrproc_t)xdr_dir, dirp, 215422e293cSPeter Wemm (xdrproc_t)xdr_void, (caddr_t)0, try); 216146e669bSIan Dowse if (clnt_stat != RPC_SUCCESS) 217d730d3b4SIan Dowse warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMOUNT")); 218146e669bSIan Dowse auth_destroy(clp->cl_auth); 219146e669bSIan Dowse clnt_destroy(clp); 220146e669bSIan Dowse return (clnt_stat == RPC_SUCCESS); 221c69a34d4SMatthew Dillon } 222c69a34d4SMatthew Dillon 223c69a34d4SMatthew Dillon /* 224c69a34d4SMatthew Dillon * Check if the entry is still/already mounted. 225c69a34d4SMatthew Dillon */ 226c69a34d4SMatthew Dillon int 227c69a34d4SMatthew Dillon is_mounted(char *hostname, char *dirp) { 228c69a34d4SMatthew Dillon struct statfs *mntbuf; 229c69a34d4SMatthew Dillon char name[MNAMELEN + 1]; 230d730d3b4SIan Dowse size_t bufsize; 231c69a34d4SMatthew Dillon int mntsize, i; 232c69a34d4SMatthew Dillon 233d730d3b4SIan Dowse if (strlen(hostname) + strlen(dirp) >= MNAMELEN) 234c69a34d4SMatthew Dillon return (0); 235d730d3b4SIan Dowse snprintf(name, sizeof(name), "%s:%s", hostname, dirp); 236c69a34d4SMatthew Dillon mntsize = getfsstat(NULL, 0, MNT_NOWAIT); 237c69a34d4SMatthew Dillon if (mntsize <= 0) 238c69a34d4SMatthew Dillon return (0); 239c69a34d4SMatthew Dillon bufsize = (mntsize + 1) * sizeof(struct statfs); 240c69a34d4SMatthew Dillon if ((mntbuf = malloc(bufsize)) == NULL) 241c69a34d4SMatthew Dillon err(1, "malloc"); 242c69a34d4SMatthew Dillon mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT); 243c69a34d4SMatthew Dillon for (i = mntsize - 1; i >= 0; i--) { 244c69a34d4SMatthew Dillon if (strcmp(mntbuf[i].f_mntfromname, name) == 0) { 245c69a34d4SMatthew Dillon free(mntbuf); 246c69a34d4SMatthew Dillon return (1); 247c69a34d4SMatthew Dillon } 248c69a34d4SMatthew Dillon } 249c69a34d4SMatthew Dillon free(mntbuf); 250c69a34d4SMatthew Dillon return (0); 251c69a34d4SMatthew Dillon } 252c69a34d4SMatthew Dillon 253c69a34d4SMatthew Dillon /* 254c69a34d4SMatthew Dillon * xdr routines for mount rpc's 255c69a34d4SMatthew Dillon */ 256c69a34d4SMatthew Dillon int 257c69a34d4SMatthew Dillon xdr_dir(XDR *xdrsp, char *dirp) { 258c69a34d4SMatthew Dillon return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 259c69a34d4SMatthew Dillon } 260c69a34d4SMatthew Dillon 261c69a34d4SMatthew Dillon static void 262c69a34d4SMatthew Dillon usage() { 263c69a34d4SMatthew Dillon (void)fprintf(stderr, "%s\n", 264d730d3b4SIan Dowse "usage: rpc.umntall [-kv] [-e expire] [-h host] [-p path]"); 265c69a34d4SMatthew Dillon exit(1); 266c69a34d4SMatthew Dillon } 267