xref: /original-bsd/sbin/umount/umount.c (revision b3c06cab)
1 /*-
2  * Copyright (c) 1980, 1989, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 static char copyright[] =
10 "@(#) Copyright (c) 1980, 1989, 1993\n\
11 	The Regents of the University of California.  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)umount.c	8.8 (Berkeley) 05/08/95";
16 #endif /* not lint */
17 
18 #include <sys/param.h>
19 #include <sys/stat.h>
20 #include <sys/mount.h>
21 #include <sys/time.h>
22 #include <sys/socket.h>
23 #include <sys/socketvar.h>
24 
25 #include <netdb.h>
26 #include <rpc/rpc.h>
27 #include <rpc/pmap_clnt.h>
28 #include <rpc/pmap_prot.h>
29 #include <nfs/rpcv2.h>
30 
31 #include <err.h>
32 #include <fstab.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 
38 typedef enum { MNTON, MNTFROM } mntwhat;
39 
40 int	fake, fflag, vflag;
41 char	*nfshost;
42 
43 int	 checkvfsname __P((const char *, char **));
44 char	*getmntname __P((char *, mntwhat, char **));
45 char	**makevfslist __P((char *));
46 int	 selected __P((int));
47 int	 namematch __P((struct hostent *));
48 int	 umountall __P((char **));
49 int	 umountfs __P((char *, char **));
50 void	 usage __P((void));
51 int	 xdr_dir __P((XDR *, char *));
52 
53 int
54 main(argc, argv)
55 	int argc;
56 	char *argv[];
57 {
58 	int all, ch, errs, mnts;
59 	char **typelist = NULL;
60 	struct statfs *mntbuf;
61 
62 	/* Start disks transferring immediately. */
63 	sync();
64 
65 	all = 0;
66 	while ((ch = getopt(argc, argv, "AaFfh:t:v")) != EOF)
67 		switch (ch) {
68 		case 'A':
69 			all = 2;
70 			break;
71 		case 'a':
72 			all = 1;
73 			break;
74 		case 'F':
75 			fake = 1;
76 			break;
77 		case 'f':
78 			fflag = MNT_FORCE;
79 			break;
80 		case 'h':	/* -h implies -A. */
81 			all = 2;
82 			nfshost = optarg;
83 			break;
84 		case 't':
85 			if (typelist != NULL)
86 				errx(1, "only one -t option may be specified.");
87 			typelist = makevfslist(optarg);
88 			break;
89 		case 'v':
90 			vflag = 1;
91 			break;
92 		default:
93 			usage();
94 			/* NOTREACHED */
95 		}
96 	argc -= optind;
97 	argv += optind;
98 
99 	if (argc == 0 && !all || argc != 0 && all)
100 		usage();
101 
102 	/* -h implies "-t nfs" if no -t flag. */
103 	if ((nfshost != NULL) && (typelist == NULL))
104 		typelist = makevfslist("nfs");
105 
106 	switch (all) {
107 	case 2:
108 		if ((mnts = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
109 			warn("getmntinfo");
110 			errs = 1;
111 			break;
112 		}
113 		for (errs = 0, mnts--; mnts > 0; mnts--) {
114 			if (checkvfsname(mntbuf[mnts].f_fstypename, typelist))
115 				continue;
116 			if (umountfs(mntbuf[mnts].f_mntonname, typelist) != 0)
117 				errs = 1;
118 		}
119 		break;
120 	case 1:
121 		if (setfsent() == 0)
122 			err(1, "%s", _PATH_FSTAB);
123 		errs = umountall(typelist);
124 		break;
125 	case 0:
126 		for (errs = 0; *argv != NULL; ++argv)
127 			if (umountfs(*argv, typelist) != 0)
128 				errs = 1;
129 		break;
130 	}
131 	exit(errs);
132 }
133 
134 int
135 umountall(typelist)
136 	char **typelist;
137 {
138 	struct fstab *fs;
139 	int rval, type;
140 	char *cp;
141 	struct vfsconf vfc;
142 
143 	while ((fs = getfsent()) != NULL) {
144 		/* Ignore the root. */
145 		if (strcmp(fs->fs_file, "/") == 0)
146 			continue;
147 		/*
148 		 * !!!
149 		 * Historic practice: ignore unknown FSTAB_* fields.
150 		 */
151 		if (strcmp(fs->fs_type, FSTAB_RW) &&
152 		    strcmp(fs->fs_type, FSTAB_RO) &&
153 		    strcmp(fs->fs_type, FSTAB_RQ))
154 			continue;
155 		/* If an unknown file system type, complain. */
156 		if (getvfsbyname(fs->fs_vfstype, &vfc) < 0) {
157 			warnx("%s: unknown mount type", fs->fs_vfstype);
158 			continue;
159 		}
160 		if (checkvfsname(fs->fs_vfstype, typelist))
161 			continue;
162 
163 		/*
164 		 * We want to unmount the file systems in the reverse order
165 		 * that they were mounted.  So, we save off the file name
166 		 * in some allocated memory, and then call recursively.
167 		 */
168 		if ((cp = malloc((size_t)strlen(fs->fs_file) + 1)) == NULL)
169 			err(1, NULL);
170 		(void)strcpy(cp, fs->fs_file);
171 		rval = umountall(typelist);
172 		return (umountfs(cp, typelist) || rval);
173 	}
174 	return (0);
175 }
176 
177 int
178 umountfs(name, typelist)
179 	char *name;
180 	char **typelist;
181 {
182 	enum clnt_stat clnt_stat;
183 	struct hostent *hp;
184 	struct sockaddr_in saddr;
185 	struct stat sb;
186 	struct timeval pertry, try;
187 	CLIENT *clp;
188 	int so;
189 	char *type, *delimp, *hostp, *mntpt, rname[MAXPATHLEN];
190 
191 	if (realpath(name, rname) == NULL) {
192 		warn("%s", rname);
193 		return (1);
194 	}
195 
196 	name = rname;
197 
198 	if (stat(name, &sb) < 0) {
199 		if (((mntpt = getmntname(name, MNTFROM, &type)) == NULL) &&
200 		    ((mntpt = getmntname(name, MNTON, &type)) == NULL)) {
201 			warnx("%s: not currently mounted", name);
202 			return (1);
203 		}
204 	} else if (S_ISBLK(sb.st_mode)) {
205 		if ((mntpt = getmntname(name, MNTON, &type)) == NULL) {
206 			warnx("%s: not currently mounted", name);
207 			return (1);
208 		}
209 	} else if (S_ISDIR(sb.st_mode)) {
210 		mntpt = name;
211 		if ((name = getmntname(mntpt, MNTFROM, &type)) == NULL) {
212 			warnx("%s: not currently mounted", mntpt);
213 			return (1);
214 		}
215 	} else {
216 		warnx("%s: not a directory or special device", name);
217 		return (1);
218 	}
219 
220 	if (checkvfsname(type, typelist))
221 		return (1);
222 
223 	hp = NULL;
224 	if (!strcmp(type, "nfs")) {
225 		if ((delimp = strchr(name, '@')) != NULL) {
226 			hostp = delimp + 1;
227 			*delimp = '\0';
228 			hp = gethostbyname(hostp);
229 			*delimp = '@';
230 		} else if ((delimp = strchr(name, ':')) != NULL) {
231 			*delimp = '\0';
232 			hostp = name;
233 			hp = gethostbyname(hostp);
234 			name = delimp + 1;
235 			*delimp = ':';
236 		}
237 	}
238 
239 	if (!namematch(hp))
240 		return (1);
241 
242 	if (vflag)
243 		(void)printf("%s: unmount from %s\n", name, mntpt);
244 	if (fake)
245 		return (0);
246 
247 	if (unmount(mntpt, fflag) < 0) {
248 		warn("%s", mntpt);
249 		return (1);
250 	}
251 
252 	if ((hp != NULL) && !(fflag & MNT_FORCE)) {
253 		*delimp = '\0';
254 		memset(&saddr, 0, sizeof(saddr));
255 		saddr.sin_family = AF_INET;
256 		saddr.sin_port = 0;
257 		memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
258 		pertry.tv_sec = 3;
259 		pertry.tv_usec = 0;
260 		so = RPC_ANYSOCK;
261 		if ((clp = clntudp_create(&saddr,
262 		    RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
263 			clnt_pcreateerror("Cannot MNT PRC");
264 			return (1);
265 		}
266 		clp->cl_auth = authunix_create_default();
267 		try.tv_sec = 20;
268 		try.tv_usec = 0;
269 		clnt_stat = clnt_call(clp,
270 		    RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
271 		if (clnt_stat != RPC_SUCCESS) {
272 			clnt_perror(clp, "Bad MNT RPC");
273 			return (1);
274 		}
275 		auth_destroy(clp->cl_auth);
276 		clnt_destroy(clp);
277 	}
278 	return (0);
279 }
280 
281 char *
282 getmntname(name, what, type)
283 	char *name;
284 	mntwhat what;
285 	char **type;
286 {
287 	static struct statfs *mntbuf;
288 	static int mntsize;
289 	int i;
290 
291 	if (mntbuf == NULL &&
292 	    (mntsize = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
293 		warn("getmntinfo");
294 		return (NULL);
295 	}
296 	for (i = 0; i < mntsize; i++) {
297 		if ((what == MNTON) && !strcmp(mntbuf[i].f_mntfromname, name)) {
298 			if (type)
299 				*type = mntbuf[i].f_fstypename;
300 			return (mntbuf[i].f_mntonname);
301 		}
302 		if ((what == MNTFROM) && !strcmp(mntbuf[i].f_mntonname, name)) {
303 			if (type)
304 				*type = mntbuf[i].f_fstypename;
305 			return (mntbuf[i].f_mntfromname);
306 		}
307 	}
308 	return (NULL);
309 }
310 
311 int
312 namematch(hp)
313 	struct hostent *hp;
314 {
315 	char *cp, **np;
316 
317 	if ((hp == NULL) || (nfshost == NULL))
318 		return (1);
319 
320 	if (strcasecmp(nfshost, hp->h_name) == 0)
321 		return (1);
322 
323 	if ((cp = strchr(hp->h_name, '.')) != NULL) {
324 		*cp = '\0';
325 		if (strcasecmp(nfshost, hp->h_name) == 0)
326 			return (1);
327 	}
328 	for (np = hp->h_aliases; *np; np++) {
329 		if (strcasecmp(nfshost, *np) == 0)
330 			return (1);
331 		if ((cp = strchr(*np, '.')) != NULL) {
332 			*cp = '\0';
333 			if (strcasecmp(nfshost, *np) == 0)
334 				return (1);
335 		}
336 	}
337 	return (0);
338 }
339 
340 /*
341  * xdr routines for mount rpc's
342  */
343 int
344 xdr_dir(xdrsp, dirp)
345 	XDR *xdrsp;
346 	char *dirp;
347 {
348 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
349 }
350 
351 void
352 usage()
353 {
354 	(void)fprintf(stderr,
355 	    "usage: %s\n       %s\n",
356 	    "umount [-fv] [-t fstypelist] special | node",
357 	    "umount -a[fv] [-h host] [-t fstypelist]");
358 	exit(1);
359 }
360