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