xref: /freebsd/usr.sbin/rpc.umntall/rpc.umntall.c (revision ab80d6fabc2f5e143d4e696a053696788ad56dad)
1c69a34d4SMatthew Dillon /*
2c69a34d4SMatthew Dillon  * Copyright (c) 1999 Martin Blapp
3c69a34d4SMatthew Dillon  * All rights reserved.
4c69a34d4SMatthew Dillon  *
5c69a34d4SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
6c69a34d4SMatthew Dillon  * modification, are permitted provided that the following conditions
7c69a34d4SMatthew Dillon  * are met:
8c69a34d4SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
9c69a34d4SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
10c69a34d4SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
11c69a34d4SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in the
12c69a34d4SMatthew Dillon  *    documentation and/or other materials provided with the distribution.
13c69a34d4SMatthew Dillon  *
14c69a34d4SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15c69a34d4SMatthew Dillon  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16c69a34d4SMatthew Dillon  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17c69a34d4SMatthew Dillon  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18c69a34d4SMatthew Dillon  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19c69a34d4SMatthew Dillon  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20c69a34d4SMatthew Dillon  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21c69a34d4SMatthew Dillon  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22c69a34d4SMatthew Dillon  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23c69a34d4SMatthew Dillon  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24c69a34d4SMatthew Dillon  * SUCH DAMAGE.
25c69a34d4SMatthew Dillon  *
26c69a34d4SMatthew Dillon  */
27c69a34d4SMatthew Dillon 
28c69a34d4SMatthew Dillon #ifndef lint
29c69a34d4SMatthew Dillon static const char rcsid[] =
30c69a34d4SMatthew Dillon   "$FreeBSD$";
31c69a34d4SMatthew Dillon #endif /* not lint */
32c69a34d4SMatthew Dillon 
33c69a34d4SMatthew Dillon #include <sys/param.h>
34c69a34d4SMatthew Dillon #include <sys/ucred.h>
35c69a34d4SMatthew Dillon #include <sys/mount.h>
36c69a34d4SMatthew Dillon 
37c69a34d4SMatthew Dillon #include <rpc/rpc.h>
38c69a34d4SMatthew Dillon #include <nfs/rpcv2.h>
39c69a34d4SMatthew Dillon 
40c69a34d4SMatthew Dillon #include <err.h>
41c69a34d4SMatthew Dillon #include <netdb.h>
42c69a34d4SMatthew Dillon #include <stdio.h>
43c69a34d4SMatthew Dillon #include <stdlib.h>
44c69a34d4SMatthew Dillon #include <string.h>
45c69a34d4SMatthew Dillon #include <unistd.h>
46c69a34d4SMatthew Dillon 
47c69a34d4SMatthew Dillon #include "mounttab.h"
48c69a34d4SMatthew Dillon 
49c69a34d4SMatthew Dillon int verbose;
50c69a34d4SMatthew Dillon 
51c69a34d4SMatthew Dillon static int do_umount (char *, char *);
52c69a34d4SMatthew Dillon static int do_umntall (char *);
53c69a34d4SMatthew Dillon static int is_mounted (char *, char *);
54c69a34d4SMatthew Dillon static void usage (void);
55c69a34d4SMatthew Dillon int	xdr_dir (XDR *, char *);
56c69a34d4SMatthew Dillon 
57c69a34d4SMatthew Dillon struct mtablist *mtabhead;
58c69a34d4SMatthew Dillon 
59c69a34d4SMatthew Dillon int
60c69a34d4SMatthew Dillon main(int argc, char **argv) {
61c69a34d4SMatthew Dillon 	int ch, keep, success, pathlen;
62c69a34d4SMatthew Dillon 	time_t expire, *now;
63c69a34d4SMatthew Dillon 	char *host, *path;
64c69a34d4SMatthew Dillon 	struct mtablist *mtab;
65c69a34d4SMatthew Dillon 
66c69a34d4SMatthew Dillon 	mtab = NULL;
67c69a34d4SMatthew Dillon 	now = NULL;
68c69a34d4SMatthew Dillon 	expire = 0;
69c69a34d4SMatthew Dillon 	host = path = '\0';
70c69a34d4SMatthew Dillon 	success = keep = verbose = 0;
71c69a34d4SMatthew Dillon 	while ((ch = getopt(argc, argv, "h:kp:ve:")) != -1)
72c69a34d4SMatthew Dillon 		switch (ch) {
73c69a34d4SMatthew Dillon 		case 'h':
74c69a34d4SMatthew Dillon 			host = optarg;
75c69a34d4SMatthew Dillon 			break;
76c69a34d4SMatthew Dillon 		case 'e':
77c69a34d4SMatthew Dillon 			expire = (time_t)optarg;
78c69a34d4SMatthew Dillon 			break;
79c69a34d4SMatthew Dillon 		case 'k':
80c69a34d4SMatthew Dillon 			keep = 1;
81c69a34d4SMatthew Dillon 			break;
82c69a34d4SMatthew Dillon 		case 'p':
83c69a34d4SMatthew Dillon 			path = optarg;
84c69a34d4SMatthew Dillon 			break;
85c69a34d4SMatthew Dillon 		case 'v':
86c69a34d4SMatthew Dillon 			verbose = 1;
87c69a34d4SMatthew Dillon 			break;
88c69a34d4SMatthew Dillon 		case '?':
89c69a34d4SMatthew Dillon 			usage();
90c69a34d4SMatthew Dillon 		default:
91c69a34d4SMatthew Dillon 		}
92c69a34d4SMatthew Dillon 	argc -= optind;
93c69a34d4SMatthew Dillon 	argv += optind;
94c69a34d4SMatthew Dillon 
95c69a34d4SMatthew Dillon 	/* Ignore SIGINT and SIGQUIT during shutdown */
96c69a34d4SMatthew Dillon 	signal(SIGINT, SIG_IGN);
97c69a34d4SMatthew Dillon 	signal(SIGQUIT, SIG_IGN);
98c69a34d4SMatthew Dillon 
99ab80d6faSBrian Feldman 	/* Default expiretime is one day */
100c69a34d4SMatthew Dillon 	if (expire == 0)
101ab80d6faSBrian Feldman 		expire = 86400;
102c69a34d4SMatthew Dillon 	/*
103c69a34d4SMatthew Dillon 	 * Read PATH_MOUNTTAB and check each entry
104c69a34d4SMatthew Dillon 	 * and do finally the unmounts.
105c69a34d4SMatthew Dillon 	 */
106c69a34d4SMatthew Dillon 	if (host == NULL && path == NULL) {
107c69a34d4SMatthew Dillon 	    	if (!read_mtab(mtab)) {
108c69a34d4SMatthew Dillon 			if (verbose)
109ab80d6faSBrian Feldman 				warnx("nothing to do, %s does not exist",
110c69a34d4SMatthew Dillon 				    PATH_MOUNTTAB);
111c69a34d4SMatthew Dillon 		}
112c69a34d4SMatthew Dillon 		for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) {
11310cb4f4aSGreg Lehey 			if (*mtab->mtab_host != '\0' ||
11410cb4f4aSGreg Lehey 			    mtab->mtab_time <= (time(now) - expire)) {
115c69a34d4SMatthew Dillon 				if (keep && is_mounted(mtab->mtab_host,
116c69a34d4SMatthew Dillon 				    mtab->mtab_dirp)) {
117c69a34d4SMatthew Dillon 					if (verbose) {
118ab80d6faSBrian Feldman 						warnx("skip entry %s:%s",
119c69a34d4SMatthew Dillon 						    mtab->mtab_host,
120c69a34d4SMatthew Dillon 						    mtab->mtab_dirp);
121c69a34d4SMatthew Dillon 					}
12210cb4f4aSGreg Lehey 				} else if (do_umount(mtab->mtab_host,
123ab80d6faSBrian Feldman 				    mtab->mtab_dirp) ||
124ab80d6faSBrian Feldman 				    mtab->mtab_time <= (time(now) - expire)) {
12510cb4f4aSGreg Lehey 					clean_mtab(mtab->mtab_host,
12610cb4f4aSGreg Lehey 					    mtab->mtab_dirp);
12710cb4f4aSGreg Lehey 				}
128c69a34d4SMatthew Dillon 			}
129c69a34d4SMatthew Dillon 		}
130c69a34d4SMatthew Dillon 	/* Only do a RPC UMNTALL for this specific host */
131c69a34d4SMatthew Dillon 	} else if (host != NULL && path == NULL) {
132c69a34d4SMatthew Dillon 		if (!do_umntall(host))
133c69a34d4SMatthew Dillon 			exit(1);
134c69a34d4SMatthew Dillon 		else
135c69a34d4SMatthew Dillon 			success = 1;
136c69a34d4SMatthew Dillon 	/* Someone forgot to enter a hostname */
137c69a34d4SMatthew Dillon 	} else if (host == NULL && path != NULL)
138c69a34d4SMatthew Dillon 		usage();
139c69a34d4SMatthew Dillon 	/* Only do a RPC UMOUNT for this specific mount */
140c69a34d4SMatthew Dillon 	else {
141c69a34d4SMatthew Dillon 		for (pathlen = strlen(path);
142c69a34d4SMatthew Dillon 		    pathlen > 1 && path[pathlen - 1] == '/'; pathlen--)
143c69a34d4SMatthew Dillon 			path[pathlen - 1] = '\0';
144c69a34d4SMatthew Dillon 		if (!do_umount(host, path))
145c69a34d4SMatthew Dillon 			exit(1);
146c69a34d4SMatthew Dillon 		else
147c69a34d4SMatthew Dillon 			success = 1;
148c69a34d4SMatthew Dillon 	}
149c69a34d4SMatthew Dillon 	/* Write and unlink PATH_MOUNTTAB if necessary */
150c69a34d4SMatthew Dillon 	if (success) {
151c69a34d4SMatthew Dillon 		if (verbose)
152c69a34d4SMatthew Dillon 			warnx("UMOUNT RPC successfully sent to %s", host);
153c69a34d4SMatthew Dillon 		if (read_mtab(mtab)) {
154c69a34d4SMatthew Dillon 			mtab = mtabhead;
155c69a34d4SMatthew Dillon 			clean_mtab(host, path);
156c69a34d4SMatthew Dillon 		}
157c69a34d4SMatthew Dillon 	}
158c69a34d4SMatthew Dillon 	if (!write_mtab()) {
159c69a34d4SMatthew Dillon 		free_mtab();
160c69a34d4SMatthew Dillon 		exit(1);
161c69a34d4SMatthew Dillon 	}
162c69a34d4SMatthew Dillon 	free_mtab();
163c69a34d4SMatthew Dillon 	exit(0);
164c69a34d4SMatthew Dillon }
165c69a34d4SMatthew Dillon 
166c69a34d4SMatthew Dillon /*
167c69a34d4SMatthew Dillon  * Send a RPC_MNT UMNTALL request to hostname.
16810cb4f4aSGreg Lehey  * XXX This works for all mountd implementations,
16910cb4f4aSGreg Lehey  * but produces a RPC IOERR on non FreeBSD systems.
170c69a34d4SMatthew Dillon  */
171c69a34d4SMatthew Dillon int
172c69a34d4SMatthew Dillon do_umntall(char *hostname) {
173c69a34d4SMatthew Dillon 	enum clnt_stat clnt_stat;
174c69a34d4SMatthew Dillon 	struct hostent *hp;
175c69a34d4SMatthew Dillon 	struct sockaddr_in saddr;
176c69a34d4SMatthew Dillon 	struct timeval pertry, try;
177c69a34d4SMatthew Dillon 	int so;
178c69a34d4SMatthew Dillon 	CLIENT *clp;
179c69a34d4SMatthew Dillon 
180c69a34d4SMatthew Dillon 	if ((hp = gethostbyname(hostname)) == NULL) {
181c69a34d4SMatthew Dillon 		warnx("gethostbyname(%s) failed", hostname);
182c69a34d4SMatthew Dillon 		return (0);
183c69a34d4SMatthew Dillon 	}
184c69a34d4SMatthew Dillon 	memset(&saddr, 0, sizeof(saddr));
185c69a34d4SMatthew Dillon 	saddr.sin_family = AF_INET;
186c69a34d4SMatthew Dillon 	saddr.sin_port = 0;
187c69a34d4SMatthew Dillon 	memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length,
188c69a34d4SMatthew Dillon 	    sizeof(saddr.sin_addr)));
189c69a34d4SMatthew Dillon 	pertry.tv_sec = 3;
190c69a34d4SMatthew Dillon 	pertry.tv_usec = 0;
191c69a34d4SMatthew Dillon 	so = RPC_ANYSOCK;
192c69a34d4SMatthew Dillon 	if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
193c69a34d4SMatthew Dillon 	    pertry, &so)) == NULL) {
194c69a34d4SMatthew Dillon 		clnt_pcreateerror("Cannot send MNT PRC");
195c69a34d4SMatthew Dillon 		return (0);
196c69a34d4SMatthew Dillon 	}
197c69a34d4SMatthew Dillon 	clp->cl_auth = authunix_create_default();
198c69a34d4SMatthew Dillon 	try.tv_sec = 3;
199c69a34d4SMatthew Dillon 	try.tv_usec = 0;
200c69a34d4SMatthew Dillon 	clnt_stat = clnt_call(clp, RPCMNT_UMNTALL, xdr_void, (caddr_t)0,
201c69a34d4SMatthew Dillon 	    xdr_void, (caddr_t)0, try);
202c69a34d4SMatthew Dillon 	if (clnt_stat != RPC_SUCCESS) {
203c69a34d4SMatthew Dillon 		clnt_perror(clp, "Bad MNT RPC");
204c69a34d4SMatthew Dillon 		return (0);
205c69a34d4SMatthew Dillon 	} else
206c69a34d4SMatthew Dillon 		return (1);
207c69a34d4SMatthew Dillon }
208c69a34d4SMatthew Dillon 
209c69a34d4SMatthew Dillon /*
210c69a34d4SMatthew Dillon  * Send a RPC_MNT UMOUNT request for dirp to hostname.
211c69a34d4SMatthew Dillon  */
212c69a34d4SMatthew Dillon int
213c69a34d4SMatthew Dillon do_umount(char *hostname, char *dirp) {
214c69a34d4SMatthew Dillon 	enum clnt_stat clnt_stat;
215c69a34d4SMatthew Dillon 	struct hostent *hp;
216c69a34d4SMatthew Dillon 	struct sockaddr_in saddr;
217c69a34d4SMatthew Dillon 	struct timeval pertry, try;
218c69a34d4SMatthew Dillon 	CLIENT *clp;
219c69a34d4SMatthew Dillon 	int so;
220c69a34d4SMatthew Dillon 
221c69a34d4SMatthew Dillon 	if ((hp = gethostbyname(hostname)) == NULL) {
222c69a34d4SMatthew Dillon 		warnx("gethostbyname(%s) failed", hostname);
223c69a34d4SMatthew Dillon 		return (0);
224c69a34d4SMatthew Dillon 	}
225c69a34d4SMatthew Dillon 	memset(&saddr, 0, sizeof(saddr));
226c69a34d4SMatthew Dillon 	saddr.sin_family = AF_INET;
227c69a34d4SMatthew Dillon 	saddr.sin_port = 0;
228c69a34d4SMatthew Dillon 	memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length,
229c69a34d4SMatthew Dillon 	    sizeof(saddr.sin_addr)));
230c69a34d4SMatthew Dillon 	pertry.tv_sec = 3;
231c69a34d4SMatthew Dillon 	pertry.tv_usec = 0;
232c69a34d4SMatthew Dillon 	so = RPC_ANYSOCK;
233c69a34d4SMatthew Dillon 	if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
234c69a34d4SMatthew Dillon 	    pertry, &so)) == NULL) {
235c69a34d4SMatthew Dillon 		clnt_pcreateerror("Cannot send MNT PRC");
236c69a34d4SMatthew Dillon 		return (0);
237c69a34d4SMatthew Dillon 	}
238c69a34d4SMatthew Dillon 	clp->cl_auth = authunix_create_default();
239c69a34d4SMatthew Dillon 	try.tv_sec = 3;
240c69a34d4SMatthew Dillon 	try.tv_usec = 0;
241c69a34d4SMatthew Dillon 	clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp,
242c69a34d4SMatthew Dillon 	    xdr_void, (caddr_t)0, try);
243c69a34d4SMatthew Dillon 	if (clnt_stat != RPC_SUCCESS) {
244c69a34d4SMatthew Dillon 		clnt_perror(clp, "Bad MNT RPC");
245c69a34d4SMatthew Dillon 		return (0);
246c69a34d4SMatthew Dillon 	}
247c69a34d4SMatthew Dillon 	return (1);
248c69a34d4SMatthew Dillon }
249c69a34d4SMatthew Dillon 
250c69a34d4SMatthew Dillon /*
251c69a34d4SMatthew Dillon  * Check if the entry is still/already mounted.
252c69a34d4SMatthew Dillon  */
253c69a34d4SMatthew Dillon int
254c69a34d4SMatthew Dillon is_mounted(char *hostname, char *dirp) {
255c69a34d4SMatthew Dillon 	struct statfs *mntbuf;
256c69a34d4SMatthew Dillon 	char name[MNAMELEN + 1];
257c69a34d4SMatthew Dillon 	size_t bufsize, hostlen, dirlen;
258c69a34d4SMatthew Dillon 	int mntsize, i;
259c69a34d4SMatthew Dillon 
260c69a34d4SMatthew Dillon 	hostlen = strlen(hostname);
261c69a34d4SMatthew Dillon 	dirlen = strlen(dirp);
262c69a34d4SMatthew Dillon 	if ((hostlen + dirlen) >= MNAMELEN)
263c69a34d4SMatthew Dillon 		return (0);
264c69a34d4SMatthew Dillon 	memmove(name, hostname, hostlen);
265c69a34d4SMatthew Dillon 	name[hostlen] = ':';
266c69a34d4SMatthew Dillon 	memmove(name + hostlen + 1, dirp, dirlen);
267c69a34d4SMatthew Dillon 	name[hostlen + dirlen + 1] = '\0';
268c69a34d4SMatthew Dillon 	mntsize = getfsstat(NULL, 0, MNT_NOWAIT);
269c69a34d4SMatthew Dillon 	if (mntsize <= 0)
270c69a34d4SMatthew Dillon 		return (0);
271c69a34d4SMatthew Dillon 	bufsize = (mntsize + 1) * sizeof(struct statfs);
272c69a34d4SMatthew Dillon 	if ((mntbuf = malloc(bufsize)) == NULL)
273c69a34d4SMatthew Dillon 		err(1, "malloc");
274c69a34d4SMatthew Dillon 	mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT);
275c69a34d4SMatthew Dillon 	for (i = mntsize - 1; i >= 0; i--) {
276c69a34d4SMatthew Dillon 		if (strcmp(mntbuf[i].f_mntfromname, name) == 0) {
277c69a34d4SMatthew Dillon 			free(mntbuf);
278c69a34d4SMatthew Dillon 			return (1);
279c69a34d4SMatthew Dillon 		}
280c69a34d4SMatthew Dillon 	}
281c69a34d4SMatthew Dillon 	free(mntbuf);
282c69a34d4SMatthew Dillon 	return (0);
283c69a34d4SMatthew Dillon }
284c69a34d4SMatthew Dillon 
285c69a34d4SMatthew Dillon /*
286c69a34d4SMatthew Dillon  * xdr routines for mount rpc's
287c69a34d4SMatthew Dillon  */
288c69a34d4SMatthew Dillon int
289c69a34d4SMatthew Dillon xdr_dir(XDR *xdrsp, char *dirp) {
290c69a34d4SMatthew Dillon 
291c69a34d4SMatthew Dillon 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
292c69a34d4SMatthew Dillon }
293c69a34d4SMatthew Dillon 
294c69a34d4SMatthew Dillon static void
295c69a34d4SMatthew Dillon usage() {
296c69a34d4SMatthew Dillon 
297c69a34d4SMatthew Dillon 	(void)fprintf(stderr, "%s\n",
298c69a34d4SMatthew Dillon 	    "usage: rpc.umntall [-h host] [-k] [-p path] [-t expire] [-v]");
299c69a34d4SMatthew Dillon 	exit(1);
300c69a34d4SMatthew Dillon }
301