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