xref: /dflybsd-src/sbin/mount_tmpfs/mount_tmpfs.c (revision a9656fbcd49c376aba5e04370d8b0f1fa96e063c)
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/cdefs.h>
34 #ifndef lint
35 #endif /* not lint */
36 
37 #include <sys/param.h>
38 #include <sys/mount.h>
39 #include <sys/stat.h>
40 
41 #include <vfs/tmpfs/tmpfs_args.h>
42 
43 #include <ctype.h>
44 #include <err.h>
45 #include <errno.h>
46 #include <grp.h>
47 #include <pwd.h>
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51 #include <sysexits.h>
52 #include <unistd.h>
53 #include <inttypes.h>
54 #include <libutil.h>
55 
56 #include "mntopts.h"
57 #include "mount_tmpfs.h"
58 
59 /* --------------------------------------------------------------------- */
60 
61 #define MOPT_TMPFSOPTS	\
62 	{ "gid=",	0,	MNT_GID, 1},	\
63 	{ "uid=",	0,	MNT_UID, 1},	\
64 	{ "mode=",	0,	MNT_MODE, 1},	\
65 	{ "inodes=",	0,	MNT_INODES, 1},	\
66 	{ "size=",	0,	MNT_SIZE, 1},	\
67 	{ "maxfilesize=",	0,	MNT_MAXFSIZE, 1}
68 
69 
70 static const struct mntopt mopts[] = {
71 	MOPT_STDOPTS,
72 	MOPT_TMPFSOPTS,
73 	MOPT_NULL
74 };
75 
76 /* --------------------------------------------------------------------- */
77 
78 static gid_t	a_gid(char *);
79 static uid_t	a_uid(char *);
80 static mode_t	a_mask(char *);
81 static int64_t a_number(char *s);
82 static void	usage(void) __dead2;
83 
84 /* --------------------------------------------------------------------- */
85 
86 void
87 mount_tmpfs_parseargs(int argc, char *argv[],
88 	struct tmpfs_args *args, int *mntflags,
89 	char *canon_dev, char *canon_dir)
90 {
91 	int gidset, modeset, uidset; /* Ought to be 'bool'. */
92 	int ch;
93 	gid_t gid;
94 	uid_t uid;
95 	mode_t mode;
96 	struct stat sb;
97 	int extend_flags = 0;
98 	char *ptr, *delim;
99 
100 	/* Set default values for mount point arguments. */
101 	memset(args, 0, sizeof(*args));
102 	args->ta_version = TMPFS_ARGS_VERSION;
103 	args->ta_size_max = 0;
104 	args->ta_nodes_max = 0;
105 	args->ta_maxfsize_max = 0;
106 	*mntflags = 0;
107 
108 	gidset = 0; gid = 0;
109 	uidset = 0; uid = 0;
110 	modeset = 0; mode = 0;
111 
112 	optind = optreset = 1;
113 	while ((ch = getopt(argc, argv, "f:g:m:n:o:s:u:")) != -1 ) {
114 		switch (ch) {
115 		case 'f':
116 			args->ta_maxfsize_max = a_number(optarg);
117 			break;
118 
119 		case 'g':
120 			gid = a_gid(optarg);
121 			gidset = 1;
122 			break;
123 
124 		case 'm':
125 			mode = a_mask(optarg);
126 			modeset = 1;
127 			break;
128 
129 		case 'n':
130 			args->ta_nodes_max = a_number(optarg);
131 			break;
132 
133 		case 'o':
134 			getmntopts(optarg, mopts, mntflags, &extend_flags);
135 			if (extend_flags & MNT_GID) {
136 				ptr = strstr(optarg, "gid=");
137 				if(ptr) {
138 					delim = strstr(ptr, ",");
139 					if (delim) {
140 						*delim = '\0';
141 						gid = a_gid(ptr + 4);
142 						*delim = ',';
143 					} else
144 						gid = a_gid(ptr + 4);
145 					gidset = 1;
146 				}
147 				extend_flags ^= MNT_GID;
148 			}
149 			if (extend_flags & MNT_UID) {
150 				ptr = strstr(optarg, "uid=");
151 				if(ptr) {
152 					delim = strstr(ptr, ",");
153 					if (delim) {
154 						*delim = '\0';
155 						uid = a_uid(ptr + 4);
156 						*delim = ',';
157 					} else
158 						uid = a_uid(ptr + 4);
159 					uidset = 1;
160 				}
161 				extend_flags ^= MNT_UID;
162 			}
163 			if (extend_flags & MNT_MODE) {
164 				ptr = strstr(optarg, "mode=");
165 				if(ptr) {
166 					delim = strstr(ptr, ",");
167 					if (delim) {
168 						*delim = '\0';
169 						mode = a_mask(ptr + 5);
170 						*delim = ',';
171 					} else
172 						mode = a_mask(ptr + 5);
173 					modeset = 1;
174 				}
175 				extend_flags ^= MNT_MODE;
176 			}
177 			if (extend_flags & MNT_INODES) {
178 				ptr = strstr(optarg, "inodes=");
179 				if(ptr) {
180 					delim = strstr(ptr, ",");
181 					if (delim) {
182 						*delim = '\0';
183 						args->ta_nodes_max = a_number(ptr + 7);
184 						*delim = ',';
185 					} else
186 						args->ta_nodes_max = a_number(ptr + 7);
187 				}
188 				extend_flags ^= MNT_INODES;
189 			}
190 			if (extend_flags & MNT_SIZE) {
191 				ptr = strstr(optarg, "size=");
192 				if(ptr) {
193 					delim = strstr(ptr, ",");
194 					if (delim) {
195 						*delim = '\0';
196 						args->ta_size_max = a_number(ptr + 5);
197 						*delim = ',';
198 					} else
199 						args->ta_size_max = a_number(ptr + 5);
200 				}
201 				extend_flags ^= MNT_SIZE;
202 			}
203 			if (extend_flags & MNT_MAXFSIZE) {
204 				ptr = strstr(optarg, "maxfilesize=");
205 				if(ptr) {
206 					delim = strstr(ptr, ",");
207 					if (delim) {
208 						*delim = '\0';
209 						args->ta_maxfsize_max = a_number(ptr + 12);
210 						*delim = ',';
211 					} else
212 						args->ta_maxfsize_max = a_number(ptr + 12);
213 				}
214 				extend_flags ^= MNT_MAXFSIZE;
215 			}
216 			break;
217 
218 		case 's':
219 			args->ta_size_max = a_number(optarg);
220 			break;
221 
222 		case 'u':
223 			uid = a_uid(optarg);
224 			uidset = 1;
225 			break;
226 
227 		case '?':
228 		default:
229 			usage();
230 		}
231 	}
232 	argc -= optind;
233 	argv += optind;
234 
235 	if (argc != 2)
236 		usage();
237 
238 	strlcpy(canon_dev, argv[0], MAXPATHLEN);
239 	strlcpy(canon_dir, argv[1], MAXPATHLEN);
240 
241 	if (stat(canon_dir, &sb) == -1)
242 		err(EXIT_FAILURE, "cannot stat `%s'", canon_dir);
243 
244 	args->ta_root_uid = uidset ? uid : sb.st_uid;
245 	args->ta_root_gid = gidset ? gid : sb.st_gid;
246 	args->ta_root_mode = modeset ? mode : sb.st_mode;
247 }
248 
249 /* --------------------------------------------------------------------- */
250 
251 static gid_t
252 a_gid(char *s)
253 {
254 	struct group *gr;
255 	char *gname;
256 	gid_t gid;
257 
258 	if ((gr = getgrnam(s)) != NULL)
259 		gid = gr->gr_gid;
260 	else {
261 		for (gname = s; *s && isdigit(*s); ++s);
262 		if (!*s)
263 			gid = atoi(gname);
264 		else
265 			errx(EX_NOUSER, "unknown group id: %s", gname);
266 	}
267 	return (gid);
268 }
269 
270 static uid_t
271 a_uid(char *s)
272 {
273 	struct passwd *pw;
274 	char *uname;
275 	uid_t uid;
276 
277 	if ((pw = getpwnam(s)) != NULL)
278 		uid = pw->pw_uid;
279 	else {
280 		for (uname = s; *s && isdigit(*s); ++s);
281 		if (!*s)
282 			uid = atoi(uname);
283 		else
284 			errx(EX_NOUSER, "unknown user id: %s", uname);
285 	}
286 	return (uid);
287 }
288 
289 static mode_t
290 a_mask(char *s)
291 {
292 	int done, rv=0;
293 	char *ep;
294 
295 	done = 0;
296 	if (*s >= '0' && *s <= '7') {
297 		done = 1;
298 		rv = strtol(s, &ep, 8);
299 	}
300 	if (!done || rv < 0 || *ep)
301 		errx(EX_USAGE, "invalid file mode: %s", s);
302 	return (rv);
303 }
304 
305 static int64_t
306 a_number(char *s)
307 {
308 	int64_t rv=0;
309 
310 	if (dehumanize_number(s, &rv) < 0 || rv < 0)
311 		errx(EX_USAGE, "bad number for option: %s", s);
312 	return (rv);
313 }
314 
315 static void
316 usage(void)
317 {
318 	(void)fprintf(stderr,
319 	    "Usage: %s [-g group] [-m mode] [-n nodes] [-o options] [-s size]\n"
320 	    "           [-u user] [-f maxfilesize]  tmpfs mountpoint\n", getprogname());
321 	exit(1);
322 }
323 
324 /* --------------------------------------------------------------------- */
325 
326 int
327 mount_tmpfs(int argc, char *argv[])
328 {
329 	struct tmpfs_args args;
330 	char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN];
331 	int mntflags;
332 	struct vfsconf vfc;
333 	int error;
334 
335 	mount_tmpfs_parseargs(argc, argv, &args, &mntflags,
336 	    canon_dev, canon_dir);
337 
338 
339 	error = getvfsbyname("tmpfs", &vfc);
340 	if (error && vfsisloadable("tmpfs")) {
341 		if(vfsload("tmpfs"))
342 			err(EX_OSERR, "vfsload(%s)", "tmpfs");
343 		endvfsent();
344 		error = getvfsbyname("tmpfs", &vfc);
345 	}
346 	if (error)
347 		errx(EX_OSERR, "%s filesystem not available", "tmpfs");
348 
349 	if (mount(vfc.vfc_name, canon_dir, mntflags, &args) == -1)
350 		err(EXIT_FAILURE, "tmpfs on %s", canon_dir);
351 
352 	return EXIT_SUCCESS;
353 }
354 
355 #ifndef MOUNT_NOMAIN
356 int
357 main(int argc, char *argv[])
358 {
359 
360 	setprogname(argv[0]);
361 	return mount_tmpfs(argc, argv);
362 }
363 #endif
364