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 struct mtablist *mtabhead; 58c69a34d4SMatthew Dillon 59c69a34d4SMatthew Dillon int 60c69a34d4SMatthew Dillon main(int argc, char **argv) { 61c69a34d4SMatthew Dillon int ch, keep, success, pathlen; 62c69a34d4SMatthew Dillon time_t expire, *now; 63c69a34d4SMatthew Dillon char *host, *path; 64c69a34d4SMatthew Dillon struct mtablist *mtab; 65c69a34d4SMatthew Dillon 66c69a34d4SMatthew Dillon mtab = NULL; 67c69a34d4SMatthew Dillon now = NULL; 68c69a34d4SMatthew Dillon expire = 0; 69c69a34d4SMatthew Dillon host = path = '\0'; 70c69a34d4SMatthew Dillon success = keep = verbose = 0; 71c69a34d4SMatthew Dillon while ((ch = getopt(argc, argv, "h:kp:ve:")) != -1) 72c69a34d4SMatthew Dillon switch (ch) { 73c69a34d4SMatthew Dillon case 'h': 74c69a34d4SMatthew Dillon host = optarg; 75c69a34d4SMatthew Dillon break; 76c69a34d4SMatthew Dillon case 'e': 77c69a34d4SMatthew Dillon expire = (time_t)optarg; 78c69a34d4SMatthew Dillon break; 79c69a34d4SMatthew Dillon case 'k': 80c69a34d4SMatthew Dillon keep = 1; 81c69a34d4SMatthew Dillon break; 82c69a34d4SMatthew Dillon case 'p': 83c69a34d4SMatthew Dillon path = optarg; 84c69a34d4SMatthew Dillon break; 85c69a34d4SMatthew Dillon case 'v': 86c69a34d4SMatthew Dillon verbose = 1; 87c69a34d4SMatthew Dillon break; 88c69a34d4SMatthew Dillon case '?': 89c69a34d4SMatthew Dillon usage(); 90c69a34d4SMatthew Dillon default: 91c69a34d4SMatthew Dillon } 92c69a34d4SMatthew Dillon argc -= optind; 93c69a34d4SMatthew Dillon argv += optind; 94c69a34d4SMatthew Dillon 95c69a34d4SMatthew Dillon /* Ignore SIGINT and SIGQUIT during shutdown */ 96c69a34d4SMatthew Dillon signal(SIGINT, SIG_IGN); 97c69a34d4SMatthew Dillon signal(SIGQUIT, SIG_IGN); 98c69a34d4SMatthew Dillon 99ab80d6faSBrian Feldman /* Default expiretime is one day */ 100c69a34d4SMatthew Dillon if (expire == 0) 101ab80d6faSBrian Feldman expire = 86400; 102c69a34d4SMatthew Dillon /* 103c69a34d4SMatthew Dillon * Read PATH_MOUNTTAB and check each entry 104c69a34d4SMatthew Dillon * and do finally the unmounts. 105c69a34d4SMatthew Dillon */ 106c69a34d4SMatthew Dillon if (host == NULL && path == NULL) { 107c69a34d4SMatthew Dillon if (!read_mtab(mtab)) { 108c69a34d4SMatthew Dillon if (verbose) 109ab80d6faSBrian Feldman warnx("nothing to do, %s does not exist", 110c69a34d4SMatthew Dillon PATH_MOUNTTAB); 111c69a34d4SMatthew Dillon } 112c69a34d4SMatthew Dillon for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) { 11310cb4f4aSGreg Lehey if (*mtab->mtab_host != '\0' || 11410cb4f4aSGreg Lehey mtab->mtab_time <= (time(now) - expire)) { 115c69a34d4SMatthew Dillon if (keep && is_mounted(mtab->mtab_host, 116c69a34d4SMatthew Dillon mtab->mtab_dirp)) { 117c69a34d4SMatthew Dillon if (verbose) { 118ab80d6faSBrian Feldman warnx("skip entry %s:%s", 119c69a34d4SMatthew Dillon mtab->mtab_host, 120c69a34d4SMatthew Dillon mtab->mtab_dirp); 121c69a34d4SMatthew Dillon } 12210cb4f4aSGreg Lehey } else if (do_umount(mtab->mtab_host, 123ab80d6faSBrian Feldman mtab->mtab_dirp) || 124ab80d6faSBrian Feldman mtab->mtab_time <= (time(now) - expire)) { 12510cb4f4aSGreg Lehey clean_mtab(mtab->mtab_host, 12610cb4f4aSGreg Lehey mtab->mtab_dirp); 12710cb4f4aSGreg Lehey } 128c69a34d4SMatthew Dillon } 129c69a34d4SMatthew Dillon } 130c69a34d4SMatthew Dillon /* Only do a RPC UMNTALL for this specific host */ 131c69a34d4SMatthew Dillon } else if (host != NULL && path == NULL) { 132c69a34d4SMatthew Dillon if (!do_umntall(host)) 133c69a34d4SMatthew Dillon exit(1); 134c69a34d4SMatthew Dillon else 135c69a34d4SMatthew Dillon success = 1; 136c69a34d4SMatthew Dillon /* Someone forgot to enter a hostname */ 137c69a34d4SMatthew Dillon } else if (host == NULL && path != NULL) 138c69a34d4SMatthew Dillon usage(); 139c69a34d4SMatthew Dillon /* Only do a RPC UMOUNT for this specific mount */ 140c69a34d4SMatthew Dillon else { 141c69a34d4SMatthew Dillon for (pathlen = strlen(path); 142c69a34d4SMatthew Dillon pathlen > 1 && path[pathlen - 1] == '/'; pathlen--) 143c69a34d4SMatthew Dillon path[pathlen - 1] = '\0'; 144c69a34d4SMatthew Dillon if (!do_umount(host, path)) 145c69a34d4SMatthew Dillon exit(1); 146c69a34d4SMatthew Dillon else 147c69a34d4SMatthew Dillon success = 1; 148c69a34d4SMatthew Dillon } 149c69a34d4SMatthew Dillon /* Write and unlink PATH_MOUNTTAB if necessary */ 150c69a34d4SMatthew Dillon if (success) { 151c69a34d4SMatthew Dillon if (verbose) 152c69a34d4SMatthew Dillon warnx("UMOUNT RPC successfully sent to %s", host); 153c69a34d4SMatthew Dillon if (read_mtab(mtab)) { 154c69a34d4SMatthew Dillon mtab = mtabhead; 155c69a34d4SMatthew Dillon clean_mtab(host, path); 156c69a34d4SMatthew Dillon } 157c69a34d4SMatthew Dillon } 158c69a34d4SMatthew Dillon if (!write_mtab()) { 159c69a34d4SMatthew Dillon free_mtab(); 160c69a34d4SMatthew Dillon exit(1); 161c69a34d4SMatthew Dillon } 162c69a34d4SMatthew Dillon free_mtab(); 163c69a34d4SMatthew Dillon exit(0); 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; 174c69a34d4SMatthew Dillon struct hostent *hp; 175c69a34d4SMatthew Dillon struct sockaddr_in saddr; 176c69a34d4SMatthew Dillon struct timeval pertry, try; 177c69a34d4SMatthew Dillon int so; 178c69a34d4SMatthew Dillon CLIENT *clp; 179c69a34d4SMatthew Dillon 180c69a34d4SMatthew Dillon if ((hp = gethostbyname(hostname)) == NULL) { 181c69a34d4SMatthew Dillon warnx("gethostbyname(%s) failed", hostname); 182c69a34d4SMatthew Dillon return (0); 183c69a34d4SMatthew Dillon } 184c69a34d4SMatthew Dillon memset(&saddr, 0, sizeof(saddr)); 185c69a34d4SMatthew Dillon saddr.sin_family = AF_INET; 186c69a34d4SMatthew Dillon saddr.sin_port = 0; 187c69a34d4SMatthew Dillon memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length, 188c69a34d4SMatthew Dillon sizeof(saddr.sin_addr))); 189c69a34d4SMatthew Dillon pertry.tv_sec = 3; 190c69a34d4SMatthew Dillon pertry.tv_usec = 0; 191c69a34d4SMatthew Dillon so = RPC_ANYSOCK; 192c69a34d4SMatthew Dillon if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, 193c69a34d4SMatthew Dillon pertry, &so)) == NULL) { 194c69a34d4SMatthew Dillon clnt_pcreateerror("Cannot send MNT PRC"); 195c69a34d4SMatthew Dillon return (0); 196c69a34d4SMatthew Dillon } 197c69a34d4SMatthew Dillon clp->cl_auth = authunix_create_default(); 198c69a34d4SMatthew Dillon try.tv_sec = 3; 199c69a34d4SMatthew Dillon try.tv_usec = 0; 200c69a34d4SMatthew Dillon clnt_stat = clnt_call(clp, RPCMNT_UMNTALL, xdr_void, (caddr_t)0, 201c69a34d4SMatthew Dillon xdr_void, (caddr_t)0, try); 202c69a34d4SMatthew Dillon if (clnt_stat != RPC_SUCCESS) { 203c69a34d4SMatthew Dillon clnt_perror(clp, "Bad MNT RPC"); 204c69a34d4SMatthew Dillon return (0); 205c69a34d4SMatthew Dillon } else 206c69a34d4SMatthew Dillon return (1); 207c69a34d4SMatthew Dillon } 208c69a34d4SMatthew Dillon 209c69a34d4SMatthew Dillon /* 210c69a34d4SMatthew Dillon * Send a RPC_MNT UMOUNT request for dirp to hostname. 211c69a34d4SMatthew Dillon */ 212c69a34d4SMatthew Dillon int 213c69a34d4SMatthew Dillon do_umount(char *hostname, char *dirp) { 214c69a34d4SMatthew Dillon enum clnt_stat clnt_stat; 215c69a34d4SMatthew Dillon struct hostent *hp; 216c69a34d4SMatthew Dillon struct sockaddr_in saddr; 217c69a34d4SMatthew Dillon struct timeval pertry, try; 218c69a34d4SMatthew Dillon CLIENT *clp; 219c69a34d4SMatthew Dillon int so; 220c69a34d4SMatthew Dillon 221c69a34d4SMatthew Dillon if ((hp = gethostbyname(hostname)) == NULL) { 222c69a34d4SMatthew Dillon warnx("gethostbyname(%s) failed", hostname); 223c69a34d4SMatthew Dillon return (0); 224c69a34d4SMatthew Dillon } 225c69a34d4SMatthew Dillon memset(&saddr, 0, sizeof(saddr)); 226c69a34d4SMatthew Dillon saddr.sin_family = AF_INET; 227c69a34d4SMatthew Dillon saddr.sin_port = 0; 228c69a34d4SMatthew Dillon memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length, 229c69a34d4SMatthew Dillon sizeof(saddr.sin_addr))); 230c69a34d4SMatthew Dillon pertry.tv_sec = 3; 231c69a34d4SMatthew Dillon pertry.tv_usec = 0; 232c69a34d4SMatthew Dillon so = RPC_ANYSOCK; 233c69a34d4SMatthew Dillon if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, 234c69a34d4SMatthew Dillon pertry, &so)) == NULL) { 235c69a34d4SMatthew Dillon clnt_pcreateerror("Cannot send MNT PRC"); 236c69a34d4SMatthew Dillon return (0); 237c69a34d4SMatthew Dillon } 238c69a34d4SMatthew Dillon clp->cl_auth = authunix_create_default(); 239c69a34d4SMatthew Dillon try.tv_sec = 3; 240c69a34d4SMatthew Dillon try.tv_usec = 0; 241c69a34d4SMatthew Dillon clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp, 242c69a34d4SMatthew Dillon xdr_void, (caddr_t)0, try); 243c69a34d4SMatthew Dillon if (clnt_stat != RPC_SUCCESS) { 244c69a34d4SMatthew Dillon clnt_perror(clp, "Bad MNT RPC"); 245c69a34d4SMatthew Dillon return (0); 246c69a34d4SMatthew Dillon } 247c69a34d4SMatthew Dillon return (1); 248c69a34d4SMatthew Dillon } 249c69a34d4SMatthew Dillon 250c69a34d4SMatthew Dillon /* 251c69a34d4SMatthew Dillon * Check if the entry is still/already mounted. 252c69a34d4SMatthew Dillon */ 253c69a34d4SMatthew Dillon int 254c69a34d4SMatthew Dillon is_mounted(char *hostname, char *dirp) { 255c69a34d4SMatthew Dillon struct statfs *mntbuf; 256c69a34d4SMatthew Dillon char name[MNAMELEN + 1]; 257c69a34d4SMatthew Dillon size_t bufsize, hostlen, dirlen; 258c69a34d4SMatthew Dillon int mntsize, i; 259c69a34d4SMatthew Dillon 260c69a34d4SMatthew Dillon hostlen = strlen(hostname); 261c69a34d4SMatthew Dillon dirlen = strlen(dirp); 262c69a34d4SMatthew Dillon if ((hostlen + dirlen) >= MNAMELEN) 263c69a34d4SMatthew Dillon return (0); 264c69a34d4SMatthew Dillon memmove(name, hostname, hostlen); 265c69a34d4SMatthew Dillon name[hostlen] = ':'; 266c69a34d4SMatthew Dillon memmove(name + hostlen + 1, dirp, dirlen); 267c69a34d4SMatthew Dillon name[hostlen + dirlen + 1] = '\0'; 268c69a34d4SMatthew Dillon mntsize = getfsstat(NULL, 0, MNT_NOWAIT); 269c69a34d4SMatthew Dillon if (mntsize <= 0) 270c69a34d4SMatthew Dillon return (0); 271c69a34d4SMatthew Dillon bufsize = (mntsize + 1) * sizeof(struct statfs); 272c69a34d4SMatthew Dillon if ((mntbuf = malloc(bufsize)) == NULL) 273c69a34d4SMatthew Dillon err(1, "malloc"); 274c69a34d4SMatthew Dillon mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT); 275c69a34d4SMatthew Dillon for (i = mntsize - 1; i >= 0; i--) { 276c69a34d4SMatthew Dillon if (strcmp(mntbuf[i].f_mntfromname, name) == 0) { 277c69a34d4SMatthew Dillon free(mntbuf); 278c69a34d4SMatthew Dillon return (1); 279c69a34d4SMatthew Dillon } 280c69a34d4SMatthew Dillon } 281c69a34d4SMatthew Dillon free(mntbuf); 282c69a34d4SMatthew Dillon return (0); 283c69a34d4SMatthew Dillon } 284c69a34d4SMatthew Dillon 285c69a34d4SMatthew Dillon /* 286c69a34d4SMatthew Dillon * xdr routines for mount rpc's 287c69a34d4SMatthew Dillon */ 288c69a34d4SMatthew Dillon int 289c69a34d4SMatthew Dillon xdr_dir(XDR *xdrsp, char *dirp) { 290c69a34d4SMatthew Dillon 291c69a34d4SMatthew Dillon return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 292c69a34d4SMatthew Dillon } 293c69a34d4SMatthew Dillon 294c69a34d4SMatthew Dillon static void 295c69a34d4SMatthew Dillon usage() { 296c69a34d4SMatthew Dillon 297c69a34d4SMatthew Dillon (void)fprintf(stderr, "%s\n", 298c69a34d4SMatthew Dillon "usage: rpc.umntall [-h host] [-k] [-p path] [-t expire] [-v]"); 299c69a34d4SMatthew Dillon exit(1); 300c69a34d4SMatthew Dillon } 301