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.6 (Berkeley) 02/03/95"; 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 (1); 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 (1); 195 196 hp = NULL; 197 if (type == MOUNT_NFS) { 198 if ((delimp = strchr(name, '@')) != NULL) { 199 hostp = delimp + 1; 200 *delimp = '\0'; 201 hp = gethostbyname(hostp); 202 *delimp = '@'; 203 } else if ((delimp = strchr(name, ':')) != NULL) { 204 *delimp = '\0'; 205 hostp = name; 206 hp = gethostbyname(hostp); 207 name = delimp + 1; 208 *delimp = ':'; 209 } 210 } 211 212 if (!namematch(hp)) 213 return (1); 214 215 if (vflag) 216 (void)printf("%s: unmount from %s\n", name, mntpt); 217 if (fake) 218 return (0); 219 220 if (unmount(mntpt, fflag) < 0) { 221 warn("%s", mntpt); 222 return (1); 223 } 224 225 if ((hp != NULL) && !(fflag & MNT_FORCE)) { 226 *delimp = '\0'; 227 memset(&saddr, 0, sizeof(saddr)); 228 saddr.sin_family = AF_INET; 229 saddr.sin_port = 0; 230 memmove(&saddr.sin_addr, hp->h_addr, hp->h_length); 231 pertry.tv_sec = 3; 232 pertry.tv_usec = 0; 233 so = RPC_ANYSOCK; 234 if ((clp = clntudp_create(&saddr, 235 RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) { 236 clnt_pcreateerror("Cannot MNT PRC"); 237 return (1); 238 } 239 clp->cl_auth = authunix_create_default(); 240 try.tv_sec = 20; 241 try.tv_usec = 0; 242 clnt_stat = clnt_call(clp, 243 RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try); 244 if (clnt_stat != RPC_SUCCESS) { 245 clnt_perror(clp, "Bad MNT RPC"); 246 return (1); 247 } 248 auth_destroy(clp->cl_auth); 249 clnt_destroy(clp); 250 } 251 return (0); 252 } 253 254 char * 255 getmntname(name, what, type) 256 char *name; 257 mntwhat what; 258 int *type; 259 { 260 struct statfs *mntbuf; 261 int i, mntsize; 262 263 if ((mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) { 264 warn("getmntinfo"); 265 return (NULL); 266 } 267 for (i = 0; i < mntsize; i++) { 268 if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) { 269 if (type) 270 *type = mntbuf[i].f_type; 271 return (mntbuf[i].f_mntonname); 272 } 273 if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) { 274 if (type) 275 *type = mntbuf[i].f_type; 276 return (mntbuf[i].f_mntfromname); 277 } 278 } 279 return (NULL); 280 } 281 282 static enum { IN_LIST, NOT_IN_LIST } which; 283 284 int 285 selected(type) 286 int type; 287 { 288 int *av; 289 290 /* If no type specified, it's always selected. */ 291 if (typelist == NULL) 292 return (1); 293 for (av = typelist; *av != NULL; ++av) 294 if (type == *typelist) 295 return (which == IN_LIST ? 1 : 0); 296 return (which == IN_LIST ? 0 : 1); 297 } 298 299 void 300 maketypelist(fslist) 301 char *fslist; 302 { 303 int *av, i; 304 char *nextcp; 305 306 if ((fslist == NULL) || (fslist[0] == '\0')) 307 errx(1, "empty type list"); 308 309 /* 310 * XXX 311 * Note: the syntax is "noxxx,yyy" for no xxx's and 312 * no yyy's, not the more intuitive "noyyy,noyyy". 313 */ 314 if (fslist[0] == 'n' && fslist[1] == 'o') { 315 fslist += 2; 316 which = NOT_IN_LIST; 317 } else 318 which = IN_LIST; 319 320 /* Count the number of types. */ 321 for (i = 0, nextcp = fslist; *nextcp != NULL; ++nextcp) 322 if (*nextcp == ',') 323 i++; 324 325 /* Build an array of that many types. */ 326 if ((av = typelist = malloc((i + 2) * sizeof(int))) == NULL) 327 err(1, NULL); 328 for (i = 0; fslist != NULL; fslist = nextcp, ++i) { 329 if ((nextcp = strchr(fslist, ',')) != NULL) 330 *nextcp++ = '\0'; 331 av[i] = fsnametotype(fslist); 332 if (av[i] == MOUNT_NONE) 333 errx(1, "%s: unknown mount type", fslist); 334 } 335 /* Terminate the array. */ 336 av[i++] = MOUNT_NONE; 337 } 338 339 int 340 fsnametotype(name) 341 char *name; 342 { 343 static char const *namelist[] = INITMOUNTNAMES; 344 char const **cp; 345 346 for (cp = namelist; *cp; ++cp) 347 if (strcmp(name, *cp) == 0) 348 return (cp - namelist); 349 return (MOUNT_NONE); 350 } 351 352 int 353 namematch(hp) 354 struct hostent *hp; 355 { 356 char *cp, **np; 357 358 if ((hp == NULL) || (nfshost == NULL)) 359 return (1); 360 361 if (strcasecmp(nfshost, hp->h_name) == 0) 362 return (1); 363 364 if ((cp = strchr(hp->h_name, '.')) != NULL) { 365 *cp = '\0'; 366 if (strcasecmp(nfshost, hp->h_name) == 0) 367 return (1); 368 } 369 for (np = hp->h_aliases; *np; np++) { 370 if (strcasecmp(nfshost, *np) == 0) 371 return (1); 372 if ((cp = strchr(*np, '.')) != NULL) { 373 *cp = '\0'; 374 if (strcasecmp(nfshost, *np) == 0) 375 return (1); 376 } 377 } 378 return (0); 379 } 380 381 /* 382 * xdr routines for mount rpc's 383 */ 384 int 385 xdr_dir(xdrsp, dirp) 386 XDR *xdrsp; 387 char *dirp; 388 { 389 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 390 } 391 392 void 393 usage() 394 { 395 (void)fprintf(stderr, 396 "usage: %s\n %s\n", 397 "umount [-fv] [-t fstypelist] special | node", 398 "umount -a[fv] [-h host] [-t fstypelist]"); 399 exit(1); 400 } 401