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