xref: /freebsd/usr.sbin/rpc.umntall/rpc.umntall.c (revision 10cb4f4a627af0b9fbdd3e6efc566962ef618599)
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 
99c69a34d4SMatthew Dillon 	/* Default expiretime is two days */
100c69a34d4SMatthew Dillon 	if (expire == 0)
101c69a34d4SMatthew Dillon 		expire = 172800;
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)
109c69a34d4SMatthew Dillon 				warnx("nothing to do, remove %s",
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) {
118c69a34d4SMatthew Dillon 						warnx("skipping entry %s:%s",
119c69a34d4SMatthew Dillon 						    mtab->mtab_host,
120c69a34d4SMatthew Dillon 						    mtab->mtab_dirp);
121c69a34d4SMatthew Dillon 					}
12210cb4f4aSGreg Lehey 				} else if (do_umount(mtab->mtab_host,
12310cb4f4aSGreg Lehey 				    mtab->mtab_dirp)) {
12410cb4f4aSGreg Lehey 					clean_mtab(mtab->mtab_host,
12510cb4f4aSGreg Lehey 					    mtab->mtab_dirp);
12610cb4f4aSGreg Lehey 				}
127c69a34d4SMatthew Dillon 			}
128c69a34d4SMatthew Dillon 		}
129c69a34d4SMatthew Dillon 	/* Only do a RPC UMNTALL for this specific host */
130c69a34d4SMatthew Dillon 	} else if (host != NULL && path == NULL) {
131c69a34d4SMatthew Dillon 		if (!do_umntall(host))
132c69a34d4SMatthew Dillon 			exit(1);
133c69a34d4SMatthew Dillon 		else
134c69a34d4SMatthew Dillon 			success = 1;
135c69a34d4SMatthew Dillon 	/* Someone forgot to enter a hostname */
136c69a34d4SMatthew Dillon 	} else if (host == NULL && path != NULL)
137c69a34d4SMatthew Dillon 		usage();
138c69a34d4SMatthew Dillon 	/* Only do a RPC UMOUNT for this specific mount */
139c69a34d4SMatthew Dillon 	else {
140c69a34d4SMatthew Dillon 		for (pathlen = strlen(path);
141c69a34d4SMatthew Dillon 		    pathlen > 1 && path[pathlen - 1] == '/'; pathlen--)
142c69a34d4SMatthew Dillon 			path[pathlen - 1] = '\0';
143c69a34d4SMatthew Dillon 		if (!do_umount(host, path))
144c69a34d4SMatthew Dillon 			exit(1);
145c69a34d4SMatthew Dillon 		else
146c69a34d4SMatthew Dillon 			success = 1;
147c69a34d4SMatthew Dillon 	}
148c69a34d4SMatthew Dillon 	/* Write and unlink PATH_MOUNTTAB if necessary */
149c69a34d4SMatthew Dillon 	if (success) {
150c69a34d4SMatthew Dillon 		if (verbose)
151c69a34d4SMatthew Dillon 			warnx("UMOUNT RPC successfully sent to %s", host);
152c69a34d4SMatthew Dillon 		if (read_mtab(mtab)) {
153c69a34d4SMatthew Dillon 			mtab = mtabhead;
154c69a34d4SMatthew Dillon 			clean_mtab(host, path);
155c69a34d4SMatthew Dillon 		}
156c69a34d4SMatthew Dillon 	}
157c69a34d4SMatthew Dillon 	if (!write_mtab()) {
158c69a34d4SMatthew Dillon 		free_mtab();
159c69a34d4SMatthew Dillon 		exit(1);
160c69a34d4SMatthew Dillon 	}
161c69a34d4SMatthew Dillon 	free_mtab();
162c69a34d4SMatthew Dillon 	exit(0);
163c69a34d4SMatthew Dillon }
164c69a34d4SMatthew Dillon 
165c69a34d4SMatthew Dillon /*
166c69a34d4SMatthew Dillon  * Send a RPC_MNT UMNTALL request to hostname.
16710cb4f4aSGreg Lehey  * XXX This works for all mountd implementations,
16810cb4f4aSGreg Lehey  * but produces a RPC IOERR on non FreeBSD systems.
169c69a34d4SMatthew Dillon  */
170c69a34d4SMatthew Dillon int
171c69a34d4SMatthew Dillon do_umntall(char *hostname) {
172c69a34d4SMatthew Dillon 	enum clnt_stat clnt_stat;
173c69a34d4SMatthew Dillon 	struct hostent *hp;
174c69a34d4SMatthew Dillon 	struct sockaddr_in saddr;
175c69a34d4SMatthew Dillon 	struct timeval pertry, try;
176c69a34d4SMatthew Dillon 	int so;
177c69a34d4SMatthew Dillon 	CLIENT *clp;
178c69a34d4SMatthew Dillon 
179c69a34d4SMatthew Dillon 	if ((hp = gethostbyname(hostname)) == NULL) {
180c69a34d4SMatthew Dillon 		warnx("gethostbyname(%s) failed", hostname);
181c69a34d4SMatthew Dillon 		return (0);
182c69a34d4SMatthew Dillon 	}
183c69a34d4SMatthew Dillon 	memset(&saddr, 0, sizeof(saddr));
184c69a34d4SMatthew Dillon 	saddr.sin_family = AF_INET;
185c69a34d4SMatthew Dillon 	saddr.sin_port = 0;
186c69a34d4SMatthew Dillon 	memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length,
187c69a34d4SMatthew Dillon 	    sizeof(saddr.sin_addr)));
188c69a34d4SMatthew Dillon 	pertry.tv_sec = 3;
189c69a34d4SMatthew Dillon 	pertry.tv_usec = 0;
190c69a34d4SMatthew Dillon 	so = RPC_ANYSOCK;
191c69a34d4SMatthew Dillon 	if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
192c69a34d4SMatthew Dillon 	    pertry, &so)) == NULL) {
193c69a34d4SMatthew Dillon 		clnt_pcreateerror("Cannot send MNT PRC");
194c69a34d4SMatthew Dillon 		return (0);
195c69a34d4SMatthew Dillon 	}
196c69a34d4SMatthew Dillon 	clp->cl_auth = authunix_create_default();
197c69a34d4SMatthew Dillon 	try.tv_sec = 3;
198c69a34d4SMatthew Dillon 	try.tv_usec = 0;
199c69a34d4SMatthew Dillon 	clnt_stat = clnt_call(clp, RPCMNT_UMNTALL, xdr_void, (caddr_t)0,
200c69a34d4SMatthew Dillon 	    xdr_void, (caddr_t)0, try);
201c69a34d4SMatthew Dillon 	if (clnt_stat != RPC_SUCCESS) {
202c69a34d4SMatthew Dillon 		clnt_perror(clp, "Bad MNT RPC");
203c69a34d4SMatthew Dillon 		return (0);
204c69a34d4SMatthew Dillon 	} else
205c69a34d4SMatthew Dillon 		return (1);
206c69a34d4SMatthew Dillon }
207c69a34d4SMatthew Dillon 
208c69a34d4SMatthew Dillon /*
209c69a34d4SMatthew Dillon  * Send a RPC_MNT UMOUNT request for dirp to hostname.
210c69a34d4SMatthew Dillon  */
211c69a34d4SMatthew Dillon int
212c69a34d4SMatthew Dillon do_umount(char *hostname, char *dirp) {
213c69a34d4SMatthew Dillon 	enum clnt_stat clnt_stat;
214c69a34d4SMatthew Dillon 	struct hostent *hp;
215c69a34d4SMatthew Dillon 	struct sockaddr_in saddr;
216c69a34d4SMatthew Dillon 	struct timeval pertry, try;
217c69a34d4SMatthew Dillon 	CLIENT *clp;
218c69a34d4SMatthew Dillon 	int so;
219c69a34d4SMatthew Dillon 
220c69a34d4SMatthew Dillon 	if ((hp = gethostbyname(hostname)) == NULL) {
221c69a34d4SMatthew Dillon 		warnx("gethostbyname(%s) failed", hostname);
222c69a34d4SMatthew Dillon 		return (0);
223c69a34d4SMatthew Dillon 	}
224c69a34d4SMatthew Dillon 	memset(&saddr, 0, sizeof(saddr));
225c69a34d4SMatthew Dillon 	saddr.sin_family = AF_INET;
226c69a34d4SMatthew Dillon 	saddr.sin_port = 0;
227c69a34d4SMatthew Dillon 	memmove(&saddr.sin_addr, hp->h_addr, MIN(hp->h_length,
228c69a34d4SMatthew Dillon 	    sizeof(saddr.sin_addr)));
229c69a34d4SMatthew Dillon 	pertry.tv_sec = 3;
230c69a34d4SMatthew Dillon 	pertry.tv_usec = 0;
231c69a34d4SMatthew Dillon 	so = RPC_ANYSOCK;
232c69a34d4SMatthew Dillon 	if ((clp = clntudp_create(&saddr, RPCPROG_MNT, RPCMNT_VER1,
233c69a34d4SMatthew Dillon 	    pertry, &so)) == NULL) {
234c69a34d4SMatthew Dillon 		clnt_pcreateerror("Cannot send MNT PRC");
235c69a34d4SMatthew Dillon 		return (0);
236c69a34d4SMatthew Dillon 	}
237c69a34d4SMatthew Dillon 	clp->cl_auth = authunix_create_default();
238c69a34d4SMatthew Dillon 	try.tv_sec = 3;
239c69a34d4SMatthew Dillon 	try.tv_usec = 0;
240c69a34d4SMatthew Dillon 	clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp,
241c69a34d4SMatthew Dillon 	    xdr_void, (caddr_t)0, try);
242c69a34d4SMatthew Dillon 	if (clnt_stat != RPC_SUCCESS) {
243c69a34d4SMatthew Dillon 		clnt_perror(clp, "Bad MNT RPC");
244c69a34d4SMatthew Dillon 		return (0);
245c69a34d4SMatthew Dillon 	}
246c69a34d4SMatthew Dillon 	return (1);
247c69a34d4SMatthew Dillon }
248c69a34d4SMatthew Dillon 
249c69a34d4SMatthew Dillon /*
250c69a34d4SMatthew Dillon  * Check if the entry is still/already mounted.
251c69a34d4SMatthew Dillon  */
252c69a34d4SMatthew Dillon int
253c69a34d4SMatthew Dillon is_mounted(char *hostname, char *dirp) {
254c69a34d4SMatthew Dillon 	struct statfs *mntbuf;
255c69a34d4SMatthew Dillon 	char name[MNAMELEN + 1];
256c69a34d4SMatthew Dillon 	size_t bufsize, hostlen, dirlen;
257c69a34d4SMatthew Dillon 	int mntsize, i;
258c69a34d4SMatthew Dillon 
259c69a34d4SMatthew Dillon 	hostlen = strlen(hostname);
260c69a34d4SMatthew Dillon 	dirlen = strlen(dirp);
261c69a34d4SMatthew Dillon 	if ((hostlen + dirlen) >= MNAMELEN)
262c69a34d4SMatthew Dillon 		return (0);
263c69a34d4SMatthew Dillon 	memmove(name, hostname, hostlen);
264c69a34d4SMatthew Dillon 	name[hostlen] = ':';
265c69a34d4SMatthew Dillon 	memmove(name + hostlen + 1, dirp, dirlen);
266c69a34d4SMatthew Dillon 	name[hostlen + dirlen + 1] = '\0';
267c69a34d4SMatthew Dillon 	mntsize = getfsstat(NULL, 0, MNT_NOWAIT);
268c69a34d4SMatthew Dillon 	if (mntsize <= 0)
269c69a34d4SMatthew Dillon 		return (0);
270c69a34d4SMatthew Dillon 	bufsize = (mntsize + 1) * sizeof(struct statfs);
271c69a34d4SMatthew Dillon 	if ((mntbuf = malloc(bufsize)) == NULL)
272c69a34d4SMatthew Dillon 		err(1, "malloc");
273c69a34d4SMatthew Dillon 	mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT);
274c69a34d4SMatthew Dillon 	for (i = mntsize - 1; i >= 0; i--) {
275c69a34d4SMatthew Dillon 		if (strcmp(mntbuf[i].f_mntfromname, name) == 0) {
276c69a34d4SMatthew Dillon 			free(mntbuf);
277c69a34d4SMatthew Dillon 			return (1);
278c69a34d4SMatthew Dillon 		}
279c69a34d4SMatthew Dillon 	}
280c69a34d4SMatthew Dillon 	free(mntbuf);
281c69a34d4SMatthew Dillon 	return (0);
282c69a34d4SMatthew Dillon }
283c69a34d4SMatthew Dillon 
284c69a34d4SMatthew Dillon /*
285c69a34d4SMatthew Dillon  * xdr routines for mount rpc's
286c69a34d4SMatthew Dillon  */
287c69a34d4SMatthew Dillon int
288c69a34d4SMatthew Dillon xdr_dir(XDR *xdrsp, char *dirp) {
289c69a34d4SMatthew Dillon 
290c69a34d4SMatthew Dillon 	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
291c69a34d4SMatthew Dillon }
292c69a34d4SMatthew Dillon 
293c69a34d4SMatthew Dillon static void
294c69a34d4SMatthew Dillon usage() {
295c69a34d4SMatthew Dillon 
296c69a34d4SMatthew Dillon 	(void)fprintf(stderr, "%s\n",
297c69a34d4SMatthew Dillon 	    "usage: rpc.umntall [-h host] [-k] [-p path] [-t expire] [-v]");
298c69a34d4SMatthew Dillon 	exit(1);
299c69a34d4SMatthew Dillon }
300