1 2 /* $NetBSD: mount_tmpfs.c,v 1.27 2013/12/04 15:10:11 martin Exp $ */ 3 4 /* 5 * Copyright (c) 2005, 2006 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Julio M. Merino Vidal, developed as part of Google's Summer of Code 10 * 2005 program. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 22 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 #ifndef lint 36 __RCSID("$NetBSD: mount_tmpfs.c,v 1.27 2013/12/04 15:10:11 martin Exp $"); 37 #endif /* not lint */ 38 39 #include <sys/param.h> 40 #include <sys/mount.h> 41 #include <sys/stat.h> 42 #include <sys/sysctl.h> 43 44 #include <fs/tmpfs/tmpfs_args.h> 45 46 #include <ctype.h> 47 #include <err.h> 48 #include <errno.h> 49 #include <grp.h> 50 #include <mntopts.h> 51 #include <pwd.h> 52 #include <stdio.h> 53 #include <stdlib.h> 54 #include <string.h> 55 #include <unistd.h> 56 57 #include "mountprog.h" 58 #include "mount_tmpfs.h" 59 60 /* --------------------------------------------------------------------- */ 61 62 static const struct mntopt mopts[] = { 63 MOPT_STDOPTS, 64 MOPT_GETARGS, 65 MOPT_NULL, 66 }; 67 68 /* --------------------------------------------------------------------- */ 69 70 static void usage(void) __dead; 71 static int64_t ram_fract(const char *arg); 72 static int64_t ram_percent(const char *arg); 73 static int64_t ram_factor(float f); 74 75 /* --------------------------------------------------------------------- */ 76 77 /* return f * available system ram */ 78 static int64_t 79 ram_factor(float f) 80 { 81 uint64_t ram; 82 size_t len; 83 84 len = sizeof(ram); 85 if (sysctlbyname("hw.physmem64", &ram, &len, NULL, 0)) 86 err(EXIT_FAILURE, "can't get \"hw.physmem64\""); 87 88 return (int64_t)((float)ram * f); 89 } 90 91 /* return fraction of available ram given by arg */ 92 static int64_t 93 ram_fract(const char *arg) 94 { 95 char *endp; 96 float f; 97 98 f = strtof(arg, &endp); 99 if (endp && *endp != 0) 100 errx(EXIT_FAILURE, "syntax error in ram fraction: ram/%s" 101 " at %s", arg, endp); 102 if (f <= 0.0f) 103 errx(EXIT_FAILURE, "ram fraction must be a positive number:" 104 " ram/%s", arg); 105 106 return ram_factor(1.0f/f); 107 } 108 109 /* --------------------------------------------------------------------- */ 110 111 /* return percentage of available ram given by arg */ 112 static int64_t 113 ram_percent(const char *arg) 114 { 115 char *endp; 116 float f; 117 118 f = strtof(arg, &endp); 119 if (endp && *endp != 0) 120 errx(EXIT_FAILURE, "syntax error in ram percentage: ram%%%s" 121 " at %s", arg, endp); 122 if (f <= 0.0f || f >= 100.0f) 123 errx(EXIT_FAILURE, "ram percentage must be a between 0 and 100" 124 " ram%%%s", arg); 125 126 return ram_factor(f/100.0f); 127 } 128 129 /* --------------------------------------------------------------------- */ 130 131 void 132 mount_tmpfs_parseargs(int argc, char *argv[], 133 struct tmpfs_args *args, int *mntflags, 134 char *canon_dev, char *canon_dir) 135 { 136 int gidset, modeset, uidset; /* Ought to be 'bool'. */ 137 int ch; 138 gid_t gid; 139 uid_t uid; 140 mode_t mode; 141 int64_t tmpnumber; 142 mntoptparse_t mp; 143 struct stat sb; 144 145 /* Set default values for mount point arguments. */ 146 memset(args, 0, sizeof(*args)); 147 args->ta_version = TMPFS_ARGS_VERSION; 148 args->ta_size_max = 0; 149 args->ta_nodes_max = 0; 150 *mntflags = 0; 151 152 gidset = 0; gid = 0; 153 uidset = 0; uid = 0; 154 modeset = 0; mode = 0; 155 156 optind = optreset = 1; 157 while ((ch = getopt(argc, argv, "g:m:n:o:s:u:")) != -1 ) { 158 switch (ch) { 159 case 'g': 160 gid = a_gid(optarg); 161 gidset = 1; 162 break; 163 164 case 'm': 165 mode = a_mask(optarg); 166 modeset = 1; 167 break; 168 169 case 'n': 170 if (dehumanize_number(optarg, &tmpnumber) == -1) 171 err(EXIT_FAILURE, "failed to parse nodes `%s'", 172 optarg); 173 args->ta_nodes_max = tmpnumber; 174 break; 175 176 case 'o': 177 mp = getmntopts(optarg, mopts, mntflags, 0); 178 if (mp == NULL) 179 err(EXIT_FAILURE, "getmntopts"); 180 freemntopts(mp); 181 break; 182 183 case 's': 184 if (strncmp(optarg, "ram/", 4) == 0) 185 tmpnumber = ram_fract(optarg+4); 186 else if (strncmp(optarg, "ram%", 4) == 0) 187 tmpnumber = ram_percent(optarg+4); 188 else if (dehumanize_number(optarg, &tmpnumber) == -1) 189 err(EXIT_FAILURE, "failed to parse size `%s'", 190 optarg); 191 args->ta_size_max = tmpnumber; 192 break; 193 194 case 'u': 195 uid = a_uid(optarg); 196 uidset = 1; 197 break; 198 199 case '?': 200 default: 201 usage(); 202 } 203 } 204 argc -= optind; 205 argv += optind; 206 207 if (argc != 2) 208 usage(); 209 210 strlcpy(canon_dev, argv[0], MAXPATHLEN); 211 pathadj(argv[1], canon_dir); 212 213 if (stat(canon_dir, &sb) == -1) 214 err(EXIT_FAILURE, "cannot stat `%s'", canon_dir); 215 216 args->ta_root_uid = uidset ? uid : sb.st_uid; 217 args->ta_root_gid = gidset ? gid : sb.st_gid; 218 args->ta_root_mode = modeset ? mode : sb.st_mode; 219 } 220 221 /* --------------------------------------------------------------------- */ 222 223 static void 224 usage(void) 225 { 226 (void)fprintf(stderr, 227 "usage: %s [-g group] [-m mode] [-n nodes] [-o options] [-s size]\n" 228 " [-u user] tmpfs mount_point\n", getprogname()); 229 exit(1); 230 } 231 232 /* --------------------------------------------------------------------- */ 233 234 int 235 mount_tmpfs(int argc, char *argv[]) 236 { 237 struct tmpfs_args args; 238 char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN]; 239 int mntflags; 240 241 mount_tmpfs_parseargs(argc, argv, &args, &mntflags, 242 canon_dev, canon_dir); 243 244 if (mount(MOUNT_TMPFS, canon_dir, mntflags, &args, sizeof args) == -1) 245 err(EXIT_FAILURE, "tmpfs on %s", canon_dir); 246 247 if (mntflags & MNT_GETARGS) { 248 struct passwd *pw; 249 struct group *gr; 250 251 (void)printf("version=%d, ", args.ta_version); 252 (void)printf("size_max=%" PRIuMAX ", ", 253 (uintmax_t)args.ta_size_max); 254 (void)printf("nodes_max=%" PRIuMAX ", ", 255 (uintmax_t)args.ta_nodes_max); 256 257 pw = getpwuid(args.ta_root_uid); 258 if (pw == NULL) 259 (void)printf("root_uid=%" PRIuMAX ", ", 260 (uintmax_t)args.ta_root_uid); 261 else 262 (void)printf("root_uid=%s, ", pw->pw_name); 263 264 gr = getgrgid(args.ta_root_gid); 265 if (gr == NULL) 266 (void)printf("root_gid=%" PRIuMAX ", ", 267 (uintmax_t)args.ta_root_gid); 268 else 269 (void)printf("root_gid=%s, ", gr->gr_name); 270 271 (void)printf("root_mode=%o\n", args.ta_root_mode); 272 } 273 274 return EXIT_SUCCESS; 275 } 276 277 #ifndef MOUNT_NOMAIN 278 int 279 main(int argc, char *argv[]) 280 { 281 282 setprogname(argv[0]); 283 return mount_tmpfs(argc, argv); 284 } 285 #endif 286