1/* $NetBSD$ */ 2 3/* 4 * Copyright (c) 1983, 1989, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32/* 33 * Copyright (c) 2002 Networks Associates Technology, Inc. 34 * All rights reserved. 35 * 36 * This software was developed for the FreeBSD Project by Marshall 37 * Kirk McKusick and Network Associates Laboratories, the Security 38 * Research Division of Network Associates, Inc. under DARPA/SPAWAR 39 * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS 40 * research program 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. All advertising materials mentioning features or use of this software 51 * must display the following acknowledgement: 52 * This product includes software developed by the University of 53 * California, Berkeley and its contributors. 54 * 4. Neither the name of the University nor the names of its contributors 55 * may be used to endorse or promote products derived from this software 56 * without specific prior written permission. 57 * 58 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 59 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 60 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 61 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 62 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 63 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 64 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 65 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 66 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 67 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 68 * SUCH DAMAGE. 69 */ 70 71#include <sys/cdefs.h> 72#ifndef lint 73__COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993, 1994\ 74 The Regents of the University of California. All rights reserved."); 75#endif /* not lint */ 76 77#ifndef lint 78#if 0 79static char sccsid[] = "@(#)newfs.c 8.13 (Berkeley) 5/1/95"; 80#else 81__RCSID("$NetBSD$"); 82#endif 83#endif /* not lint */ 84 85/* 86 * newfs: friendly front end to mkfs 87 */ 88#include <sys/param.h> 89#include <sys/ioctl.h> 90#include <sys/disklabel.h> 91#include <sys/disk.h> 92#include <sys/file.h> 93#include <sys/mount.h> 94#include <sys/sysctl.h> 95#include <sys/wait.h> 96 97#include <ufs/ufs/dir.h> 98#include <ufs/ufs/dinode.h> 99#include <ufs/ufs/ufsmount.h> 100#include <ufs/ufs/quota2.h> 101#include <ufs/ffs/fs.h> 102 103#include <ctype.h> 104#include <disktab.h> 105#include <err.h> 106#include <errno.h> 107#include <grp.h> 108#include <limits.h> 109#include <paths.h> 110#include <pwd.h> 111#include <signal.h> 112#include <stdint.h> 113#include <stdio.h> 114#include <stdlib.h> 115#include <string.h> 116#include <syslog.h> 117#include <unistd.h> 118#include <util.h> 119#include <mntopts.h> 120 121#ifdef MFS 122#include <mountprog.h> 123#endif 124 125#include "dkcksum.h" 126#include "extern.h" 127#include "partutil.h" 128 129struct mntopt mopts[] = { 130 MOPT_STDOPTS, 131 MOPT_ASYNC, 132 MOPT_UPDATE, 133 MOPT_GETARGS, 134 MOPT_NOATIME, 135 { .m_option = NULL }, 136}; 137 138static gid_t mfs_group(const char *); 139static uid_t mfs_user(const char *); 140static int64_t strsuftoi64(const char *, const char *, int64_t, int64_t, int *); 141static void usage(void) __dead; 142 143#define COMPAT /* allow non-labeled disks */ 144 145#ifdef COMPAT 146const char lmsg[] = "%s: can't read disk label; disk type must be specified"; 147#else 148const char lmsg[] = "%s: can't read disk label"; 149#endif 150 151/* 152 * The following two constants set the default block and fragment sizes. 153 * Both constants must be a power of 2 and meet the following constraints: 154 * MINBSIZE <= DESBLKSIZE <= MAXBSIZE 155 * sectorsize <= DESFRAGSIZE <= DESBLKSIZE 156 * DESBLKSIZE / DESFRAGSIZE <= 8 157 */ 158/* 159 * For file systems smaller than SMALL_FSSIZE we use the S_DFL_* defaults, 160 * otherwise if less than MEDIUM_FSSIZE use M_DFL_*, 161 * otherwise if less than LARGE_FSSIZE use L_DFL_*, 162 * otherwise use LL_DFL_* especially for modern AFT disks. 163 */ 164#define SMALL_FSSIZE (20*1024*2) 165#define S_DFL_FRAGSIZE 512 166#define MEDIUM_FSSIZE (1000*1024*2) 167#define M_DFL_FRAGSIZE 1024 168#define LARGE_FSSIZE (128*1024*1024*2) 169#define L_DFL_FRAGSIZE 2048 170#define LL_DFL_FRAGSIZE 4096 171#define DFL_FRAG_BLK 8 172 173/* Apple requires the fragment size to be at least APPLEUFS_DIRBLKSIZ 174 * but the block size cannot be larger than Darwin's PAGE_SIZE. See 175 * the mount check in Darwin's ffs_mountfs for an explanation. 176 */ 177#define APPLEUFS_DFL_FRAGSIZE APPLEUFS_DIRBLKSIZ /* 1024 */ 178#define APPLEUFS_DFL_BLKSIZE 4096 /* default Darwin PAGE_SIZE */ 179 180/* 181 * Default sector size. 182 */ 183#define DFL_SECSIZE 512 184 185/* 186 * Default file system size for "mount_mfs swap /dir" case. 187 */ 188#define DFL_FSSIZE (8 * 1024 * 1024) 189 190/* 191 * MAXBLKPG determines the maximum number of data blocks which are 192 * placed in a single cylinder group. The default is one indirect 193 * block worth of data blocks. 194 */ 195#define MAXBLKPG_UFS1(bsize) ((bsize) / sizeof(int32_t)) 196#define MAXBLKPG_UFS2(bsize) ((bsize) / sizeof(int64_t)) 197 198/* 199 * Each file system has a number of inodes statically allocated. 200 * We allocate one inode slot per NFPI fragments, expecting this 201 * to be far more than we will ever need. 202 */ 203#define NFPI 4 204 205 206int mfs; /* run as the memory based filesystem */ 207int Gflag; /* allow garbage parameters (for testing) */ 208int Nflag; /* run without writing file system */ 209int Oflag = 1; /* format as an 4.3BSD file system */ 210int verbosity; /* amount of printf() output */ 211#define DEFAULT_VERBOSITY 3 /* 4 is traditional behavior */ 212int64_t fssize; /* file system size */ 213int sectorsize; /* bytes/sector */ 214int fsize = 0; /* fragment size */ 215int bsize = 0; /* block size */ 216int maxbsize = 0; /* maximum clustering */ 217int minfree = MINFREE; /* free space threshold */ 218int opt = DEFAULTOPT; /* optimization preference (space or time) */ 219int density; /* number of bytes per inode */ 220int num_inodes; /* number of inodes (overrides density) */ 221int maxcontig = 0; /* max contiguous blocks to allocate */ 222int maxbpg; /* maximum blocks per file in a cyl group */ 223int avgfilesize = AVFILESIZ;/* expected average file size */ 224int avgfpdir = AFPDIR; /* expected number of files per directory */ 225int mntflags = 0; /* flags to be passed to mount */ 226u_long memleft; /* virtual memory available */ 227caddr_t membase; /* start address of memory based filesystem */ 228int needswap; /* Filesystem not in native byte order */ 229char *disktype = NULL; 230int unlabeled; 231char *appleufs_volname = 0; /* Apple UFS volume name */ 232int isappleufs = 0; 233int quotas = 0; 234 235char device[MAXPATHLEN]; 236 237int 238main(int argc, char *argv[]) 239{ 240 struct disk_geom geo; 241 struct dkwedge_info dkw; 242 struct statvfs *mp; 243 struct stat sb; 244 int ch, fsi, fso, len, n, Fflag, Iflag, Zflag; 245 char *s1, *s2, *special; 246 const char *opstring; 247 int byte_sized = 0; 248#ifdef MFS 249 struct mfs_args args; 250 char mountfromname[100]; 251 char mounttoname[MAXPATHLEN]; 252 pid_t pid, res; 253 struct statvfs sf; 254 int status; 255#endif 256 mode_t mfsmode = 01777; /* default mode for a /tmp-type directory */ 257 uid_t mfsuid = 0; /* user root */ 258 gid_t mfsgid = 0; /* group wheel */ 259 mntoptparse_t mo; 260 261 fsi = fso = -1; 262 Fflag = Iflag = Zflag = 0; 263 verbosity = -1; 264 if (strstr(getprogname(), "mfs")) { 265 mfs = 1; 266 } else { 267 /* Undocumented, for ease of testing */ 268 if (argv[1] != NULL && !strcmp(argv[1], "-mfs")) { 269 argv++; 270 argc--; 271 mfs = 1; 272 } 273 } 274 275 opstring = mfs ? 276 "NT:V:a:b:d:e:f:g:h:i:m:n:o:p:q:s:u:" : 277 "B:FGINO:S:T:V:Za:b:d:e:f:g:h:i:l:m:n:o:q:r:s:v:"; 278 while ((ch = getopt(argc, argv, opstring)) != -1) 279 switch (ch) { 280 case 'B': 281 if (strcmp(optarg, "be") == 0) { 282#if BYTE_ORDER == LITTLE_ENDIAN 283 needswap = 1; 284#endif 285 } else if (strcmp(optarg, "le") == 0) { 286#if BYTE_ORDER == BIG_ENDIAN 287 needswap = 1; 288#endif 289 } else 290 usage(); 291 break; 292 case 'F': 293 Fflag = 1; 294 break; 295 case 'G': 296 fprintf(stderr, "WARNING: -G may create file systems " 297 "which cause kernel panics\n"); 298 Gflag = 1; 299 break; 300 case 'I': 301 Iflag = 1; 302 break; 303 case 'N': 304 Nflag = 1; 305 if (verbosity == -1) 306 verbosity = DEFAULT_VERBOSITY; 307 break; 308 case 'O': 309 Oflag = strsuftoi64("format", optarg, 0, 2, NULL); 310 break; 311 case 'S': 312 /* XXX: non-512 byte sectors almost certainly don't work. */ 313 sectorsize = strsuftoi64("sector size", 314 optarg, 512, 65536, NULL); 315 if (sectorsize & (sectorsize - 1)) 316 errx(1, "sector size `%s' is not a power of 2.", 317 optarg); 318 break; 319#ifdef COMPAT 320 case 'T': 321 disktype = optarg; 322 break; 323#endif 324 case 'V': 325 verbosity = strsuftoi64("verbose", optarg, 0, 4, NULL); 326 break; 327 case 'Z': 328 Zflag = 1; 329 break; 330 case 'a': 331 maxcontig = strsuftoi64("maximum contiguous blocks", 332 optarg, 1, INT_MAX, NULL); 333 break; 334 case 'b': 335 bsize = strsuftoi64("block size", 336 optarg, MINBSIZE, MAXBSIZE, NULL); 337 break; 338 case 'd': 339 maxbsize = strsuftoi64("maximum extent size", 340 optarg, 0, INT_MAX, NULL); 341 break; 342 case 'e': 343 maxbpg = strsuftoi64( 344 "blocks per file in a cylinder group", 345 optarg, 1, INT_MAX, NULL); 346 break; 347 case 'f': 348 fsize = strsuftoi64("fragment size", 349 optarg, 1, MAXBSIZE, NULL); 350 break; 351 case 'g': 352 if (mfs) 353 mfsgid = mfs_group(optarg); 354 else { 355 avgfilesize = strsuftoi64("average file size", 356 optarg, 1, INT_MAX, NULL); 357 } 358 break; 359 case 'h': 360 avgfpdir = strsuftoi64("expected files per directory", 361 optarg, 1, INT_MAX, NULL); 362 break; 363 case 'i': 364 density = strsuftoi64("bytes per inode", 365 optarg, 1, INT_MAX, NULL); 366 break; 367 case 'm': 368 minfree = strsuftoi64("free space %", 369 optarg, 0, 99, NULL); 370 break; 371 case 'n': 372 num_inodes = strsuftoi64("number of inodes", 373 optarg, 1, INT_MAX, NULL); 374 break; 375 case 'o': 376 if (mfs) { 377 mo = getmntopts(optarg, mopts, &mntflags, 0); 378 if (mo == NULL) 379 err(1, "getmntopts"); 380 freemntopts(mo); 381 } else { 382 if (strcmp(optarg, "space") == 0) 383 opt = FS_OPTSPACE; 384 else if (strcmp(optarg, "time") == 0) 385 opt = FS_OPTTIME; 386 else 387 errx(1, "%s %s", 388 "unknown optimization preference: ", 389 "use `space' or `time'."); 390 } 391 break; 392 case 'q': 393 if (strcmp(optarg, "user") == 0) 394 quotas |= FS_Q2_DO_TYPE(USRQUOTA); 395 else if (strcmp(optarg, "group") == 0) 396 quotas |= FS_Q2_DO_TYPE(GRPQUOTA); 397 else 398 errx(1, "invalid quota type %s", optarg); 399 break; 400 case 'p': 401 /* mfs only */ 402 if ((mfsmode = strtol(optarg, NULL, 8)) <= 0) 403 errx(1, "bad mode `%s'", optarg); 404 break; 405 case 's': 406 fssize = strsuftoi64("file system size", 407 optarg, INT64_MIN, INT64_MAX, &byte_sized); 408 break; 409 case 'u': 410 /* mfs only */ 411 mfsuid = mfs_user(optarg); 412 break; 413 case 'v': 414 appleufs_volname = optarg; 415 if (strchr(appleufs_volname, ':') || strchr(appleufs_volname, '/')) 416 errx(1,"Apple UFS volume name cannot contain ':' or '/'"); 417 if (appleufs_volname[0] == '\0') 418 errx(1,"Apple UFS volume name cannot be zero length"); 419 isappleufs = 1; 420 break; 421 case '?': 422 default: 423 usage(); 424 } 425 argc -= optind; 426 argv += optind; 427 428 if (Oflag < 1 && quotas != 0) 429 errx(1, "in-filesystem quota is incompatible with -O0"); 430 431 if (verbosity == -1) 432 /* Default to not showing CG info if mfs */ 433 verbosity = mfs ? 0 : DEFAULT_VERBOSITY; 434 435#ifdef MFS 436 /* This is enough to get through the correct kernel code paths */ 437 memset(&args, 0, sizeof args); 438 args.fspec = mountfromname; 439 if (mntflags & (MNT_GETARGS | MNT_UPDATE)) { 440 if ((mntflags & MNT_GETARGS) == 0) 441 mntflags |= MNT_ASYNC; 442 if (mount(MOUNT_MFS, argv[1], mntflags, 443 &args, sizeof args) == -1) 444 err(1, "mount `%s' failed", argv[1]); 445 if (mntflags & MNT_GETARGS) 446 printf("base=%p, size=%ld\n", args.base, args.size); 447 exit(0); 448 } 449#endif 450 451 if (argc != 2 && (mfs || argc != 1)) 452 usage(); 453 454 memset(&sb, 0, sizeof sb); 455 memset(&dkw, 0, sizeof dkw); 456 special = argv[0]; 457 if (Fflag || mfs) { 458 /* 459 * It's a file system image or an MFS, 460 * no label, use fixed default for sectorsize. 461 */ 462 if (sectorsize == 0) 463 sectorsize = DFL_SECSIZE; 464 465 if (mfs) { 466 /* 467 * Default filesystem size to that of supplied device, 468 * and fall back to 8M 469 */ 470 if (fssize == 0) 471 if (stat(special, &sb) == -1) 472 fssize = DFL_FSSIZE / sectorsize; 473 } else { 474 /* creating image in a regular file */ 475 int fl; 476 if (Nflag) 477 fl = O_RDONLY; 478 else { 479 if (fssize > 0) 480 fl = O_RDWR | O_CREAT; 481 else 482 fl = O_RDWR; 483 } 484 fsi = open(special, fl, 0777); 485 if (fsi == -1) 486 err(1, "can't open file %s", special); 487 if (fstat(fsi, &sb) == -1) 488 err(1, "can't fstat opened %s", special); 489 if (!Nflag) 490 fso = fsi; 491 } 492 } else { /* !Fflag && !mfs */ 493 fsi = opendisk(special, O_RDONLY, device, sizeof(device), 0); 494 special = device; 495 if (fsi < 0 || fstat(fsi, &sb) == -1) 496 err(1, "%s: open for read", special); 497 if (S_ISBLK(sb.st_mode)) { 498 errx(1, "%s is a block device. use raw device", 499 special); 500 } 501 502 if (!Nflag) { 503 fso = open(special, O_WRONLY, 0); 504 if (fso < 0) 505 err(1, "%s: open for write", special); 506 507 /* Bail if target special is mounted */ 508 n = getmntinfo(&mp, MNT_NOWAIT); 509 if (n == 0) 510 err(1, "%s: getmntinfo", special); 511 512 len = sizeof(_PATH_DEV) - 1; 513 s1 = special; 514 if (strncmp(_PATH_DEV, s1, len) == 0) 515 s1 += len; 516 517 while (--n >= 0) { 518 s2 = mp->f_mntfromname; 519 if (strncmp(_PATH_DEV, s2, len) == 0) { 520 s2 += len - 1; 521 *s2 = 'r'; 522 } 523 if (strcmp(s1, s2) == 0 || 524 strcmp(s1, &s2[1]) == 0) 525 errx(1, "%s is mounted on %s", 526 special, mp->f_mntonname); 527 ++mp; 528 } 529 } 530 531#ifdef COMPAT 532 if (disktype == NULL) 533 disktype = argv[1]; 534#endif 535 if (getdiskinfo(special, fsi, disktype, &geo, &dkw) == -1) 536 errx(1, lmsg, special); 537 unlabeled = disktype != NULL; 538 539 if (sectorsize == 0) { 540 sectorsize = geo.dg_secsize; 541 if (sectorsize <= 0) 542 errx(1, "no default sector size"); 543 } 544 545 if (dkw.dkw_parent[0]) { 546 if (dkw.dkw_size == 0) 547 errx(1, "%s partition is unavailable", special); 548 549 if (strcmp(dkw.dkw_ptype, DKW_PTYPE_APPLEUFS) == 0) 550 isappleufs = 1; 551 552 if (!Iflag) { 553 static const char m[] = 554 "%s partition type is not `%s'"; 555 if (isappleufs) { 556 if (strcmp(dkw.dkw_ptype, 557 DKW_PTYPE_APPLEUFS)) 558 errx(1, m, 559 special, "Apple UFS"); 560 } else { 561 if (strcmp(dkw.dkw_ptype, 562 DKW_PTYPE_FFS)) 563 errx(1, m, special, "4.2BSD"); 564 } 565 } 566 } /* !Fflag && !mfs */ 567 } 568 569 if (byte_sized) 570 fssize /= sectorsize; 571 if (fssize <= 0) { 572 if (sb.st_size != 0) 573 fssize += sb.st_size / sectorsize; 574 else 575 fssize += dkw.dkw_size; 576 if (fssize <= 0) 577 errx(1, "Unable to determine file system size"); 578 } 579 580 if (dkw.dkw_parent[0] && (uint64_t)fssize > dkw.dkw_size) 581 errx(1, "size %" PRIu64 " exceeds maximum file system size on " 582 "`%s' of %" PRIu64 " sectors", 583 fssize, special, dkw.dkw_size); 584 585 /* XXXLUKEM: only ftruncate() regular files ? (dsl: or at all?) */ 586 if (Fflag && fso != -1 587 && ftruncate(fso, (off_t)fssize * sectorsize) == -1) 588 err(1, "can't ftruncate %s to %" PRId64, special, fssize); 589 590 if (Zflag && fso != -1) { /* pre-zero (and de-sparce) the file */ 591 char *buf; 592 int bufsize, i; 593 off_t bufrem; 594 struct statvfs sfs; 595 596 if (fstatvfs(fso, &sfs) == -1) { 597 warn("can't fstatvfs `%s'", special); 598 bufsize = 8192; 599 } else 600 bufsize = sfs.f_iosize; 601 602 if ((buf = calloc(1, bufsize)) == NULL) 603 err(1, "can't malloc buffer of %d", 604 bufsize); 605 bufrem = fssize * sectorsize; 606 if (verbosity > 0) 607 printf( "Creating file system image in `%s', " 608 "size %lld bytes, in %d byte chunks.\n", 609 special, (long long)bufrem, bufsize); 610 while (bufrem > 0) { 611 i = write(fso, buf, MIN(bufsize, bufrem)); 612 if (i == -1) 613 err(1, "writing image"); 614 bufrem -= i; 615 } 616 free(buf); 617 } 618 619 /* Sort out fragment and block sizes */ 620 if (fsize == 0) { 621 fsize = bsize / DFL_FRAG_BLK; 622 if (fsize <= 0) { 623 if (isappleufs) { 624 fsize = APPLEUFS_DFL_FRAGSIZE; 625 } else { 626 if (fssize < SMALL_FSSIZE) 627 fsize = S_DFL_FRAGSIZE; 628 else if (fssize < MEDIUM_FSSIZE) 629 fsize = M_DFL_FRAGSIZE; 630 else if (fssize < LARGE_FSSIZE) 631 fsize = L_DFL_FRAGSIZE; 632 else 633 fsize = LL_DFL_FRAGSIZE; 634 if (fsize < sectorsize) 635 fsize = sectorsize; 636 } 637 } 638 } 639 if (bsize <= 0) { 640 if (isappleufs) 641 bsize = APPLEUFS_DFL_BLKSIZE; 642 else 643 bsize = DFL_FRAG_BLK * fsize; 644 } 645 646 if (isappleufs && (fsize < APPLEUFS_DFL_FRAGSIZE)) { 647 warnx("Warning: chosen fsize of %d is less than Apple UFS minimum of %d", 648 fsize, APPLEUFS_DFL_FRAGSIZE); 649 } 650 if (isappleufs && (bsize > APPLEUFS_DFL_BLKSIZE)) { 651 warnx("Warning: chosen bsize of %d is greater than Apple UFS maximum of %d", 652 bsize, APPLEUFS_DFL_BLKSIZE); 653 } 654 655 /* 656 * Maxcontig sets the default for the maximum number of blocks 657 * that may be allocated sequentially. With filesystem clustering 658 * it is possible to allocate contiguous blocks up to the maximum 659 * transfer size permitted by the controller or buffering. 660 */ 661 if (maxcontig == 0) 662 maxcontig = MAX(1, MIN(MAXPHYS, MAXBSIZE) / bsize); 663 if (density == 0) 664 density = NFPI * fsize; 665 if (minfree < MINFREE && opt != FS_OPTSPACE) { 666 warnx("%s %s %d%%", "Warning: changing optimization to space", 667 "because minfree is less than", MINFREE); 668 opt = FS_OPTSPACE; 669 } 670 if (maxbpg == 0) { 671 if (Oflag <= 1) 672 maxbpg = MAXBLKPG_UFS1(bsize); 673 else 674 maxbpg = MAXBLKPG_UFS2(bsize); 675 } 676 mkfs(special, fsi, fso, mfsmode, mfsuid, mfsgid); 677 if (fsi != -1 && fsi != fso) 678 close(fsi); 679 if (fso != -1) 680 close(fso); 681#ifdef MFS 682 if (mfs) { 683 684 pathadj(argv[1], mounttoname); 685 switch (pid = fork()) { 686 case -1: 687 perror("mfs"); 688 exit(10); 689 case 0: 690 (void)snprintf(mountfromname, sizeof(mountfromname), 691 "mfs:%d", getpid()); 692 break; 693 default: 694 (void)snprintf(mountfromname, sizeof(mountfromname), 695 "mfs:%d", pid); 696 for (;;) { 697 /* 698 * spin until the mount succeeds 699 * or the child exits 700 */ 701 usleep(1); 702 703 /* 704 * XXX Here is a race condition: another process 705 * can mount a filesystem which hides our 706 * ramdisk before we see the success. 707 */ 708 if (statvfs(mounttoname, &sf) < 0) 709 err(88, "statvfs %s", mounttoname); 710 if (!strcmp(sf.f_mntfromname, mountfromname) && 711 !strncmp(sf.f_mntonname, mounttoname, 712 MNAMELEN) && 713 !strcmp(sf.f_fstypename, "mfs")) 714 exit(0); 715 716 res = waitpid(pid, &status, WNOHANG); 717 if (res == -1) 718 err(11, "waitpid"); 719 if (res != pid) 720 continue; 721 if (WIFEXITED(status)) { 722 if (WEXITSTATUS(status) == 0) 723 exit(0); 724 errx(1, "%s: mount: %s", mounttoname, 725 strerror(WEXITSTATUS(status))); 726 } else 727 errx(11, "abnormal termination"); 728 } 729 /* NOTREACHED */ 730 } 731 732 (void) setsid(); 733 (void) close(0); 734 (void) close(1); 735 (void) close(2); 736 (void) chdir("/"); 737 738 args.base = membase; 739 args.size = fssize * sectorsize; 740 if (mount(MOUNT_MFS, mounttoname, mntflags | MNT_ASYNC, 741 &args, sizeof args) == -1) 742 exit(errno); /* parent prints message */ 743 } 744#endif 745 exit(0); 746} 747 748static gid_t 749mfs_group(const char *gname) 750{ 751 struct group *gp; 752 753 if (!(gp = getgrnam(gname)) && !isdigit((unsigned char)*gname)) 754 errx(1, "unknown gname %s", gname); 755 return gp ? gp->gr_gid : (gid_t)atoi(gname); 756} 757 758static uid_t 759mfs_user(const char *uname) 760{ 761 struct passwd *pp; 762 763 if (!(pp = getpwnam(uname)) && !isdigit((unsigned char)*uname)) 764 errx(1, "unknown user %s", uname); 765 return pp ? pp->pw_uid : (uid_t)atoi(uname); 766} 767 768static int64_t 769strsuftoi64(const char *desc, const char *arg, int64_t min, int64_t max, int *num_suffix) 770{ 771 int64_t result, r1; 772 int shift = 0; 773 char *ep; 774 775 errno = 0; 776 r1 = strtoll(arg, &ep, 10); 777 if (ep[0] != '\0' && ep[1] != '\0') 778 errx(1, "%s `%s' is not a valid number.", desc, arg); 779 switch (ep[0]) { 780 case '\0': 781 case 's': case 'S': 782 if (num_suffix != NULL) 783 *num_suffix = 0; 784 break; 785 case 't': case 'T': 786 shift += 10; 787 /* FALLTHROUGH */ 788 case 'g': case 'G': 789 shift += 10; 790 /* FALLTHROUGH */ 791 case 'm': case 'M': 792 shift += 10; 793 /* FALLTHROUGH */ 794 case 'k': case 'K': 795 shift += 10; 796 /* FALLTHROUGH */ 797 case 'b': case 'B': 798 if (num_suffix != NULL) 799 *num_suffix = 1; 800 break; 801 default: 802 errx(1, "`%s' is not a valid suffix for %s.", ep, desc); 803 } 804 result = r1 << shift; 805 if (errno == ERANGE || result >> shift != r1) 806 errx(1, "%s `%s' is too large to convert.", desc, arg); 807 if (result < min) { 808 if (Gflag) { 809 warnx("%s `%s' (%" PRId64 ") is less than the " 810 "minimum (%" PRId64 ").", desc, arg, result, min); 811 } else { 812 errx(1, "%s `%s' (%" PRId64 ") is less than the " 813 "minimum (%" PRId64 ").", desc, arg, result, min); 814 } 815 } 816 if (result > max) { 817 if (Gflag) { 818 warnx("%s `%s' (%" PRId64 ") is greater than the " 819 "maximum (%" PRId64 ").", desc, arg, result, max); 820 } else { 821 errx(1, "%s `%s' (%" PRId64 ") is greater than the " 822 "maximum (%" PRId64 ").", desc, arg, result, max); 823 } 824 } 825 return result; 826} 827 828#define NEWFS 1 829#define MFS_MOUNT 2 830#define BOTH NEWFS | MFS_MOUNT 831 832struct help_strings { 833 int flags; 834 const char *str; 835} const help_strings[] = { 836 { NEWFS, "-B byteorder\tbyte order (`be' or `le')" }, 837 { NEWFS, "-F \t\tcreate file system image in regular file" }, 838 { NEWFS, "-G \t\tmake sanity calculations non-fatal (testing only!)" }, 839 { NEWFS, "-I \t\tdo not check that the file system type is '4.2BSD'" }, 840 { BOTH, "-N \t\tdo not create file system, just print out " 841 "parameters" }, 842 { NEWFS, "-O N\t\tfilesystem format: 0 => 4.3BSD, 1 => FFSv1, 2 => FFSv2" }, 843 { NEWFS, "-S secsize\tsector size" }, 844#ifdef COMPAT 845 { NEWFS, "-T disktype\tdisk type" }, 846#endif 847 { BOTH, "-V verbose\toutput verbosity: 0 ==> none, 4 ==> max" }, 848 { NEWFS, "-Z \t\tpre-zero the image file" }, 849 { BOTH, "-a maxcontig\tmaximum contiguous blocks" }, 850 { BOTH, "-b bsize\tblock size" }, 851 { BOTH, "-d maxbsize\tmaximum extent size" }, 852 { BOTH, "-e maxbpg\tmaximum blocks per file in a cylinder group" 853 }, 854 { BOTH, "-f fsize\tfrag size" }, 855 { NEWFS, "-g avgfilesize\taverage file size" }, 856 { MFS_MOUNT, "-g groupname\tgroup name of mount point" }, 857 { BOTH, "-h avgfpdir\taverage files per directory" }, 858 { BOTH, "-i density\tnumber of bytes per inode" }, 859 { BOTH, "-m minfree\tminimum free space %%" }, 860 { BOTH, "-n inodes\tnumber of inodes (overrides -i density)" }, 861 { BOTH, "-o optim\toptimization preference (`space' or `time')" 862 }, 863 { BOTH, "-q (user|group) enable specified quota" }, 864 { MFS_MOUNT, "-p perm\t\tpermissions (in octal)" }, 865 { BOTH, "-s fssize\tfile system size (sectors)" }, 866 { MFS_MOUNT, "-u username\tuser name of mount point" }, 867 { NEWFS, "-v volname\tApple UFS volume name" }, 868 { 0, NULL } 869}; 870 871static void 872usage(void) 873{ 874 int match; 875 const struct help_strings *hs; 876 877 if (mfs) { 878 fprintf(stderr, 879 "usage: %s [ fsoptions ] special-device mount-point\n", 880 getprogname()); 881 } else 882 fprintf(stderr, 883 "usage: %s [ fsoptions ] special-device%s\n", 884 getprogname(), 885#ifdef COMPAT 886 " [disk-type]"); 887#else 888 ""); 889#endif 890 fprintf(stderr, "where fsoptions are:\n"); 891 892 match = mfs ? MFS_MOUNT : NEWFS; 893 for (hs = help_strings; hs->flags != 0; hs++) 894 if (hs->flags & match) 895 fprintf(stderr, "\t%s\n", hs->str); 896 exit(1); 897} 898