xref: /dragonfly/sbin/mount_tmpfs/mount_tmpfs.c (revision cfd1aba3)
1 /*	$NetBSD: mount_tmpfs.c,v 1.24 2008/08/05 20:57:45 pooka Exp $	*/
2 
3 /*
4  * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Julio M. Merino Vidal, developed as part of Google's Summer of Code
9  * 2005 program.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 #include <sys/param.h>
34 #include <sys/mount.h>
35 #include <sys/stat.h>
36 
37 #include <vfs/tmpfs/tmpfs_args.h>
38 
39 #include <ctype.h>
40 #include <err.h>
41 #include <errno.h>
42 #include <grp.h>
43 #include <mntopts.h>
44 #include <pwd.h>
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48 #include <sysexits.h>
49 #include <unistd.h>
50 #include <inttypes.h>
51 #include <libutil.h>
52 
53 #include "defs.h"
54 #include "mount_tmpfs.h"
55 
56 /* --------------------------------------------------------------------- */
57 
58 #define MOPT_TMPFSOPTS	\
59 	{ "gid=",	0,	MNT_GID, 1},	\
60 	{ "uid=",	0,	MNT_UID, 1},	\
61 	{ "mode=",	0,	MNT_MODE, 1},	\
62 	{ "inodes=",	0,	MNT_INODES, 1},	\
63 	{ "size=",	0,	MNT_SIZE, 1},	\
64 	{ "maxfilesize=",	0,	MNT_MAXFSIZE, 1}
65 
66 
67 static const struct mntopt mopts[] = {
68 	MOPT_STDOPTS,
69 	MOPT_TMPFSOPTS,
70 	MOPT_NULL
71 };
72 
73 static int Cflag;
74 
75 /* --------------------------------------------------------------------- */
76 
77 static gid_t	a_gid(char *);
78 static uid_t	a_uid(char *);
79 static mode_t	a_mask(char *);
80 static int64_t a_number(char *s);
81 static void	usage(void) __dead2;
82 
83 /* --------------------------------------------------------------------- */
84 
85 void
86 mount_tmpfs_parseargs(int argc, char *argv[],
87 	struct tmpfs_args *args, int *mntflags,
88 	char *canon_dev, char *canon_dir)
89 {
90 	int gidset, modeset, uidset; /* Ought to be 'bool'. */
91 	int ch;
92 	gid_t gid;
93 	uid_t uid;
94 	mode_t mode;
95 	struct stat sb;
96 	int extend_flags = 0;
97 	char *ptr, *delim;
98 
99 	/* Set default values for mount point arguments. */
100 	memset(args, 0, sizeof(*args));
101 	args->ta_version = TMPFS_ARGS_VERSION;
102 	args->ta_size_max = 0;
103 	args->ta_nodes_max = 0;
104 	args->ta_maxfsize_max = 0;
105 	*mntflags = 0;
106 
107 	gidset = 0; gid = 0;
108 	uidset = 0; uid = 0;
109 	modeset = 0; mode = 0;
110 
111 	optind = optreset = 1;
112 	while ((ch = getopt(argc, argv, "Cf:g:m:n:o:s:u:")) != -1 ) {
113 		switch (ch) {
114 		case 'C':
115 			Cflag = 1;
116 			break;
117 		case 'f':
118 			args->ta_maxfsize_max = a_number(optarg);
119 			break;
120 
121 		case 'g':
122 			gid = a_gid(optarg);
123 			gidset = 1;
124 			break;
125 
126 		case 'm':
127 			mode = a_mask(optarg);
128 			modeset = 1;
129 			break;
130 
131 		case 'n':
132 			args->ta_nodes_max = a_number(optarg);
133 			break;
134 
135 		case 'o':
136 			getmntopts(optarg, mopts, mntflags, &extend_flags);
137 			if (extend_flags & MNT_GID) {
138 				ptr = strstr(optarg, "gid=");
139 				if(ptr) {
140 					delim = strstr(ptr, ",");
141 					if (delim) {
142 						*delim = '\0';
143 						gid = a_gid(ptr + 4);
144 						*delim = ',';
145 					} else
146 						gid = a_gid(ptr + 4);
147 					gidset = 1;
148 				}
149 				extend_flags ^= MNT_GID;
150 			}
151 			if (extend_flags & MNT_UID) {
152 				ptr = strstr(optarg, "uid=");
153 				if(ptr) {
154 					delim = strstr(ptr, ",");
155 					if (delim) {
156 						*delim = '\0';
157 						uid = a_uid(ptr + 4);
158 						*delim = ',';
159 					} else
160 						uid = a_uid(ptr + 4);
161 					uidset = 1;
162 				}
163 				extend_flags ^= MNT_UID;
164 			}
165 			if (extend_flags & MNT_MODE) {
166 				ptr = strstr(optarg, "mode=");
167 				if(ptr) {
168 					delim = strstr(ptr, ",");
169 					if (delim) {
170 						*delim = '\0';
171 						mode = a_mask(ptr + 5);
172 						*delim = ',';
173 					} else
174 						mode = a_mask(ptr + 5);
175 					modeset = 1;
176 				}
177 				extend_flags ^= MNT_MODE;
178 			}
179 			if (extend_flags & MNT_INODES) {
180 				ptr = strstr(optarg, "inodes=");
181 				if(ptr) {
182 					delim = strstr(ptr, ",");
183 					if (delim) {
184 						*delim = '\0';
185 						args->ta_nodes_max = a_number(ptr + 7);
186 						*delim = ',';
187 					} else
188 						args->ta_nodes_max = a_number(ptr + 7);
189 				}
190 				extend_flags ^= MNT_INODES;
191 			}
192 			if (extend_flags & MNT_SIZE) {
193 				ptr = strstr(optarg, "size=");
194 				if(ptr) {
195 					delim = strstr(ptr, ",");
196 					if (delim) {
197 						*delim = '\0';
198 						args->ta_size_max = a_number(ptr + 5);
199 						*delim = ',';
200 					} else
201 						args->ta_size_max = a_number(ptr + 5);
202 				}
203 				extend_flags ^= MNT_SIZE;
204 			}
205 			if (extend_flags & MNT_MAXFSIZE) {
206 				ptr = strstr(optarg, "maxfilesize=");
207 				if(ptr) {
208 					delim = strstr(ptr, ",");
209 					if (delim) {
210 						*delim = '\0';
211 						args->ta_maxfsize_max = a_number(ptr + 12);
212 						*delim = ',';
213 					} else
214 						args->ta_maxfsize_max = a_number(ptr + 12);
215 				}
216 				extend_flags ^= MNT_MAXFSIZE;
217 			}
218 			break;
219 
220 		case 's':
221 			args->ta_size_max = a_number(optarg);
222 			break;
223 
224 		case 'u':
225 			uid = a_uid(optarg);
226 			uidset = 1;
227 			break;
228 
229 		case '?':
230 		default:
231 			usage();
232 		}
233 	}
234 	argc -= optind;
235 	argv += optind;
236 
237 	if (argc != 2)
238 		usage();
239 
240 	strlcpy(canon_dev, argv[0], MAXPATHLEN);
241 	strlcpy(canon_dir, argv[1], MAXPATHLEN);
242 
243 	if (stat(canon_dir, &sb) == -1)
244 		err(EXIT_FAILURE, "cannot stat `%s'", canon_dir);
245 
246 	args->ta_root_uid = uidset ? uid : sb.st_uid;
247 	args->ta_root_gid = gidset ? gid : sb.st_gid;
248 	args->ta_root_mode = modeset ? mode : sb.st_mode;
249 }
250 
251 /* --------------------------------------------------------------------- */
252 
253 static gid_t
254 a_gid(char *s)
255 {
256 	struct group *gr;
257 	char *gname;
258 	gid_t gid;
259 
260 	if ((gr = getgrnam(s)) != NULL)
261 		gid = gr->gr_gid;
262 	else {
263 		for (gname = s; *s && isdigit(*s); ++s);
264 		if (!*s)
265 			gid = atoi(gname);
266 		else
267 			errx(EX_NOUSER, "unknown group id: %s", gname);
268 	}
269 	return (gid);
270 }
271 
272 static uid_t
273 a_uid(char *s)
274 {
275 	struct passwd *pw;
276 	char *uname;
277 	uid_t uid;
278 
279 	if ((pw = getpwnam(s)) != NULL)
280 		uid = pw->pw_uid;
281 	else {
282 		for (uname = s; *s && isdigit(*s); ++s);
283 		if (!*s)
284 			uid = atoi(uname);
285 		else
286 			errx(EX_NOUSER, "unknown user id: %s", uname);
287 	}
288 	return (uid);
289 }
290 
291 static mode_t
292 a_mask(char *s)
293 {
294 	int done, rv = 0;
295 	char *ep;
296 
297 	done = 0;
298 	if (*s >= '0' && *s <= '7') {
299 		done = 1;
300 		rv = strtol(s, &ep, 8);
301 	}
302 	if (!done || rv < 0 || *ep)
303 		errx(EX_USAGE, "invalid file mode: %s", s);
304 	return (rv);
305 }
306 
307 static int64_t
308 a_number(char *s)
309 {
310 	int64_t rv = 0;
311 
312 	if (dehumanize_number(s, &rv) < 0 || rv < 0)
313 		errx(EX_USAGE, "bad number for option: %s", s);
314 	return (rv);
315 }
316 
317 static void
318 usage(void)
319 {
320 	fprintf(stderr,
321 	    "Usage: %s [-C] [-g group] [-m mode] [-n nodes] [-o options] [-s size]\n"
322 	    "           [-u user] [-f maxfilesize] tmpfs mountpoint\n", getprogname());
323 	exit(1);
324 }
325 
326 /* --------------------------------------------------------------------- */
327 
328 int
329 mount_tmpfs(int argc, char *argv[])
330 {
331 	struct tmpfs_args args;
332 	char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN];
333 	int mntflags;
334 	struct vfsconf vfc;
335 	int error;
336 	fsnode_t copyroot = NULL, copyhlinks;
337 
338 	mount_tmpfs_parseargs(argc, argv, &args, &mntflags,
339 	    canon_dev, canon_dir);
340 
341 	error = getvfsbyname("tmpfs", &vfc);
342 	if (error && vfsisloadable("tmpfs")) {
343 		if(vfsload("tmpfs"))
344 			err(EX_OSERR, "vfsload(%s)", "tmpfs");
345 		endvfsent();
346 		error = getvfsbyname("tmpfs", &vfc);
347 	}
348 	if (error)
349 		errx(EX_OSERR, "%s filesystem not available", "tmpfs");
350 
351 	if (Cflag)
352 		copyroot = FSCopy(&copyhlinks, canon_dir);
353 
354 	if (mount(vfc.vfc_name, canon_dir, mntflags, &args) == -1)
355 		err(EXIT_FAILURE, "tmpfs on %s", canon_dir);
356 
357 	if (Cflag)
358 		FSPaste(canon_dir, copyroot, copyhlinks);
359 
360 	return EXIT_SUCCESS;
361 }
362 
363 #ifndef MOUNT_NOMAIN
364 int
365 main(int argc, char *argv[])
366 {
367 	setprogname(argv[0]);
368 	return mount_tmpfs(argc, argv);
369 }
370 #endif
371