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