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