xref: /dragonfly/sbin/mount_tmpfs/mount_tmpfs.c (revision 25a86e4415665b1c1970a7192fabe0ac86b0353a)
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_mount.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
mount_tmpfs_parseargs(int argc,char * argv[],struct tmpfs_mount_info * args,int * mntflags,char * canon_dev,char * canon_dir)86 mount_tmpfs_parseargs(int argc, char *argv[],
87           struct tmpfs_mount_info *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
a_gid(char * s)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
a_uid(char * s)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
a_mask(char * s)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
a_number(char * s)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
usage(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
mount_tmpfs(int argc,char * argv[])329 mount_tmpfs(int argc, char *argv[])
330 {
331           struct tmpfs_mount_info 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;
338 
339           mount_tmpfs_parseargs(argc, argv, &args, &mntflags,
340               canon_dev, canon_dir);
341 
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);
348           }
349           if (error)
350                     errx(EX_OSERR, "%s filesystem not available", "tmpfs");
351 
352           if (Cflag)
353                     copyroot = FSCopy(&copyhlinks, canon_dir);
354 
355           if (mount(vfc.vfc_name, canon_dir, mntflags, &args) == -1)
356                     err(EXIT_FAILURE, "tmpfs on %s", canon_dir);
357 
358           if (Cflag)
359                     FSPaste(canon_dir, copyroot, copyhlinks);
360 
361           return EXIT_SUCCESS;
362 }
363 
364 #ifndef MOUNT_NOMAIN
365 int
main(int argc,char * argv[])366 main(int argc, char *argv[])
367 {
368           setprogname(argv[0]);
369           return mount_tmpfs(argc, argv);
370 }
371 #endif
372