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