kernel - Fix races created by a comedy of circumstansces (3)
[dragonfly.git] / sbin / mount_tmpfs / mount_tmpfs.c
blobae6c6e3bf8828fbd7ab4b195d70fa71380053d50
1 /* $NetBSD: mount_tmpfs.c,v 1.24 2008/08/05 20:57:45 pooka Exp $ */
3 /*
4 * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
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.
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.
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.
33 #include <sys/param.h>
34 #include <sys/mount.h>
35 #include <sys/stat.h>
37 #include <vfs/tmpfs/tmpfs_args.h>
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>
53 #include "defs.h"
54 #include "mount_tmpfs.h"
56 /* --------------------------------------------------------------------- */
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}
67 static const struct mntopt mopts[] = {
68 MOPT_STDOPTS,
69 MOPT_TMPFSOPTS,
70 MOPT_NULL
73 static int Cflag;
75 /* --------------------------------------------------------------------- */
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;
83 /* --------------------------------------------------------------------- */
85 void
86 mount_tmpfs_parseargs(int argc, char *argv[],
87 struct tmpfs_args *args, int *mntflags,
88 char *canon_dev, char *canon_dir)
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;
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;
107 gidset = 0; gid = 0;
108 uidset = 0; uid = 0;
109 modeset = 0; mode = 0;
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;
121 case 'g':
122 gid = a_gid(optarg);
123 gidset = 1;
124 break;
126 case 'm':
127 mode = a_mask(optarg);
128 modeset = 1;
129 break;
131 case 'n':
132 args->ta_nodes_max = a_number(optarg);
133 break;
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;
149 extend_flags ^= MNT_GID;
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;
163 extend_flags ^= MNT_UID;
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;
177 extend_flags ^= MNT_MODE;
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);
190 extend_flags ^= MNT_INODES;
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);
203 extend_flags ^= MNT_SIZE;
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);
216 extend_flags ^= MNT_MAXFSIZE;
218 break;
220 case 's':
221 args->ta_size_max = a_number(optarg);
222 break;
224 case 'u':
225 uid = a_uid(optarg);
226 uidset = 1;
227 break;
229 case '?':
230 default:
231 usage();
234 argc -= optind;
235 argv += optind;
237 if (argc != 2)
238 usage();
240 strlcpy(canon_dev, argv[0], MAXPATHLEN);
241 strlcpy(canon_dir, argv[1], MAXPATHLEN);
243 if (stat(canon_dir, &sb) == -1)
244 err(EXIT_FAILURE, "cannot stat `%s'", canon_dir);
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;
251 /* --------------------------------------------------------------------- */
253 static gid_t
254 a_gid(char *s)
256 struct group *gr;
257 char *gname;
258 gid_t gid;
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);
269 return (gid);
272 static uid_t
273 a_uid(char *s)
275 struct passwd *pw;
276 char *uname;
277 uid_t uid;
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);
288 return (uid);
291 static mode_t
292 a_mask(char *s)
294 int done, rv = 0;
295 char *ep;
297 done = 0;
298 if (*s >= '0' && *s <= '7') {
299 done = 1;
300 rv = strtol(s, &ep, 8);
302 if (!done || rv < 0 || *ep)
303 errx(EX_USAGE, "invalid file mode: %s", s);
304 return (rv);
307 static int64_t
308 a_number(char *s)
310 int64_t rv = 0;
312 if (dehumanize_number(s, &rv) < 0 || rv < 0)
313 errx(EX_USAGE, "bad number for option: %s", s);
314 return (rv);
317 static void
318 usage(void)
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);
326 /* --------------------------------------------------------------------- */
329 mount_tmpfs(int argc, char *argv[])
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;
337 fsnode_t copyhlinks = NULL;
339 mount_tmpfs_parseargs(argc, argv, &args, &mntflags,
340 canon_dev, canon_dir);
342 error = getvfsbyname("tmpfs", &vfc);
343 if (error && vfsisloadable("tmpfs")) {
344 if(vfsload("tmpfs"))
345 err(EX_OSERR, "vfsload(%s)", "tmpfs");
346 endvfsent();
347 error = getvfsbyname("tmpfs", &vfc);
349 if (error)
350 errx(EX_OSERR, "%s filesystem not available", "tmpfs");
352 if (Cflag)
353 copyroot = FSCopy(&copyhlinks, canon_dir);
355 if (mount(vfc.vfc_name, canon_dir, mntflags, &args) == -1)
356 err(EXIT_FAILURE, "tmpfs on %s", canon_dir);
358 if (Cflag)
359 FSPaste(canon_dir, copyroot, copyhlinks);
361 return EXIT_SUCCESS;
364 #ifndef MOUNT_NOMAIN
366 main(int argc, char *argv[])
368 setprogname(argv[0]);
369 return mount_tmpfs(argc, argv);
371 #endif