Merge branch 'master' into net80211-update
[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 static const struct mntopt mopts[] = {
62         MOPT_STDOPTS,
63         MOPT_NULL
64 };
65
66 /* --------------------------------------------------------------------- */
67
68 static gid_t    a_gid(char *);
69 static uid_t    a_uid(char *);
70 static mode_t   a_mask(char *);
71 static void     usage(void) __dead2;
72
73 /* --------------------------------------------------------------------- */
74
75 void
76 mount_tmpfs_parseargs(int argc, char *argv[],
77         struct tmpfs_args *args, int *mntflags,
78         char *canon_dev, char *canon_dir)
79 {
80         int gidset, modeset, uidset; /* Ought to be 'bool'. */
81         int ch;
82         gid_t gid;
83         uid_t uid;
84         mode_t mode;
85         int64_t tmpnumber;
86         struct stat sb;
87
88         /* Set default values for mount point arguments. */
89         memset(args, 0, sizeof(*args));
90         args->ta_version = TMPFS_ARGS_VERSION;
91         args->ta_size_max = 0;
92         args->ta_nodes_max = 0;
93         *mntflags = 0;
94
95         gidset = 0; gid = 0;
96         uidset = 0; uid = 0;
97         modeset = 0; mode = 0;
98
99         optind = optreset = 1;
100         while ((ch = getopt(argc, argv, "g:m:n:o:s:u:")) != -1 ) {
101                 switch (ch) {
102                 case 'g':
103                         gid = a_gid(optarg);
104                         gidset = 1;
105                         break;
106
107                 case 'm':
108                         mode = a_mask(optarg);
109                         modeset = 1;
110                         break;
111
112                 case 'n':
113                         if (dehumanize_number(optarg, &tmpnumber) < 0) {
114                                 fprintf(stderr, "bad number for -n\n");
115                                 usage();
116                         }
117                         args->ta_nodes_max = tmpnumber;
118                         break;
119
120                 case 'o':
121                         getmntopts(optarg, mopts, mntflags, 0);
122                         break;
123
124                 case 's':
125                         if (dehumanize_number(optarg, &tmpnumber) < 0) {
126                                 fprintf(stderr, "bad number for -s\n");
127                                 usage();
128                         }
129                         args->ta_size_max = tmpnumber;
130                         break;
131
132                 case 'u':
133                         uid = a_uid(optarg);
134                         uidset = 1;
135                         break;
136
137                 case '?':
138                 default:
139                         usage();
140                 }
141         }
142         argc -= optind;
143         argv += optind;
144
145         if (argc != 2)
146                 usage();
147
148         strlcpy(canon_dev, argv[0], MAXPATHLEN);
149         strlcpy(canon_dir, argv[1], MAXPATHLEN);
150
151         if (stat(canon_dir, &sb) == -1)
152                 err(EXIT_FAILURE, "cannot stat `%s'", canon_dir);
153
154         args->ta_root_uid = uidset ? uid : sb.st_uid;
155         args->ta_root_gid = gidset ? gid : sb.st_gid;
156         args->ta_root_mode = modeset ? mode : sb.st_mode;
157 }
158
159 /* --------------------------------------------------------------------- */
160
161 static gid_t
162 a_gid(char *s)
163 {
164         struct group *gr;
165         char *gname;
166         gid_t gid;
167
168         if ((gr = getgrnam(s)) != NULL)
169                 gid = gr->gr_gid;
170         else {
171                 for (gname = s; *s && isdigit(*s); ++s);
172                 if (!*s)
173                         gid = atoi(gname);
174                 else
175                         errx(EX_NOUSER, "unknown group id: %s", gname);
176         }
177         return (gid);
178 }
179
180 static uid_t
181 a_uid(char *s)
182 {
183         struct passwd *pw;
184         char *uname;
185         uid_t uid;
186
187         if ((pw = getpwnam(s)) != NULL)
188                 uid = pw->pw_uid;
189         else {
190                 for (uname = s; *s && isdigit(*s); ++s);
191                 if (!*s)
192                         uid = atoi(uname);
193                 else
194                         errx(EX_NOUSER, "unknown user id: %s", uname);
195         }
196         return (uid);
197 }
198
199 static mode_t
200 a_mask(char *s)
201 {
202         int done, rv=0;
203         char *ep;
204
205         done = 0;
206         if (*s >= '0' && *s <= '7') {
207                 done = 1;
208                 rv = strtol(optarg, &ep, 8);
209         }
210         if (!done || rv < 0 || *ep)
211                 errx(EX_USAGE, "invalid file mode: %s", s);
212         return (rv);
213 }
214
215 static void
216 usage(void)
217 {
218         (void)fprintf(stderr,
219             "Usage: %s [-g group] [-m mode] [-n nodes] [-o options] [-s size]\n"
220             "           [-u user] tmpfs mountpoint\n", getprogname());
221         exit(1);
222 }
223
224 /* --------------------------------------------------------------------- */
225
226 int
227 mount_tmpfs(int argc, char *argv[])
228 {
229         struct tmpfs_args args;
230         char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN];
231         int mntflags;
232         struct vfsconf vfc;
233         int error;
234
235         mount_tmpfs_parseargs(argc, argv, &args, &mntflags,
236             canon_dev, canon_dir);
237
238
239         error = getvfsbyname("tmpfs", &vfc);
240         if (error && vfsisloadable("tmpfs")) {
241                 if(vfsload("tmpfs"))
242                         err(EX_OSERR, "vfsload(%s)", "tmpfs");
243                 endvfsent();
244                 error = getvfsbyname("tmpfs", &vfc);
245         }
246         if (error)
247                 errx(EX_OSERR, "%s filesystem not available", "tmpfs");
248
249         if (mount(vfc.vfc_name, canon_dir, mntflags, &args) == -1)
250                 err(EXIT_FAILURE, "tmpfs on %s", canon_dir);
251
252         return EXIT_SUCCESS;
253 }
254
255 #ifndef MOUNT_NOMAIN
256 int
257 main(int argc, char *argv[])
258 {
259
260         setprogname(argv[0]);
261         return mount_tmpfs(argc, argv);
262 }
263 #endif