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