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