xref: /dflybsd-src/usr.sbin/autofs/automount.c (revision 1dfea00f11e2d4fba2bae6d98e5df8391209d1d7)
1e2950f41STomohiro Kusumi /*-
263bc4984STomohiro Kusumi  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
363bc4984STomohiro Kusumi  *
4e2950f41STomohiro Kusumi  * Copyright (c) 2016 The DragonFly Project
5e2950f41STomohiro Kusumi  * Copyright (c) 2014 The FreeBSD Foundation
6e2950f41STomohiro Kusumi  * All rights reserved.
7e2950f41STomohiro Kusumi  *
8e2950f41STomohiro Kusumi  * This software was developed by Edward Tomasz Napierala under sponsorship
9e2950f41STomohiro Kusumi  * from the FreeBSD Foundation.
10e2950f41STomohiro Kusumi  *
11e2950f41STomohiro Kusumi  * Redistribution and use in source and binary forms, with or without
12e2950f41STomohiro Kusumi  * modification, are permitted provided that the following conditions
13e2950f41STomohiro Kusumi  * are met:
14e2950f41STomohiro Kusumi  * 1. Redistributions of source code must retain the above copyright
15e2950f41STomohiro Kusumi  *    notice, this list of conditions and the following disclaimer.
16e2950f41STomohiro Kusumi  * 2. Redistributions in binary form must reproduce the above copyright
17e2950f41STomohiro Kusumi  *    notice, this list of conditions and the following disclaimer in the
18e2950f41STomohiro Kusumi  *    documentation and/or other materials provided with the distribution.
19e2950f41STomohiro Kusumi  *
20e2950f41STomohiro Kusumi  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21e2950f41STomohiro Kusumi  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22e2950f41STomohiro Kusumi  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23e2950f41STomohiro Kusumi  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24e2950f41STomohiro Kusumi  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25e2950f41STomohiro Kusumi  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26e2950f41STomohiro Kusumi  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27e2950f41STomohiro Kusumi  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28e2950f41STomohiro Kusumi  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29e2950f41STomohiro Kusumi  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30e2950f41STomohiro Kusumi  * SUCH DAMAGE.
31e2950f41STomohiro Kusumi  *
32e2950f41STomohiro Kusumi  */
33e2950f41STomohiro Kusumi 
34e2950f41STomohiro Kusumi #include <sys/types.h>
35e2950f41STomohiro Kusumi #include <sys/mount.h>
36e2950f41STomohiro Kusumi #include <stdio.h>
37e2950f41STomohiro Kusumi #include <stdlib.h>
38e2950f41STomohiro Kusumi #include <string.h>
39e2950f41STomohiro Kusumi #include <unistd.h>
40e2950f41STomohiro Kusumi #include <vfs/autofs/autofs_mount.h>
41e2950f41STomohiro Kusumi 
42e2950f41STomohiro Kusumi #include "common.h"
43e2950f41STomohiro Kusumi 
44e2950f41STomohiro Kusumi static int
unmount_by_statfs(const struct statfs * sb,bool force)45e2950f41STomohiro Kusumi unmount_by_statfs(const struct statfs *sb, bool force)
46e2950f41STomohiro Kusumi {
47e2950f41STomohiro Kusumi 	int error, flags;
48e2950f41STomohiro Kusumi 
49e2950f41STomohiro Kusumi 	log_debugx("unmounting %s", sb->f_mntonname);
50e2950f41STomohiro Kusumi 
51e2950f41STomohiro Kusumi 	flags = 0;
52e2950f41STomohiro Kusumi 	if (force)
53e2950f41STomohiro Kusumi 		flags |= MNT_FORCE;
54e2950f41STomohiro Kusumi 	error = unmount(sb->f_mntonname, flags);
55e2950f41STomohiro Kusumi 	if (error != 0)
56e2950f41STomohiro Kusumi 		log_warn("cannot unmount %s", sb->f_mntonname);
57*1dfea00fSTomohiro Kusumi 	else
58*1dfea00fSTomohiro Kusumi 		rpc_umntall();
59e2950f41STomohiro Kusumi 
60e2950f41STomohiro Kusumi 	return (error);
61e2950f41STomohiro Kusumi }
62e2950f41STomohiro Kusumi 
63e2950f41STomohiro Kusumi static const struct statfs *
find_statfs(const struct statfs * mntbuf,int nitems,const char * mountpoint)64e2950f41STomohiro Kusumi find_statfs(const struct statfs *mntbuf, int nitems, const char *mountpoint)
65e2950f41STomohiro Kusumi {
66e2950f41STomohiro Kusumi 	int i;
67e2950f41STomohiro Kusumi 
68e2950f41STomohiro Kusumi 	for (i = 0; i < nitems; i++) {
69e2950f41STomohiro Kusumi 		if (strcmp(mntbuf[i].f_mntonname, mountpoint) == 0)
70e2950f41STomohiro Kusumi 			return (mntbuf + i);
71e2950f41STomohiro Kusumi 	}
72e2950f41STomohiro Kusumi 
73e2950f41STomohiro Kusumi 	return (NULL);
74e2950f41STomohiro Kusumi }
75e2950f41STomohiro Kusumi 
76e2950f41STomohiro Kusumi static void
mount_autofs(const char * from,const char * fspath,const char * options,const char * prefix)77e2950f41STomohiro Kusumi mount_autofs(const char *from, const char *fspath, const char *options,
78e2950f41STomohiro Kusumi     const char *prefix)
79e2950f41STomohiro Kusumi {
80e2950f41STomohiro Kusumi 	struct autofs_mount_info info;
81e2950f41STomohiro Kusumi 	int error;
82e2950f41STomohiro Kusumi 
83e2950f41STomohiro Kusumi 	create_directory(fspath);
84e2950f41STomohiro Kusumi 
85e2950f41STomohiro Kusumi 	log_debugx("mounting %s on %s, prefix \"%s\", options \"%s\"",
86e2950f41STomohiro Kusumi 	    from, fspath, prefix, options);
87e2950f41STomohiro Kusumi 
88e2950f41STomohiro Kusumi 	memset(&info, 0, sizeof(info));
89e2950f41STomohiro Kusumi 	info.from = from;
90e2950f41STomohiro Kusumi 	info.master_options = options;
91e2950f41STomohiro Kusumi 	info.master_prefix = prefix;
92e2950f41STomohiro Kusumi 
93e2950f41STomohiro Kusumi 	error = mount("autofs", fspath, 0, &info);
94e2950f41STomohiro Kusumi 	if (error != 0)
95e2950f41STomohiro Kusumi 		log_err(1, "cannot mount %s on %s", from, fspath);
96e2950f41STomohiro Kusumi }
97e2950f41STomohiro Kusumi 
98e2950f41STomohiro Kusumi static void
mount_if_not_already(const struct node * n,const char * map,const char * options,const char * prefix,const struct statfs * mntbuf,int nitems)99e2950f41STomohiro Kusumi mount_if_not_already(const struct node *n, const char *map, const char *options,
100e2950f41STomohiro Kusumi     const char *prefix, const struct statfs *mntbuf, int nitems)
101e2950f41STomohiro Kusumi {
102e2950f41STomohiro Kusumi 	const struct statfs *sb;
103e2950f41STomohiro Kusumi 	char *mountpoint;
104e2950f41STomohiro Kusumi 	char *from;
105e2950f41STomohiro Kusumi 	int ret;
106e2950f41STomohiro Kusumi 
107e2950f41STomohiro Kusumi 	ret = asprintf(&from, "map %s", map);
108e2950f41STomohiro Kusumi 	if (ret < 0)
109e2950f41STomohiro Kusumi 		log_err(1, "asprintf");
110e2950f41STomohiro Kusumi 
111e2950f41STomohiro Kusumi 	mountpoint = node_path(n);
112e2950f41STomohiro Kusumi 	sb = find_statfs(mntbuf, nitems, mountpoint);
113e2950f41STomohiro Kusumi 	if (sb != NULL) {
114e2950f41STomohiro Kusumi 		if (strcmp(sb->f_fstypename, "autofs") != 0) {
115e2950f41STomohiro Kusumi 			log_debugx("unknown filesystem mounted "
116e2950f41STomohiro Kusumi 			    "on %s; mounting", mountpoint);
117e2950f41STomohiro Kusumi 			/*
118e2950f41STomohiro Kusumi 			 * XXX: Compare options and 'from',
119e2950f41STomohiro Kusumi 			 *	and update the mount if necessary.
120e2950f41STomohiro Kusumi 			 */
121e2950f41STomohiro Kusumi 		} else {
122e2950f41STomohiro Kusumi 			log_debugx("autofs already mounted "
123e2950f41STomohiro Kusumi 			    "on %s", mountpoint);
124e2950f41STomohiro Kusumi 			free(from);
125e2950f41STomohiro Kusumi 			free(mountpoint);
126e2950f41STomohiro Kusumi 			return;
127e2950f41STomohiro Kusumi 		}
128e2950f41STomohiro Kusumi 	} else {
129e2950f41STomohiro Kusumi 		log_debugx("nothing mounted on %s; mounting",
130e2950f41STomohiro Kusumi 		    mountpoint);
131e2950f41STomohiro Kusumi 	}
132e2950f41STomohiro Kusumi 
133e2950f41STomohiro Kusumi 	mount_autofs(from, mountpoint, options, prefix);
134e2950f41STomohiro Kusumi 	free(from);
135e2950f41STomohiro Kusumi 	free(mountpoint);
136e2950f41STomohiro Kusumi }
137e2950f41STomohiro Kusumi 
138e2950f41STomohiro Kusumi static void
mount_unmount(struct node * root)139e2950f41STomohiro Kusumi mount_unmount(struct node *root)
140e2950f41STomohiro Kusumi {
141e2950f41STomohiro Kusumi 	struct statfs *mntbuf;
142e2950f41STomohiro Kusumi 	struct node *n, *n2;
143e2950f41STomohiro Kusumi 	int i, nitems;
144e2950f41STomohiro Kusumi 
145e2950f41STomohiro Kusumi 	nitems = getmntinfo(&mntbuf, MNT_WAIT);
146e2950f41STomohiro Kusumi 	if (nitems <= 0)
147e2950f41STomohiro Kusumi 		log_err(1, "getmntinfo");
148e2950f41STomohiro Kusumi 
149e2950f41STomohiro Kusumi 	log_debugx("unmounting stale autofs mounts");
150e2950f41STomohiro Kusumi 
151e2950f41STomohiro Kusumi 	for (i = 0; i < nitems; i++) {
152e2950f41STomohiro Kusumi 		if (strcmp(mntbuf[i].f_fstypename, "autofs") != 0) {
153e2950f41STomohiro Kusumi 			log_debugx("skipping %s, filesystem type is not autofs",
154e2950f41STomohiro Kusumi 			    mntbuf[i].f_mntonname);
155e2950f41STomohiro Kusumi 			continue;
156e2950f41STomohiro Kusumi 		}
157e2950f41STomohiro Kusumi 
158e2950f41STomohiro Kusumi 		n = node_find(root, mntbuf[i].f_mntonname);
159e2950f41STomohiro Kusumi 		if (n != NULL) {
160e2950f41STomohiro Kusumi 			log_debugx("leaving autofs mounted on %s",
161e2950f41STomohiro Kusumi 			    mntbuf[i].f_mntonname);
162e2950f41STomohiro Kusumi 			continue;
163e2950f41STomohiro Kusumi 		}
164e2950f41STomohiro Kusumi 
165e2950f41STomohiro Kusumi 		log_debugx("autofs mounted on %s not found "
166e2950f41STomohiro Kusumi 		    "in new configuration; unmounting", mntbuf[i].f_mntonname);
167e2950f41STomohiro Kusumi 		unmount_by_statfs(&(mntbuf[i]), false);
168e2950f41STomohiro Kusumi 	}
169e2950f41STomohiro Kusumi 
170e2950f41STomohiro Kusumi 	log_debugx("mounting new autofs mounts");
171e2950f41STomohiro Kusumi 
172e2950f41STomohiro Kusumi 	TAILQ_FOREACH(n, &root->n_children, n_next) {
173e2950f41STomohiro Kusumi 		if (!node_is_direct_map(n)) {
174e2950f41STomohiro Kusumi 			mount_if_not_already(n, n->n_map, n->n_options,
175e2950f41STomohiro Kusumi 			    n->n_key, mntbuf, nitems);
176e2950f41STomohiro Kusumi 			continue;
177e2950f41STomohiro Kusumi 		}
178e2950f41STomohiro Kusumi 
179e2950f41STomohiro Kusumi 		TAILQ_FOREACH(n2, &n->n_children, n_next) {
180e2950f41STomohiro Kusumi 			mount_if_not_already(n2, n->n_map, n->n_options,
181e2950f41STomohiro Kusumi 			    "/", mntbuf, nitems);
182e2950f41STomohiro Kusumi 		}
183e2950f41STomohiro Kusumi 	}
184e2950f41STomohiro Kusumi }
185e2950f41STomohiro Kusumi 
186e2950f41STomohiro Kusumi static void
flush_autofs(const char * fspath)187e2950f41STomohiro Kusumi flush_autofs(const char *fspath)
188e2950f41STomohiro Kusumi {
189e2950f41STomohiro Kusumi 	int error;
190e2950f41STomohiro Kusumi 
191e2950f41STomohiro Kusumi 	log_debugx("flushing %s", fspath);
192e2950f41STomohiro Kusumi 
193e2950f41STomohiro Kusumi 	error = mount("autofs", fspath, MNT_UPDATE, NULL);
194e2950f41STomohiro Kusumi 	if (error != 0)
195e2950f41STomohiro Kusumi 		log_err(1, "cannot flush %s", fspath);
196e2950f41STomohiro Kusumi }
197e2950f41STomohiro Kusumi 
198e2950f41STomohiro Kusumi static void
flush_caches(void)199e2950f41STomohiro Kusumi flush_caches(void)
200e2950f41STomohiro Kusumi {
201e2950f41STomohiro Kusumi 	struct statfs *mntbuf;
202e2950f41STomohiro Kusumi 	int i, nitems;
203e2950f41STomohiro Kusumi 
204e2950f41STomohiro Kusumi 	nitems = getmntinfo(&mntbuf, MNT_WAIT);
205e2950f41STomohiro Kusumi 	if (nitems <= 0)
206e2950f41STomohiro Kusumi 		log_err(1, "getmntinfo");
207e2950f41STomohiro Kusumi 
208e2950f41STomohiro Kusumi 	log_debugx("flushing autofs caches");
209e2950f41STomohiro Kusumi 
210e2950f41STomohiro Kusumi 	for (i = 0; i < nitems; i++) {
211e2950f41STomohiro Kusumi 		if (strcmp(mntbuf[i].f_fstypename, "autofs") != 0) {
212e2950f41STomohiro Kusumi 			log_debugx("skipping %s, filesystem type is not autofs",
213e2950f41STomohiro Kusumi 			    mntbuf[i].f_mntonname);
214e2950f41STomohiro Kusumi 			continue;
215e2950f41STomohiro Kusumi 		}
216e2950f41STomohiro Kusumi 
217e2950f41STomohiro Kusumi 		flush_autofs(mntbuf[i].f_mntonname);
218e2950f41STomohiro Kusumi 	}
219e2950f41STomohiro Kusumi }
220e2950f41STomohiro Kusumi 
221e2950f41STomohiro Kusumi static void
unmount_automounted(bool force)222e2950f41STomohiro Kusumi unmount_automounted(bool force)
223e2950f41STomohiro Kusumi {
224e2950f41STomohiro Kusumi 	struct statfs *mntbuf;
225e2950f41STomohiro Kusumi 	int i, nitems;
226e2950f41STomohiro Kusumi 
227e2950f41STomohiro Kusumi 	nitems = getmntinfo(&mntbuf, MNT_WAIT);
228e2950f41STomohiro Kusumi 	if (nitems <= 0)
229e2950f41STomohiro Kusumi 		log_err(1, "getmntinfo");
230e2950f41STomohiro Kusumi 
231e2950f41STomohiro Kusumi 	log_debugx("unmounting automounted filesystems");
232e2950f41STomohiro Kusumi 
233e2950f41STomohiro Kusumi 	for (i = 0; i < nitems; i++) {
234e2950f41STomohiro Kusumi 		if (strcmp(mntbuf[i].f_fstypename, "autofs") == 0) {
235e2950f41STomohiro Kusumi 			log_debugx("skipping %s, filesystem type is autofs",
236e2950f41STomohiro Kusumi 			    mntbuf[i].f_mntonname);
237e2950f41STomohiro Kusumi 			continue;
238e2950f41STomohiro Kusumi 		}
239e2950f41STomohiro Kusumi 
240e2950f41STomohiro Kusumi 		if ((mntbuf[i].f_flags & MNT_AUTOMOUNTED) == 0) {
241e2950f41STomohiro Kusumi 			log_debugx("skipping %s, not automounted",
242e2950f41STomohiro Kusumi 			    mntbuf[i].f_mntonname);
243e2950f41STomohiro Kusumi 			continue;
244e2950f41STomohiro Kusumi 		}
245e2950f41STomohiro Kusumi 
246e2950f41STomohiro Kusumi 		unmount_by_statfs(&(mntbuf[i]), force);
247e2950f41STomohiro Kusumi 	}
248e2950f41STomohiro Kusumi }
249e2950f41STomohiro Kusumi 
250e2950f41STomohiro Kusumi static void
usage_automount(void)251e2950f41STomohiro Kusumi usage_automount(void)
252e2950f41STomohiro Kusumi {
253e2950f41STomohiro Kusumi 
254e2950f41STomohiro Kusumi 	fprintf(stderr, "usage: automount [-D name=value][-o opts][-Lcfuv]\n");
255e2950f41STomohiro Kusumi 	exit(1);
256e2950f41STomohiro Kusumi }
257e2950f41STomohiro Kusumi 
258e2950f41STomohiro Kusumi int
main_automount(int argc,char ** argv)259e2950f41STomohiro Kusumi main_automount(int argc, char **argv)
260e2950f41STomohiro Kusumi {
261e2950f41STomohiro Kusumi 	struct node *root;
262e2950f41STomohiro Kusumi 	int ch, debug = 0, show_maps = 0;
263e2950f41STomohiro Kusumi 	char *options = NULL;
264e2950f41STomohiro Kusumi 	bool do_unmount = false, force_unmount = false, flush = false;
265e2950f41STomohiro Kusumi 
266e2950f41STomohiro Kusumi 	/*
267e2950f41STomohiro Kusumi 	 * Note that in automount(8), the only purpose of variable
268e2950f41STomohiro Kusumi 	 * handling is to aid in debugging maps (automount -L).
269e2950f41STomohiro Kusumi 	 */
270e2950f41STomohiro Kusumi 	defined_init();
271e2950f41STomohiro Kusumi 
272e2950f41STomohiro Kusumi 	while ((ch = getopt(argc, argv, "D:Lfco:uv")) != -1) {
273e2950f41STomohiro Kusumi 		switch (ch) {
274e2950f41STomohiro Kusumi 		case 'D':
275e2950f41STomohiro Kusumi 			defined_parse_and_add(optarg);
276e2950f41STomohiro Kusumi 			break;
277e2950f41STomohiro Kusumi 		case 'L':
278e2950f41STomohiro Kusumi 			show_maps++;
279e2950f41STomohiro Kusumi 			break;
280e2950f41STomohiro Kusumi 		case 'c':
281e2950f41STomohiro Kusumi 			flush = true;
282e2950f41STomohiro Kusumi 			break;
283e2950f41STomohiro Kusumi 		case 'f':
284e2950f41STomohiro Kusumi 			force_unmount = true;
285e2950f41STomohiro Kusumi 			break;
286e2950f41STomohiro Kusumi 		case 'o':
287e2950f41STomohiro Kusumi 			options = concat(options, ',', optarg);
288e2950f41STomohiro Kusumi 			break;
289e2950f41STomohiro Kusumi 		case 'u':
290e2950f41STomohiro Kusumi 			do_unmount = true;
291e2950f41STomohiro Kusumi 			break;
292e2950f41STomohiro Kusumi 		case 'v':
293e2950f41STomohiro Kusumi 			debug++;
294e2950f41STomohiro Kusumi 			break;
295e2950f41STomohiro Kusumi 		case '?':
296e2950f41STomohiro Kusumi 		default:
297e2950f41STomohiro Kusumi 			usage_automount();
298e2950f41STomohiro Kusumi 		}
299e2950f41STomohiro Kusumi 	}
300e2950f41STomohiro Kusumi 	argc -= optind;
301e2950f41STomohiro Kusumi 	if (argc != 0)
302e2950f41STomohiro Kusumi 		usage_automount();
303e2950f41STomohiro Kusumi 
304e2950f41STomohiro Kusumi 	if (force_unmount && !do_unmount)
305e2950f41STomohiro Kusumi 		usage_automount();
306e2950f41STomohiro Kusumi 
307e2950f41STomohiro Kusumi 	log_init(debug);
308e2950f41STomohiro Kusumi 
309e2950f41STomohiro Kusumi 	if (flush) {
310e2950f41STomohiro Kusumi 		flush_caches();
311e2950f41STomohiro Kusumi 		return (0);
312e2950f41STomohiro Kusumi 	}
313e2950f41STomohiro Kusumi 
314e2950f41STomohiro Kusumi 	if (do_unmount) {
315e2950f41STomohiro Kusumi 		unmount_automounted(force_unmount);
316e2950f41STomohiro Kusumi 		return (0);
317e2950f41STomohiro Kusumi 	}
318e2950f41STomohiro Kusumi 
319e2950f41STomohiro Kusumi 	root = node_new_root();
320e2950f41STomohiro Kusumi 	parse_master(root, AUTO_MASTER_PATH);
321e2950f41STomohiro Kusumi 
322e2950f41STomohiro Kusumi 	if (show_maps) {
323e2950f41STomohiro Kusumi 		if (show_maps > 1) {
324e2950f41STomohiro Kusumi 			node_expand_indirect_maps(root);
325e2950f41STomohiro Kusumi 			node_expand_ampersand(root, NULL);
326e2950f41STomohiro Kusumi 		}
327e2950f41STomohiro Kusumi 		node_expand_defined(root);
328e2950f41STomohiro Kusumi 		node_print(root, options);
329e2950f41STomohiro Kusumi 		return (0);
330e2950f41STomohiro Kusumi 	}
331e2950f41STomohiro Kusumi 
332e2950f41STomohiro Kusumi 	mount_unmount(root);
333e2950f41STomohiro Kusumi 
334e2950f41STomohiro Kusumi 	return (0);
335e2950f41STomohiro Kusumi }
336