rpc.umntall.c revision 146664
153494Sdillon/*
253494Sdillon * Copyright (c) 1999 Martin Blapp
353494Sdillon * All rights reserved.
453494Sdillon *
553494Sdillon * Redistribution and use in source and binary forms, with or without
653494Sdillon * modification, are permitted provided that the following conditions
753494Sdillon * are met:
853494Sdillon * 1. Redistributions of source code must retain the above copyright
953494Sdillon *    notice, this list of conditions and the following disclaimer.
1053494Sdillon * 2. Redistributions in binary form must reproduce the above copyright
1153494Sdillon *    notice, this list of conditions and the following disclaimer in the
1253494Sdillon *    documentation and/or other materials provided with the distribution.
1353494Sdillon *
1453494Sdillon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1553494Sdillon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1653494Sdillon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1753494Sdillon * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1853494Sdillon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1953494Sdillon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2053494Sdillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2153494Sdillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2253494Sdillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2353494Sdillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2453494Sdillon * SUCH DAMAGE.
2553494Sdillon *
2653494Sdillon */
2753494Sdillon
2853494Sdillon#ifndef lint
2953494Sdillonstatic const char rcsid[] =
3053494Sdillon  "$FreeBSD: head/usr.sbin/rpc.umntall/rpc.umntall.c 146664 2005-05-27 00:05:16Z mux $";
3153494Sdillon#endif /* not lint */
3253494Sdillon
3353494Sdillon#include <sys/param.h>
3453494Sdillon#include <sys/ucred.h>
3553494Sdillon#include <sys/mount.h>
3653494Sdillon
3753494Sdillon#include <rpc/rpc.h>
3853494Sdillon#include <nfs/rpcv2.h>
3953494Sdillon
4053494Sdillon#include <err.h>
4153494Sdillon#include <netdb.h>
4253494Sdillon#include <stdio.h>
4353494Sdillon#include <stdlib.h>
4453494Sdillon#include <string.h>
4553494Sdillon#include <unistd.h>
4653494Sdillon
4753494Sdillon#include "mounttab.h"
4853494Sdillon
4953494Sdillonint verbose;
5053494Sdillon
5153494Sdillonstatic int do_umount (char *, char *);
5253494Sdillonstatic int do_umntall (char *);
5353494Sdillonstatic int is_mounted (char *, char *);
5453494Sdillonstatic void usage (void);
5553494Sdillonint	xdr_dir (XDR *, char *);
5653494Sdillon
5753494Sdillonint
5853494Sdillonmain(int argc, char **argv) {
5953494Sdillon	int ch, keep, success, pathlen;
6080123Siedowse	time_t expire, now;
6153494Sdillon	char *host, *path;
6253494Sdillon	struct mtablist *mtab;
6353494Sdillon
6453494Sdillon	expire = 0;
6580123Siedowse	host = path = NULL;
6653494Sdillon	success = keep = verbose = 0;
6753494Sdillon	while ((ch = getopt(argc, argv, "h:kp:ve:")) != -1)
6853494Sdillon		switch (ch) {
6953494Sdillon		case 'h':
7053494Sdillon			host = optarg;
7153494Sdillon			break;
7253494Sdillon		case 'e':
7378343Sjlemon			expire = atoi(optarg);
7453494Sdillon			break;
7553494Sdillon		case 'k':
7653494Sdillon			keep = 1;
7753494Sdillon			break;
7853494Sdillon		case 'p':
7953494Sdillon			path = optarg;
8053494Sdillon			break;
8153494Sdillon		case 'v':
8253494Sdillon			verbose = 1;
8353494Sdillon			break;
8453494Sdillon		case '?':
8553494Sdillon			usage();
8653494Sdillon		default:
87114119Simp			break;
8853494Sdillon		}
8953494Sdillon	argc -= optind;
9053494Sdillon	argv += optind;
9153494Sdillon
9256038Sgreen	/* Default expiretime is one day */
9353494Sdillon	if (expire == 0)
9456038Sgreen		expire = 86400;
9580123Siedowse	time(&now);
9680123Siedowse
9780123Siedowse	/* Read PATH_MOUNTTAB. */
9880146Siedowse	if (!read_mtab()) {
9980123Siedowse		if (verbose)
10080123Siedowse			warnx("no mounttab entries (%s does not exist)",
10180123Siedowse			    PATH_MOUNTTAB);
10280123Siedowse		mtabhead = NULL;
10380123Siedowse	}
10480123Siedowse
10553494Sdillon	if (host == NULL && path == NULL) {
10680123Siedowse		/* Check each entry and do any necessary unmount RPCs. */
10753494Sdillon		for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) {
10880123Siedowse			if (*mtab->mtab_host == '\0')
10980123Siedowse				continue;
11080123Siedowse			if (mtab->mtab_time + expire < now) {
11180123Siedowse				/* Clear expired entry. */
11280123Siedowse				if (verbose)
11380123Siedowse					warnx("remove expired entry %s:%s",
11480123Siedowse					    mtab->mtab_host, mtab->mtab_dirp);
11580123Siedowse				bzero(mtab->mtab_host,
11680123Siedowse				    sizeof(mtab->mtab_host));
11780123Siedowse				continue;
11853494Sdillon			}
11980123Siedowse			if (keep && is_mounted(mtab->mtab_host,
12080123Siedowse			    mtab->mtab_dirp)) {
12180123Siedowse				if (verbose)
12280123Siedowse					warnx("skip entry %s:%s",
12380123Siedowse					    mtab->mtab_host, mtab->mtab_dirp);
12480123Siedowse				continue;
12580123Siedowse			}
12680123Siedowse			if (do_umount(mtab->mtab_host, mtab->mtab_dirp)) {
12780123Siedowse				if (verbose)
12880123Siedowse					warnx("umount RPC for %s:%s succeeded",
12980123Siedowse					    mtab->mtab_host, mtab->mtab_dirp);
13080123Siedowse				/* Remove all entries for this host + path. */
13180146Siedowse				clean_mtab(mtab->mtab_host, mtab->mtab_dirp,
13280146Siedowse				    verbose);
13380123Siedowse			}
13453494Sdillon		}
13580123Siedowse		success = 1;
13680123Siedowse	} else {
13780123Siedowse		if (host == NULL && path != NULL)
13880123Siedowse			/* Missing hostname. */
13980123Siedowse			usage();
14080123Siedowse		if (path == NULL) {
14180123Siedowse			/* Do a RPC UMNTALL for this specific host */
14280123Siedowse			success = do_umntall(host);
14380123Siedowse			if (verbose && success)
14480123Siedowse				warnx("umntall RPC for %s succeeded", host);
14580123Siedowse		} else {
14680123Siedowse			/* Do a RPC UMNTALL for this specific mount */
14780123Siedowse			for (pathlen = strlen(path);
14880123Siedowse			    pathlen > 1 && path[pathlen - 1] == '/'; pathlen--)
14980123Siedowse				path[pathlen - 1] = '\0';
15080123Siedowse			success = do_umount(host, path);
15180123Siedowse			if (verbose && success)
15280123Siedowse				warnx("umount RPC for %s:%s succeeded", host,
15380123Siedowse				    path);
15480123Siedowse		}
15580123Siedowse		/* If successful, remove any corresponding mounttab entries. */
15680123Siedowse		if (success)
15780146Siedowse			clean_mtab(host, path, verbose);
15853494Sdillon	}
15953494Sdillon	/* Write and unlink PATH_MOUNTTAB if necessary */
16080123Siedowse	if (success)
16180146Siedowse		success = write_mtab(verbose);
16253494Sdillon	free_mtab();
16380123Siedowse	exit (success ? 0 : 1);
16453494Sdillon}
16553494Sdillon
16653494Sdillon/*
16753494Sdillon * Send a RPC_MNT UMNTALL request to hostname.
16854341Sgrog * XXX This works for all mountd implementations,
16954341Sgrog * but produces a RPC IOERR on non FreeBSD systems.
17053494Sdillon */
17153494Sdillonint
17253494Sdillondo_umntall(char *hostname) {
17353494Sdillon	enum clnt_stat clnt_stat;
17474462Salfred	struct timeval try;
17553494Sdillon	CLIENT *clp;
17653494Sdillon
177146664Smux	try.tv_sec = 3;
178146664Smux	try.tv_usec = 0;
179146664Smux	clp = clnt_create_timed(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp",
180146664Smux	    &try);
18180123Siedowse	if (clp == NULL) {
18280123Siedowse		warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT"));
18381070Siedowse		return (0);
18453494Sdillon	}
18553494Sdillon	clp->cl_auth = authunix_create_default();
186121560Speter	clnt_stat = clnt_call(clp, RPCMNT_UMNTALL,
187121560Speter	    (xdrproc_t)xdr_void, (caddr_t)0,
188121560Speter	    (xdrproc_t)xdr_void, (caddr_t)0, try);
18981070Siedowse	if (clnt_stat != RPC_SUCCESS)
19081070Siedowse		warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMNTALL"));
19181070Siedowse	auth_destroy(clp->cl_auth);
19280123Siedowse	clnt_destroy(clp);
19381070Siedowse	return (clnt_stat == RPC_SUCCESS);
19453494Sdillon}
19553494Sdillon
19653494Sdillon/*
19753494Sdillon * Send a RPC_MNT UMOUNT request for dirp to hostname.
19853494Sdillon */
19953494Sdillonint
20053494Sdillondo_umount(char *hostname, char *dirp) {
20153494Sdillon	enum clnt_stat clnt_stat;
20274462Salfred	struct timeval try;
20353494Sdillon	CLIENT *clp;
20453494Sdillon
205146664Smux	try.tv_sec = 3;
206146664Smux	try.tv_usec = 0;
207146664Smux	clp = clnt_create_timed(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp",
208146664Smux	    &try);
20974462Salfred	if (clp  == NULL) {
21080123Siedowse		warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT"));
21181070Siedowse		return (0);
21253494Sdillon	}
21374462Salfred	clp->cl_auth = authsys_create_default();
214121560Speter	clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, (xdrproc_t)xdr_dir, dirp,
215121560Speter	    (xdrproc_t)xdr_void, (caddr_t)0, try);
21681070Siedowse	if (clnt_stat != RPC_SUCCESS)
21781070Siedowse		warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMOUNT"));
21881070Siedowse	auth_destroy(clp->cl_auth);
21980123Siedowse	clnt_destroy(clp);
22081070Siedowse	return (clnt_stat == RPC_SUCCESS);
22153494Sdillon}
22253494Sdillon
22353494Sdillon/*
22453494Sdillon * Check if the entry is still/already mounted.
22553494Sdillon */
22653494Sdillonint
22753494Sdillonis_mounted(char *hostname, char *dirp) {
22853494Sdillon	struct statfs *mntbuf;
22953494Sdillon	char name[MNAMELEN + 1];
23080123Siedowse	size_t bufsize;
23153494Sdillon	int mntsize, i;
23253494Sdillon
23380123Siedowse	if (strlen(hostname) + strlen(dirp) >= MNAMELEN)
23453494Sdillon		return (0);
23580123Siedowse	snprintf(name, sizeof(name), "%s:%s", hostname, dirp);
23653494Sdillon	mntsize = getfsstat(NULL, 0, MNT_NOWAIT);
23753494Sdillon	if (mntsize <= 0)
23853494Sdillon		return (0);
23953494Sdillon	bufsize = (mntsize + 1) * sizeof(struct statfs);
24053494Sdillon	if ((mntbuf = malloc(bufsize)) == NULL)
24153494Sdillon		err(1, "malloc");
24253494Sdillon	mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT);
24353494Sdillon	for (i = mntsize - 1; i >= 0; i--) {
24453494Sdillon		if (strcmp(mntbuf[i].f_mntfromname, name) == 0) {
24553494Sdillon			free(mntbuf);
24653494Sdillon			return (1);
24753494Sdillon		}
24853494Sdillon	}
24953494Sdillon	free(mntbuf);
25053494Sdillon	return (0);
25153494Sdillon}
25253494Sdillon
25353494Sdillon/*
25453494Sdillon * xdr routines for mount rpc's
25553494Sdillon */
25653494Sdillonint
25753494Sdillonxdr_dir(XDR *xdrsp, char *dirp) {
25853494Sdillon	return (xdr_string(xdrsp, &dirp, RPCMNT_PATHLEN));
25953494Sdillon}
26053494Sdillon
26153494Sdillonstatic void
26253494Sdillonusage() {
26353494Sdillon	(void)fprintf(stderr, "%s\n",
26480123Siedowse	    "usage: rpc.umntall [-kv] [-e expire] [-h host] [-p path]");
26553494Sdillon	exit(1);
26653494Sdillon}
267