1 /* $NetBSD: umount.c,v 1.21 1997/11/01 12:54:45 drochner Exp $ */ 2 3 /*- 4 * Copyright (c) 1980, 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) Copyright (c) 1980, 1989, 1993\n\ 39 The Regents of the University of California. All rights reserved.\n"); 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "@(#)umount.c 8.8 (Berkeley) 5/8/95"; 45 #else 46 __RCSID("$NetBSD: umount.c,v 1.21 1997/11/01 12:54:45 drochner Exp $"); 47 #endif 48 #endif /* not lint */ 49 50 #include <sys/param.h> 51 #include <sys/stat.h> 52 #include <sys/mount.h> 53 #include <sys/time.h> 54 #include <sys/socket.h> 55 #include <sys/socketvar.h> 56 57 #include <netdb.h> 58 #include <rpc/rpc.h> 59 #include <rpc/pmap_clnt.h> 60 #include <rpc/pmap_prot.h> 61 #include <nfs/rpcv2.h> 62 63 #include <err.h> 64 #include <fstab.h> 65 #include <stdio.h> 66 #include <stdlib.h> 67 #include <string.h> 68 #include <unistd.h> 69 70 typedef enum { MNTANY, MNTON, MNTFROM } mntwhat; 71 72 int fake, fflag, verbose; 73 char *nfshost; 74 75 int checkvfsname __P((const char *, char **)); 76 char *getmntname __P((char *, mntwhat, char **)); 77 char **makevfslist __P((char *)); 78 int main __P((int, char *[])); 79 int namematch __P((struct hostent *)); 80 int selected __P((int)); 81 int umountall __P((char **)); 82 int umountfs __P((char *, char **)); 83 void usage __P((void)); 84 int xdr_dir __P((XDR *, char *)); 85 86 int 87 main(argc, argv) 88 int argc; 89 char *argv[]; 90 { 91 int all, ch, errs, mnts; 92 char **typelist = NULL; 93 struct statfs *mntbuf; 94 95 /* Start disks transferring immediately. */ 96 sync(); 97 98 all = 0; 99 while ((ch = getopt(argc, argv, "AaFfh:t:v")) != -1) 100 switch (ch) { 101 case 'A': 102 all = 2; 103 break; 104 case 'a': 105 all = 1; 106 break; 107 case 'F': 108 fake = 1; 109 break; 110 case 'f': 111 fflag = MNT_FORCE; 112 break; 113 case 'h': /* -h implies -A. */ 114 all = 2; 115 nfshost = optarg; 116 break; 117 case 't': 118 if (typelist != NULL) 119 errx(1, "only one -t option may be specified."); 120 typelist = makevfslist(optarg); 121 break; 122 case 'v': 123 verbose = 1; 124 break; 125 default: 126 usage(); 127 /* NOTREACHED */ 128 } 129 argc -= optind; 130 argv += optind; 131 132 if ((argc == 0 && !all) || (argc != 0 && all)) 133 usage(); 134 135 /* -h implies "-t nfs" if no -t flag. */ 136 if ((nfshost != NULL) && (typelist == NULL)) 137 typelist = makevfslist("nfs"); 138 139 errs = 0; 140 switch (all) { 141 case 2: 142 if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) { 143 warn("getmntinfo"); 144 errs = 1; 145 break; 146 } 147 for (errs = 0, mnts--; mnts > 0; mnts--) { 148 if (checkvfsname(mntbuf[mnts].f_fstypename, typelist)) 149 continue; 150 if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0) 151 errs = 1; 152 } 153 break; 154 case 1: 155 if (setfsent() == 0) 156 err(1, "%s", _PATH_FSTAB); 157 errs = umountall(typelist); 158 break; 159 case 0: 160 for (errs = 0; *argv != NULL; ++argv) 161 if (umountfs(*argv, typelist) != 0) 162 errs = 1; 163 break; 164 } 165 exit(errs); 166 } 167 168 169 int 170 umountall(typelist) 171 char **typelist; 172 { 173 struct statfs *fs; 174 int n; 175 int rval; 176 177 n = getmntinfo(&fs, MNT_NOWAIT); 178 if (n == 0) 179 err(1, "%s", ""); 180 181 rval = 0; 182 while (--n >= 0) { 183 /* Ignore the root. */ 184 if (strncmp(fs[n].f_mntonname, "/", MNAMELEN) == 0) 185 continue; 186 187 if (checkvfsname(fs[n].f_fstypename, typelist)) 188 continue; 189 190 if (umountfs(fs[n].f_mntonname, typelist)) 191 rval = 1; 192 } 193 return (rval); 194 } 195 196 int 197 umountfs(name, typelist) 198 char *name; 199 char **typelist; 200 { 201 enum clnt_stat clnt_stat; 202 struct hostent *hp; 203 struct sockaddr_in saddr; 204 struct stat sb; 205 struct timeval pertry, try; 206 CLIENT *clp; 207 int so; 208 char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN]; 209 mntwhat what; 210 211 hp = NULL; 212 delimp = NULL; 213 if (realpath(name, rname) == NULL) { 214 warn("%s", rname); 215 return (1); 216 } 217 218 what = MNTANY; 219 mntpt = name = rname; 220 221 if (stat(name, &sb) == 0) { 222 if (S_ISBLK(sb.st_mode)) 223 what = MNTON; 224 else if (S_ISDIR(sb.st_mode)) 225 what = MNTFROM; 226 } 227 228 switch (what) { 229 case MNTON: 230 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) { 231 warnx("%s: not currently mounted", name); 232 return (1); 233 } 234 break; 235 case MNTFROM: 236 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) { 237 warnx("%s: not currently mounted", mntpt); 238 return (1); 239 } 240 break; 241 default: 242 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) { 243 name = rname; 244 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) { 245 warnx("%s: not currently mounted", name); 246 return (1); 247 } 248 } 249 } 250 251 if (checkvfsname(type, typelist)) 252 return (1); 253 254 hp = NULL; 255 if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) { 256 if ((delimp = strchr(name, '@')) != NULL) { 257 hostp = delimp + 1; 258 *delimp = '\0'; 259 hp = gethostbyname(hostp); 260 *delimp = '@'; 261 } else if ((delimp = strchr(name, ':')) != NULL) { 262 *delimp = '\0'; 263 hostp = name; 264 hp = gethostbyname(hostp); 265 name = delimp + 1; 266 *delimp = ':'; 267 } 268 } 269 270 if (!namematch(hp)) 271 return (1); 272 273 if (verbose) 274 (void)printf("%s: unmount from %s\n", name, mntpt); 275 if (fake) 276 return (0); 277 278 if (unmount(mntpt, fflag) < 0) { 279 warn("%s", mntpt); 280 return (1); 281 } 282 283 if (!strncmp(type, MOUNT_NFS, MFSNAMELEN) && 284 (hp != NULL) && !(fflag & MNT_FORCE)) { 285 *delimp = '\0'; 286 memset(&saddr, 0, sizeof(saddr)); 287 saddr.sin_family = AF_INET; 288 saddr.sin_port = 0; 289 memmove(&saddr.sin_addr, hp->h_addr, hp->h_length); 290 pertry.tv_sec = 3; 291 pertry.tv_usec = 0; 292 so = RPC_ANYSOCK; 293 if ((clp = clntudp_create(&saddr, 294 RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) { 295 clnt_pcreateerror("Cannot MNT PRC"); 296 return (1); 297 } 298 clp->cl_auth = authunix_create_default(); 299 try.tv_sec = 20; 300 try.tv_usec = 0; 301 clnt_stat = clnt_call(clp, 302 RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try); 303 if (clnt_stat != RPC_SUCCESS) { 304 clnt_perror(clp, "Bad MNT RPC"); 305 return (1); 306 } 307 auth_destroy(clp->cl_auth); 308 clnt_destroy(clp); 309 } 310 return (0); 311 } 312 313 char * 314 getmntname(name, what, type) 315 char *name; 316 mntwhat what; 317 char **type; 318 { 319 static struct statfs *mntbuf; 320 static int mntsize; 321 int i; 322 323 if (mntbuf == NULL && 324 (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) { 325 warn("getmntinfo"); 326 return (NULL); 327 } 328 for (i = mntsize - 1; i >= 0; i--) { 329 if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) { 330 if (type) 331 *type = mntbuf[i].f_fstypename; 332 return (mntbuf[i].f_mntonname); 333 } 334 if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) { 335 if (type) 336 *type = mntbuf[i].f_fstypename; 337 return (mntbuf[i].f_mntfromname); 338 } 339 } 340 return (NULL); 341 } 342 343 int 344 namematch(hp) 345 struct hostent *hp; 346 { 347 char *cp, **np; 348 349 if ((hp == NULL) || (nfshost == NULL)) 350 return (1); 351 352 if (strcasecmp(nfshost, hp->h_name) == 0) 353 return (1); 354 355 if ((cp = strchr(hp->h_name, '.')) != NULL) { 356 *cp = '\0'; 357 if (strcasecmp(nfshost, hp->h_name) == 0) 358 return (1); 359 } 360 for (np = hp->h_aliases; *np; np++) { 361 if (strcasecmp(nfshost, *np) == 0) 362 return (1); 363 if ((cp = strchr(*np, '.')) != NULL) { 364 *cp = '\0'; 365 if (strcasecmp(nfshost, *np) == 0) 366 return (1); 367 } 368 } 369 return (0); 370 } 371 372 /* 373 * xdr routines for mount rpc's 374 */ 375 int 376 xdr_dir(xdrsp, dirp) 377 XDR *xdrsp; 378 char *dirp; 379 { 380 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 381 } 382 383 void 384 usage() 385 { 386 (void)fprintf(stderr, 387 "usage: %s\n %s\n", 388 "umount [-fv] [-t fstypelist] special | node", 389 "umount -a[fv] [-h host] [-t fstypelist]"); 390 exit(1); 391 } 392