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