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