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