umount.c revision 1.30 1 /* $NetBSD: umount.c,v 1.30 2004/03/12 21:14:29 dsl 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.30 2004/03/12 21:14:29 dsl 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 what = MNTANY;
182 if (realpath(name, rname) != NULL) {
183 name = rname;
184
185 if (stat(name, &sb) == 0) {
186 if (S_ISBLK(sb.st_mode))
187 what = MNTON;
188 else if (S_ISDIR(sb.st_mode))
189 what = MNTFROM;
190 }
191 }
192 mntpt = name;
193
194 switch (what) {
195 case MNTON:
196 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
197 warnx("%s: not currently mounted", name);
198 return (1);
199 }
200 break;
201 case MNTFROM:
202 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
203 warnx("%s: not currently mounted", mntpt);
204 return (1);
205 }
206 break;
207 default:
208 if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
209 name = mntpt;
210 if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
211 warnx("%s: not currently mounted", name);
212 return (1);
213 }
214 }
215 }
216
217 if (checkvfsname(type, typelist))
218 return (1);
219
220 memset(&hints, 0, sizeof hints);
221 ai = NULL;
222 if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
223 /* look for host:mountpoint */
224 if ((delimp = strrchr(name, ':')) != NULL) {
225 *delimp = '\0';
226 hostp = name;
227 getaddrinfo(hostp, NULL, &hints, &ai);
228 name = delimp + 1;
229 *delimp = ':';
230 }
231 }
232
233 if (!namematch(ai))
234 return (1);
235 }
236
237 if (verbose)
238 (void)printf("%s: unmount from %s\n", name, mntpt);
239 if (fake)
240 return (0);
241
242 if (unmount(mntpt, fflag) < 0) {
243 warn("%s", mntpt);
244 return (1);
245 }
246
247 if (!raw && !strncmp(type, MOUNT_NFS, MFSNAMELEN) &&
248 (ai != NULL) && !(fflag & MNT_FORCE)) {
249 *delimp = '\0';
250 clp = clnt_create(hostp, RPCPROG_MNT, RPCMNT_VER1, "udp");
251 if (clp == NULL) {
252 clnt_pcreateerror("Cannot MNT PRC");
253 return (1);
254 }
255 clp->cl_auth = authsys_create_default();
256 try.tv_sec = 20;
257 try.tv_usec = 0;
258 clnt_stat = clnt_call(clp,
259 RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
260 if (clnt_stat != RPC_SUCCESS) {
261 clnt_perror(clp, "Bad MNT RPC");
262 return (1);
263 }
264 auth_destroy(clp->cl_auth);
265 clnt_destroy(clp);
266 }
267 return (0);
268 }
269
270 char *
271 getmntname(name, what, type)
272 char *name;
273 mntwhat what;
274 char **type;
275 {
276 static struct statfs *mntbuf;
277 static int mntsize;
278 int i;
279
280 if (mntbuf == NULL &&
281 (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
282 warn("getmntinfo");
283 return (NULL);
284 }
285 for (i = mntsize - 1; i >= 0; i--) {
286 if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
287 if (type)
288 *type = mntbuf[i].f_fstypename;
289 return (mntbuf[i].f_mntonname);
290 }
291 if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
292 if (type)
293 *type = mntbuf[i].f_fstypename;
294 return (mntbuf[i].f_mntfromname);
295 }
296 }
297 return (NULL);
298 }
299
300 int
301 sacmp(struct sockaddr *sa1, struct sockaddr *sa2)
302 {
303 void *p1, *p2;
304 int len;
305
306 if (sa1->sa_family != sa2->sa_family)
307 return 1;
308
309 switch (sa1->sa_family) {
310 case AF_INET:
311 p1 = &((struct sockaddr_in *)sa1)->sin_addr;
312 p2 = &((struct sockaddr_in *)sa2)->sin_addr;
313 len = 4;
314 break;
315 case AF_INET6:
316 p1 = &((struct sockaddr_in6 *)sa1)->sin6_addr;
317 p2 = &((struct sockaddr_in6 *)sa2)->sin6_addr;
318 len = 16;
319 if (((struct sockaddr_in6 *)sa1)->sin6_scope_id !=
320 ((struct sockaddr_in6 *)sa2)->sin6_scope_id)
321 return 1;
322 break;
323 default:
324 return 1;
325 }
326
327 return memcmp(p1, p2, len);
328 }
329
330 int
331 namematch(ai)
332 struct addrinfo *ai;
333 {
334 struct addrinfo *aip;
335
336 if (nfshost == NULL || nfshost_ai == NULL)
337 return (1);
338
339 while (ai != NULL) {
340 aip = nfshost_ai;
341 while (aip != NULL) {
342 if (sacmp(ai->ai_addr, aip->ai_addr) == 0)
343 return 1;
344 aip = aip->ai_next;
345 }
346 ai = ai->ai_next;
347 }
348
349 return 0;
350 }
351
352 /*
353 * xdr routines for mount rpc's
354 */
355 int
356 xdr_dir(xdrsp, dirp)
357 XDR *xdrsp;
358 char *dirp;
359 {
360 return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
361 }
362
363 void
364 usage()
365 {
366 (void)fprintf(stderr,
367 "usage: %s\n %s\n",
368 "umount [-fvFR] [-t fstypelist] special | node",
369 "umount -a[fvF] [-h host] [-t fstypelist]");
370 exit(1);
371 }
372