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 struct mtablist *mtabhead; 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 mtab = NULL; 67 now = NULL; 68 expire = 0; 69 host = path = '\0'; 70 success = keep = verbose = 0; 71 while ((ch = getopt(argc, argv, "h:kp:ve:")) != -1) 72 switch (ch) { 73 case 'h': 74 host = optarg; 75 break; 76 case 'e': 77 expire = (time_t)optarg; 78 break; 79 case 'k': 80 keep = 1; 81 break; 82 case 'p': 83 path = optarg; 84 break; 85 case 'v': 86 verbose = 1; 87 break; 88 case '?': 89 usage(); 90 default: 91 } 92 argc -= optind; 93 argv += optind; 94 95 /* Ignore SIGINT and SIGQUIT during shutdown */ 96 signal(SIGINT, SIG_IGN); 97 signal(SIGQUIT, SIG_IGN); 98 99 /* Default expiretime is one day */ 100 if (expire == 0) 101 expire = 86400; 102 /* 103 * Read PATH_MOUNTTAB and check each entry 104 * and do finally the unmounts. 105 */ 106 if (host == NULL && path == NULL) { 107 if (!read_mtab(mtab)) { 108 if (verbose) 109 warnx("nothing to do, %s does not exist", 110 PATH_MOUNTTAB); 111 } 112 for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) { 113 if (*mtab->mtab_host != '\0' || 114 mtab->mtab_time <= (time(now) - expire)) { 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, 120 mtab->mtab_dirp); 121 } 122 } else if (do_umount(mtab->mtab_host, 123 mtab->mtab_dirp) || 124 mtab->mtab_time <= (time(now) - expire)) { 125 clean_mtab(mtab->mtab_host, 126 mtab->mtab_dirp); 127 } 128 } 129 } 130 /* Only do a RPC UMNTALL for this specific host */ 131 } else if (host != NULL && path == NULL) { 132 if (!do_umntall(host)) 133 exit(1); 134 else 135 success = 1; 136 /* Someone forgot to enter a hostname */ 137 } else if (host == NULL && path != NULL) 138 usage(); 139 /* Only do a RPC UMOUNT for this specific mount */ 140 else { 141 for (pathlen = strlen(path); 142 pathlen > 1 && path[pathlen - 1] == '/'; pathlen--) 143 path[pathlen - 1] = '\0'; 144 if (!do_umount(host, path)) 145 exit(1); 146 else 147 success = 1; 148 } 149 /* Write and unlink PATH_MOUNTTAB if necessary */ 150 if (success) { 151 if (verbose) 152 warnx("UMOUNT RPC successfully sent to %s", host); 153 if (read_mtab(mtab)) { 154 mtab = mtabhead; 155 clean_mtab(host, path); 156 } 157 } 158 if (!write_mtab()) { 159 free_mtab(); 160 exit(1); 161 } 162 free_mtab(); 163 exit(0); 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 hostent *hp; 175 struct sockaddr_in saddr; 176 struct timeval pertry, try; 177 int so; 178 CLIENT *clp; 179 180 if ((hp = gethostbyname(hostname)) == NULL) { 181 warnx("gethostbyname(%s) failed", hostname); 182 return (0); 183 } 184 memset(&saddr, 0, sizeof(saddr)); 185 saddr.sin_family = AF_INET; 186 saddr.sin_port = 0; 187 memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length, 188 sizeof(saddr.sin_addr))); 189 pertry.tv_sec = 3; 190 pertry.tv_usec = 0; 191 so = RPC_ANYSOCK; 192 if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, 193 pertry, &so)) == NULL) { 194 clnt_pcreateerror("Cannot send MNT PRC"); 195 return (0); 196 } 197 clp->cl_auth = authunix_create_default(); 198 try.tv_sec = 3; 199 try.tv_usec = 0; 200 clnt_stat = clnt_call(clp, RPCMNT_UMNTALL, xdr_void, (caddr_t)0, 201 xdr_void, (caddr_t)0, try); 202 if (clnt_stat != RPC_SUCCESS) { 203 clnt_perror(clp, "Bad MNT RPC"); 204 return (0); 205 } else 206 return (1); 207 } 208 209 /* 210 * Send a RPC_MNT UMOUNT request for dirp to hostname. 211 */ 212 int 213 do_umount(char *hostname, char *dirp) { 214 enum clnt_stat clnt_stat; 215 struct hostent *hp; 216 struct sockaddr_in saddr; 217 struct timeval pertry, try; 218 CLIENT *clp; 219 int so; 220 221 if ((hp = gethostbyname(hostname)) == NULL) { 222 warnx("gethostbyname(%s) failed", hostname); 223 return (0); 224 } 225 memset(&saddr, 0, sizeof(saddr)); 226 saddr.sin_family = AF_INET; 227 saddr.sin_port = 0; 228 memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length, 229 sizeof(saddr.sin_addr))); 230 pertry.tv_sec = 3; 231 pertry.tv_usec = 0; 232 so = RPC_ANYSOCK; 233 if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1, 234 pertry, &so)) == NULL) { 235 clnt_pcreateerror("Cannot send MNT PRC"); 236 return (0); 237 } 238 clp->cl_auth = authunix_create_default(); 239 try.tv_sec = 3; 240 try.tv_usec = 0; 241 clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp, 242 xdr_void, (caddr_t)0, try); 243 if (clnt_stat != RPC_SUCCESS) { 244 clnt_perror(clp, "Bad MNT RPC"); 245 return (0); 246 } 247 return (1); 248 } 249 250 /* 251 * Check if the entry is still/already mounted. 252 */ 253 int 254 is_mounted(char *hostname, char *dirp) { 255 struct statfs *mntbuf; 256 char name[MNAMELEN + 1]; 257 size_t bufsize, hostlen, dirlen; 258 int mntsize, i; 259 260 hostlen = strlen(hostname); 261 dirlen = strlen(dirp); 262 if ((hostlen + dirlen) >= MNAMELEN) 263 return (0); 264 memmove(name, hostname, hostlen); 265 name[hostlen] = ':'; 266 memmove(name + hostlen + 1, dirp, dirlen); 267 name[hostlen + dirlen + 1] = '\0'; 268 mntsize = getfsstat(NULL, 0, MNT_NOWAIT); 269 if (mntsize <= 0) 270 return (0); 271 bufsize = (mntsize + 1) * sizeof(struct statfs); 272 if ((mntbuf = malloc(bufsize)) == NULL) 273 err(1, "malloc"); 274 mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT); 275 for (i = mntsize - 1; i >= 0; i--) { 276 if (strcmp(mntbuf[i].f_mntfromname, name) == 0) { 277 free(mntbuf); 278 return (1); 279 } 280 } 281 free(mntbuf); 282 return (0); 283 } 284 285 /* 286 * xdr routines for mount rpc's 287 */ 288 int 289 xdr_dir(XDR *xdrsp, char *dirp) { 290 291 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 292 } 293 294 static void 295 usage() { 296 297 (void)fprintf(stderr, "%s\n", 298 "usage: rpc.umntall [-h host] [-k] [-p path] [-t expire] [-v]"); 299 exit(1); 300 } 301