1/* 2 * Copyright (c) 2001 Dima Dorfman. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* 28 * mdmfs (md/MFS) is a wrapper around mdconfig(8), 29 * newfs(8), and mount(8) that mimics the command line option set of 30 * the deprecated mount_mfs(8). 31 */ 32 33#include <sys/cdefs.h>
| 1/* 2 * Copyright (c) 2001 Dima Dorfman. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27/* 28 * mdmfs (md/MFS) is a wrapper around mdconfig(8), 29 * newfs(8), and mount(8) that mimics the command line option set of 30 * the deprecated mount_mfs(8). 31 */ 32 33#include <sys/cdefs.h>
|
34__FBSDID("$FreeBSD: head/sbin/mdmfs/mdmfs.c 163952 2006-11-03 12:02:24Z ru $");
| 34__FBSDID("$FreeBSD: head/sbin/mdmfs/mdmfs.c 166749 2007-02-15 13:49:44Z matteo $");
|
35 36#include <sys/param.h> 37#include <sys/mdioctl.h> 38#include <sys/stat.h> 39#include <sys/wait.h> 40 41#include <assert.h> 42#include <err.h> 43#include <fcntl.h> 44#include <grp.h> 45#include <paths.h> 46#include <pwd.h> 47#include <stdarg.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <string.h>
| 35 36#include <sys/param.h> 37#include <sys/mdioctl.h> 38#include <sys/stat.h> 39#include <sys/wait.h> 40 41#include <assert.h> 42#include <err.h> 43#include <fcntl.h> 44#include <grp.h> 45#include <paths.h> 46#include <pwd.h> 47#include <stdarg.h> 48#include <stdio.h> 49#include <stdlib.h> 50#include <string.h>
|
| 51#include <ctype.h>
|
51#include <unistd.h> 52 53typedef enum { false, true } bool; 54 55struct mtpt_info { 56 uid_t mi_uid; 57 bool mi_have_uid; 58 gid_t mi_gid; 59 bool mi_have_gid; 60 mode_t mi_mode; 61 bool mi_have_mode; 62}; 63 64static bool debug; /* Emit debugging information? */ 65static bool loudsubs; /* Suppress output from helper programs? */ 66static bool norun; /* Actually run the helper programs? */ 67static int unit; /* The unit we're working with. */ 68static const char *mdname; /* Name of memory disk device (e.g., "md"). */
| 52#include <unistd.h> 53 54typedef enum { false, true } bool; 55 56struct mtpt_info { 57 uid_t mi_uid; 58 bool mi_have_uid; 59 gid_t mi_gid; 60 bool mi_have_gid; 61 mode_t mi_mode; 62 bool mi_have_mode; 63}; 64 65static bool debug; /* Emit debugging information? */ 66static bool loudsubs; /* Suppress output from helper programs? */ 67static bool norun; /* Actually run the helper programs? */ 68static int unit; /* The unit we're working with. */ 69static const char *mdname; /* Name of memory disk device (e.g., "md"). */
|
| 70static const char *mdsuffix; /* Suffix of memory disk device (e.g., ".uzip"). */
|
69static size_t mdnamelen; /* Length of mdname. */ 70static const char *path_mdconfig =_PATH_MDCONFIG; 71 72static void argappend(char **, const char *, ...) __printflike(2, 3); 73static void debugprintf(const char *, ...) __printflike(1, 2); 74static void do_mdconfig_attach(const char *, const enum md_types); 75static void do_mdconfig_attach_au(const char *, const enum md_types); 76static void do_mdconfig_detach(void); 77static void do_mount(const char *, const char *); 78static void do_mtptsetup(const char *, struct mtpt_info *); 79static void do_newfs(const char *); 80static void extract_ugid(const char *, struct mtpt_info *); 81static int run(int *, const char *, ...) __printflike(2, 3); 82static void usage(void); 83 84int 85main(int argc, char **argv) 86{ 87 struct mtpt_info mi; /* Mountpoint info. */ 88 char *mdconfig_arg, *newfs_arg, /* Args to helper programs. */ 89 *mount_arg; 90 enum md_types mdtype; /* The type of our memory disk. */ 91 bool have_mdtype; 92 bool detach, softdep, autounit, newfs; 93 char *mtpoint, *unitstr; 94 char *p; 95 int ch; 96 void *set; 97 unsigned long ul; 98 99 /* Misc. initialization. */ 100 (void)memset(&mi, '\0', sizeof(mi)); 101 detach = true; 102 softdep = true; 103 autounit = false; 104 newfs = true; 105 have_mdtype = false; 106 mdtype = MD_SWAP; 107 mdname = MD_NAME; 108 mdnamelen = strlen(mdname); 109 /* 110 * Can't set these to NULL. They may be passed to the 111 * respective programs without modification. I.e., we may not 112 * receive any command-line options which will caused them to 113 * be modified. 114 */ 115 mdconfig_arg = strdup(""); 116 newfs_arg = strdup(""); 117 mount_arg = strdup(""); 118 119 /* If we were started as mount_mfs or mfs, imply -C. */ 120 if (strcmp(getprogname(), "mount_mfs") == 0 || 121 strcmp(getprogname(), "mfs") == 0) { 122 /* Make compatibility assumptions. */ 123 mi.mi_mode = 01777; 124 mi.mi_have_mode = true; 125 } 126 127 while ((ch = getopt(argc, argv, 128 "a:b:Cc:Dd:E:e:F:f:hi:LlMm:Nn:O:o:Pp:Ss:t:Uv:w:X")) != -1) 129 switch (ch) { 130 case 'a': 131 argappend(&newfs_arg, "-a %s", optarg); 132 break; 133 case 'b': 134 argappend(&newfs_arg, "-b %s", optarg); 135 break; 136 case 'C': 137 /* Ignored for compatibility. */ 138 break; 139 case 'c': 140 argappend(&newfs_arg, "-c %s", optarg); 141 break; 142 case 'D': 143 detach = false; 144 break; 145 case 'd': 146 argappend(&newfs_arg, "-d %s", optarg); 147 break; 148 case 'E': 149 path_mdconfig = optarg; 150 break; 151 case 'e': 152 argappend(&newfs_arg, "-e %s", optarg); 153 break; 154 case 'F': 155 if (have_mdtype) 156 usage(); 157 mdtype = MD_VNODE; 158 have_mdtype = true; 159 argappend(&mdconfig_arg, "-f %s", optarg); 160 break; 161 case 'f': 162 argappend(&newfs_arg, "-f %s", optarg); 163 break; 164 case 'h': 165 usage(); 166 break; 167 case 'i': 168 argappend(&newfs_arg, "-i %s", optarg); 169 break; 170 case 'L': 171 loudsubs = true; 172 break; 173 case 'l': 174 argappend(&newfs_arg, "-l"); 175 break; 176 case 'M': 177 if (have_mdtype) 178 usage(); 179 mdtype = MD_MALLOC; 180 have_mdtype = true; 181 break; 182 case 'm': 183 argappend(&newfs_arg, "-m %s", optarg); 184 break; 185 case 'N': 186 norun = true; 187 break; 188 case 'n': 189 argappend(&newfs_arg, "-n %s", optarg); 190 break; 191 case 'O': 192 argappend(&newfs_arg, "-o %s", optarg); 193 break; 194 case 'o': 195 argappend(&mount_arg, "-o %s", optarg); 196 break; 197 case 'P': 198 newfs = false; 199 break; 200 case 'p': 201 if ((set = setmode(optarg)) == NULL) 202 usage(); 203 mi.mi_mode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO); 204 mi.mi_have_mode = true; 205 free(set); 206 break; 207 case 'S': 208 softdep = false; 209 break; 210 case 's': 211 argappend(&mdconfig_arg, "-s %s", optarg); 212 break; 213 case 'U': 214 softdep = true; 215 break; 216 case 'v': 217 argappend(&newfs_arg, "-O %s", optarg); 218 break; 219 case 'w': 220 extract_ugid(optarg, &mi); 221 break; 222 case 'X': 223 debug = true; 224 break; 225 default: 226 usage(); 227 } 228 argc -= optind; 229 argv += optind; 230 if (argc < 2) 231 usage(); 232 233 /* Derive 'unit' (global). */ 234 unitstr = argv[0]; 235 if (strncmp(unitstr, "/dev/", 5) == 0) 236 unitstr += 5; 237 if (strncmp(unitstr, mdname, mdnamelen) == 0) 238 unitstr += mdnamelen;
| 71static size_t mdnamelen; /* Length of mdname. */ 72static const char *path_mdconfig =_PATH_MDCONFIG; 73 74static void argappend(char **, const char *, ...) __printflike(2, 3); 75static void debugprintf(const char *, ...) __printflike(1, 2); 76static void do_mdconfig_attach(const char *, const enum md_types); 77static void do_mdconfig_attach_au(const char *, const enum md_types); 78static void do_mdconfig_detach(void); 79static void do_mount(const char *, const char *); 80static void do_mtptsetup(const char *, struct mtpt_info *); 81static void do_newfs(const char *); 82static void extract_ugid(const char *, struct mtpt_info *); 83static int run(int *, const char *, ...) __printflike(2, 3); 84static void usage(void); 85 86int 87main(int argc, char **argv) 88{ 89 struct mtpt_info mi; /* Mountpoint info. */ 90 char *mdconfig_arg, *newfs_arg, /* Args to helper programs. */ 91 *mount_arg; 92 enum md_types mdtype; /* The type of our memory disk. */ 93 bool have_mdtype; 94 bool detach, softdep, autounit, newfs; 95 char *mtpoint, *unitstr; 96 char *p; 97 int ch; 98 void *set; 99 unsigned long ul; 100 101 /* Misc. initialization. */ 102 (void)memset(&mi, '\0', sizeof(mi)); 103 detach = true; 104 softdep = true; 105 autounit = false; 106 newfs = true; 107 have_mdtype = false; 108 mdtype = MD_SWAP; 109 mdname = MD_NAME; 110 mdnamelen = strlen(mdname); 111 /* 112 * Can't set these to NULL. They may be passed to the 113 * respective programs without modification. I.e., we may not 114 * receive any command-line options which will caused them to 115 * be modified. 116 */ 117 mdconfig_arg = strdup(""); 118 newfs_arg = strdup(""); 119 mount_arg = strdup(""); 120 121 /* If we were started as mount_mfs or mfs, imply -C. */ 122 if (strcmp(getprogname(), "mount_mfs") == 0 || 123 strcmp(getprogname(), "mfs") == 0) { 124 /* Make compatibility assumptions. */ 125 mi.mi_mode = 01777; 126 mi.mi_have_mode = true; 127 } 128 129 while ((ch = getopt(argc, argv, 130 "a:b:Cc:Dd:E:e:F:f:hi:LlMm:Nn:O:o:Pp:Ss:t:Uv:w:X")) != -1) 131 switch (ch) { 132 case 'a': 133 argappend(&newfs_arg, "-a %s", optarg); 134 break; 135 case 'b': 136 argappend(&newfs_arg, "-b %s", optarg); 137 break; 138 case 'C': 139 /* Ignored for compatibility. */ 140 break; 141 case 'c': 142 argappend(&newfs_arg, "-c %s", optarg); 143 break; 144 case 'D': 145 detach = false; 146 break; 147 case 'd': 148 argappend(&newfs_arg, "-d %s", optarg); 149 break; 150 case 'E': 151 path_mdconfig = optarg; 152 break; 153 case 'e': 154 argappend(&newfs_arg, "-e %s", optarg); 155 break; 156 case 'F': 157 if (have_mdtype) 158 usage(); 159 mdtype = MD_VNODE; 160 have_mdtype = true; 161 argappend(&mdconfig_arg, "-f %s", optarg); 162 break; 163 case 'f': 164 argappend(&newfs_arg, "-f %s", optarg); 165 break; 166 case 'h': 167 usage(); 168 break; 169 case 'i': 170 argappend(&newfs_arg, "-i %s", optarg); 171 break; 172 case 'L': 173 loudsubs = true; 174 break; 175 case 'l': 176 argappend(&newfs_arg, "-l"); 177 break; 178 case 'M': 179 if (have_mdtype) 180 usage(); 181 mdtype = MD_MALLOC; 182 have_mdtype = true; 183 break; 184 case 'm': 185 argappend(&newfs_arg, "-m %s", optarg); 186 break; 187 case 'N': 188 norun = true; 189 break; 190 case 'n': 191 argappend(&newfs_arg, "-n %s", optarg); 192 break; 193 case 'O': 194 argappend(&newfs_arg, "-o %s", optarg); 195 break; 196 case 'o': 197 argappend(&mount_arg, "-o %s", optarg); 198 break; 199 case 'P': 200 newfs = false; 201 break; 202 case 'p': 203 if ((set = setmode(optarg)) == NULL) 204 usage(); 205 mi.mi_mode = getmode(set, S_IRWXU | S_IRWXG | S_IRWXO); 206 mi.mi_have_mode = true; 207 free(set); 208 break; 209 case 'S': 210 softdep = false; 211 break; 212 case 's': 213 argappend(&mdconfig_arg, "-s %s", optarg); 214 break; 215 case 'U': 216 softdep = true; 217 break; 218 case 'v': 219 argappend(&newfs_arg, "-O %s", optarg); 220 break; 221 case 'w': 222 extract_ugid(optarg, &mi); 223 break; 224 case 'X': 225 debug = true; 226 break; 227 default: 228 usage(); 229 } 230 argc -= optind; 231 argv += optind; 232 if (argc < 2) 233 usage(); 234 235 /* Derive 'unit' (global). */ 236 unitstr = argv[0]; 237 if (strncmp(unitstr, "/dev/", 5) == 0) 238 unitstr += 5; 239 if (strncmp(unitstr, mdname, mdnamelen) == 0) 240 unitstr += mdnamelen;
|
239 if (*unitstr == '\0') {
| 241 if (!isdigit(*unitstr)) {
|
240 autounit = true; 241 unit = -1;
| 242 autounit = true; 243 unit = -1;
|
| 244 mdsuffix = unitstr;
|
242 } else { 243 ul = strtoul(unitstr, &p, 10);
| 245 } else { 246 ul = strtoul(unitstr, &p, 10);
|
244 if (ul == ULONG_MAX || *p != '\0')
| 247 if (ul == ULONG_MAX)
|
245 errx(1, "bad device unit: %s", unitstr);
| 248 errx(1, "bad device unit: %s", unitstr);
|
| 249 if (*p != '\0') 250 mdsuffix = p;
|
246 unit = ul; 247 } 248 249 mtpoint = argv[1]; 250 if (!have_mdtype) 251 mdtype = MD_SWAP; 252 if (softdep) 253 argappend(&newfs_arg, "-U"); 254 if (mdtype != MD_VNODE && !newfs) 255 errx(1, "-P requires a vnode-backed disk"); 256 257 /* Do the work. */ 258 if (detach && !autounit) 259 do_mdconfig_detach(); 260 if (autounit) 261 do_mdconfig_attach_au(mdconfig_arg, mdtype); 262 else 263 do_mdconfig_attach(mdconfig_arg, mdtype); 264 if (newfs) 265 do_newfs(newfs_arg); 266 do_mount(mount_arg, mtpoint); 267 do_mtptsetup(mtpoint, &mi); 268 269 return (0); 270} 271 272/* 273 * Append the expansion of 'fmt' to the buffer pointed to by '*dstp'; 274 * reallocate as required. 275 */ 276static void 277argappend(char **dstp, const char *fmt, ...) 278{ 279 char *old, *new; 280 va_list ap; 281 282 old = *dstp; 283 assert(old != NULL); 284 285 va_start(ap, fmt); 286 if (vasprintf(&new, fmt,ap) == -1) 287 errx(1, "vasprintf"); 288 va_end(ap); 289 290 *dstp = new; 291 if (asprintf(&new, "%s %s", old, new) == -1) 292 errx(1, "asprintf"); 293 free(*dstp); 294 free(old); 295 296 *dstp = new; 297} 298 299/* 300 * If run-time debugging is enabled, print the expansion of 'fmt'. 301 * Otherwise, do nothing. 302 */ 303static void 304debugprintf(const char *fmt, ...) 305{ 306 va_list ap; 307 308 if (!debug) 309 return; 310 fprintf(stderr, "DEBUG: "); 311 va_start(ap, fmt); 312 vfprintf(stderr, fmt, ap); 313 va_end(ap); 314 fprintf(stderr, "\n"); 315 fflush(stderr); 316} 317 318/* 319 * Attach a memory disk with a known unit. 320 */ 321static void 322do_mdconfig_attach(const char *args, const enum md_types mdtype) 323{ 324 int rv; 325 const char *ta; /* Type arg. */ 326 327 switch (mdtype) { 328 case MD_SWAP: 329 ta = "-t swap"; 330 break; 331 case MD_VNODE: 332 ta = "-t vnode"; 333 break; 334 case MD_MALLOC: 335 ta = "-t malloc"; 336 break; 337 default: 338 abort(); 339 } 340 rv = run(NULL, "%s -a %s%s -u %s%d", path_mdconfig, ta, args, 341 mdname, unit); 342 if (rv) 343 errx(1, "mdconfig (attach) exited with error code %d", rv); 344} 345 346/* 347 * Attach a memory disk with an unknown unit; use autounit. 348 */ 349static void 350do_mdconfig_attach_au(const char *args, const enum md_types mdtype) 351{ 352 const char *ta; /* Type arg. */ 353 char *linep, *linebuf; /* Line pointer, line buffer. */ 354 int fd; /* Standard output of mdconfig invocation. */ 355 FILE *sfd; 356 int rv; 357 char *p; 358 size_t linelen; 359 unsigned long ul; 360 361 switch (mdtype) { 362 case MD_SWAP: 363 ta = "-t swap"; 364 break; 365 case MD_VNODE: 366 ta = "-t vnode"; 367 break; 368 case MD_MALLOC: 369 ta = "-t malloc"; 370 break; 371 default: 372 abort(); 373 } 374 rv = run(&fd, "%s -a %s%s", path_mdconfig, ta, args); 375 if (rv) 376 errx(1, "mdconfig (attach) exited with error code %d", rv); 377 378 /* Receive the unit number. */ 379 if (norun) { /* Since we didn't run, we can't read. Fake it. */ 380 unit = 0; 381 return; 382 } 383 sfd = fdopen(fd, "r"); 384 if (sfd == NULL) 385 err(1, "fdopen"); 386 linep = fgetln(sfd, &linelen); 387 if (linep == NULL && linelen < mdnamelen + 1) 388 errx(1, "unexpected output from mdconfig (attach)"); 389 /* If the output format changes, we want to know about it. */ 390 assert(strncmp(linep, mdname, mdnamelen) == 0); 391 linebuf = malloc(linelen - mdnamelen + 1); 392 assert(linebuf != NULL); 393 /* Can't use strlcpy because linep is not NULL-terminated. */ 394 strncpy(linebuf, linep + mdnamelen, linelen); 395 linebuf[linelen] = '\0'; 396 ul = strtoul(linebuf, &p, 10); 397 if (ul == ULONG_MAX || *p != '\n') 398 errx(1, "unexpected output from mdconfig (attach)"); 399 unit = ul; 400 401 fclose(sfd); 402 close(fd); 403} 404 405/* 406 * Detach a memory disk. 407 */ 408static void 409do_mdconfig_detach(void) 410{ 411 int rv; 412 413 rv = run(NULL, "%s -d -u %s%d", path_mdconfig, mdname, unit); 414 if (rv && debug) /* This is allowed to fail. */ 415 warnx("mdconfig (detach) exited with error code %d (ignored)", 416 rv); 417} 418 419/* 420 * Mount the configured memory disk. 421 */ 422static void 423do_mount(const char *args, const char *mtpoint) 424{ 425 int rv; 426
| 251 unit = ul; 252 } 253 254 mtpoint = argv[1]; 255 if (!have_mdtype) 256 mdtype = MD_SWAP; 257 if (softdep) 258 argappend(&newfs_arg, "-U"); 259 if (mdtype != MD_VNODE && !newfs) 260 errx(1, "-P requires a vnode-backed disk"); 261 262 /* Do the work. */ 263 if (detach && !autounit) 264 do_mdconfig_detach(); 265 if (autounit) 266 do_mdconfig_attach_au(mdconfig_arg, mdtype); 267 else 268 do_mdconfig_attach(mdconfig_arg, mdtype); 269 if (newfs) 270 do_newfs(newfs_arg); 271 do_mount(mount_arg, mtpoint); 272 do_mtptsetup(mtpoint, &mi); 273 274 return (0); 275} 276 277/* 278 * Append the expansion of 'fmt' to the buffer pointed to by '*dstp'; 279 * reallocate as required. 280 */ 281static void 282argappend(char **dstp, const char *fmt, ...) 283{ 284 char *old, *new; 285 va_list ap; 286 287 old = *dstp; 288 assert(old != NULL); 289 290 va_start(ap, fmt); 291 if (vasprintf(&new, fmt,ap) == -1) 292 errx(1, "vasprintf"); 293 va_end(ap); 294 295 *dstp = new; 296 if (asprintf(&new, "%s %s", old, new) == -1) 297 errx(1, "asprintf"); 298 free(*dstp); 299 free(old); 300 301 *dstp = new; 302} 303 304/* 305 * If run-time debugging is enabled, print the expansion of 'fmt'. 306 * Otherwise, do nothing. 307 */ 308static void 309debugprintf(const char *fmt, ...) 310{ 311 va_list ap; 312 313 if (!debug) 314 return; 315 fprintf(stderr, "DEBUG: "); 316 va_start(ap, fmt); 317 vfprintf(stderr, fmt, ap); 318 va_end(ap); 319 fprintf(stderr, "\n"); 320 fflush(stderr); 321} 322 323/* 324 * Attach a memory disk with a known unit. 325 */ 326static void 327do_mdconfig_attach(const char *args, const enum md_types mdtype) 328{ 329 int rv; 330 const char *ta; /* Type arg. */ 331 332 switch (mdtype) { 333 case MD_SWAP: 334 ta = "-t swap"; 335 break; 336 case MD_VNODE: 337 ta = "-t vnode"; 338 break; 339 case MD_MALLOC: 340 ta = "-t malloc"; 341 break; 342 default: 343 abort(); 344 } 345 rv = run(NULL, "%s -a %s%s -u %s%d", path_mdconfig, ta, args, 346 mdname, unit); 347 if (rv) 348 errx(1, "mdconfig (attach) exited with error code %d", rv); 349} 350 351/* 352 * Attach a memory disk with an unknown unit; use autounit. 353 */ 354static void 355do_mdconfig_attach_au(const char *args, const enum md_types mdtype) 356{ 357 const char *ta; /* Type arg. */ 358 char *linep, *linebuf; /* Line pointer, line buffer. */ 359 int fd; /* Standard output of mdconfig invocation. */ 360 FILE *sfd; 361 int rv; 362 char *p; 363 size_t linelen; 364 unsigned long ul; 365 366 switch (mdtype) { 367 case MD_SWAP: 368 ta = "-t swap"; 369 break; 370 case MD_VNODE: 371 ta = "-t vnode"; 372 break; 373 case MD_MALLOC: 374 ta = "-t malloc"; 375 break; 376 default: 377 abort(); 378 } 379 rv = run(&fd, "%s -a %s%s", path_mdconfig, ta, args); 380 if (rv) 381 errx(1, "mdconfig (attach) exited with error code %d", rv); 382 383 /* Receive the unit number. */ 384 if (norun) { /* Since we didn't run, we can't read. Fake it. */ 385 unit = 0; 386 return; 387 } 388 sfd = fdopen(fd, "r"); 389 if (sfd == NULL) 390 err(1, "fdopen"); 391 linep = fgetln(sfd, &linelen); 392 if (linep == NULL && linelen < mdnamelen + 1) 393 errx(1, "unexpected output from mdconfig (attach)"); 394 /* If the output format changes, we want to know about it. */ 395 assert(strncmp(linep, mdname, mdnamelen) == 0); 396 linebuf = malloc(linelen - mdnamelen + 1); 397 assert(linebuf != NULL); 398 /* Can't use strlcpy because linep is not NULL-terminated. */ 399 strncpy(linebuf, linep + mdnamelen, linelen); 400 linebuf[linelen] = '\0'; 401 ul = strtoul(linebuf, &p, 10); 402 if (ul == ULONG_MAX || *p != '\n') 403 errx(1, "unexpected output from mdconfig (attach)"); 404 unit = ul; 405 406 fclose(sfd); 407 close(fd); 408} 409 410/* 411 * Detach a memory disk. 412 */ 413static void 414do_mdconfig_detach(void) 415{ 416 int rv; 417 418 rv = run(NULL, "%s -d -u %s%d", path_mdconfig, mdname, unit); 419 if (rv && debug) /* This is allowed to fail. */ 420 warnx("mdconfig (detach) exited with error code %d (ignored)", 421 rv); 422} 423 424/* 425 * Mount the configured memory disk. 426 */ 427static void 428do_mount(const char *args, const char *mtpoint) 429{ 430 int rv; 431
|
427 rv = run(NULL, "%s%s /dev/%s%d %s", _PATH_MOUNT, args, 428 mdname, unit, mtpoint);
| 432 rv = run(NULL, "%s%s /dev/%s%d%s %s", _PATH_MOUNT, args, 433 mdname, unit, mdsuffix, mtpoint);
|
429 if (rv) 430 errx(1, "mount exited with error code %d", rv); 431} 432 433/* 434 * Various configuration of the mountpoint. Mostly, enact 'mip'. 435 */ 436static void 437do_mtptsetup(const char *mtpoint, struct mtpt_info *mip) 438{ 439 440 if (mip->mi_have_mode) { 441 debugprintf("changing mode of %s to %o.", mtpoint, 442 mip->mi_mode); 443 if (!norun) 444 if (chmod(mtpoint, mip->mi_mode) == -1) 445 err(1, "chmod: %s", mtpoint); 446 } 447 /* 448 * We have to do these separately because the user may have 449 * only specified one of them. 450 */ 451 if (mip->mi_have_uid) { 452 debugprintf("changing owner (user) or %s to %u.", mtpoint, 453 mip->mi_uid); 454 if (!norun) 455 if (chown(mtpoint, mip->mi_uid, -1) == -1) 456 err(1, "chown %s to %u (user)", mtpoint, 457 mip->mi_uid); 458 } 459 if (mip->mi_have_gid) { 460 debugprintf("changing owner (group) or %s to %u.", mtpoint, 461 mip->mi_gid); 462 if (!norun) 463 if (chown(mtpoint, -1, mip->mi_gid) == -1) 464 err(1, "chown %s to %u (group)", mtpoint, 465 mip->mi_gid); 466 } 467} 468 469/* 470 * Put a file system on the memory disk. 471 */ 472static void 473do_newfs(const char *args) 474{ 475 int rv; 476 477 rv = run(NULL, "%s%s /dev/%s%d", _PATH_NEWFS, args, mdname, unit); 478 if (rv) 479 errx(1, "newfs exited with error code %d", rv); 480} 481 482/* 483 * 'str' should be a user and group name similar to the last argument 484 * to chown(1); i.e., a user, followed by a colon, followed by a 485 * group. The user and group in 'str' may be either a [ug]id or a 486 * name. Upon return, the uid and gid fields in 'mip' will contain 487 * the uid and gid of the user and group name in 'str', respectively. 488 * 489 * In other words, this derives a user and group id from a string 490 * formatted like the last argument to chown(1). 491 * 492 * Notice: At this point we don't support only a username or only a 493 * group name. do_mtptsetup already does, so when this feature is 494 * desired, this is the only routine that needs to be changed. 495 */ 496static void 497extract_ugid(const char *str, struct mtpt_info *mip) 498{ 499 char *ug; /* Writable 'str'. */ 500 char *user, *group; /* Result of extracton. */ 501 struct passwd *pw; 502 struct group *gr; 503 char *p; 504 uid_t *uid; 505 gid_t *gid; 506 507 uid = &mip->mi_uid; 508 gid = &mip->mi_gid; 509 mip->mi_have_uid = mip->mi_have_gid = false; 510 511 /* Extract the user and group from 'str'. Format above. */ 512 ug = strdup(str); 513 assert(ug != NULL); 514 group = ug; 515 user = strsep(&group, ":"); 516 if (user == NULL || group == NULL || *user == '\0' || *group == '\0') 517 usage(); 518 519 /* Derive uid. */ 520 *uid = strtoul(user, &p, 10); 521 if (*uid == (uid_t)ULONG_MAX) 522 usage(); 523 if (*p != '\0') { 524 pw = getpwnam(user); 525 if (pw == NULL) 526 errx(1, "invalid user: %s", user); 527 *uid = pw->pw_uid; 528 } 529 mip->mi_have_uid = true; 530 531 /* Derive gid. */ 532 *gid = strtoul(group, &p, 10); 533 if (*gid == (gid_t)ULONG_MAX) 534 usage(); 535 if (*p != '\0') { 536 gr = getgrnam(group); 537 if (gr == NULL) 538 errx(1, "invalid group: %s", group); 539 *gid = gr->gr_gid; 540 } 541 mip->mi_have_gid = true; 542 543 free(ug); 544} 545 546/* 547 * Run a process with command name and arguments pointed to by the 548 * formatted string 'cmdline'. Since system(3) is not used, the first 549 * space-delimited token of 'cmdline' must be the full pathname of the 550 * program to run. The return value is the return code of the process 551 * spawned. If 'ofd' is non-NULL, it is set to the standard output of 552 * the program spawned (i.e., you can read from ofd and get the output 553 * of the program). 554 */ 555static int 556run(int *ofd, const char *cmdline, ...) 557{ 558 char **argv, **argvp; /* Result of splitting 'cmd'. */ 559 int argc; 560 char *cmd; /* Expansion of 'cmdline'. */ 561 int pid, status; /* Child info. */ 562 int pfd[2]; /* Pipe to the child. */ 563 int nfd; /* Null (/dev/null) file descriptor. */ 564 bool dup2dn; /* Dup /dev/null to stdout? */ 565 va_list ap; 566 char *p; 567 int rv, i; 568 569 dup2dn = true; 570 va_start(ap, cmdline); 571 rv = vasprintf(&cmd, cmdline, ap); 572 if (rv == -1) 573 err(1, "vasprintf"); 574 va_end(ap); 575 576 /* Split up 'cmd' into 'argv' for use with execve. */ 577 for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++) 578 argc++; /* 'argc' generation loop. */ 579 argv = (char **)malloc(sizeof(*argv) * (argc + 1)); 580 assert(argv != NULL); 581 for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;) 582 if (**argv != '\0') 583 if (++argvp >= &argv[argc]) { 584 *argvp = NULL; 585 break; 586 } 587 assert(*argv); 588 589 /* Make sure the above loop works as expected. */ 590 if (debug) { 591 /* 592 * We can't, but should, use debugprintf here. First, 593 * it appends a trailing newline to the output, and 594 * second it prepends "DEBUG: " to the output. The 595 * former is a problem for this would-be first call, 596 * and the latter for the would-be call inside the 597 * loop. 598 */ 599 (void)fprintf(stderr, "DEBUG: running:"); 600 /* Should be equivilent to 'cmd' (before strsep, of course). */ 601 for (i = 0; argv[i] != NULL; i++) 602 (void)fprintf(stderr, " %s", argv[i]); 603 (void)fprintf(stderr, "\n"); 604 } 605 606 /* Create a pipe if necessary and fork the helper program. */ 607 if (ofd != NULL) { 608 if (pipe(&pfd[0]) == -1) 609 err(1, "pipe"); 610 *ofd = pfd[0]; 611 dup2dn = false; 612 } 613 pid = fork(); 614 switch (pid) { 615 case 0: 616 /* XXX can we call err() in here? */ 617 if (norun) 618 _exit(0); 619 if (ofd != NULL) 620 if (dup2(pfd[1], STDOUT_FILENO) < 0) 621 err(1, "dup2"); 622 if (!loudsubs) { 623 nfd = open(_PATH_DEVNULL, O_RDWR); 624 if (nfd == -1) 625 err(1, "open: %s", _PATH_DEVNULL); 626 if (dup2(nfd, STDIN_FILENO) < 0) 627 err(1, "dup2"); 628 if (dup2dn) 629 if (dup2(nfd, STDOUT_FILENO) < 0) 630 err(1, "dup2"); 631 if (dup2(nfd, STDERR_FILENO) < 0) 632 err(1, "dup2"); 633 } 634 635 (void)execv(argv[0], argv); 636 warn("exec: %s", argv[0]); 637 _exit(-1); 638 case -1: 639 err(1, "fork"); 640 } 641 642 free(cmd); 643 free(argv); 644 while (waitpid(pid, &status, 0) != pid) 645 ; 646 return (WEXITSTATUS(status)); 647} 648 649static void 650usage(void) 651{ 652 653 fprintf(stderr, 654"usage: %s [-DLlMNPSUX] [-a maxcontig] [-b block-size] [-c cylinders]\n" 655"\t[-d rotdelay] [-E path-mdconfig] [-e maxbpg] [-F file] [-f frag-size]\n" 656"\t[-i bytes] [-m percent-free] [-n rotational-positions] [-O optimization]\n" 657"\t[-o mount-options] [-p permissions] [-s size] [-v version]\n" 658"\t[-w user:group] md-device mount-point\n", getprogname()); 659 exit(1); 660}
| 434 if (rv) 435 errx(1, "mount exited with error code %d", rv); 436} 437 438/* 439 * Various configuration of the mountpoint. Mostly, enact 'mip'. 440 */ 441static void 442do_mtptsetup(const char *mtpoint, struct mtpt_info *mip) 443{ 444 445 if (mip->mi_have_mode) { 446 debugprintf("changing mode of %s to %o.", mtpoint, 447 mip->mi_mode); 448 if (!norun) 449 if (chmod(mtpoint, mip->mi_mode) == -1) 450 err(1, "chmod: %s", mtpoint); 451 } 452 /* 453 * We have to do these separately because the user may have 454 * only specified one of them. 455 */ 456 if (mip->mi_have_uid) { 457 debugprintf("changing owner (user) or %s to %u.", mtpoint, 458 mip->mi_uid); 459 if (!norun) 460 if (chown(mtpoint, mip->mi_uid, -1) == -1) 461 err(1, "chown %s to %u (user)", mtpoint, 462 mip->mi_uid); 463 } 464 if (mip->mi_have_gid) { 465 debugprintf("changing owner (group) or %s to %u.", mtpoint, 466 mip->mi_gid); 467 if (!norun) 468 if (chown(mtpoint, -1, mip->mi_gid) == -1) 469 err(1, "chown %s to %u (group)", mtpoint, 470 mip->mi_gid); 471 } 472} 473 474/* 475 * Put a file system on the memory disk. 476 */ 477static void 478do_newfs(const char *args) 479{ 480 int rv; 481 482 rv = run(NULL, "%s%s /dev/%s%d", _PATH_NEWFS, args, mdname, unit); 483 if (rv) 484 errx(1, "newfs exited with error code %d", rv); 485} 486 487/* 488 * 'str' should be a user and group name similar to the last argument 489 * to chown(1); i.e., a user, followed by a colon, followed by a 490 * group. The user and group in 'str' may be either a [ug]id or a 491 * name. Upon return, the uid and gid fields in 'mip' will contain 492 * the uid and gid of the user and group name in 'str', respectively. 493 * 494 * In other words, this derives a user and group id from a string 495 * formatted like the last argument to chown(1). 496 * 497 * Notice: At this point we don't support only a username or only a 498 * group name. do_mtptsetup already does, so when this feature is 499 * desired, this is the only routine that needs to be changed. 500 */ 501static void 502extract_ugid(const char *str, struct mtpt_info *mip) 503{ 504 char *ug; /* Writable 'str'. */ 505 char *user, *group; /* Result of extracton. */ 506 struct passwd *pw; 507 struct group *gr; 508 char *p; 509 uid_t *uid; 510 gid_t *gid; 511 512 uid = &mip->mi_uid; 513 gid = &mip->mi_gid; 514 mip->mi_have_uid = mip->mi_have_gid = false; 515 516 /* Extract the user and group from 'str'. Format above. */ 517 ug = strdup(str); 518 assert(ug != NULL); 519 group = ug; 520 user = strsep(&group, ":"); 521 if (user == NULL || group == NULL || *user == '\0' || *group == '\0') 522 usage(); 523 524 /* Derive uid. */ 525 *uid = strtoul(user, &p, 10); 526 if (*uid == (uid_t)ULONG_MAX) 527 usage(); 528 if (*p != '\0') { 529 pw = getpwnam(user); 530 if (pw == NULL) 531 errx(1, "invalid user: %s", user); 532 *uid = pw->pw_uid; 533 } 534 mip->mi_have_uid = true; 535 536 /* Derive gid. */ 537 *gid = strtoul(group, &p, 10); 538 if (*gid == (gid_t)ULONG_MAX) 539 usage(); 540 if (*p != '\0') { 541 gr = getgrnam(group); 542 if (gr == NULL) 543 errx(1, "invalid group: %s", group); 544 *gid = gr->gr_gid; 545 } 546 mip->mi_have_gid = true; 547 548 free(ug); 549} 550 551/* 552 * Run a process with command name and arguments pointed to by the 553 * formatted string 'cmdline'. Since system(3) is not used, the first 554 * space-delimited token of 'cmdline' must be the full pathname of the 555 * program to run. The return value is the return code of the process 556 * spawned. If 'ofd' is non-NULL, it is set to the standard output of 557 * the program spawned (i.e., you can read from ofd and get the output 558 * of the program). 559 */ 560static int 561run(int *ofd, const char *cmdline, ...) 562{ 563 char **argv, **argvp; /* Result of splitting 'cmd'. */ 564 int argc; 565 char *cmd; /* Expansion of 'cmdline'. */ 566 int pid, status; /* Child info. */ 567 int pfd[2]; /* Pipe to the child. */ 568 int nfd; /* Null (/dev/null) file descriptor. */ 569 bool dup2dn; /* Dup /dev/null to stdout? */ 570 va_list ap; 571 char *p; 572 int rv, i; 573 574 dup2dn = true; 575 va_start(ap, cmdline); 576 rv = vasprintf(&cmd, cmdline, ap); 577 if (rv == -1) 578 err(1, "vasprintf"); 579 va_end(ap); 580 581 /* Split up 'cmd' into 'argv' for use with execve. */ 582 for (argc = 1, p = cmd; (p = strchr(p, ' ')) != NULL; p++) 583 argc++; /* 'argc' generation loop. */ 584 argv = (char **)malloc(sizeof(*argv) * (argc + 1)); 585 assert(argv != NULL); 586 for (p = cmd, argvp = argv; (*argvp = strsep(&p, " ")) != NULL;) 587 if (**argv != '\0') 588 if (++argvp >= &argv[argc]) { 589 *argvp = NULL; 590 break; 591 } 592 assert(*argv); 593 594 /* Make sure the above loop works as expected. */ 595 if (debug) { 596 /* 597 * We can't, but should, use debugprintf here. First, 598 * it appends a trailing newline to the output, and 599 * second it prepends "DEBUG: " to the output. The 600 * former is a problem for this would-be first call, 601 * and the latter for the would-be call inside the 602 * loop. 603 */ 604 (void)fprintf(stderr, "DEBUG: running:"); 605 /* Should be equivilent to 'cmd' (before strsep, of course). */ 606 for (i = 0; argv[i] != NULL; i++) 607 (void)fprintf(stderr, " %s", argv[i]); 608 (void)fprintf(stderr, "\n"); 609 } 610 611 /* Create a pipe if necessary and fork the helper program. */ 612 if (ofd != NULL) { 613 if (pipe(&pfd[0]) == -1) 614 err(1, "pipe"); 615 *ofd = pfd[0]; 616 dup2dn = false; 617 } 618 pid = fork(); 619 switch (pid) { 620 case 0: 621 /* XXX can we call err() in here? */ 622 if (norun) 623 _exit(0); 624 if (ofd != NULL) 625 if (dup2(pfd[1], STDOUT_FILENO) < 0) 626 err(1, "dup2"); 627 if (!loudsubs) { 628 nfd = open(_PATH_DEVNULL, O_RDWR); 629 if (nfd == -1) 630 err(1, "open: %s", _PATH_DEVNULL); 631 if (dup2(nfd, STDIN_FILENO) < 0) 632 err(1, "dup2"); 633 if (dup2dn) 634 if (dup2(nfd, STDOUT_FILENO) < 0) 635 err(1, "dup2"); 636 if (dup2(nfd, STDERR_FILENO) < 0) 637 err(1, "dup2"); 638 } 639 640 (void)execv(argv[0], argv); 641 warn("exec: %s", argv[0]); 642 _exit(-1); 643 case -1: 644 err(1, "fork"); 645 } 646 647 free(cmd); 648 free(argv); 649 while (waitpid(pid, &status, 0) != pid) 650 ; 651 return (WEXITSTATUS(status)); 652} 653 654static void 655usage(void) 656{ 657 658 fprintf(stderr, 659"usage: %s [-DLlMNPSUX] [-a maxcontig] [-b block-size] [-c cylinders]\n" 660"\t[-d rotdelay] [-E path-mdconfig] [-e maxbpg] [-F file] [-f frag-size]\n" 661"\t[-i bytes] [-m percent-free] [-n rotational-positions] [-O optimization]\n" 662"\t[-o mount-options] [-p permissions] [-s size] [-v version]\n" 663"\t[-w user:group] md-device mount-point\n", getprogname()); 664 exit(1); 665}
|