xref: /netbsd-src/sbin/umount/umount.c (revision 4d7e773266e3c3f48566c86c0ad52d51c6454fd1)
1 /*	$NetBSD: umount.c,v 1.21 1997/11/01 12:54:45 drochner 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.21 1997/11/01 12:54:45 drochner 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 #include <sys/socketvar.h>
56 
57 #include <netdb.h>
58 #include <rpc/rpc.h>
59 #include <rpc/pmap_clnt.h>
60 #include <rpc/pmap_prot.h>
61 #include <nfs/rpcv2.h>
62 
63 #include <err.h>
64 #include <fstab.h>
65 #include <stdio.h>
66 #include <stdlib.h>
67 #include <string.h>
68 #include <unistd.h>
69 
70 typedef enum { MNTANY, MNTON, MNTFROM } mntwhat;
71 
72 int	fake, fflag, verbose;
73 char	*nfshost;
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 hostent *));
80 int	 selected __P((int));
81 int	 umountall __P((char **));
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 
95 	/* Start disks transferring immediately. */
96 	sync();
97 
98 	all = 0;
99 	while ((ch = getopt(argc, argv, "AaFfh:t:v")) != -1)
100 		switch (ch) {
101 		case 'A':
102 			all = 2;
103 			break;
104 		case 'a':
105 			all = 1;
106 			break;
107 		case 'F':
108 			fake = 1;
109 			break;
110 		case 'f':
111 			fflag = MNT_FORCE;
112 			break;
113 		case 'h':	/* -h implies -A. */
114 			all = 2;
115 			nfshost = optarg;
116 			break;
117 		case 't':
118 			if (typelist != NULL)
119 				errx(1, "only one -t option may be specified.");
120 			typelist = makevfslist(optarg);
121 			break;
122 		case 'v':
123 			verbose = 1;
124 			break;
125 		default:
126 			usage();
127 			/* NOTREACHED */
128 		}
129 	argc -= optind;
130 	argv += optind;
131 
132 	if ((argc == 0 && !all) || (argc != 0 && all))
133 		usage();
134 
135 	/* -h implies "-t nfs" if no -t flag. */
136 	if ((nfshost != NULL) && (typelist == NULL))
137 		typelist = makevfslist("nfs");
138 
139 	errs = 0;
140 	switch (all) {
141 	case 2:
142 		if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
143 			warn("getmntinfo");
144 			errs = 1;
145 			break;
146 		}
147 		for (errs = 0, mnts--; mnts > 0; mnts--) {
148 			if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
149 				continue;
150 			if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0)
151 				errs = 1;
152 		}
153 		break;
154 	case 1:
155 		if (setfsent() == 0)
156 			err(1, "%s", _PATH_FSTAB);
157 		errs = umountall(typelist);
158 		break;
159 	case 0:
160 		for (errs = 0; *argv != NULL; ++argv)
161 			if (umountfs(*argv, typelist) != 0)
162 				errs = 1;
163 		break;
164 	}
165 	exit(errs);
166 }
167 
168 
169 int
170 umountall(typelist)
171 	char **typelist;
172 {
173 	struct statfs *fs;
174 	int n;
175 	int rval;
176 
177 	n = getmntinfo(&fs, MNT_NOWAIT);
178 	if (n == 0)
179 		err(1, "%s", "");
180 
181 	rval = 0;
182 	while (--n >= 0) {
183 		/* Ignore the root. */
184 		if (strncmp(fs[n].f_mntonname, "/", MNAMELEN) == 0)
185 			continue;
186 
187 		if (checkvfsname(fs[n].f_fstypename, typelist))
188 			continue;
189 
190 		if (umountfs(fs[n].f_mntonname, typelist))
191 			rval = 1;
192 	}
193 	return (rval);
194 }
195 
196 int
197 umountfs(name, typelist)
198 	char *name;
199 	char **typelist;
200 {
201 	enum clnt_stat clnt_stat;
202 	struct hostent *hp;
203 	struct sockaddr_in saddr;
204 	struct stat sb;
205 	struct timeval pertry, try;
206 	CLIENT *clp;
207 	int so;
208 	char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN];
209 	mntwhat what;
210 
211 	hp = NULL;
212 	delimp = NULL;
213 	if (realpath(name, rname) == NULL) {
214 		warn("%s", rname);
215 		return (1);
216 	}
217 
218 	what = MNTANY;
219 	mntpt = name = rname;
220 
221 	if (stat(name, &sb) == 0) {
222 		if (S_ISBLK(sb.st_mode))
223 			what = MNTON;
224 		else if (S_ISDIR(sb.st_mode))
225 			what = MNTFROM;
226 	}
227 
228 	switch (what) {
229 	case MNTON:
230 		if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
231 			warnx("%s: not currently mounted", name);
232 			return (1);
233 		}
234 		break;
235 	case MNTFROM:
236 		if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
237 			warnx("%s: not currently mounted", mntpt);
238 			return (1);
239 		}
240 		break;
241 	default:
242 		if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
243 			name = rname;
244 			if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
245 				warnx("%s: not currently mounted", name);
246 				return (1);
247 			}
248 		}
249 	}
250 
251 	if (checkvfsname(type, typelist))
252 		return (1);
253 
254 	hp = NULL;
255 	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
256 		if ((delimp = strchr(name, '@')) != NULL) {
257 			hostp = delimp + 1;
258 			*delimp = '\0';
259 			hp = gethostbyname(hostp);
260 			*delimp = '@';
261 		} else if ((delimp = strchr(name, ':')) != NULL) {
262 			*delimp = '\0';
263 			hostp = name;
264 			hp = gethostbyname(hostp);
265 			name = delimp + 1;
266 			*delimp = ':';
267 		}
268 	}
269 
270 	if (!namematch(hp))
271 		return (1);
272 
273 	if (verbose)
274 		(void)printf("%s: unmount from %s\n", name, mntpt);
275 	if (fake)
276 		return (0);
277 
278 	if (unmount(mntpt, fflag) < 0) {
279 		warn("%s", mntpt);
280 		return (1);
281 	}
282 
283 	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN) &&
284 	    (hp != NULL) && !(fflag & MNT_FORCE)) {
285 		*delimp = '\0';
286 		memset(&saddr, 0, sizeof(saddr));
287 		saddr.sin_family = AF_INET;
288 		saddr.sin_port = 0;
289 		memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
290 		pertry.tv_sec = 3;
291 		pertry.tv_usec = 0;
292 		so = RPC_ANYSOCK;
293 		if ((clp = clntudp_create(&saddr,
294 		    RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
295 			clnt_pcreateerror("Cannot MNT PRC");
296 			return (1);
297 		}
298 		clp->cl_auth = authunix_create_default();
299 		try.tv_sec = 20;
300 		try.tv_usec = 0;
301 		clnt_stat = clnt_call(clp,
302 		    RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
303 		if (clnt_stat != RPC_SUCCESS) {
304 			clnt_perror(clp, "Bad MNT RPC");
305 			return (1);
306 		}
307 		auth_destroy(clp->cl_auth);
308 		clnt_destroy(clp);
309 	}
310 	return (0);
311 }
312 
313 char *
314 getmntname(name, what, type)
315 	char *name;
316 	mntwhat what;
317 	char **type;
318 {
319 	static struct statfs *mntbuf;
320 	static int mntsize;
321 	int i;
322 
323 	if (mntbuf == NULL &&
324 	    (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
325 		warn("getmntinfo");
326 		return (NULL);
327 	}
328 	for (i = mntsize - 1; i >= 0; i--) {
329 		if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
330 			if (type)
331 				*type = mntbuf[i].f_fstypename;
332 			return (mntbuf[i].f_mntonname);
333 		}
334 		if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
335 			if (type)
336 				*type = mntbuf[i].f_fstypename;
337 			return (mntbuf[i].f_mntfromname);
338 		}
339 	}
340 	return (NULL);
341 }
342 
343 int
344 namematch(hp)
345 	struct hostent *hp;
346 {
347 	char *cp, **np;
348 
349 	if ((hp == NULL) || (nfshost == NULL))
350 		return (1);
351 
352 	if (strcasecmp(nfshost, hp->h_name) == 0)
353 		return (1);
354 
355 	if ((cp = strchr(hp->h_name, '.')) != NULL) {
356 		*cp = '\0';
357 		if (strcasecmp(nfshost, hp->h_name) == 0)
358 			return (1);
359 	}
360 	for (np = hp->h_aliases; *np; np++) {
361 		if (strcasecmp(nfshost, *np) == 0)
362 			return (1);
363 		if ((cp = strchr(*np, '.')) != NULL) {
364 			*cp = '\0';
365 			if (strcasecmp(nfshost, *np) == 0)
366 				return (1);
367 		}
368 	}
369 	return (0);
370 }
371 
372 /*
373  * xdr routines for mount rpc's
374  */
375 int
376 xdr_dir(xdrsp, dirp)
377 	XDR *xdrsp;
378 	char *dirp;
379 {
380 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
381 }
382 
383 void
384 usage()
385 {
386 	(void)fprintf(stderr,
387 	    "usage: %s\n       %s\n",
388 	    "umount [-fv] [-t fstypelist] special | node",
389 	    "umount -a[fv] [-h host] [-t fstypelist]");
390 	exit(1);
391 }
392