1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 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 #ifndef lint 31 static const char rcsid[] = 32 "$FreeBSD$"; 33 #endif /* not lint */ 34 35 #include <sys/param.h> 36 #include <sys/ucred.h> 37 #include <sys/mount.h> 38 39 #include <rpc/rpc.h> 40 #include <rpcsvc/mount.h> 41 42 #include <err.h> 43 #include <netdb.h> 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 49 #include "mounttab.h" 50 51 int verbose; 52 53 static int do_umount (char *, char *); 54 static int do_umntall (char *); 55 static int is_mounted (char *, char *); 56 static void usage (void); 57 int xdr_dir (XDR *, char *); 58 59 int 60 main(int argc, char **argv) { 61 int ch, keep, success, pathlen; 62 time_t expire, now; 63 char *host, *path; 64 struct mtablist *mtab; 65 66 expire = 0; 67 host = path = NULL; 68 success = keep = verbose = 0; 69 while ((ch = getopt(argc, argv, "h:kp:ve:")) != -1) 70 switch (ch) { 71 case 'h': 72 host = optarg; 73 break; 74 case 'e': 75 expire = atoi(optarg); 76 break; 77 case 'k': 78 keep = 1; 79 break; 80 case 'p': 81 path = optarg; 82 break; 83 case 'v': 84 verbose = 1; 85 break; 86 case '?': 87 usage(); 88 default: 89 break; 90 } 91 argc -= optind; 92 argv += optind; 93 94 /* Default expiretime is one day */ 95 if (expire == 0) 96 expire = 86400; 97 time(&now); 98 99 /* Read PATH_MOUNTTAB. */ 100 if (!read_mtab()) { 101 if (verbose) 102 warnx("no mounttab entries (%s does not exist)", 103 PATH_MOUNTTAB); 104 mtabhead = NULL; 105 } 106 107 if (host == NULL && path == NULL) { 108 /* Check each entry and do any necessary unmount RPCs. */ 109 for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) { 110 if (*mtab->mtab_host == '\0') 111 continue; 112 if (mtab->mtab_time + expire < now) { 113 /* Clear expired entry. */ 114 if (verbose) 115 warnx("remove expired entry %s:%s", 116 mtab->mtab_host, mtab->mtab_dirp); 117 bzero(mtab->mtab_host, 118 sizeof(mtab->mtab_host)); 119 continue; 120 } 121 if (keep && is_mounted(mtab->mtab_host, 122 mtab->mtab_dirp)) { 123 if (verbose) 124 warnx("skip entry %s:%s", 125 mtab->mtab_host, mtab->mtab_dirp); 126 continue; 127 } 128 if (do_umount(mtab->mtab_host, mtab->mtab_dirp)) { 129 if (verbose) 130 warnx("umount RPC for %s:%s succeeded", 131 mtab->mtab_host, mtab->mtab_dirp); 132 /* Remove all entries for this host + path. */ 133 clean_mtab(mtab->mtab_host, mtab->mtab_dirp, 134 verbose); 135 } 136 } 137 success = 1; 138 } else { 139 if (host == NULL && path != NULL) 140 /* Missing hostname. */ 141 usage(); 142 if (path == NULL) { 143 /* Do a RPC UMNTALL for this specific host */ 144 success = do_umntall(host); 145 if (verbose && success) 146 warnx("umntall RPC for %s succeeded", host); 147 } else { 148 /* Do a RPC UMNTALL for this specific mount */ 149 for (pathlen = strlen(path); 150 pathlen > 1 && path[pathlen - 1] == '/'; pathlen--) 151 path[pathlen - 1] = '\0'; 152 success = do_umount(host, path); 153 if (verbose && success) 154 warnx("umount RPC for %s:%s succeeded", host, 155 path); 156 } 157 /* If successful, remove any corresponding mounttab entries. */ 158 if (success) 159 clean_mtab(host, path, verbose); 160 } 161 /* Write and unlink PATH_MOUNTTAB if necessary */ 162 if (success) 163 success = write_mtab(verbose); 164 free_mtab(); 165 exit (success ? 0 : 1); 166 } 167 168 /* 169 * Send a RPC_MNT UMNTALL request to hostname. 170 * XXX This works for all mountd implementations, 171 * but produces a RPC IOERR on non FreeBSD systems. 172 */ 173 int 174 do_umntall(char *hostname) { 175 enum clnt_stat clnt_stat; 176 struct timeval try; 177 CLIENT *clp; 178 179 try.tv_sec = 3; 180 try.tv_usec = 0; 181 clp = clnt_create_timed(hostname, MOUNTPROG, MOUNTVERS, "udp", 182 &try); 183 if (clp == NULL) { 184 warnx("%s: %s", hostname, clnt_spcreateerror("MOUNTPROG")); 185 return (0); 186 } 187 clp->cl_auth = authunix_create_default(); 188 clnt_stat = clnt_call(clp, MOUNTPROC_UMNTALL, 189 (xdrproc_t)xdr_void, (caddr_t)0, 190 (xdrproc_t)xdr_void, (caddr_t)0, try); 191 if (clnt_stat != RPC_SUCCESS) 192 warnx("%s: %s", hostname, clnt_sperror(clp, "MOUNTPROC_UMNTALL")); 193 auth_destroy(clp->cl_auth); 194 clnt_destroy(clp); 195 return (clnt_stat == RPC_SUCCESS); 196 } 197 198 /* 199 * Send a RPC_MNT UMOUNT request for dirp to hostname. 200 */ 201 int 202 do_umount(char *hostname, char *dirp) { 203 enum clnt_stat clnt_stat; 204 struct timeval try; 205 CLIENT *clp; 206 207 try.tv_sec = 3; 208 try.tv_usec = 0; 209 clp = clnt_create_timed(hostname, MOUNTPROG, MOUNTVERS, "udp", 210 &try); 211 if (clp == NULL) { 212 warnx("%s: %s", hostname, clnt_spcreateerror("MOUNTPROG")); 213 return (0); 214 } 215 clp->cl_auth = authsys_create_default(); 216 clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t)xdr_dir, dirp, 217 (xdrproc_t)xdr_void, (caddr_t)0, try); 218 if (clnt_stat != RPC_SUCCESS) 219 warnx("%s: %s", hostname, clnt_sperror(clp, "MOUNTPROC_UMNT")); 220 auth_destroy(clp->cl_auth); 221 clnt_destroy(clp); 222 return (clnt_stat == RPC_SUCCESS); 223 } 224 225 /* 226 * Check if the entry is still/already mounted. 227 */ 228 int 229 is_mounted(char *hostname, char *dirp) { 230 struct statfs *mntbuf; 231 char name[MNAMELEN + 1]; 232 size_t bufsize; 233 int mntsize, i; 234 235 if (strlen(hostname) + strlen(dirp) >= MNAMELEN) 236 return (0); 237 snprintf(name, sizeof(name), "%s:%s", hostname, dirp); 238 mntsize = getfsstat(NULL, 0, MNT_NOWAIT); 239 if (mntsize <= 0) 240 return (0); 241 bufsize = (mntsize + 1) * sizeof(struct statfs); 242 if ((mntbuf = malloc(bufsize)) == NULL) 243 err(1, "malloc"); 244 mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT); 245 for (i = mntsize - 1; i >= 0; i--) { 246 if (strcmp(mntbuf[i].f_mntfromname, name) == 0) { 247 free(mntbuf); 248 return (1); 249 } 250 } 251 free(mntbuf); 252 return (0); 253 } 254 255 /* 256 * xdr routines for mount rpc's 257 */ 258 int 259 xdr_dir(XDR *xdrsp, char *dirp) { 260 return (xdr_string(xdrsp, &dirp, MNTPATHLEN)); 261 } 262 263 static void 264 usage() { 265 (void)fprintf(stderr, "%s\n", 266 "usage: rpc.umntall [-kv] [-e expire] [-h host] [-p path]"); 267 exit(1); 268 } 269