umount.c revision 1.23 1 /* $NetBSD: umount.c,v 1.23 1998/04/01 15:20:25 kleink Exp $ */
2
3 /*-
4 * Copyright (c) 1980, 1989, 1993
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 __COPYRIGHT("@(#) Copyright (c) 1980, 1989, 1993\n\
39 The Regents of the University of California. All rights reserved.\n");
40 #endif /* not lint */
41
42 #ifndef lint
43 #if 0
44 static char sccsid[] = "@(#)umount.c 8.8 (Berkeley) 5/8/95";
45 #else
46 __RCSID("$NetBSD: umount.c,v 1.23 1998/04/01 15:20:25 kleink Exp $");
47 #endif
48 #endif /* not lint */
49
50 #include <sys/param.h>
51 #include <sys/stat.h>
52 #include <sys/mount.h>
53 #include <sys/time.h>
54 #include <sys/socket.h>
55
56 #include <netdb.h>
57 #include <rpc/rpc.h>
58 #include <rpc/pmap_clnt.h>
59 #include <rpc/pmap_prot.h>
60 #include <nfs/rpcv2.h>
61
62 #include <err.h>
63 #include <fstab.h>
64 #include <stdio.h>
65 #include <stdlib.h>
66 #include <string.h>
67 #include <unistd.h>
68
69 typedef enum { MNTANY, MNTON, MNTFROM } mntwhat;
70
71 int fake, fflag, verbose;
72 char *nfshost;
73
74 int checkvfsname __P((const char *, char **));
75 char *getmntname __P((char *, mntwhat, char **));
76 char **makevfslist __P((char *));
77 int main __P((int, char *[]));
78 int namematch __P((struct hostent *));
79 int selected __P((int));
80 int umountall __P((char **));
81 int umountfs __P((char *, char **));
82 void usage __P((void));
83 int xdr_dir __P((XDR *, char *));
84
85 int
86 main(argc, argv)
87 int argc;
88 char *argv[];
89 {
90 int all, ch, errs, mnts;
91 char **typelist = NULL;
92 struct statfs *mntbuf;
93
94 /* Start disks transferring immediately. */
95 sync();
96
97 all = 0;
98 while ((ch = getopt(argc, argv, "AaFfh:t:v")) != -1)
99 switch (ch) {
100 case 'A':
101 all = 2;
102 break;
103 case 'a':
104 all = 1;
105 break;
106 case 'F':
107 fake = 1;
108 break;
109 case 'f':
110 fflag = MNT_FORCE;
111 break;
112 case 'h': /* -h implies -A. */
113 all = 2;
114 nfshost = optarg;
115 break;
116 case 't':
117 if (typelist != NULL)
118 errx(1, "only one -t option may be specified.");
119 typelist = makevfslist(optarg);
120 break;
121 case 'v':
122 verbose = 1;
123 break;
124 default:
125 usage();
126 /* NOTREACHED */
127 }
128 argc -= optind;
129 argv += optind;
130
131 if ((argc == 0 && !all) || (argc != 0 && all))
132 usage();
133
134 /* -h implies "-t nfs" if no -t flag. */
135 if ((nfshost != NULL) && (typelist == NULL))
136 typelist = makevfslist("nfs");
137
138 errs = 0;
139 switch (all) {
140 case 2:
141 if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
142 warn("getmntinfo");
143 errs = 1;
144 break;
145 }
146 for (errs = 0, mnts--; mnts > 0; mnts--) {
147 if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
148 continue;
149 if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0)
150 errs = 1;
151 }
152 break;
153 case 1:
154 if (setfsent() == 0)
155 err(1, "%s", _PATH_FSTAB);
156 errs = umountall(typelist);
157 break;
158 case 0:
159 for (errs = 0; *argv != NULL; ++argv)
160 if (umountfs(*argv, typelist) != 0)
161 errs = 1;
162 break;
163 }
164 exit(errs);
165 }
166
167
168 int
169 umountall(typelist)
170 char **typelist;
171 {
172 struct statfs *fs;
173 int n;
174 int rval;
175
176 n = getmntinfo(&fs, MNT_NOWAIT);
177 if (n == 0)
178 err(1, "%s", "");
179
180 rval = 0;
181 while (--n >= 0) {
182 /* Ignore the root. */
183 if (strncmp(fs[n].f_mntonname, "/", MNAMELEN) == 0)
184 continue;
185
186 if (checkvfsname(fs[n].f_fstypename, typelist))
187 continue;
188
189 if (umountfs(fs[n].f_mntonname, typelist))
190 rval = 1;
191 }
192 return (rval);
193 }
194
195 int
196 umountfs(name, typelist)
197 char *name;
198 char **typelist;
199 {
200 enum clnt_stat clnt_stat;
201 struct hostent *hp;
202 struct sockaddr_in saddr;
203 struct stat sb;
204 struct timeval pertry, try;
205 CLIENT *clp;
206 int so;
207 char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN];
208 mntwhat what;
209
210 hp = NULL;
211 delimp = NULL;
212 if (realpath(name, rname) == NULL) {
213 warn("%s", rname);
214 return (1);
215 }
216
217 what = MNTANY;
218 mntpt = name = rname;
219
220 if (stat(name, &sb) == 0) {
221 if (S_ISBLK(sb.st_mode))
222 what = MNTON;
223 else if (S_ISDIR(sb.st_mode))
224 what = MNTFROM;
225 }
226
227 switch (what) {
228 case MNTON:
229 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
230 warnx("%s: not currently mounted", name);
231 return (1);
232 }
233 break;
234 case MNTFROM:
235 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
236 warnx("%s: not currently mounted", mntpt);
237 return (1);
238 }
239 break;
240 default:
241 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
242 name = rname;
243 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
244 warnx("%s: not currently mounted", name);
245 return (1);
246 }
247 }
248 }
249
250 if (checkvfsname(type, typelist))
251 return (1);
252
253 hp = NULL;
254 if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
255 if ((delimp = strchr(name, '@')) != NULL) {
256 hostp = delimp + 1;
257 *delimp = '\0';
258 hp = gethostbyname(hostp);
259 *delimp = '@';
260 } else if ((delimp = strchr(name, ':')) != NULL) {
261 *delimp = '\0';
262 hostp = name;
263 hp = gethostbyname(hostp);
264 name = delimp + 1;
265 *delimp = ':';
266 }
267 }
268
269 if (!namematch(hp))
270 return (1);
271
272 if (verbose)
273 (void)printf("%s: unmount from %s\n", name, mntpt);
274 if (fake)
275 return (0);
276
277 if (unmount(mntpt, fflag) < 0) {
278 warn("%s", mntpt);
279 return (1);
280 }
281
282 if (!strncmp(type, MOUNT_NFS, MFSNAMELEN) &&
283 (hp != NULL) && !(fflag & MNT_FORCE)) {
284 *delimp = '\0';
285 memset(&saddr, 0, sizeof(saddr));
286 saddr.sin_family = AF_INET;
287 saddr.sin_port = 0;
288 memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
289 pertry.tv_sec = 3;
290 pertry.tv_usec = 0;
291 so = RPC_ANYSOCK;
292 if ((clp = clntudp_create(&saddr,
293 RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
294 clnt_pcreateerror("Cannot MNT PRC");
295 return (1);
296 }
297 clp->cl_auth = authunix_create_default();
298 try.tv_sec = 20;
299 try.tv_usec = 0;
300 clnt_stat = clnt_call(clp,
301 RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
302 if (clnt_stat != RPC_SUCCESS) {
303 clnt_perror(clp, "Bad MNT RPC");
304 return (1);
305 }
306 auth_destroy(clp->cl_auth);
307 clnt_destroy(clp);
308 }
309 return (0);
310 }
311
312 char *
313 getmntname(name, what, type)
314 char *name;
315 mntwhat what;
316 char **type;
317 {
318 static struct statfs *mntbuf;
319 static int mntsize;
320 int i;
321
322 if (mntbuf == NULL &&
323 (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
324 warn("getmntinfo");
325 return (NULL);
326 }
327 for (i = mntsize - 1; i >= 0; i--) {
328 if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
329 if (type)
330 *type = mntbuf[i].f_fstypename;
331 return (mntbuf[i].f_mntonname);
332 }
333 if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
334 if (type)
335 *type = mntbuf[i].f_fstypename;
336 return (mntbuf[i].f_mntfromname);
337 }
338 }
339 return (NULL);
340 }
341
342 int
343 namematch(hp)
344 struct hostent *hp;
345 {
346 char *cp, **np;
347
348 if ((hp == NULL) || (nfshost == NULL))
349 return (1);
350
351 if (strcasecmp(nfshost, hp->h_name) == 0)
352 return (1);
353
354 if ((cp = strchr(hp->h_name, '.')) != NULL) {
355 *cp = '\0';
356 if (strcasecmp(nfshost, hp->h_name) == 0)
357 return (1);
358 }
359 for (np = hp->h_aliases; *np; np++) {
360 if (strcasecmp(nfshost, *np) == 0)
361 return (1);
362 if ((cp = strchr(*np, '.')) != NULL) {
363 *cp = '\0';
364 if (strcasecmp(nfshost, *np) == 0)
365 return (1);
366 }
367 }
368 return (0);
369 }
370
371 /*
372 * xdr routines for mount rpc's
373 */
374 int
375 xdr_dir(xdrsp, dirp)
376 XDR *xdrsp;
377 char *dirp;
378 {
379 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
380 }
381
382 void
383 usage()
384 {
385 (void)fprintf(stderr,
386 "usage: %s\n %s\n",
387 "umount [-fvF] [-t fstypelist] special | node",
388 "umount -a[fvF] [-h host] [-t fstypelist]");
389 exit(1);
390 }
391