rpc.umntall.c revision 80123
1235723Sbapt/* 2235723Sbapt * Copyright (c) 1999 Martin Blapp 3235723Sbapt * All rights reserved. 4235723Sbapt * 5235723Sbapt * Redistribution and use in source and binary forms, with or without 6235723Sbapt * modification, are permitted provided that the following conditions 7235723Sbapt * are met: 8235723Sbapt * 1. Redistributions of source code must retain the above copyright 9235723Sbapt * notice, this list of conditions and the following disclaimer. 10235723Sbapt * 2. Redistributions in binary form must reproduce the above copyright 11235723Sbapt * notice, this list of conditions and the following disclaimer in the 12235723Sbapt * documentation and/or other materials provided with the distribution. 13235723Sbapt * 14235723Sbapt * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15235723Sbapt * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16235723Sbapt * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17235723Sbapt * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18235723Sbapt * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19235723Sbapt * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20235723Sbapt * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21235723Sbapt * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22235723Sbapt * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23235723Sbapt * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24235723Sbapt * SUCH DAMAGE. 25235723Sbapt * 26235723Sbapt */ 27235723Sbapt 28235723Sbapt#ifndef lint 29235723Sbaptstatic const char rcsid[] = 30235723Sbapt "$FreeBSD: head/usr.sbin/rpc.umntall/rpc.umntall.c 80123 2001-07-22 01:25:25Z iedowse $"; 31235723Sbapt#endif /* not lint */ 32235723Sbapt 33235723Sbapt#include <sys/param.h> 34235723Sbapt#include <sys/ucred.h> 35235723Sbapt#include <sys/mount.h> 36235723Sbapt 37235723Sbapt#include <rpc/rpc.h> 38235723Sbapt#include <nfs/rpcv2.h> 39235723Sbapt 40235723Sbapt#include <err.h> 41235723Sbapt#include <netdb.h> 42235723Sbapt#include <stdio.h> 43235723Sbapt#include <stdlib.h> 44235723Sbapt#include <string.h> 45235723Sbapt#include <unistd.h> 46235723Sbapt 47235723Sbapt#include "mounttab.h" 48235723Sbapt 49235723Sbaptint verbose; 50235723Sbapt 51235723Sbaptstatic int do_umount (char *, char *); 52235723Sbaptstatic int do_umntall (char *); 53235723Sbaptstatic int is_mounted (char *, char *); 54235723Sbaptstatic void usage (void); 55235723Sbaptint xdr_dir (XDR *, char *); 56235723Sbapt 57235723Sbaptstruct mtablist *mtabhead; 58235723Sbapt 59235723Sbaptint 60235723Sbaptmain(int argc, char **argv) { 61235723Sbapt int ch, keep, success, pathlen; 62235723Sbapt time_t expire, now; 63235723Sbapt char *host, *path; 64235723Sbapt struct mtablist *mtab; 65235723Sbapt 66235723Sbapt expire = 0; 67235723Sbapt host = path = NULL; 68235723Sbapt success = keep = verbose = 0; 69235723Sbapt while ((ch = getopt(argc, argv, "h:kp:ve:")) != -1) 70235723Sbapt switch (ch) { 71235723Sbapt case 'h': 72235723Sbapt host = optarg; 73235723Sbapt break; 74235723Sbapt case 'e': 75235723Sbapt expire = atoi(optarg); 76235723Sbapt break; 77235723Sbapt case 'k': 78235723Sbapt keep = 1; 79235723Sbapt break; 80235723Sbapt case 'p': 81235723Sbapt path = optarg; 82235723Sbapt break; 83235723Sbapt case 'v': 84235723Sbapt verbose = 1; 85235723Sbapt break; 86235723Sbapt case '?': 87235723Sbapt usage(); 88235723Sbapt default: 89235723Sbapt } 90235723Sbapt argc -= optind; 91235723Sbapt argv += optind; 92235723Sbapt 93235723Sbapt /* Ignore SIGINT and SIGQUIT during shutdown */ 94235723Sbapt signal(SIGINT, SIG_IGN); 95235723Sbapt signal(SIGQUIT, SIG_IGN); 96235723Sbapt 97235723Sbapt /* Default expiretime is one day */ 98235723Sbapt if (expire == 0) 99235723Sbapt expire = 86400; 100235723Sbapt time(&now); 101235723Sbapt 102235723Sbapt /* Read PATH_MOUNTTAB. */ 103235723Sbapt if (!read_mtab(NULL)) { 104235723Sbapt if (verbose) 105235723Sbapt warnx("no mounttab entries (%s does not exist)", 106235723Sbapt PATH_MOUNTTAB); 107235723Sbapt mtabhead = NULL; 108235723Sbapt } 109235723Sbapt 110235723Sbapt if (host == NULL && path == NULL) { 111235723Sbapt /* Check each entry and do any necessary unmount RPCs. */ 112235723Sbapt for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) { 113 if (*mtab->mtab_host == '\0') 114 continue; 115 if (mtab->mtab_time + expire < now) { 116 /* Clear expired entry. */ 117 if (verbose) 118 warnx("remove expired entry %s:%s", 119 mtab->mtab_host, mtab->mtab_dirp); 120 bzero(mtab->mtab_host, 121 sizeof(mtab->mtab_host)); 122 continue; 123 } 124 if (keep && is_mounted(mtab->mtab_host, 125 mtab->mtab_dirp)) { 126 if (verbose) 127 warnx("skip entry %s:%s", 128 mtab->mtab_host, mtab->mtab_dirp); 129 continue; 130 } 131 if (do_umount(mtab->mtab_host, mtab->mtab_dirp)) { 132 if (verbose) 133 warnx("umount RPC for %s:%s succeeded", 134 mtab->mtab_host, mtab->mtab_dirp); 135 /* Remove all entries for this host + path. */ 136 clean_mtab(mtab->mtab_host, mtab->mtab_dirp); 137 } 138 } 139 success = 1; 140 } else { 141 if (host == NULL && path != NULL) 142 /* Missing hostname. */ 143 usage(); 144 if (path == NULL) { 145 /* Do a RPC UMNTALL for this specific host */ 146 success = do_umntall(host); 147 if (verbose && success) 148 warnx("umntall RPC for %s succeeded", host); 149 } else { 150 /* Do a RPC UMNTALL for this specific mount */ 151 for (pathlen = strlen(path); 152 pathlen > 1 && path[pathlen - 1] == '/'; pathlen--) 153 path[pathlen - 1] = '\0'; 154 success = do_umount(host, path); 155 if (verbose && success) 156 warnx("umount RPC for %s:%s succeeded", host, 157 path); 158 } 159 /* If successful, remove any corresponding mounttab entries. */ 160 if (success) 161 clean_mtab(host, path); 162 } 163 /* Write and unlink PATH_MOUNTTAB if necessary */ 164 if (success) 165 success = write_mtab(); 166 free_mtab(); 167 exit (success ? 0 : 1); 168} 169 170/* 171 * Send a RPC_MNT UMNTALL request to hostname. 172 * XXX This works for all mountd implementations, 173 * but produces a RPC IOERR on non FreeBSD systems. 174 */ 175int 176do_umntall(char *hostname) { 177 enum clnt_stat clnt_stat; 178 struct timeval try; 179 CLIENT *clp; 180 181 clp = clnt_create(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp"); 182 if (clp == NULL) { 183 warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT")); 184 return (1); 185 } 186 clp->cl_auth = authunix_create_default(); 187 try.tv_sec = 3; 188 try.tv_usec = 0; 189 clnt_stat = clnt_call(clp, RPCMNT_UMNTALL, xdr_void, (caddr_t)0, 190 xdr_void, (caddr_t)0, try); 191 clnt_destroy(clp); 192 if (clnt_stat != RPC_SUCCESS) { 193 warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMNTALL")); 194 return (0); 195 } else 196 return (1); 197} 198 199/* 200 * Send a RPC_MNT UMOUNT request for dirp to hostname. 201 */ 202int 203do_umount(char *hostname, char *dirp) { 204 enum clnt_stat clnt_stat; 205 struct timeval try; 206 CLIENT *clp; 207 208 clp = clnt_create(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp"); 209 if (clp == NULL) { 210 warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT")); 211 return (1); 212 } 213 clp->cl_auth = authsys_create_default(); 214 try.tv_sec = 3; 215 try.tv_usec = 0; 216 clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp, 217 xdr_void, (caddr_t)0, try); 218 clnt_destroy(clp); 219 if (clnt_stat != RPC_SUCCESS) { 220 warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMOUNT")); 221 return (0); 222 } 223 return (1); 224} 225 226/* 227 * Check if the entry is still/already mounted. 228 */ 229int 230is_mounted(char *hostname, char *dirp) { 231 struct statfs *mntbuf; 232 char name[MNAMELEN + 1]; 233 size_t bufsize; 234 int mntsize, i; 235 236 if (strlen(hostname) + strlen(dirp) >= MNAMELEN) 237 return (0); 238 snprintf(name, sizeof(name), "%s:%s", hostname, dirp); 239 mntsize = getfsstat(NULL, 0, MNT_NOWAIT); 240 if (mntsize <= 0) 241 return (0); 242 bufsize = (mntsize + 1) * sizeof(struct statfs); 243 if ((mntbuf = malloc(bufsize)) == NULL) 244 err(1, "malloc"); 245 mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT); 246 for (i = mntsize - 1; i >= 0; i--) { 247 if (strcmp(mntbuf[i].f_mntfromname, name) == 0) { 248 free(mntbuf); 249 return (1); 250 } 251 } 252 free(mntbuf); 253 return (0); 254} 255 256/* 257 * xdr routines for mount rpc's 258 */ 259int 260xdr_dir(XDR *xdrsp, char *dirp) { 261 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 262} 263 264static void 265usage() { 266 (void)fprintf(stderr, "%s\n", 267 "usage: rpc.umntall [-kv] [-e expire] [-h host] [-p path]"); 268 exit(1); 269} 270