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