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