rpc.umntall.c revision 81070
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 81070 2001-08-02 21:46:21Z iedowse $";
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:
8753494Sdillon		}
8853494Sdillon	argc -= optind;
8953494Sdillon	argv += optind;
9053494Sdillon
9153494Sdillon	/* Ignore SIGINT and SIGQUIT during shutdown */
9253494Sdillon	signal(SIGINT, SIG_IGN);
9353494Sdillon	signal(SIGQUIT, SIG_IGN);
9453494Sdillon
9556038Sgreen	/* Default expiretime is one day */
9653494Sdillon	if (expire == 0)
9756038Sgreen		expire = 86400;
9880123Siedowse	time(&now);
9980123Siedowse
10080123Siedowse	/* Read PATH_MOUNTTAB. */
10180146Siedowse	if (!read_mtab()) {
10280123Siedowse		if (verbose)
10380123Siedowse			warnx("no mounttab entries (%s does not exist)",
10480123Siedowse			    PATH_MOUNTTAB);
10580123Siedowse		mtabhead = NULL;
10680123Siedowse	}
10780123Siedowse
10853494Sdillon	if (host == NULL && path == NULL) {
10980123Siedowse		/* Check each entry and do any necessary unmount RPCs. */
11053494Sdillon		for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) {
11180123Siedowse			if (*mtab->mtab_host == '\0')
11280123Siedowse				continue;
11380123Siedowse			if (mtab->mtab_time + expire < now) {
11480123Siedowse				/* Clear expired entry. */
11580123Siedowse				if (verbose)
11680123Siedowse					warnx("remove expired entry %s:%s",
11780123Siedowse					    mtab->mtab_host, mtab->mtab_dirp);
11880123Siedowse				bzero(mtab->mtab_host,
11980123Siedowse				    sizeof(mtab->mtab_host));
12080123Siedowse				continue;
12153494Sdillon			}
12280123Siedowse			if (keep && is_mounted(mtab->mtab_host,
12380123Siedowse			    mtab->mtab_dirp)) {
12480123Siedowse				if (verbose)
12580123Siedowse					warnx("skip entry %s:%s",
12680123Siedowse					    mtab->mtab_host, mtab->mtab_dirp);
12780123Siedowse				continue;
12880123Siedowse			}
12980123Siedowse			if (do_umount(mtab->mtab_host, mtab->mtab_dirp)) {
13080123Siedowse				if (verbose)
13180123Siedowse					warnx("umount RPC for %s:%s succeeded",
13280123Siedowse					    mtab->mtab_host, mtab->mtab_dirp);
13380123Siedowse				/* Remove all entries for this host + path. */
13480146Siedowse				clean_mtab(mtab->mtab_host, mtab->mtab_dirp,
13580146Siedowse				    verbose);
13680123Siedowse			}
13753494Sdillon		}
13880123Siedowse		success = 1;
13980123Siedowse	} else {
14080123Siedowse		if (host == NULL && path != NULL)
14180123Siedowse			/* Missing hostname. */
14280123Siedowse			usage();
14380123Siedowse		if (path == NULL) {
14480123Siedowse			/* Do a RPC UMNTALL for this specific host */
14580123Siedowse			success = do_umntall(host);
14680123Siedowse			if (verbose && success)
14780123Siedowse				warnx("umntall RPC for %s succeeded", host);
14880123Siedowse		} else {
14980123Siedowse			/* Do a RPC UMNTALL for this specific mount */
15080123Siedowse			for (pathlen = strlen(path);
15180123Siedowse			    pathlen > 1 && path[pathlen - 1] == '/'; pathlen--)
15280123Siedowse				path[pathlen - 1] = '\0';
15380123Siedowse			success = do_umount(host, path);
15480123Siedowse			if (verbose && success)
15580123Siedowse				warnx("umount RPC for %s:%s succeeded", host,
15680123Siedowse				    path);
15780123Siedowse		}
15880123Siedowse		/* If successful, remove any corresponding mounttab entries. */
15980123Siedowse		if (success)
16080146Siedowse			clean_mtab(host, path, verbose);
16153494Sdillon	}
16253494Sdillon	/* Write and unlink PATH_MOUNTTAB if necessary */
16380123Siedowse	if (success)
16480146Siedowse		success = write_mtab(verbose);
16553494Sdillon	free_mtab();
16680123Siedowse	exit (success ? 0 : 1);
16753494Sdillon}
16853494Sdillon
16953494Sdillon/*
17053494Sdillon * Send a RPC_MNT UMNTALL request to hostname.
17154341Sgrog * XXX This works for all mountd implementations,
17254341Sgrog * but produces a RPC IOERR on non FreeBSD systems.
17353494Sdillon */
17453494Sdillonint
17553494Sdillondo_umntall(char *hostname) {
17653494Sdillon	enum clnt_stat clnt_stat;
17774462Salfred	struct timeval try;
17853494Sdillon	CLIENT *clp;
17953494Sdillon
18074462Salfred	clp = clnt_create(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp");
18180123Siedowse	if (clp == NULL) {
18280123Siedowse		warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT"));
18381070Siedowse		return (0);
18453494Sdillon	}
18553494Sdillon	clp->cl_auth = authunix_create_default();
18653494Sdillon	try.tv_sec = 3;
18753494Sdillon	try.tv_usec = 0;
18853494Sdillon	clnt_stat = clnt_call(clp, RPCMNT_UMNTALL, xdr_void, (caddr_t)0,
18953494Sdillon	    xdr_void, (caddr_t)0, try);
19081070Siedowse	if (clnt_stat != RPC_SUCCESS)
19181070Siedowse		warnx("%s: %s", hostname, clnt_sperror(clp, "RPCMNT_UMNTALL"));
19281070Siedowse	auth_destroy(clp->cl_auth);
19380123Siedowse	clnt_destroy(clp);
19481070Siedowse	return (clnt_stat == RPC_SUCCESS);
19553494Sdillon}
19653494Sdillon
19753494Sdillon/*
19853494Sdillon * Send a RPC_MNT UMOUNT request for dirp to hostname.
19953494Sdillon */
20053494Sdillonint
20153494Sdillondo_umount(char *hostname, char *dirp) {
20253494Sdillon	enum clnt_stat clnt_stat;
20374462Salfred	struct timeval try;
20453494Sdillon	CLIENT *clp;
20553494Sdillon
20674462Salfred	clp = clnt_create(hostname, RPCPROG_MNT, RPCMNT_VER1, "udp");
20774462Salfred	if (clp  == NULL) {
20880123Siedowse		warnx("%s: %s", hostname, clnt_spcreateerror("RPCPROG_MNT"));
20981070Siedowse		return (0);
21053494Sdillon	}
21174462Salfred	clp->cl_auth = authsys_create_default();
21253494Sdillon	try.tv_sec = 3;
21353494Sdillon	try.tv_usec = 0;
21453494Sdillon	clnt_stat = clnt_call(clp, RPCMNT_UMOUNT, xdr_dir, dirp,
21553494Sdillon	    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