1 2 /* $NetBSD: mount_tmpfs.c,v 1.29 2016/02/21 22:51:30 christos 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.29 2016/02/21 22:51:30 christos 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_UPDATE, 64 MOPT_STDOPTS, 65 MOPT_GETARGS, 66 MOPT_NOATIME, 67 MOPT_RELATIME, 68 MOPT_NULL, 69 }; 70 71 /* --------------------------------------------------------------------- */ 72 73 static void usage(void) __dead; 74 static int64_t ram_fract(const char *arg); 75 static int64_t ram_percent(const char *arg); 76 static int64_t ram_factor(float f); 77 78 /* --------------------------------------------------------------------- */ 79 80 /* return f * available system ram */ 81 static int64_t 82 ram_factor(float f) 83 { 84 uint64_t ram; 85 size_t len; 86 87 len = sizeof(ram); 88 if (sysctlbyname("hw.physmem64", &ram, &len, NULL, 0)) 89 err(EXIT_FAILURE, "can't get \"hw.physmem64\""); 90 91 return (int64_t)((float)ram * f); 92 } 93 94 /* return fraction of available ram given by arg */ 95 static int64_t 96 ram_fract(const char *arg) 97 { 98 char *endp; 99 float f; 100 101 f = strtof(arg, &endp); 102 if (endp && *endp != 0) 103 errx(EXIT_FAILURE, "syntax error in ram fraction: ram/%s" 104 " at %s", arg, endp); 105 if (f <= 0.0f) 106 errx(EXIT_FAILURE, "ram fraction must be a positive number:" 107 " ram/%s", arg); 108 109 return ram_factor(1.0f/f); 110 } 111 112 /* --------------------------------------------------------------------- */ 113 114 /* return percentage of available ram given by arg */ 115 static int64_t 116 ram_percent(const char *arg) 117 { 118 char *endp; 119 float f; 120 121 f = strtof(arg, &endp); 122 if (endp && *endp != 0) 123 errx(EXIT_FAILURE, "syntax error in ram percentage: ram%%%s" 124 " at %s", arg, endp); 125 if (f <= 0.0f || f >= 100.0f) 126 errx(EXIT_FAILURE, "ram percentage must be a between 0 and 100" 127 " ram%%%s", arg); 128 129 return ram_factor(f/100.0f); 130 } 131 132 /* --------------------------------------------------------------------- */ 133 134 void 135 mount_tmpfs_parseargs(int argc, char *argv[], 136 struct tmpfs_args *args, int *mntflags, 137 char *canon_dev, char *canon_dir) 138 { 139 int gidset, modeset, uidset; /* Ought to be 'bool'. */ 140 int ch; 141 gid_t gid; 142 uid_t uid; 143 mode_t mode; 144 int64_t tmpnumber; 145 mntoptparse_t mp; 146 struct stat sb; 147 148 /* Set default values for mount point arguments. */ 149 memset(args, 0, sizeof(*args)); 150 args->ta_version = TMPFS_ARGS_VERSION; 151 args->ta_size_max = 0; 152 args->ta_nodes_max = 0; 153 *mntflags = 0; 154 155 gidset = 0; gid = 0; 156 uidset = 0; uid = 0; 157 modeset = 0; mode = 0; 158 159 optind = optreset = 1; 160 while ((ch = getopt(argc, argv, "g:m:n:o:s:u:")) != -1 ) { 161 switch (ch) { 162 case 'g': 163 gid = a_gid(optarg); 164 gidset = 1; 165 break; 166 167 case 'm': 168 mode = a_mask(optarg); 169 modeset = 1; 170 break; 171 172 case 'n': 173 if (dehumanize_number(optarg, &tmpnumber) == -1) 174 err(EXIT_FAILURE, "failed to parse nodes `%s'", 175 optarg); 176 args->ta_nodes_max = tmpnumber; 177 break; 178 179 case 'o': 180 mp = getmntopts(optarg, mopts, mntflags, 0); 181 if (mp == NULL) 182 err(EXIT_FAILURE, "getmntopts"); 183 freemntopts(mp); 184 break; 185 186 case 's': 187 if (strncmp(optarg, "ram/", 4) == 0) 188 tmpnumber = ram_fract(optarg+4); 189 else if (strncmp(optarg, "ram%", 4) == 0) 190 tmpnumber = ram_percent(optarg+4); 191 else if (dehumanize_number(optarg, &tmpnumber) == -1) 192 err(EXIT_FAILURE, "failed to parse size `%s'", 193 optarg); 194 args->ta_size_max = tmpnumber; 195 break; 196 197 case 'u': 198 uid = a_uid(optarg); 199 uidset = 1; 200 break; 201 202 case '?': 203 default: 204 usage(); 205 } 206 } 207 argc -= optind; 208 argv += optind; 209 210 if (argc != 2) 211 usage(); 212 213 strlcpy(canon_dev, argv[0], MAXPATHLEN); 214 pathadj(argv[1], canon_dir); 215 216 if (stat(canon_dir, &sb) == -1) 217 err(EXIT_FAILURE, "cannot stat `%s'", canon_dir); 218 219 args->ta_root_uid = uidset ? uid : sb.st_uid; 220 args->ta_root_gid = gidset ? gid : sb.st_gid; 221 args->ta_root_mode = modeset ? mode : sb.st_mode; 222 } 223 224 /* --------------------------------------------------------------------- */ 225 226 static void 227 usage(void) 228 { 229 (void)fprintf(stderr, 230 "usage: %s [-g group] [-m mode] [-n nodes] [-o options] [-s size]\n" 231 " [-u user] tmpfs mount_point\n", getprogname()); 232 exit(1); 233 } 234 235 /* --------------------------------------------------------------------- */ 236 237 int 238 mount_tmpfs(int argc, char *argv[]) 239 { 240 struct tmpfs_args args; 241 char canon_dev[MAXPATHLEN], canon_dir[MAXPATHLEN]; 242 int mntflags; 243 244 mount_tmpfs_parseargs(argc, argv, &args, &mntflags, 245 canon_dev, canon_dir); 246 247 if (mount(MOUNT_TMPFS, canon_dir, mntflags, &args, sizeof args) == -1) 248 err(EXIT_FAILURE, "tmpfs on %s", canon_dir); 249 250 if (mntflags & MNT_GETARGS) { 251 struct passwd *pw; 252 struct group *gr; 253 254 (void)printf("version=%d, ", args.ta_version); 255 (void)printf("size_max=%" PRIuMAX ", ", 256 (uintmax_t)args.ta_size_max); 257 (void)printf("nodes_max=%" PRIuMAX ", ", 258 (uintmax_t)args.ta_nodes_max); 259 260 pw = getpwuid(args.ta_root_uid); 261 if (pw == NULL) 262 (void)printf("root_uid=%" PRIuMAX ", ", 263 (uintmax_t)args.ta_root_uid); 264 else 265 (void)printf("root_uid=%s, ", pw->pw_name); 266 267 gr = getgrgid(args.ta_root_gid); 268 if (gr == NULL) 269 (void)printf("root_gid=%" PRIuMAX ", ", 270 (uintmax_t)args.ta_root_gid); 271 else 272 (void)printf("root_gid=%s, ", gr->gr_name); 273 274 (void)printf("root_mode=%o\n", args.ta_root_mode); 275 } 276 277 return EXIT_SUCCESS; 278 } 279 280 #ifndef MOUNT_NOMAIN 281 int 282 main(int argc, char *argv[]) 283 { 284 285 setprogname(argv[0]); 286 return mount_tmpfs(argc, argv); 287 } 288 #endif 289