xref: /dragonfly/sbin/mount_fuse/mount_fusefs.c (revision a4da4a90)
1 /*-
2  * Copyright (c) 2019 Tomohiro Kusumi <tkusumi@netbsd.org>
3  * Copyright (c) 2019 The DragonFly Project
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <vfs/fuse/fuse_mount.h>
31 
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <stdbool.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <getopt.h>
38 #include <mntopts.h>
39 #include <err.h>
40 
41 #define MOPT_FUSE_LINUX_OPTS \
42 	{ "default_permissions", 0, FUSE_MOUNT_DEFAULT_PERMISSIONS, 1 }, \
43 	{ "allow_other", 0, FUSE_MOUNT_ALLOW_OTHER, 1 }, \
44 	{ "max_read=", 0, FUSE_MOUNT_MAX_READ, 1 }, \
45 	{ "subtype=", 0, FUSE_MOUNT_SUBTYPE, 1 }
46 
47 /* XXX */
48 #define MOPT_FUSE_LINUX_IGNORE_OPTS \
49 	{ "fsname=", 0, 0, 1 }, \
50 	{ "fd=", 0, 0, 1 }, \
51 	{ "rootmode=", 0, 0, 1 }, \
52 	{ "user_id=", 0, 0, 1 }, \
53 	{ "group_id=", 0, 0, 1 }, \
54 	\
55 	{ "auto_unmount", 0, 0, 1 }, \
56 	{ "blkdev", 0, 0, 1 }, \
57 	{ "blksize=", 0, 0, 1 }, \
58 	{ "context=", 0, 0, 1 }, \
59 	{ "fscontext=", 0, 0, 1 }, \
60 	{ "defcontext=", 0, 0, 1 }, \
61 	{ "rootcontext=", 0, 0, 1 }, \
62 	{ "user=", 0, 0, 1 }, \
63 	{ "-r", 0, 0, 1 }, \
64 	{ "ro", 0, 0, 1 }, \
65 	{ "rw", 0, 0, 1 }, \
66 	{ "suid", 0, 0, 1 }, \
67 	{ "nosuid", 0, 0, 1 }, \
68 	{ "dev", 0, 0, 1 }, \
69 	{ "nodev", 0, 0, 1 }, \
70 	{ "exec", 0, 0, 1 }, \
71 	{ "noexec", 0, 0, 1 }, \
72 	{ "async", 0, 0, 1 }, \
73 	{ "sync", 0, 0, 1 }, \
74 	{ "dirsync", 0, 0, 1 }, \
75 	{ "atime", 0, 0, 1 }, \
76 	{ "noatime", 0, 0, 1 }
77 
78 static struct mntopt mopts[] = {
79 	MOPT_FUSE_LINUX_OPTS,
80 	MOPT_FUSE_LINUX_IGNORE_OPTS,
81 	MOPT_STDOPTS,
82 	MOPT_NULL
83 };
84 
85 static void
86 usage(void)
87 {
88 	fprintf(stderr, "usage: mount_fusefs [-o options] fd mountpoint\n");
89 	exit(1);
90 }
91 
92 static char*
93 get_optval(const char *ptr)
94 {
95 	char *ret = strdup(ptr);
96 	const char *end = strstr(ptr, ",");
97 
98 	if (!end)
99 		return ret;
100 
101 	ret[(int)(end - ptr)] = '\0';
102 	return ret;
103 }
104 
105 /*
106  * e.g.
107  * argv[0] = "mount_fusefs"
108  * argv[1] = "-o"
109  * argv[2] = "max_read=...,subtype=hello"
110  * argv[3] = "3"
111  * argv[4] = "/mnt/fuse"
112  * argv[5] = "(null)"
113  */
114 int
115 main(int argc, char **argv)
116 {
117 	struct fuse_mount_info args;
118 	struct vfsconf vfc;
119 	struct stat st;
120 	const char *fdstr, *mntpt;
121 	char *ep, mntpath[MAXPATHLEN], fusedev[64];
122 	int error, c, fd, mntflags;
123 
124 	mntflags = 0;
125 	memset(&args, 0, sizeof(args));
126 
127 	while ((c = getopt_long(argc, argv, "ho:", NULL, NULL)) != -1) {
128 		switch(c) {
129 		case 'o':
130 			getmntopts(optarg, mopts, &mntflags, &args.flags);
131 			if (args.flags & FUSE_MOUNT_MAX_READ) {
132 				char *p = strstr(optarg, "max_read=");
133 				if (p) {
134 					p = get_optval(p + 9);
135 					args.max_read = strtol(p, NULL, 0);
136 					free(p);
137 				}
138 			}
139 			if (args.flags & FUSE_MOUNT_SUBTYPE) {
140 				char *p = strstr(optarg, "subtype=");
141 				if (p) {
142 					p = get_optval(p + 8);
143 					args.subtype = strdup(p);
144 					free(p);
145 				}
146 			}
147 			break;
148 		case 'h':
149 		default:
150 			usage(); /* exit */
151 		}
152 	}
153 	argc -= optind;
154 	argv += optind;
155 
156 	if (argc < 2)
157 		usage();
158 
159 	fdstr = argv[0];
160 	mntpt = argv[1];
161 	checkpath(mntpt, mntpath);
162 
163 	fd = strtol(fdstr, &ep, 10);
164 	if (fd <= 0 || *ep != '\0')
165 		err(1, "Invalid FUSE fd %s", fdstr);
166 
167 	if (fstat(fd, &st) == -1)
168 		err(1, "Failed to stat FUSE fd %d", fd);
169 	strcpy(fusedev, "/dev/");
170 	devname_r(st.st_rdev, S_IFCHR, fusedev + strlen(fusedev),
171 		sizeof(fusedev) - strlen(fusedev));
172 	if (stat(fusedev, &st) == -1)
173 		err(1, "Failed to stat FUSE device %s", fusedev);
174 	if (strncmp(fusedev, "/dev/fuse", 9))
175 		err(1, "Invalid FUSE device %s", fusedev);
176 	args.fd = fd;
177 	args.from = strdup(fusedev);
178 
179 	error = getvfsbyname("fuse", &vfc);
180 	if (error && vfsisloadable("fuse")) {
181 		if(vfsload("fuse"))
182 			err(1, "vfsload(%s)", "fuse");
183 		endvfsent();
184 		error = getvfsbyname("fuse", &vfc);
185 	}
186 	if (error)
187 		errx(1, "%s filesystem not available", "fuse");
188 
189 	if (mount(vfc.vfc_name, mntpath, mntflags, &args) == -1)
190 		err(1, "mount");
191 
192 	return 0;
193 }
194