umount.c revision 1.28 1 /* $NetBSD: umount.c,v 1.28 2000/06/20 00:45:24 fvdl 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.28 2000/06/20 00:45:24 fvdl 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, raw;
72 char *nfshost;
73 struct addrinfo *nfshost_ai = NULL;
74
75 int checkvfsname __P((const char *, char **));
76 char *getmntname __P((char *, mntwhat, char **));
77 char **makevfslist __P((char *));
78 int main __P((int, char *[]));
79 int namematch __P((struct addrinfo *));
80 int sacmp __P((struct sockaddr *, struct sockaddr *));
81 int selected __P((int));
82 int umountfs __P((char *, char **));
83 void usage __P((void));
84 int xdr_dir __P((XDR *, char *));
85
86 int
87 main(argc, argv)
88 int argc;
89 char *argv[];
90 {
91 int all, ch, errs, mnts;
92 char **typelist = NULL;
93 struct statfs *mntbuf;
94 struct addrinfo hints;
95
96 /* Start disks transferring immediately. */
97 sync();
98
99 all = 0;
100 while ((ch = getopt(argc, argv, "AaFfRh:t:v")) != -1)
101 switch (ch) {
102 case 'A':
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 = 1;
114 nfshost = optarg;
115 break;
116 case 'R':
117 raw = 1;
118 break;
119 case 't':
120 if (typelist != NULL)
121 errx(1, "only one -t option may be specified.");
122 typelist = makevfslist(optarg);
123 break;
124 case 'v':
125 verbose = 1;
126 break;
127 default:
128 usage();
129 /* NOTREACHED */
130 }
131 argc -= optind;
132 argv += optind;
133
134 if ((argc == 0 && !all) || (argc != 0 && all) || (all && raw))
135 usage();
136
137 /* -h implies "-t nfs" if no -t flag. */
138 if ((nfshost != NULL) && (typelist == NULL))
139 typelist = makevfslist("nfs");
140
141 if (nfshost != NULL) {
142 memset(&hints, 0, sizeof hints);
143 getaddrinfo(nfshost, NULL, &hints, &nfshost_ai);
144 }
145
146 errs = 0;
147 if (all) {
148 if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
149 warn("getmntinfo");
150 errs = 1;
151 }
152 for (errs = 0, mnts--; mnts > 0; mnts--) {
153 if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
154 continue;
155 if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0)
156 errs = 1;
157 }
158 } else {
159 for (errs = 0; *argv != NULL; ++argv)
160 if (umountfs(*argv, typelist) != 0)
161 errs = 1;
162 }
163 exit(errs);
164 }
165
166 int
167 umountfs(name, typelist)
168 char *name;
169 char **typelist;
170 {
171 enum clnt_stat clnt_stat;
172 struct stat sb;
173 struct timeval try;
174 CLIENT *clp;
175 char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN];
176 mntwhat what;
177 struct addrinfo *ai, hints;
178
179 delimp = NULL;
180
181 if (raw) {
182 mntpt = name;
183 } else {
184
185 if (realpath(name, rname) == NULL) {
186 warn("%s", rname);
187 return (1);
188 }
189
190 what = MNTANY;
191 mntpt = name = rname;
192
193 if (stat(name, &sb) == 0) {
194 if (S_ISBLK(sb.st_mode))
195 what = MNTON;
196 else if (S_ISDIR(sb.st_mode))
197 what = MNTFROM;
198 }
199
200 switch (what) {
201 case MNTON:
202 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
203 warnx("%s: not currently mounted", name);
204 return (1);
205 }
206 break;
207 case MNTFROM:
208 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
209 warnx("%s: not currently mounted", mntpt);
210 return (1);
211 }
212 break;
213 default:
214 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
215 name = rname;
216 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
217 warnx("%s: not currently mounted", name);
218 return (1);
219 }
220 }
221 }
222
223 if (checkvfsname(type, typelist))
224 return (1);
225
226 memset(&hints, 0, sizeof hints);
227 ai = NULL;
228 if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
229 if ((delimp = strchr(name, '@')) != NULL) {
230 hostp = delimp + 1;
231 *delimp = '\0';
232 getaddrinfo(hostp, NULL, &hints, &ai);
233 *delimp = '@';
234 } else if ((delimp = strrchr(name, ':')) != NULL) {
235 *delimp = '\0';
236 hostp = name;
237 getaddrinfo(hostp, NULL, &hints, &ai);
238 name = delimp + 1;
239 *delimp = ':';
240 }
241 }
242
243 if (!namematch(ai))
244 return (1);
245 }
246
247 if (verbose)
248 (void)printf("%s: unmount from %s\n", name, mntpt);
249 if (fake)
250 return (0);
251
252 if (unmount(mntpt, fflag) < 0) {
253 warn("%s", mntpt);
254 return (1);
255 }
256
257 if (!raw && !strncmp(type, MOUNT_NFS, MFSNAMELEN) &&
258 (ai != NULL) && !(fflag & MNT_FORCE)) {
259 *delimp = '\0';
260 clp = clnt_create(hostp, RPCPROG_MNT, RPCMNT_VER1, "udp");
261 if (clp == NULL) {
262 clnt_pcreateerror("Cannot MNT PRC");
263 return (1);
264 }
265 clp->cl_auth = authsys_create_default();
266 try.tv_sec = 20;
267 try.tv_usec = 0;
268 clnt_stat = clnt_call(clp,
269 RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
270 if (clnt_stat != RPC_SUCCESS) {
271 clnt_perror(clp, "Bad MNT RPC");
272 return (1);
273 }
274 auth_destroy(clp->cl_auth);
275 clnt_destroy(clp);
276 }
277 return (0);
278 }
279
280 char *
281 getmntname(name, what, type)
282 char *name;
283 mntwhat what;
284 char **type;
285 {
286 static struct statfs *mntbuf;
287 static int mntsize;
288 int i;
289
290 if (mntbuf == NULL &&
291 (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
292 warn("getmntinfo");
293 return (NULL);
294 }
295 for (i = mntsize - 1; i >= 0; i--) {
296 if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
297 if (type)
298 *type = mntbuf[i].f_fstypename;
299 return (mntbuf[i].f_mntonname);
300 }
301 if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
302 if (type)
303 *type = mntbuf[i].f_fstypename;
304 return (mntbuf[i].f_mntfromname);
305 }
306 }
307 return (NULL);
308 }
309
310 int
311 sacmp(struct sockaddr *sa1, struct sockaddr *sa2)
312 {
313 void *p1, *p2;
314 int len;
315
316 if (sa1->sa_family != sa2->sa_family)
317 return 1;
318
319 switch (sa1->sa_family) {
320 case AF_INET:
321 p1 = &((struct sockaddr_in *)sa1)->sin_addr;
322 p2 = &((struct sockaddr_in *)sa2)->sin_addr;
323 len = 4;
324 break;
325 case AF_INET6:
326 p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
327 p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
328 len = 16;
329 if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
330 ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
331 return 1;
332 break;
333 default:
334 return 1;
335 }
336
337 return memcmp(p1, p2, len);
338 }
339
340 int
341 namematch(ai)
342 struct addrinfo *ai;
343 {
344 struct addrinfo *aip;
345
346 if (nfshost == NULL || nfshost_ai == NULL)
347 return (1);
348
349 while (ai != NULL) {
350 aip = nfshost_ai;
351 while (aip != NULL) {
352 if (sacmp(ai->ai_addr, aip->ai_addr) == 0)
353 return 1;
354 aip = aip->ai_next;
355 }
356 ai = ai->ai_next;
357 }
358
359 return 0;
360 }
361
362 /*
363 * xdr routines for mount rpc's
364 */
365 int
366 xdr_dir(xdrsp, dirp)
367 XDR *xdrsp;
368 char *dirp;
369 {
370 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
371 }
372
373 void
374 usage()
375 {
376 (void)fprintf(stderr,
377 "usage: %s\n %s\n",
378 "umount [-fvFR] [-t fstypelist] special | node",
379 "umount -a[fvF] [-h host] [-t fstypelist]");
380 exit(1);
381 }
382