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