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