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.8 (Berkeley) 05/08/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; 41 char *nfshost; 42 43 int checkvfsname __P((const char *, char **)); 44 char *getmntname __P((char *, mntwhat, char **)); 45 char **makevfslist __P((char *)); 46 int selected __P((int)); 47 int namematch __P((struct hostent *)); 48 int umountall __P((char **)); 49 int umountfs __P((char *, 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, mnts; 59 char **typelist = NULL; 60 struct statfs *mntbuf; 61 62 /* Start disks transferring immediately. */ 63 sync(); 64 65 all = 0; 66 while ((ch = getopt(argc, argv, "AaFfh:t:v")) != EOF) 67 switch (ch) { 68 case 'A': 69 all = 2; 70 break; 71 case 'a': 72 all = 1; 73 break; 74 case 'F': 75 fake = 1; 76 break; 77 case 'f': 78 fflag = MNT_FORCE; 79 break; 80 case 'h': /* -h implies -A. */ 81 all = 2; 82 nfshost = optarg; 83 break; 84 case 't': 85 if (typelist != NULL) 86 errx(1, "only one -t option may be specified."); 87 typelist = makevfslist(optarg); 88 break; 89 case 'v': 90 vflag = 1; 91 break; 92 default: 93 usage(); 94 /* NOTREACHED */ 95 } 96 argc -= optind; 97 argv += optind; 98 99 if (argc == 0 && !all || argc != 0 && all) 100 usage(); 101 102 /* -h implies "-t nfs" if no -t flag. */ 103 if ((nfshost != NULL) && (typelist == NULL)) 104 typelist = makevfslist("nfs"); 105 106 switch (all) { 107 case 2: 108 if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) { 109 warn("getmntinfo"); 110 errs = 1; 111 break; 112 } 113 for (errs = 0, mnts--; mnts > 0; mnts--) { 114 if (checkvfsname(mntbuf[mnts].f_fstypename, typelist)) 115 continue; 116 if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0) 117 errs = 1; 118 } 119 break; 120 case 1: 121 if (setfsent() == 0) 122 err(1, "%s", _PATH_FSTAB); 123 errs = umountall(typelist); 124 break; 125 case 0: 126 for (errs = 0; *argv != NULL; ++argv) 127 if (umountfs(*argv, typelist) != 0) 128 errs = 1; 129 break; 130 } 131 exit(errs); 132 } 133 134 int 135 umountall(typelist) 136 char **typelist; 137 { 138 struct fstab *fs; 139 int rval, type; 140 char *cp; 141 struct vfsconf vfc; 142 143 while ((fs = getfsent()) != NULL) { 144 /* Ignore the root. */ 145 if (strcmp(fs->fs_file, "/") == 0) 146 continue; 147 /* 148 * !!! 149 * Historic practice: ignore unknown FSTAB_* fields. 150 */ 151 if (strcmp(fs->fs_type, FSTAB_RW) && 152 strcmp(fs->fs_type, FSTAB_RO) && 153 strcmp(fs->fs_type, FSTAB_RQ)) 154 continue; 155 /* If an unknown file system type, complain. */ 156 if (getvfsbyname(fs->fs_vfstype, &vfc) < 0) { 157 warnx("%s: unknown mount type", fs->fs_vfstype); 158 continue; 159 } 160 if (checkvfsname(fs->fs_vfstype, typelist)) 161 continue; 162 163 /* 164 * We want to unmount the file systems in the reverse order 165 * that they were mounted. So, we save off the file name 166 * in some allocated memory, and then call recursively. 167 */ 168 if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL) 169 err(1, NULL); 170 (void)strcpy(cp, fs->fs_file); 171 rval = umountall(typelist); 172 return (umountfs(cp, typelist) || rval); 173 } 174 return (0); 175 } 176 177 int 178 umountfs(name, typelist) 179 char *name; 180 char **typelist; 181 { 182 enum clnt_stat clnt_stat; 183 struct hostent *hp; 184 struct sockaddr_in saddr; 185 struct stat sb; 186 struct timeval pertry, try; 187 CLIENT *clp; 188 int so; 189 char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN]; 190 191 if (realpath(name, rname) == NULL) { 192 warn("%s", rname); 193 return (1); 194 } 195 196 name = rname; 197 198 if (stat(name, &sb) < 0) { 199 if (((mntpt = getmntname(name, MNTFROM, &type)) == NULL) && 200 ((mntpt = getmntname(name, MNTON, &type)) == NULL)) { 201 warnx("%s: not currently mounted", name); 202 return (1); 203 } 204 } else if (S_ISBLK(sb.st_mode)) { 205 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) { 206 warnx("%s: not currently mounted", name); 207 return (1); 208 } 209 } else if (S_ISDIR(sb.st_mode)) { 210 mntpt = name; 211 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) { 212 warnx("%s: not currently mounted", mntpt); 213 return (1); 214 } 215 } else { 216 warnx("%s: not a directory or special device", name); 217 return (1); 218 } 219 220 if (checkvfsname(type, typelist)) 221 return (1); 222 223 hp = NULL; 224 if (!strcmp(type, "nfs")) { 225 if ((delimp = strchr(name, '@')) != NULL) { 226 hostp = delimp + 1; 227 *delimp = '\0'; 228 hp = gethostbyname(hostp); 229 *delimp = '@'; 230 } else if ((delimp = strchr(name, ':')) != NULL) { 231 *delimp = '\0'; 232 hostp = name; 233 hp = gethostbyname(hostp); 234 name = delimp + 1; 235 *delimp = ':'; 236 } 237 } 238 239 if (!namematch(hp)) 240 return (1); 241 242 if (vflag) 243 (void)printf("%s: unmount from %s\n", name, mntpt); 244 if (fake) 245 return (0); 246 247 if (unmount(mntpt, fflag) < 0) { 248 warn("%s", mntpt); 249 return (1); 250 } 251 252 if ((hp != NULL) && !(fflag & MNT_FORCE)) { 253 *delimp = '\0'; 254 memset(&saddr, 0, sizeof(saddr)); 255 saddr.sin_family = AF_INET; 256 saddr.sin_port = 0; 257 memmove(&saddr.sin_addr, hp->h_addr, hp->h_length); 258 pertry.tv_sec = 3; 259 pertry.tv_usec = 0; 260 so = RPC_ANYSOCK; 261 if ((clp = clntudp_create(&saddr, 262 RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) { 263 clnt_pcreateerror("Cannot MNT PRC"); 264 return (1); 265 } 266 clp->cl_auth = authunix_create_default(); 267 try.tv_sec = 20; 268 try.tv_usec = 0; 269 clnt_stat = clnt_call(clp, 270 RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try); 271 if (clnt_stat != RPC_SUCCESS) { 272 clnt_perror(clp, "Bad MNT RPC"); 273 return (1); 274 } 275 auth_destroy(clp->cl_auth); 276 clnt_destroy(clp); 277 } 278 return (0); 279 } 280 281 char * 282 getmntname(name, what, type) 283 char *name; 284 mntwhat what; 285 char **type; 286 { 287 static struct statfs *mntbuf; 288 static int mntsize; 289 int i; 290 291 if (mntbuf == NULL && 292 (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) { 293 warn("getmntinfo"); 294 return (NULL); 295 } 296 for (i = 0; i < mntsize; i++) { 297 if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) { 298 if (type) 299 *type = mntbuf[i].f_fstypename; 300 return (mntbuf[i].f_mntonname); 301 } 302 if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) { 303 if (type) 304 *type = mntbuf[i].f_fstypename; 305 return (mntbuf[i].f_mntfromname); 306 } 307 } 308 return (NULL); 309 } 310 311 int 312 namematch(hp) 313 struct hostent *hp; 314 { 315 char *cp, **np; 316 317 if ((hp == NULL) || (nfshost == NULL)) 318 return (1); 319 320 if (strcasecmp(nfshost, hp->h_name) == 0) 321 return (1); 322 323 if ((cp = strchr(hp->h_name, '.')) != NULL) { 324 *cp = '\0'; 325 if (strcasecmp(nfshost, hp->h_name) == 0) 326 return (1); 327 } 328 for (np = hp->h_aliases; *np; np++) { 329 if (strcasecmp(nfshost, *np) == 0) 330 return (1); 331 if ((cp = strchr(*np, '.')) != NULL) { 332 *cp = '\0'; 333 if (strcasecmp(nfshost, *np) == 0) 334 return (1); 335 } 336 } 337 return (0); 338 } 339 340 /* 341 * xdr routines for mount rpc's 342 */ 343 int 344 xdr_dir(xdrsp, dirp) 345 XDR *xdrsp; 346 char *dirp; 347 { 348 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN)); 349 } 350 351 void 352 usage() 353 { 354 (void)fprintf(stderr, 355 "usage: %s\n %s\n", 356 "umount [-fv] [-t fstypelist] special | node", 357 "umount -a[fv] [-h host] [-t fstypelist]"); 358 exit(1); 359 } 360