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: 87c69a34d4SMatthew Dillon } 88c69a34d4SMatthew Dillon argc -= optind; 89c69a34d4SMatthew Dillon argv += optind; 90c69a34d4SMatthew Dillon 91c69a34d4SMatthew Dillon /* Ignore SIGINT and SIGQUIT during shutdown */ 92c69a34d4SMatthew Dillon signal(SIGINT, SIG_IGN); 93c69a34d4SMatthew Dillon signal(SIGQUIT, SIG_IGN); 94c69a34d4SMatthew Dillon 95ab80d6faSBrian Feldman /* Default expiretime is one day */ 96c69a34d4SMatthew Dillon if (expire == 0) 97ab80d6faSBrian Feldman expire = 86400; 98d730d3b4SIan Dowse time(&now); 99d730d3b4SIan Dowse 100d730d3b4SIan Dowse /* Read PATH_MOUNTTAB. */ 101afe1ef24SIan Dowse if (!read_mtab()) { 102c69a34d4SMatthew Dillon if (verbose) 103d730d3b4SIan Dowse warnx("no mounttab entries (%s does not exist)", 104c69a34d4SMatthew Dillon PATH_MOUNTTAB); 105d730d3b4SIan Dowse mtabhead = NULL; 106c69a34d4SMatthew Dillon } 107d730d3b4SIan Dowse 108d730d3b4SIan Dowse if (host == NULL && path == NULL) { 109d730d3b4SIan Dowse /* Check each entry and do any necessary unmount RPCs. */ 110c69a34d4SMatthew Dillon for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) { 111d730d3b4SIan Dowse if (*mtab->mtab_host == '\0') 112d730d3b4SIan Dowse continue; 113d730d3b4SIan Dowse if (mtab->mtab_time + expire < now) { 114d730d3b4SIan Dowse /* Clear expired entry. */ 115d730d3b4SIan Dowse if (verbose) 116d730d3b4SIan Dowse warnx("remove expired entry %s:%s", 117d730d3b4SIan Dowse mtab->mtab_host, mtab->mtab_dirp); 118d730d3b4SIan Dowse bzero(mtab->mtab_host, 119d730d3b4SIan Dowse sizeof(mtab->mtab_host)); 120d730d3b4SIan Dowse continue; 121d730d3b4SIan Dowse } 122c69a34d4SMatthew Dillon if (keep && is_mounted(mtab->mtab_host, 123c69a34d4SMatthew Dillon mtab->mtab_dirp)) { 124d730d3b4SIan Dowse if (verbose) 125ab80d6faSBrian Feldman warnx("skip entry %s:%s", 126d730d3b4SIan Dowse mtab->mtab_host, mtab->mtab_dirp); 127d730d3b4SIan Dowse continue; 128c69a34d4SMatthew Dillon } 129d730d3b4SIan Dowse if (do_umount(mtab->mtab_host, mtab->mtab_dirp)) { 130d730d3b4SIan Dowse if (verbose) 131d730d3b4SIan Dowse warnx("umount RPC for %s:%s succeeded", 132d730d3b4SIan Dowse mtab->mtab_host, mtab->mtab_dirp); 133d730d3b4SIan Dowse /* Remove all entries for this host + path. */ 134afe1ef24SIan Dowse clean_mtab(mtab->mtab_host, mtab->mtab_dirp, 135afe1ef24SIan Dowse verbose); 13610cb4f4aSGreg Lehey } 137c69a34d4SMatthew Dillon } 138c69a34d4SMatthew Dillon success = 1; 139d730d3b4SIan Dowse } else { 140d730d3b4SIan Dowse if (host == NULL && path != NULL) 141d730d3b4SIan Dowse /* Missing hostname. */ 142c69a34d4SMatthew Dillon usage(); 143d730d3b4SIan Dowse if (path == NULL) { 144d730d3b4SIan Dowse /* Do a RPC UMNTALL for this specific host */ 145d730d3b4SIan Dowse success = do_umntall(host); 146d730d3b4SIan Dowse if (verbose && success) 147d730d3b4SIan Dowse warnx("umntall RPC for %s succeeded", host); 148d730d3b4SIan Dowse } else { 149d730d3b4SIan Dowse /* Do a RPC UMNTALL for this specific mount */ 150c69a34d4SMatthew Dillon for (pathlen = strlen(path); 151c69a34d4SMatthew Dillon pathlen > 1 && path[pathlen - 1] == '/'; pathlen--) 152c69a34d4SMatthew Dillon path[pathlen - 1] = '\0'; 153d730d3b4SIan Dowse success = do_umount(host, path); 154d730d3b4SIan Dowse if (verbose && success) 155d730d3b4SIan Dowse warnx("umount RPC for %s:%s succeeded", host, 156d730d3b4SIan Dowse path); 157c69a34d4SMatthew Dillon } 158d730d3b4SIan Dowse /* If successful, remove any corresponding mounttab entries. */ 159d730d3b4SIan Dowse if (success) 160afe1ef24SIan Dowse clean_mtab(host, path, verbose); 161c69a34d4SMatthew Dillon } 162d730d3b4SIan Dowse /* Write and unlink PATH_MOUNTTAB if necessary */ 163d730d3b4SIan Dowse if (success) 164afe1ef24SIan Dowse success = write_mtab(verbose); 165c69a34d4SMatthew Dillon free_mtab(); 166d730d3b4SIan Dowse exit (success ? 0 : 1); 167c69a34d4SMatthew Dillon } 168c69a34d4SMatthew Dillon 169c69a34d4SMatthew Dillon /* 170c69a34d4SMatthew Dillon * Send a RPC_MNT UMNTALL request to hostname. 17110cb4f4aSGreg Lehey * XXX This works for all mountd implementations, 17210cb4f4aSGreg Lehey * but produces a RPC IOERR on non FreeBSD systems. 173c69a34d4SMatthew Dillon */ 174c69a34d4SMatthew Dillon int 175c69a34d4SMatthew Dillon do_umntall(char *hostname) { 176c69a34d4SMatthew Dillon enum clnt_stat clnt_stat; 1778360efbdSAlfred Perlstein struct timeval try; 178c69a34d4SMatthew Dillon CLIENT *clp; 179c69a34d4SMatthew Dillon 1808360efbdSAlfred Perlstein clp = clnt_create(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp"); 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(); 186c69a34d4SMatthew Dillon try.tv_sec = 3; 187c69a34d4SMatthew Dillon try.tv_usec = 0; 188c69a34d4SMatthew Dillon clnt_stat = clnt_call(clp, RPCMNT_UMNTALL, xdr_void, (caddr_t)0, 189c69a34d4SMatthew Dillon xdr_void, (caddr_t)0, try); 190146e669bSIan Dowse if (clnt_stat != RPC_SUCCESS) 191d730d3b4SIan Dowse warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMNTALL")); 192146e669bSIan Dowse auth_destroy(clp->cl_auth); 193146e669bSIan Dowse clnt_destroy(clp); 194146e669bSIan Dowse return (clnt_stat == RPC_SUCCESS); 195c69a34d4SMatthew Dillon } 196c69a34d4SMatthew Dillon 197c69a34d4SMatthew Dillon /* 198c69a34d4SMatthew Dillon * Send a RPC_MNT UMOUNT request for dirp to hostname. 199c69a34d4SMatthew Dillon */ 200c69a34d4SMatthew Dillon int 201c69a34d4SMatthew Dillon do_umount(char *hostname, char *dirp) { 202c69a34d4SMatthew Dillon enum clnt_stat clnt_stat; 2038360efbdSAlfred Perlstein struct timeval try; 204c69a34d4SMatthew Dillon CLIENT *clp; 205c69a34d4SMatthew Dillon 2068360efbdSAlfred Perlstein clp = clnt_create(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp"); 2078360efbdSAlfred Perlstein if (clp == NULL) { 208d730d3b4SIan Dowse warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT")); 209146e669bSIan Dowse return (0); 210c69a34d4SMatthew Dillon } 2118360efbdSAlfred Perlstein clp->cl_auth = authsys_create_default(); 212c69a34d4SMatthew Dillon try.tv_sec = 3; 213c69a34d4SMatthew Dillon try.tv_usec = 0; 214c69a34d4SMatthew Dillon clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp, 215c69a34d4SMatthew Dillon 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