mount_tmpfs.c revision 1.2 1 1.2 jmmv /* $NetBSD: mount_tmpfs.c,v 1.2 2005/09/23 12:10:35 jmmv Exp $ */
2 1.1 jmmv
3 1.1 jmmv /*
4 1.1 jmmv * Copyright (c) 2005 The NetBSD Foundation, Inc.
5 1.1 jmmv * All rights reserved.
6 1.1 jmmv *
7 1.1 jmmv * This code is derived from software contributed to The NetBSD Foundation
8 1.1 jmmv * by Julio M. Merino Vidal.
9 1.1 jmmv *
10 1.1 jmmv * Redistribution and use in source and binary forms, with or without
11 1.1 jmmv * modification, are permitted provided that the following conditions
12 1.1 jmmv * are met:
13 1.1 jmmv * 1. Redistributions of source code must retain the above copyright
14 1.1 jmmv * notice, this list of conditions and the following disclaimer.
15 1.1 jmmv * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 jmmv * notice, this list of conditions and the following disclaimer in the
17 1.1 jmmv * documentation and/or other materials provided with the distribution.
18 1.1 jmmv * 3. All advertising materials mentioning features or use of this software
19 1.1 jmmv * must display the following acknowledgement:
20 1.1 jmmv * This product includes software developed by the NetBSD
21 1.1 jmmv * Foundation, Inc. and its contributors.
22 1.1 jmmv * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.1 jmmv * contributors may be used to endorse or promote products derived
24 1.1 jmmv * from this software without specific prior written permission.
25 1.1 jmmv *
26 1.1 jmmv * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.1 jmmv * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.1 jmmv * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.1 jmmv * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.1 jmmv * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.1 jmmv * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.1 jmmv * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.1 jmmv * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.1 jmmv * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.1 jmmv * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.1 jmmv * POSSIBILITY OF SUCH DAMAGE.
37 1.1 jmmv */
38 1.1 jmmv
39 1.1 jmmv #include <sys/cdefs.h>
40 1.1 jmmv #ifndef lint
41 1.2 jmmv __RCSID("$NetBSD: mount_tmpfs.c,v 1.2 2005/09/23 12:10:35 jmmv Exp $");
42 1.1 jmmv #endif /* not lint */
43 1.1 jmmv
44 1.1 jmmv #include <sys/param.h>
45 1.1 jmmv #include <sys/mount.h>
46 1.1 jmmv
47 1.1 jmmv #include <fs/tmpfs/tmpfs.h>
48 1.1 jmmv
49 1.1 jmmv #include <ctype.h>
50 1.1 jmmv #include <err.h>
51 1.1 jmmv #include <errno.h>
52 1.1 jmmv #include <grp.h>
53 1.1 jmmv #include <mntopts.h>
54 1.1 jmmv #include <pwd.h>
55 1.1 jmmv #include <stdio.h>
56 1.1 jmmv #include <stdlib.h>
57 1.1 jmmv #include <string.h>
58 1.1 jmmv #include <unistd.h>
59 1.1 jmmv
60 1.1 jmmv /* --------------------------------------------------------------------- */
61 1.1 jmmv
62 1.1 jmmv static const struct mntopt mopts[] = {
63 1.1 jmmv MOPT_STDOPTS,
64 1.1 jmmv { NULL }
65 1.1 jmmv };
66 1.1 jmmv
67 1.1 jmmv /* --------------------------------------------------------------------- */
68 1.1 jmmv
69 1.1 jmmv static int mount_tmpfs(int argc, char **argv);
70 1.1 jmmv static void usage(void);
71 1.1 jmmv static int dehumanize_group(const char *str, gid_t *gid);
72 1.1 jmmv static int dehumanize_mode(const char *str, mode_t *mode);
73 1.1 jmmv static int dehumanize_off(const char *str, off_t *size);
74 1.1 jmmv static int dehumanize_user(const char *str, uid_t *uid);
75 1.1 jmmv
76 1.1 jmmv /* --------------------------------------------------------------------- */
77 1.1 jmmv
78 1.1 jmmv int
79 1.1 jmmv mount_tmpfs(int argc, char *argv[])
80 1.1 jmmv {
81 1.1 jmmv char canon_dir[MAXPATHLEN];
82 1.1 jmmv int ch, mntflags;
83 1.1 jmmv off_t offtmp;
84 1.1 jmmv mntoptparse_t mo;
85 1.1 jmmv struct tmpfs_args args;
86 1.1 jmmv
87 1.1 jmmv setprogname(argv[0]);
88 1.1 jmmv
89 1.1 jmmv /* Set default values for mount point arguments. */
90 1.1 jmmv args.ta_version = TMPFS_ARGS_VERSION;
91 1.1 jmmv args.ta_size_max = 0;
92 1.1 jmmv args.ta_nodes_max = 0;
93 1.1 jmmv args.ta_root_uid = getuid();
94 1.1 jmmv args.ta_root_gid = getgid();
95 1.1 jmmv args.ta_root_mode = 0755;
96 1.1 jmmv mntflags = 0;
97 1.1 jmmv
98 1.1 jmmv optind = optreset = 1;
99 1.1 jmmv while ((ch = getopt(argc, argv, "g:m:n:o:s:u:")) != -1 ) {
100 1.1 jmmv switch (ch) {
101 1.1 jmmv case 'g':
102 1.1 jmmv if (!dehumanize_group(optarg, &args.ta_root_gid)) {
103 1.1 jmmv errx(EXIT_FAILURE, "failed to parse group "
104 1.1 jmmv "'%s'", optarg);
105 1.1 jmmv /* NOTREACHED */
106 1.1 jmmv }
107 1.1 jmmv break;
108 1.1 jmmv
109 1.1 jmmv case 'm':
110 1.1 jmmv if (!dehumanize_mode(optarg, &args.ta_root_mode)) {
111 1.1 jmmv errx(EXIT_FAILURE, "failed to parse mode "
112 1.1 jmmv "'%s'", optarg);
113 1.1 jmmv /* NOTREACHED */
114 1.1 jmmv }
115 1.1 jmmv break;
116 1.1 jmmv
117 1.1 jmmv case 'n':
118 1.1 jmmv if (!dehumanize_off(optarg, &offtmp)) {
119 1.1 jmmv errx(EXIT_FAILURE, "failed to parse size "
120 1.1 jmmv "'%s'", optarg);
121 1.1 jmmv /* NOTREACHED */
122 1.1 jmmv }
123 1.1 jmmv args.ta_nodes_max = offtmp;
124 1.1 jmmv break;
125 1.1 jmmv
126 1.1 jmmv case 'o':
127 1.1 jmmv mo = getmntopts(optarg, mopts, &mntflags, 0);
128 1.1 jmmv freemntopts(mo);
129 1.1 jmmv break;
130 1.1 jmmv
131 1.1 jmmv case 's':
132 1.1 jmmv if (!dehumanize_off(optarg, &offtmp)) {
133 1.1 jmmv errx(EXIT_FAILURE, "failed to parse size "
134 1.1 jmmv "'%s'", optarg);
135 1.1 jmmv /* NOTREACHED */
136 1.1 jmmv }
137 1.1 jmmv args.ta_size_max = offtmp;
138 1.1 jmmv break;
139 1.1 jmmv
140 1.1 jmmv case 'u':
141 1.1 jmmv if (!dehumanize_user(optarg, &args.ta_root_uid)) {
142 1.1 jmmv errx(EXIT_FAILURE, "failed to parse user "
143 1.1 jmmv "'%s'", optarg);
144 1.1 jmmv /* NOTREACHED */
145 1.1 jmmv }
146 1.1 jmmv break;
147 1.1 jmmv
148 1.1 jmmv case '?':
149 1.1 jmmv default:
150 1.1 jmmv usage();
151 1.1 jmmv /* NOTREACHED */
152 1.1 jmmv }
153 1.1 jmmv }
154 1.1 jmmv argc -= optind;
155 1.1 jmmv argv += optind;
156 1.1 jmmv
157 1.1 jmmv if (argc != 2) {
158 1.1 jmmv usage();
159 1.1 jmmv /* NOTREACHED */
160 1.1 jmmv }
161 1.1 jmmv
162 1.1 jmmv if (realpath(argv[1], canon_dir) == NULL) {
163 1.1 jmmv err(EXIT_FAILURE, "realpath %s", argv[0]);
164 1.1 jmmv /* NOTREACHED */
165 1.1 jmmv }
166 1.1 jmmv
167 1.1 jmmv if (strncmp(argv[1], canon_dir, MAXPATHLEN) != 0) {
168 1.1 jmmv warnx("\"%s\" is a relative path", argv[0]);
169 1.1 jmmv warnx("using \"%s\" instead", canon_dir);
170 1.1 jmmv }
171 1.1 jmmv
172 1.1 jmmv if (mount(MOUNT_TMPFS, canon_dir, mntflags, &args)) {
173 1.1 jmmv err(EXIT_FAILURE, "tmpfs on %s", canon_dir);
174 1.1 jmmv /* NOTREACHED */
175 1.1 jmmv }
176 1.1 jmmv
177 1.1 jmmv return EXIT_SUCCESS;
178 1.1 jmmv }
179 1.1 jmmv
180 1.1 jmmv /* --------------------------------------------------------------------- */
181 1.1 jmmv
182 1.1 jmmv static void
183 1.1 jmmv usage(void)
184 1.1 jmmv {
185 1.1 jmmv (void)fprintf(stderr,
186 1.1 jmmv "Usage: %s [-g group] [-m mode] [-n nodes] [-o options] [-s size]\n"
187 1.1 jmmv " [-u user] tmpfs mountpoint\n", getprogname());
188 1.1 jmmv exit(1);
189 1.1 jmmv }
190 1.1 jmmv
191 1.1 jmmv /* --------------------------------------------------------------------- */
192 1.1 jmmv
193 1.1 jmmv /*
194 1.1 jmmv * Obtains a GID number based on the contents of 'str'. If it is a string
195 1.1 jmmv * and is found in group(5), its corresponding ID is used. Otherwise, an
196 1.1 jmmv * attempt is made to convert the string to a number and use that as a GID.
197 1.1 jmmv * In case of success, true is returned and *gid holds the GID value.
198 1.1 jmmv * Otherwise, false is returned and *gid is untouched.
199 1.1 jmmv */
200 1.1 jmmv static int
201 1.1 jmmv dehumanize_group(const char *str, gid_t *gid)
202 1.1 jmmv {
203 1.1 jmmv int error;
204 1.1 jmmv struct group *gr;
205 1.1 jmmv
206 1.1 jmmv gr = getgrnam(str);
207 1.1 jmmv if (gr != NULL) {
208 1.1 jmmv *gid = gr->gr_gid;
209 1.1 jmmv error = 1;
210 1.1 jmmv } else {
211 1.1 jmmv char *ep;
212 1.1 jmmv long tmp;
213 1.1 jmmv
214 1.1 jmmv errno = 0;
215 1.1 jmmv tmp = strtol(str, &ep, 10);
216 1.1 jmmv if (str[0] == '\0' || *ep != '\0')
217 1.1 jmmv error = 0; /* Not a number. */
218 1.1 jmmv else if (errno == ERANGE &&
219 1.1 jmmv (tmp == LONG_MAX || tmp == LONG_MIN))
220 1.1 jmmv error = 0; /* Out of range. */
221 1.1 jmmv else {
222 1.1 jmmv *gid = (gid_t)tmp;
223 1.1 jmmv error = 1;
224 1.1 jmmv }
225 1.1 jmmv }
226 1.1 jmmv
227 1.1 jmmv return error;
228 1.1 jmmv }
229 1.1 jmmv
230 1.1 jmmv /* --------------------------------------------------------------------- */
231 1.1 jmmv
232 1.1 jmmv /*
233 1.1 jmmv * Obtains a mode number based on the contents of 'str'.
234 1.1 jmmv * In case of success, true is returned and *mode holds the mode value.
235 1.1 jmmv * Otherwise, false is returned and *mode is untouched.
236 1.1 jmmv */
237 1.1 jmmv static int
238 1.1 jmmv dehumanize_mode(const char *str, mode_t *mode)
239 1.1 jmmv {
240 1.1 jmmv char *ep;
241 1.1 jmmv int error;
242 1.1 jmmv long tmp;
243 1.1 jmmv
244 1.1 jmmv errno = 0;
245 1.1 jmmv tmp = strtol(str, &ep, 8);
246 1.1 jmmv if (str[0] == '\0' || *ep != '\0')
247 1.1 jmmv error = 0; /* Not a number. */
248 1.1 jmmv else if (errno == ERANGE &&
249 1.1 jmmv (tmp == LONG_MAX || tmp == LONG_MIN))
250 1.1 jmmv error = 0; /* Out of range. */
251 1.1 jmmv else {
252 1.1 jmmv *mode = (mode_t)tmp;
253 1.1 jmmv error = 1;
254 1.1 jmmv }
255 1.1 jmmv
256 1.1 jmmv return error;
257 1.1 jmmv }
258 1.1 jmmv
259 1.1 jmmv /* --------------------------------------------------------------------- */
260 1.1 jmmv
261 1.1 jmmv /*
262 1.1 jmmv * Converts the number given in 'str', which may be given in a humanized
263 1.1 jmmv * form (as described in humanize_number(3), but with some limitations),
264 1.1 jmmv * to a file size (off_t) without units.
265 1.1 jmmv * In case of success, true is returned and *size holds the value.
266 1.1 jmmv * Otherwise, false is returned and *size is untouched.
267 1.1 jmmv */
268 1.1 jmmv static int
269 1.1 jmmv dehumanize_off(const char *str, off_t *size)
270 1.1 jmmv {
271 1.1 jmmv char *ep, unit;
272 1.1 jmmv const char *delimit;
273 1.1 jmmv size_t len, multiplier, tmp;
274 1.1 jmmv
275 1.1 jmmv len = strlen(str);
276 1.1 jmmv if (len < 1)
277 1.1 jmmv return 0;
278 1.1 jmmv
279 1.1 jmmv multiplier = 1;
280 1.1 jmmv
281 1.1 jmmv unit = str[len - 1];
282 1.1 jmmv if (isalpha((int)unit)) {
283 1.1 jmmv switch (unit) {
284 1.1 jmmv case 'b':
285 1.1 jmmv multiplier = 1;
286 1.1 jmmv break;
287 1.1 jmmv
288 1.1 jmmv case 'k':
289 1.1 jmmv multiplier = 1024;
290 1.1 jmmv break;
291 1.1 jmmv
292 1.1 jmmv case 'M':
293 1.1 jmmv multiplier = 1024 * 1024;
294 1.1 jmmv break;
295 1.1 jmmv
296 1.1 jmmv case 'G':
297 1.1 jmmv multiplier = 1024 * 1024 * 1024;
298 1.1 jmmv break;
299 1.1 jmmv
300 1.1 jmmv default:
301 1.1 jmmv return 0; /* Invalid suffix. */
302 1.1 jmmv }
303 1.1 jmmv
304 1.1 jmmv delimit = &str[len - 1];
305 1.1 jmmv } else
306 1.1 jmmv delimit = NULL;
307 1.1 jmmv
308 1.1 jmmv errno = 0;
309 1.1 jmmv tmp = strtol(str, &ep, 10);
310 1.1 jmmv if (str[0] == '\0' || (ep != delimit && *ep != '\0'))
311 1.1 jmmv return 0; /* Not a number. */
312 1.1 jmmv else if (errno == ERANGE &&
313 1.1 jmmv (tmp == LONG_MAX || tmp == LONG_MIN))
314 1.1 jmmv return 0; /* Out of range. */
315 1.1 jmmv
316 1.1 jmmv *size = tmp * multiplier;
317 1.1 jmmv
318 1.1 jmmv return 1;
319 1.1 jmmv }
320 1.1 jmmv
321 1.1 jmmv /* --------------------------------------------------------------------- */
322 1.1 jmmv
323 1.1 jmmv /*
324 1.1 jmmv * Obtains a UID number based on the contents of 'str'. If it is a string
325 1.1 jmmv * and is found in passwd(5), its corresponding ID is used. Otherwise, an
326 1.1 jmmv * attempt is made to convert the string to a number and use that as a UID.
327 1.1 jmmv * In case of success, true is returned and *uid holds the UID value.
328 1.1 jmmv * Otherwise, false is returned and *uid is untouched.
329 1.1 jmmv */
330 1.1 jmmv static int
331 1.1 jmmv dehumanize_user(const char *str, uid_t *uid)
332 1.1 jmmv {
333 1.1 jmmv int error;
334 1.1 jmmv struct passwd *pw;
335 1.1 jmmv
336 1.1 jmmv pw = getpwnam(str);
337 1.1 jmmv if (pw != NULL) {
338 1.1 jmmv *uid = pw->pw_uid;
339 1.1 jmmv error = 1;
340 1.1 jmmv } else {
341 1.1 jmmv char *ep;
342 1.1 jmmv long tmp;
343 1.1 jmmv
344 1.1 jmmv errno = 0;
345 1.1 jmmv tmp = strtol(str, &ep, 10);
346 1.1 jmmv if (str[0] == '\0' || *ep != '\0')
347 1.1 jmmv error = 0; /* Not a number. */
348 1.1 jmmv else if (errno == ERANGE &&
349 1.1 jmmv (tmp == LONG_MAX || tmp == LONG_MIN))
350 1.1 jmmv error = 0; /* Out of range. */
351 1.1 jmmv else {
352 1.1 jmmv *uid = (uid_t)tmp;
353 1.1 jmmv error = 1;
354 1.1 jmmv }
355 1.1 jmmv }
356 1.1 jmmv
357 1.1 jmmv return error;
358 1.1 jmmv }
359 1.1 jmmv
360 1.1 jmmv /* --------------------------------------------------------------------- */
361 1.1 jmmv
362 1.1 jmmv #ifndef MOUNT_NOMAIN
363 1.1 jmmv int
364 1.1 jmmv main(int argc, char *argv[])
365 1.1 jmmv {
366 1.1 jmmv
367 1.1 jmmv return mount_tmpfs(argc, argv);
368 1.1 jmmv }
369 1.1 jmmv #endif
370