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 * $FreeBSD: src/usr.sbin/rpc.umntall/rpc.umntall.c,v 1.3.2.1 2001/12/13 01:27:20 iedowse Exp $ 27 * $DragonFly: src/usr.sbin/rpc.umntall/rpc.umntall.c,v 1.2 2003/06/17 04:30:02 dillon Exp $ 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 <nfs/rpcv2.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 } 85 argc -= optind; 86 argv += optind; 87 88 /* Default expiretime is one day */ 89 if (expire == 0) 90 expire = 86400; 91 time(&now); 92 93 /* Read PATH_MOUNTTAB. */ 94 if (!read_mtab()) { 95 if (verbose) 96 warnx("no mounttab entries (%s does not exist)", 97 PATH_MOUNTTAB); 98 mtabhead = NULL; 99 } 100 101 if (host == NULL && path == NULL) { 102 /* Check each entry and do any necessary unmount RPCs. */ 103 for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) { 104 if (*mtab->mtab_host == '\0') 105 continue; 106 if (mtab->mtab_time + expire < now) { 107 /* Clear expired entry. */ 108 if (verbose) 109 warnx("remove expired entry %s:%s", 110 mtab->mtab_host, mtab->mtab_dirp); 111 bzero(mtab->mtab_host, 112 sizeof(mtab->mtab_host)); 113 continue; 114 } 115 if (keep && is_mounted(mtab->mtab_host, 116 mtab->mtab_dirp)) { 117 if (verbose) 118 warnx("skip entry %s:%s", 119 mtab->mtab_host, mtab->mtab_dirp); 120 continue; 121 } 122 if (do_umount(mtab->mtab_host, mtab->mtab_dirp)) { 123 if (verbose) 124 warnx("umount RPC for %s:%s succeeded", 125 mtab->mtab_host, mtab->mtab_dirp); 126 /* Remove all entries for this host + path. */ 127 clean_mtab(mtab->mtab_host, mtab->mtab_dirp, 128 verbose); 129 } 130 } 131 success = 1; 132 } else { 133 if (host == NULL && path != NULL) 134 /* Missing hostname. */ 135 usage(); 136 if (path == NULL) { 137 /* Do a RPC UMNTALL for this specific host */ 138 success = do_umntall(host); 139 if (verbose && success) 140 warnx("umntall RPC for %s succeeded", host); 141 } else { 142 /* Do a RPC UMNTALL for this specific mount */ 143 for (pathlen = strlen(path); 144 pathlen > 1 && path[pathlen - 1] == '/'; pathlen--) 145 path[pathlen - 1] = '\0'; 146 success = do_umount(host, path); 147 if (verbose && success) 148 warnx("umount RPC for %s:%s succeeded", host, 149 path); 150 } 151 /* If successful, remove any corresponding mounttab entries. */ 152 if (success) 153 clean_mtab(host, path, verbose); 154 } 155 /* Write and unlink PATH_MOUNTTAB if necessary */ 156 if (success) 157 success = write_mtab(verbose); 158 free_mtab(); 159 exit (success ? 0 : 1); 160 } 161 162 /* 163 * Send a RPC_MNT UMNTALL request to hostname. 164 * XXX This works for all mountd implementations, 165 * but produces a RPC IOERR on non FreeBSD systems. 166 */ 167 int 168 do_umntall(char *hostname) { 169 enum clnt_stat clnt_stat; 170 struct hostent *hp; 171 struct sockaddr_in saddr; 172 struct timeval pertry, try; 173 int so; 174 CLIENT *clp; 175 176 if ((hp = gethostbyname(hostname)) == NULL) { 177 warnx("gethostbyname(%s) failed", hostname); 178 return (0); 179 } 180 memset(&saddr, 0, sizeof(saddr)); 181 saddr.sin_family = AF_INET; 182 saddr.sin_port = 0; 183 memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length, 184 sizeof(saddr.sin_addr))); 185 pertry.tv_sec = 3; 186 pertry.tv_usec = 0; 187 so = RPC_ANYSOCK; 188 clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, pertry, &so); 189 if (clp == NULL) { 190 warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT")); 191 return (0); 192 } 193 clp->cl_auth = authunix_create_default(); 194 try.tv_sec = 3; 195 try.tv_usec = 0; 196 clnt_stat = clnt_call(clp, RPCMNT_UMNTALL, xdr_void, (caddr_t)0, 197 xdr_void, (caddr_t)0, try); 198 if (clnt_stat != RPC_SUCCESS) 199 warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMNTALL")); 200 auth_destroy(clp->cl_auth); 201 clnt_destroy(clp); 202 return (clnt_stat == RPC_SUCCESS); 203 } 204 205 /* 206 * Send a RPC_MNT UMOUNT request for dirp to hostname. 207 */ 208 int 209 do_umount(char *hostname, char *dirp) { 210 enum clnt_stat clnt_stat; 211 struct hostent *hp; 212 struct sockaddr_in saddr; 213 struct timeval pertry, try; 214 CLIENT *clp; 215 int so; 216 217 if ((hp = gethostbyname(hostname)) == NULL) { 218 warnx("gethostbyname(%s) failed", hostname); 219 return (0); 220 } 221 memset(&saddr, 0, sizeof(saddr)); 222 saddr.sin_family = AF_INET; 223 saddr.sin_port = 0; 224 memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length, 225 sizeof(saddr.sin_addr))); 226 pertry.tv_sec = 3; 227 pertry.tv_usec = 0; 228 so = RPC_ANYSOCK; 229 clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, pertry, &so); 230 if (clp == NULL) { 231 warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT")); 232 return (0); 233 } 234 clp->cl_auth = authunix_create_default(); 235 try.tv_sec = 3; 236 try.tv_usec = 0; 237 clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp, 238 xdr_void, (caddr_t)0, try); 239 if (clnt_stat != RPC_SUCCESS) 240 warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMOUNT")); 241 auth_destroy(clp->cl_auth); 242 clnt_destroy(clp); 243 return (clnt_stat == RPC_SUCCESS); 244 } 245 246 /* 247 * Check if the entry is still/already mounted. 248 */ 249 int 250 is_mounted(char *hostname, char *dirp) { 251 struct statfs *mntbuf; 252 char name[MNAMELEN + 1]; 253 size_t bufsize; 254 int mntsize, i; 255 256 if (strlen(hostname) + strlen(dirp) >= MNAMELEN) 257 return (0); 258 snprintf(name, sizeof(name), "%s:%s", hostname, dirp); 259 mntsize = getfsstat(NULL, 0, MNT_NOWAIT); 260 if (mntsize <= 0) 261 return (0); 262 bufsize = (mntsize + 1) * sizeof(struct statfs); 263 if ((mntbuf = malloc(bufsize)) == NULL) 264 err(1, "malloc"); 265 mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT); 266 for (i = mntsize - 1; i >= 0; i--) { 267 if (strcmp(mntbuf[i].f_mntfromname, name) == 0) { 268 free(mntbuf); 269 return (1); 270 } 271 } 272 free(mntbuf); 273 return (0); 274 } 275 276 /* 277 * xdr routines for mount rpc's 278 */ 279 int 280 xdr_dir(XDR *xdrsp, char *dirp) { 281 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 282 } 283 284 static void 285 usage() { 286 (void)fprintf(stderr, "%s\n", 287 "usage: rpc.umntall [-kv] [-e expire] [-h host] [-p path]"); 288 exit(1); 289 } 290