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