1330449Seadler/*-
2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3330449Seadler *
453494Sdillon * Copyright (c) 1999 Martin Blapp
553494Sdillon * All rights reserved.
653494Sdillon *
753494Sdillon * Redistribution and use in source and binary forms, with or without
853494Sdillon * modification, are permitted provided that the following conditions
953494Sdillon * are met:
1053494Sdillon * 1. Redistributions of source code must retain the above copyright
1153494Sdillon *    notice, this list of conditions and the following disclaimer.
1253494Sdillon * 2. Redistributions in binary form must reproduce the above copyright
1353494Sdillon *    notice, this list of conditions and the following disclaimer in the
1453494Sdillon *    documentation and/or other materials provided with the distribution.
1553494Sdillon *
1653494Sdillon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1753494Sdillon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1853494Sdillon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1953494Sdillon * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2053494Sdillon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2153494Sdillon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2253494Sdillon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2353494Sdillon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2453494Sdillon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2553494Sdillon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2653494Sdillon * SUCH DAMAGE.
2753494Sdillon *
2853494Sdillon */
2953494Sdillon
3053494Sdillon#ifndef lint
3153494Sdillonstatic const char rcsid[] =
3253494Sdillon  "$FreeBSD: stable/11/usr.sbin/rpc.umntall/rpc.umntall.c 330449 2018-03-05 07:26:05Z eadler $";
3353494Sdillon#endif /* not lint */
3453494Sdillon
3553494Sdillon#include <sys/param.h>
3653494Sdillon#include <sys/ucred.h>
3753494Sdillon#include <sys/mount.h>
3853494Sdillon
3953494Sdillon#include <rpc/rpc.h>
40194880Sdfr#include <rpcsvc/mount.h>
4153494Sdillon
4253494Sdillon#include <err.h>
4353494Sdillon#include <netdb.h>
4453494Sdillon#include <stdio.h>
4553494Sdillon#include <stdlib.h>
4653494Sdillon#include <string.h>
4753494Sdillon#include <unistd.h>
4853494Sdillon
4953494Sdillon#include "mounttab.h"
5053494Sdillon
5153494Sdillonint verbose;
5253494Sdillon
5353494Sdillonstatic int do_umount (char *, char *);
5453494Sdillonstatic int do_umntall (char *);
5553494Sdillonstatic int is_mounted (char *, char *);
5653494Sdillonstatic void usage (void);
5753494Sdillonint	xdr_dir (XDR *, char *);
5853494Sdillon
5953494Sdillonint
6053494Sdillonmain(int argc, char **argv) {
6153494Sdillon	int ch, keep, success, pathlen;
6280123Siedowse	time_t expire, now;
6353494Sdillon	char *host, *path;
6453494Sdillon	struct mtablist *mtab;
6553494Sdillon
6653494Sdillon	expire = 0;
6780123Siedowse	host = path = NULL;
6853494Sdillon	success = keep = verbose = 0;
6953494Sdillon	while ((ch = getopt(argc, argv, "h:kp:ve:")) != -1)
7053494Sdillon		switch (ch) {
7153494Sdillon		case 'h':
7253494Sdillon			host = optarg;
7353494Sdillon			break;
7453494Sdillon		case 'e':
7578343Sjlemon			expire = atoi(optarg);
7653494Sdillon			break;
7753494Sdillon		case 'k':
7853494Sdillon			keep = 1;
7953494Sdillon			break;
8053494Sdillon		case 'p':
8153494Sdillon			path = optarg;
8253494Sdillon			break;
8353494Sdillon		case 'v':
8453494Sdillon			verbose = 1;
8553494Sdillon			break;
8653494Sdillon		case '?':
8753494Sdillon			usage();
8853494Sdillon		default:
89114119Simp			break;
9053494Sdillon		}
9153494Sdillon	argc -= optind;
9253494Sdillon	argv += optind;
9353494Sdillon
9456038Sgreen	/* Default expiretime is one day */
9553494Sdillon	if (expire == 0)
9656038Sgreen		expire = 86400;
9780123Siedowse	time(&now);
9880123Siedowse
9980123Siedowse	/* Read PATH_MOUNTTAB. */
10080146Siedowse	if (!read_mtab()) {
10180123Siedowse		if (verbose)
10280123Siedowse			warnx("no mounttab entries (%s does not exist)",
10380123Siedowse			    PATH_MOUNTTAB);
10480123Siedowse		mtabhead = NULL;
10580123Siedowse	}
10680123Siedowse
10753494Sdillon	if (host == NULL && path == NULL) {
10880123Siedowse		/* Check each entry and do any necessary unmount RPCs. */
10953494Sdillon		for (mtab = mtabhead; mtab != NULL; mtab = mtab->mtab_next) {
11080123Siedowse			if (*mtab->mtab_host == '\0')
11180123Siedowse				continue;
11280123Siedowse			if (mtab->mtab_time + expire < now) {
11380123Siedowse				/* Clear expired entry. */
11480123Siedowse				if (verbose)
11580123Siedowse					warnx("remove expired entry %s:%s",
11680123Siedowse					    mtab->mtab_host, mtab->mtab_dirp);
11780123Siedowse				bzero(mtab->mtab_host,
11880123Siedowse				    sizeof(mtab->mtab_host));
11980123Siedowse				continue;
12053494Sdillon			}
12180123Siedowse			if (keep && is_mounted(mtab->mtab_host,
12280123Siedowse			    mtab->mtab_dirp)) {
12380123Siedowse				if (verbose)
12480123Siedowse					warnx("skip entry %s:%s",
12580123Siedowse					    mtab->mtab_host, mtab->mtab_dirp);
12680123Siedowse				continue;
12780123Siedowse			}
12880123Siedowse			if (do_umount(mtab->mtab_host, mtab->mtab_dirp)) {
12980123Siedowse				if (verbose)
13080123Siedowse					warnx("umount RPC for %s:%s succeeded",
13180123Siedowse					    mtab->mtab_host, mtab->mtab_dirp);
13280123Siedowse				/* Remove all entries for this host + path. */
13380146Siedowse				clean_mtab(mtab->mtab_host, mtab->mtab_dirp,
13480146Siedowse				    verbose);
13580123Siedowse			}
13653494Sdillon		}
13780123Siedowse		success = 1;
13880123Siedowse	} else {
13980123Siedowse		if (host == NULL && path != NULL)
14080123Siedowse			/* Missing hostname. */
14180123Siedowse			usage();
14280123Siedowse		if (path == NULL) {
14380123Siedowse			/* Do a RPC UMNTALL for this specific host */
14480123Siedowse			success = do_umntall(host);
14580123Siedowse			if (verbose && success)
14680123Siedowse				warnx("umntall RPC for %s succeeded", host);
14780123Siedowse		} else {
14880123Siedowse			/* Do a RPC UMNTALL for this specific mount */
14980123Siedowse			for (pathlen = strlen(path);
15080123Siedowse			    pathlen > 1 && path[pathlen - 1] == '/'; pathlen--)
15180123Siedowse				path[pathlen - 1] = '\0';
15280123Siedowse			success = do_umount(host, path);
15380123Siedowse			if (verbose && success)
15480123Siedowse				warnx("umount RPC for %s:%s succeeded", host,
15580123Siedowse				    path);
15680123Siedowse		}
15780123Siedowse		/* If successful, remove any corresponding mounttab entries. */
15880123Siedowse		if (success)
15980146Siedowse			clean_mtab(host, path, verbose);
16053494Sdillon	}
16153494Sdillon	/* Write and unlink PATH_MOUNTTAB if necessary */
16280123Siedowse	if (success)
16380146Siedowse		success = write_mtab(verbose);
16453494Sdillon	free_mtab();
16580123Siedowse	exit (success ? 0 : 1);
16653494Sdillon}
16753494Sdillon
16853494Sdillon/*
16953494Sdillon * Send a RPC_MNT UMNTALL request to hostname.
17054341Sgrog * XXX This works for all mountd implementations,
17154341Sgrog * but produces a RPC IOERR on non FreeBSD systems.
17253494Sdillon */
17353494Sdillonint
17453494Sdillondo_umntall(char *hostname) {
17553494Sdillon	enum clnt_stat clnt_stat;
17674462Salfred	struct timeval try;
17753494Sdillon	CLIENT *clp;
17853494Sdillon
179146664Smux	try.tv_sec = 3;
180146664Smux	try.tv_usec = 0;
181194880Sdfr	clp = clnt_create_timed(hostname, MOUNTPROG, MOUNTVERS, "udp",
182146664Smux	    &try);
18380123Siedowse	if (clp == NULL) {
184194880Sdfr		warnx("%s: %s", hostname, clnt_spcreateerror("MOUNTPROG"));
18581070Siedowse		return (0);
18653494Sdillon	}
18753494Sdillon	clp->cl_auth = authunix_create_default();
188194880Sdfr	clnt_stat = clnt_call(clp, MOUNTPROC_UMNTALL,
189121560Speter	    (xdrproc_t)xdr_void, (caddr_t)0,
190121560Speter	    (xdrproc_t)xdr_void, (caddr_t)0, try);
19181070Siedowse	if (clnt_stat != RPC_SUCCESS)
192194880Sdfr		warnx("%s: %s", hostname, clnt_sperror(clp, "MOUNTPROC_UMNTALL"));
19381070Siedowse	auth_destroy(clp->cl_auth);
19480123Siedowse	clnt_destroy(clp);
19581070Siedowse	return (clnt_stat == RPC_SUCCESS);
19653494Sdillon}
19753494Sdillon
19853494Sdillon/*
19953494Sdillon * Send a RPC_MNT UMOUNT request for dirp to hostname.
20053494Sdillon */
20153494Sdillonint
20253494Sdillondo_umount(char *hostname, char *dirp) {
20353494Sdillon	enum clnt_stat clnt_stat;
20474462Salfred	struct timeval try;
20553494Sdillon	CLIENT *clp;
20653494Sdillon
207146664Smux	try.tv_sec = 3;
208146664Smux	try.tv_usec = 0;
209194880Sdfr	clp = clnt_create_timed(hostname, MOUNTPROG, MOUNTVERS, "udp",
210146664Smux	    &try);
21174462Salfred	if (clp  == NULL) {
212194880Sdfr		warnx("%s: %s", hostname, clnt_spcreateerror("MOUNTPROG"));
21381070Siedowse		return (0);
21453494Sdillon	}
21574462Salfred	clp->cl_auth = authsys_create_default();
216194880Sdfr	clnt_stat = clnt_call(clp, MOUNTPROC_UMNT, (xdrproc_t)xdr_dir, dirp,
217121560Speter	    (xdrproc_t)xdr_void, (caddr_t)0, try);
21881070Siedowse	if (clnt_stat != RPC_SUCCESS)
219194880Sdfr		warnx("%s: %s", hostname, clnt_sperror(clp, "MOUNTPROC_UMNT"));
22081070Siedowse	auth_destroy(clp->cl_auth);
22180123Siedowse	clnt_destroy(clp);
22281070Siedowse	return (clnt_stat == RPC_SUCCESS);
22353494Sdillon}
22453494Sdillon
22553494Sdillon/*
22653494Sdillon * Check if the entry is still/already mounted.
22753494Sdillon */
22853494Sdillonint
22953494Sdillonis_mounted(char *hostname, char *dirp) {
23053494Sdillon	struct statfs *mntbuf;
23153494Sdillon	char name[MNAMELEN + 1];
23280123Siedowse	size_t bufsize;
23353494Sdillon	int mntsize, i;
23453494Sdillon
23580123Siedowse	if (strlen(hostname) + strlen(dirp) >= MNAMELEN)
23653494Sdillon		return (0);
23780123Siedowse	snprintf(name, sizeof(name), "%s:%s", hostname, dirp);
23853494Sdillon	mntsize = getfsstat(NULL, 0, MNT_NOWAIT);
23953494Sdillon	if (mntsize <= 0)
24053494Sdillon		return (0);
24153494Sdillon	bufsize = (mntsize + 1) * sizeof(struct statfs);
24253494Sdillon	if ((mntbuf = malloc(bufsize)) == NULL)
24353494Sdillon		err(1, "malloc");
24453494Sdillon	mntsize = getfsstat(mntbuf, (long)bufsize, MNT_NOWAIT);
24553494Sdillon	for (i = mntsize - 1; i >= 0; i--) {
24653494Sdillon		if (strcmp(mntbuf[i].f_mntfromname, name) == 0) {
24753494Sdillon			free(mntbuf);
24853494Sdillon			return (1);
24953494Sdillon		}
25053494Sdillon	}
25153494Sdillon	free(mntbuf);
25253494Sdillon	return (0);
25353494Sdillon}
25453494Sdillon
25553494Sdillon/*
25653494Sdillon * xdr routines for mount rpc's
25753494Sdillon */
25853494Sdillonint
25953494Sdillonxdr_dir(XDR *xdrsp, char *dirp) {
260194880Sdfr	return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
26153494Sdillon}
26253494Sdillon
26353494Sdillonstatic void
26453494Sdillonusage() {
26553494Sdillon	(void)fprintf(stderr, "%s\n",
26680123Siedowse	    "usage: rpc.umntall [-kv] [-e expire] [-h host] [-p path]");
26753494Sdillon	exit(1);
26853494Sdillon}
269