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