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