tmpfs - Add additional mount options
[dragonfly.git] / sbin / mount_tmpfs / mount_tmpfs.c
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         fprintf(stderr, "%ld", rv);
313         return (rv);
314 }
315
316 static void
317 usage(void)
318 {
319         (void)fprintf(stderr,
320             "Usage: %s [-g group] [-m mode] [-n nodes] [-o options] [-s size]\n"
321             "           [-u user] [-f maxfilesize]  tmpfs mountpoint\n", getprogname());
322         exit(1);
323 }
324
325 /* --------------------------------------------------------------------- */
326
327 int
328 mount_tmpfs(int argc, char *argv[])
329 {
330         struct tmpfs_args args;
331         char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN];
332         int mntflags;
333         struct vfsconf vfc;
334         int error;
335
336         mount_tmpfs_parseargs(argc, argv, &args, &mntflags,
337             canon_dev, canon_dir);
338
339
340         error = getvfsbyname("tmpfs", &vfc);
341         if (error && vfsisloadable("tmpfs")) {
342                 if(vfsload("tmpfs"))
343                         err(EX_OSERR, "vfsload(%s)", "tmpfs");
344                 endvfsent();
345                 error = getvfsbyname("tmpfs", &vfc);
346         }
347         if (error)
348                 errx(EX_OSERR, "%s filesystem not available", "tmpfs");
349
350         if (mount(vfc.vfc_name, canon_dir, mntflags, &args) == -1)
351                 err(EXIT_FAILURE, "tmpfs on %s", canon_dir);
352
353         return EXIT_SUCCESS;
354 }
355
356 #ifndef MOUNT_NOMAIN
357 int
358 main(int argc, char *argv[])
359 {
360
361         setprogname(argv[0]);
362         return mount_tmpfs(argc, argv);
363 }
364 #endif