xref: /openbsd-src/sbin/umount/umount.c (revision df69c215c7c66baf660f3f65414fd34796c96152)
1*df69c215Sderaadt /*	$OpenBSD: umount.c,v 1.29 2019/06/28 13:32:46 deraadt Exp $	*/
2daf2c1c7Sderaadt /*	$NetBSD: umount.c,v 1.16 1996/05/11 14:13:55 mycroft Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*-
5df930be7Sderaadt  * Copyright (c) 1980, 1989, 1993
6df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
7df930be7Sderaadt  *
8df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
9df930be7Sderaadt  * modification, are permitted provided that the following conditions
10df930be7Sderaadt  * are met:
11df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
12df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
13df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
14df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
15df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
161ef0d710Smillert  * 3. Neither the name of the University nor the names of its contributors
17df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
18df930be7Sderaadt  *    without specific prior written permission.
19df930be7Sderaadt  *
20df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30df930be7Sderaadt  * SUCH DAMAGE.
31df930be7Sderaadt  */
32df930be7Sderaadt 
33df930be7Sderaadt #include <sys/stat.h>
34df930be7Sderaadt #include <sys/mount.h>
35df930be7Sderaadt #include <sys/time.h>
36df930be7Sderaadt #include <sys/socket.h>
37df930be7Sderaadt 
38df930be7Sderaadt #include <netdb.h>
39df930be7Sderaadt #include <rpc/rpc.h>
40df930be7Sderaadt #include <rpc/pmap_clnt.h>
41df930be7Sderaadt #include <rpc/pmap_prot.h>
42df930be7Sderaadt #include <nfs/rpcv2.h>
43df930be7Sderaadt 
44df930be7Sderaadt #include <err.h>
45df930be7Sderaadt #include <stdio.h>
46df930be7Sderaadt #include <stdlib.h>
47df930be7Sderaadt #include <string.h>
48df930be7Sderaadt #include <unistd.h>
49b9fc9a72Sderaadt #include <limits.h>
504f8d7d4eSjsing #include <util.h>
51df930be7Sderaadt 
52df930be7Sderaadt typedef enum { MNTON, MNTFROM } mntwhat;
53df930be7Sderaadt 
549748606aSotto int	fflag, verbose;
55df930be7Sderaadt char	**typelist = NULL;
56df930be7Sderaadt char	*nfshost;
57df930be7Sderaadt 
58c72b5b24Smillert char	*getmntname(char *, mntwhat, char *);
59c72b5b24Smillert void	 maketypelist(char *);
60c72b5b24Smillert int	 selected(const char *);
61c72b5b24Smillert int	 namematch(struct hostent *);
62c72b5b24Smillert int	 umountall(void);
63c72b5b24Smillert int	 umountfs(char *);
64c72b5b24Smillert void	 usage(void);
65c72b5b24Smillert int	 xdr_dir(XDR *, char *);
66df930be7Sderaadt 
67df930be7Sderaadt int
main(int argc,char * argv[])68bc52e260Sderaadt main(int argc, char *argv[])
69df930be7Sderaadt {
70df930be7Sderaadt 	int all, ch, errs;
71df930be7Sderaadt 
72df930be7Sderaadt 	/* Start disks transferring immediately. */
73df930be7Sderaadt 	sync();
74df930be7Sderaadt 
75df930be7Sderaadt 	all = 0;
769748606aSotto 	while ((ch = getopt(argc, argv, "afh:t:v")) != -1)
77df930be7Sderaadt 		switch (ch) {
78df930be7Sderaadt 		case 'a':
79df930be7Sderaadt 			all = 1;
80df930be7Sderaadt 			break;
81df930be7Sderaadt 		case 'f':
82df930be7Sderaadt 			fflag = MNT_FORCE;
83df930be7Sderaadt 			break;
84df930be7Sderaadt 		case 'h':	/* -h implies -a. */
85df930be7Sderaadt 			all = 1;
86df930be7Sderaadt 			nfshost = optarg;
87df930be7Sderaadt 			break;
88df930be7Sderaadt 		case 't':
89df930be7Sderaadt 			if (typelist != NULL)
90df930be7Sderaadt 				errx(1, "only one -t option may be specified.");
91df930be7Sderaadt 			maketypelist(optarg);
92df930be7Sderaadt 			break;
93df930be7Sderaadt 		case 'v':
94df930be7Sderaadt 			verbose = 1;
95df930be7Sderaadt 			break;
96df930be7Sderaadt 		default:
97df930be7Sderaadt 			usage();
98df930be7Sderaadt 			/* NOTREACHED */
99df930be7Sderaadt 		}
100df930be7Sderaadt 	argc -= optind;
101df930be7Sderaadt 	argv += optind;
102df930be7Sderaadt 
103d163d384Smillert 	if ((argc == 0 && !all) || (argc != 0 && all))
104df930be7Sderaadt 		usage();
105df930be7Sderaadt 
106df930be7Sderaadt 	/* -h implies "-t nfs" if no -t flag. */
107df930be7Sderaadt 	if ((nfshost != NULL) && (typelist == NULL))
108f36c79e0Sbluhm 		maketypelist(MOUNT_NFS);
109df930be7Sderaadt 
110daf2c1c7Sderaadt 	if (all)
111df930be7Sderaadt 		errs = umountall();
112daf2c1c7Sderaadt 	else
113df930be7Sderaadt 		for (errs = 0; *argv != NULL; ++argv)
114df930be7Sderaadt 			if (umountfs(*argv) != 0)
115df930be7Sderaadt 				errs = 1;
11678033796Smickey 	return (errs);
117df930be7Sderaadt }
118df930be7Sderaadt 
119df930be7Sderaadt int
umountall(void)120bc52e260Sderaadt umountall(void)
121df930be7Sderaadt {
122daf2c1c7Sderaadt 	struct statfs *fs;
123daf2c1c7Sderaadt 	int n;
124daf2c1c7Sderaadt 	int rval;
125df930be7Sderaadt 
126daf2c1c7Sderaadt 	n = getmntinfo(&fs, MNT_NOWAIT);
127daf2c1c7Sderaadt 	if (n == 0)
128daf2c1c7Sderaadt 		err(1, NULL);
129daf2c1c7Sderaadt 
130daf2c1c7Sderaadt 	rval = 0;
131daf2c1c7Sderaadt 	while (--n >= 0) {
132daf2c1c7Sderaadt 		/* Ignore the root. */
133daf2c1c7Sderaadt 		if (strncmp(fs[n].f_mntonname, "/", MNAMELEN) == 0)
134daf2c1c7Sderaadt 			continue;
135daf2c1c7Sderaadt 		if (!selected(fs[n].f_fstypename))
136daf2c1c7Sderaadt 			continue;
137daf2c1c7Sderaadt 		if (umountfs(fs[n].f_mntonname))
138daf2c1c7Sderaadt 			rval = 1;
139eaa059b4Sderaadt 	}
140eaa059b4Sderaadt 	return (rval);
141df930be7Sderaadt }
142df930be7Sderaadt 
143df930be7Sderaadt int
umountfs(char * oname)144bc52e260Sderaadt umountfs(char *oname)
145df930be7Sderaadt {
146df930be7Sderaadt 	struct hostent *hp;
1471c6ffb17Skrw #ifndef NO_NFS
148df930be7Sderaadt 	struct sockaddr_in saddr;
149df930be7Sderaadt 	struct timeval pertry, try;
150df930be7Sderaadt 	CLIENT *clp;
151df930be7Sderaadt 	int so;
1521c6ffb17Skrw #endif
1531c6ffb17Skrw 	struct stat sb;
154d163d384Smillert 	char *delimp, *hostp, *mntpt;
155b9fc9a72Sderaadt 	char *name, *newname, rname[PATH_MAX], type[MFSNAMELEN];
156df930be7Sderaadt 
1574f8d7d4eSjsing 	if (isduid(oname, 0) || realpath(oname, rname) == NULL)
158286915a4Smillert 		mntpt = name = oname;
159286915a4Smillert 	else
160df930be7Sderaadt 		mntpt = name = rname;
161d163d384Smillert 	newname = NULL;
162df930be7Sderaadt 
163a9e0b2b4Smillert 	/* If we can stat the file, check to see if it is a device or non-dir */
164a9e0b2b4Smillert 	if (stat(name, &sb) == 0) {
165a9e0b2b4Smillert 	    if (S_ISBLK(sb.st_mode)) {
166a9e0b2b4Smillert 		if ((mntpt = getmntname(name, MNTON, type)) == NULL) {
167a9e0b2b4Smillert 			warnx("%s: not currently mounted", name);
168a9e0b2b4Smillert 			return (1);
169a9e0b2b4Smillert 		}
170a9e0b2b4Smillert 	    } else if (!S_ISDIR(sb.st_mode)) {
171a9e0b2b4Smillert 		warnx("%s: not a directory or special device", name);
172a9e0b2b4Smillert 		return (1);
173a9e0b2b4Smillert 	    }
174a9e0b2b4Smillert 	}
175a9e0b2b4Smillert 
176d163d384Smillert 	/*
177a9e0b2b4Smillert 	 * Look up the name in the mount table.
178d163d384Smillert 	 * 99.9% of the time the path in the kernel is the one
179d163d384Smillert 	 * realpath() returns but check the original just in case...
180d163d384Smillert 	 */
181d163d384Smillert 	if (!(newname = getmntname(name, MNTFROM, type)) &&
182d163d384Smillert 	    !(mntpt = getmntname(name, MNTON, type)) ) {
183d163d384Smillert 		mntpt = oname;
184d163d384Smillert 		if (!(newname = getmntname(oname, MNTFROM, type)) &&
185d163d384Smillert 		    !(mntpt = getmntname(oname, MNTON, type))) {
186d163d384Smillert 			warnx("%s: not currently mounted", oname);
187df930be7Sderaadt 			return (1);
188df930be7Sderaadt 		}
189df930be7Sderaadt 	}
190d163d384Smillert 	if (newname)
191d163d384Smillert 		name = newname;
192df930be7Sderaadt 
193df930be7Sderaadt 	if (!selected(type))
194df930be7Sderaadt 		return (1);
195df930be7Sderaadt 
196df930be7Sderaadt 	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN)) {
197df930be7Sderaadt 		if ((delimp = strchr(name, '@')) != NULL) {
198df930be7Sderaadt 			hostp = delimp + 1;
199df930be7Sderaadt 			*delimp = '\0';
200df930be7Sderaadt 			hp = gethostbyname(hostp);
201df930be7Sderaadt 			*delimp = '@';
202df930be7Sderaadt 		} else if ((delimp = strchr(name, ':')) != NULL) {
203df930be7Sderaadt 			*delimp = '\0';
204df930be7Sderaadt 			hostp = name;
205df930be7Sderaadt 			hp = gethostbyname(hostp);
206df930be7Sderaadt 			name = delimp + 1;
207df930be7Sderaadt 			*delimp = ':';
208df930be7Sderaadt 		} else
209df930be7Sderaadt 			hp = NULL;
210df930be7Sderaadt 		if (!namematch(hp))
211df930be7Sderaadt 			return (1);
212df930be7Sderaadt 	}
213df930be7Sderaadt 
214df930be7Sderaadt 	if (verbose)
2154f8d7d4eSjsing 		printf("%s: unmount from %s\n", name, mntpt);
216df930be7Sderaadt 
217*df69c215Sderaadt 	if (unmount(mntpt, fflag) == -1) {
218df930be7Sderaadt 		warn("%s", mntpt);
219df930be7Sderaadt 		return (1);
220df930be7Sderaadt 	}
221df930be7Sderaadt 
222cc96206aSderaadt #ifndef NO_NFS
223df930be7Sderaadt 	if (!strncmp(type, MOUNT_NFS, MFSNAMELEN) &&
224df930be7Sderaadt 	    (hp != NULL) && !(fflag & MNT_FORCE)) {
225cc96206aSderaadt 		enum clnt_stat clnt_stat;
226cc96206aSderaadt 
227df930be7Sderaadt 		*delimp = '\0';
228df930be7Sderaadt 		memset(&saddr, 0, sizeof(saddr));
229df930be7Sderaadt 		saddr.sin_family = AF_INET;
230df930be7Sderaadt 		saddr.sin_port = 0;
231df930be7Sderaadt 		memmove(&saddr.sin_addr, hp->h_addr, hp->h_length);
232df930be7Sderaadt 		pertry.tv_sec = 3;
233df930be7Sderaadt 		pertry.tv_usec = 0;
234df930be7Sderaadt 		so = RPC_ANYSOCK;
235df930be7Sderaadt 		if ((clp = clntudp_create(&saddr,
236df930be7Sderaadt 		    RPCPROG_MNT, RPCMNT_VER1, pertry, &so)) == NULL) {
23767bfe771Slandry 			clnt_pcreateerror("Cannot MNT RPC");
238df930be7Sderaadt 			return (1);
239df930be7Sderaadt 		}
240df930be7Sderaadt 		clp->cl_auth = authunix_create_default();
241df930be7Sderaadt 		try.tv_sec = 20;
242df930be7Sderaadt 		try.tv_usec = 0;
243df930be7Sderaadt 		clnt_stat = clnt_call(clp,
244df930be7Sderaadt 		    RPCMNT_UMOUNT, xdr_dir, name, xdr_void, (caddr_t)0, try);
245df930be7Sderaadt 		if (clnt_stat != RPC_SUCCESS) {
246df930be7Sderaadt 			clnt_perror(clp, "Bad MNT RPC");
247df930be7Sderaadt 			return (1);
248df930be7Sderaadt 		}
249df930be7Sderaadt 		auth_destroy(clp->cl_auth);
250df930be7Sderaadt 		clnt_destroy(clp);
251df930be7Sderaadt 	}
252cc96206aSderaadt #endif
253df930be7Sderaadt 	return (0);
254df930be7Sderaadt }
255df930be7Sderaadt 
256df930be7Sderaadt char *
getmntname(char * name,mntwhat what,char * type)257bc52e260Sderaadt getmntname(char *name, mntwhat what, char *type)
258df930be7Sderaadt {
259df930be7Sderaadt 	struct statfs *mntbuf;
2601c5a97dcSmillert 	int n;
261df930be7Sderaadt 
2621c5a97dcSmillert 	if ((n = getmntinfo(&mntbuf, MNT_NOWAIT)) == 0) {
263df930be7Sderaadt 		warn("getmntinfo");
264df930be7Sderaadt 		return (NULL);
265df930be7Sderaadt 	}
2661c5a97dcSmillert 	while (--n >= 0) {
2674f8d7d4eSjsing 		if ((what == MNTON) &&
2681c5a97dcSmillert 		    (strncmp(mntbuf[n].f_mntfromname, name, MNAMELEN) == 0 ||
2691c5a97dcSmillert 		     strncmp(mntbuf[n].f_mntfromspec, name, MNAMELEN) == 0)) {
270df930be7Sderaadt 			if (type)
2711c5a97dcSmillert 				memcpy(type, mntbuf[n].f_fstypename,
2721c5a97dcSmillert 				    sizeof(mntbuf[n].f_fstypename));
2731c5a97dcSmillert 			return (mntbuf[n].f_mntonname);
274df930be7Sderaadt 		}
2754f8d7d4eSjsing 		if ((what == MNTFROM) &&
2761c5a97dcSmillert 		    (strncmp(mntbuf[n].f_mntonname, name, MNAMELEN) == 0)) {
277df930be7Sderaadt 			if (type)
2781c5a97dcSmillert 				memcpy(type, mntbuf[n].f_fstypename,
2791c5a97dcSmillert 				    sizeof(mntbuf[n].f_fstypename));
2801c5a97dcSmillert 			return (mntbuf[n].f_mntfromname);
281df930be7Sderaadt 		}
282df930be7Sderaadt 	}
283df930be7Sderaadt 	return (NULL);
284df930be7Sderaadt }
285df930be7Sderaadt 
286df930be7Sderaadt static enum { IN_LIST, NOT_IN_LIST } which;
287df930be7Sderaadt 
288df930be7Sderaadt int
selected(const char * type)289bc52e260Sderaadt selected(const char *type)
290df930be7Sderaadt {
291df930be7Sderaadt 	char **av;
292df930be7Sderaadt 
293df930be7Sderaadt 	/* If no type specified, it's always selected. */
294df930be7Sderaadt 	if (typelist == NULL)
295df930be7Sderaadt 		return (1);
296df930be7Sderaadt 	for (av = typelist; *av != NULL; ++av)
297df930be7Sderaadt 		if (!strncmp(type, *av, MFSNAMELEN))
298df930be7Sderaadt 			return (which == IN_LIST ? 1 : 0);
299df930be7Sderaadt 	return (which == IN_LIST ? 0 : 1);
300df930be7Sderaadt }
301df930be7Sderaadt 
302df930be7Sderaadt void
maketypelist(char * fslist)303bc52e260Sderaadt maketypelist(char *fslist)
304df930be7Sderaadt {
305df930be7Sderaadt 	int i;
306df930be7Sderaadt 	char *nextcp, **av;
307df930be7Sderaadt 
308df930be7Sderaadt 	if ((fslist == NULL) || (fslist[0] == '\0'))
309df930be7Sderaadt 		errx(1, "empty type list");
310df930be7Sderaadt 
311df930be7Sderaadt 	/*
312df930be7Sderaadt 	 * XXX
313df930be7Sderaadt 	 * Note: the syntax is "noxxx,yyy" for no xxx's and
314f36c79e0Sbluhm 	 * no yyy's, not the more intuitive "noxxx,noyyy".
315df930be7Sderaadt 	 */
316df930be7Sderaadt 	if (fslist[0] == 'n' && fslist[1] == 'o') {
317df930be7Sderaadt 		fslist += 2;
318df930be7Sderaadt 		which = NOT_IN_LIST;
319df930be7Sderaadt 	} else
320df930be7Sderaadt 		which = IN_LIST;
321df930be7Sderaadt 
322df930be7Sderaadt 	/* Count the number of types. */
323d163d384Smillert 	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++)
324df930be7Sderaadt 		++nextcp;
325df930be7Sderaadt 
326df930be7Sderaadt 	/* Build an array of that many types. */
3271ed98fdfSderaadt 	if ((av = typelist = calloc(i + 1, sizeof(char *))) == NULL)
328df930be7Sderaadt 		err(1, NULL);
329df930be7Sderaadt 	av[0] = fslist;
330d163d384Smillert 	for (i = 1, nextcp = fslist; (nextcp = strchr(nextcp, ',')); i++) {
331df930be7Sderaadt 		*nextcp = '\0';
332df930be7Sderaadt 		av[i] = ++nextcp;
333df930be7Sderaadt 	}
334df930be7Sderaadt 	/* Terminate the array. */
335df930be7Sderaadt 	av[i] = NULL;
336df930be7Sderaadt }
337df930be7Sderaadt 
338df930be7Sderaadt int
namematch(struct hostent * hp)339bc52e260Sderaadt namematch(struct hostent *hp)
340df930be7Sderaadt {
341df930be7Sderaadt 	char *cp, **np;
342df930be7Sderaadt 
343df930be7Sderaadt 	if ((hp == NULL) || (nfshost == NULL))
344df930be7Sderaadt 		return (1);
345df930be7Sderaadt 
346df930be7Sderaadt 	if (strcasecmp(nfshost, hp->h_name) == 0)
347df930be7Sderaadt 		return (1);
348df930be7Sderaadt 
349df930be7Sderaadt 	if ((cp = strchr(hp->h_name, '.')) != NULL) {
350df930be7Sderaadt 		*cp = '\0';
351df930be7Sderaadt 		if (strcasecmp(nfshost, hp->h_name) == 0)
352df930be7Sderaadt 			return (1);
353df930be7Sderaadt 	}
354df930be7Sderaadt 	for (np = hp->h_aliases; *np; np++) {
355df930be7Sderaadt 		if (strcasecmp(nfshost, *np) == 0)
356df930be7Sderaadt 			return (1);
357df930be7Sderaadt 		if ((cp = strchr(*np, '.')) != NULL) {
358df930be7Sderaadt 			*cp = '\0';
359df930be7Sderaadt 			if (strcasecmp(nfshost, *np) == 0)
360df930be7Sderaadt 				return (1);
361df930be7Sderaadt 		}
362df930be7Sderaadt 	}
363df930be7Sderaadt 	return (0);
364df930be7Sderaadt }
365df930be7Sderaadt 
366cc96206aSderaadt #ifndef NO_NFS
367df930be7Sderaadt /*
368df930be7Sderaadt  * xdr routines for mount rpc's
369df930be7Sderaadt  */
370df930be7Sderaadt int
xdr_dir(XDR * xdrsp,char * dirp)371bc52e260Sderaadt xdr_dir(XDR *xdrsp, char *dirp)
372df930be7Sderaadt {
373df930be7Sderaadt 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
374df930be7Sderaadt }
375cc96206aSderaadt #endif
376df930be7Sderaadt 
377df930be7Sderaadt void
usage(void)378bc52e260Sderaadt usage(void)
379df930be7Sderaadt {
3804f8d7d4eSjsing 	fprintf(stderr,
381df930be7Sderaadt 	    "usage: %s\n       %s\n",
38263f0fc50Sjmc 	    "umount [-fv] special | node",
38363f0fc50Sjmc 	    "umount -a [-fv] [-h host] [-t type]");
384df930be7Sderaadt 	exit(1);
385df930be7Sderaadt }
386