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