1 /* $NetBSD: newfs.c,v 1.61 2002/09/28 20:11:07 dbj 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. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36 #include <sys/cdefs.h> 37 #ifndef lint 38 __COPYRIGHT("@(#) Copyright (c) 1983, 1989, 1993, 1994\n\ 39 The Regents of the University of California. All rights reserved.\n"); 40 #endif /* not lint */ 41 42 #ifndef lint 43 #if 0 44 static char sccsid[] = "@(#)newfs.c 8.13 (Berkeley) 5/1/95"; 45 #else 46 __RCSID("$NetBSD: newfs.c,v 1.61 2002/09/28 20:11:07 dbj Exp $"); 47 #endif 48 #endif /* not lint */ 49 50 /* 51 * newfs: friendly front end to mkfs 52 */ 53 #include <sys/param.h> 54 #include <sys/ioctl.h> 55 #include <sys/disklabel.h> 56 #include <sys/file.h> 57 #include <sys/mount.h> 58 #include <sys/sysctl.h> 59 #include <sys/wait.h> 60 61 #include <ufs/ufs/dir.h> 62 #include <ufs/ufs/dinode.h> 63 #include <ufs/ufs/ufsmount.h> 64 #include <ufs/ffs/fs.h> 65 66 #include <ctype.h> 67 #include <disktab.h> 68 #include <err.h> 69 #include <errno.h> 70 #include <grp.h> 71 #include <paths.h> 72 #include <pwd.h> 73 #include <signal.h> 74 #include <stdio.h> 75 #include <stdlib.h> 76 #include <string.h> 77 #include <syslog.h> 78 #include <unistd.h> 79 #include <util.h> 80 81 #include "mntopts.h" 82 #include "dkcksum.h" 83 #include "extern.h" 84 85 struct mntopt mopts[] = { 86 MOPT_STDOPTS, 87 MOPT_ASYNC, 88 MOPT_UPDATE, 89 MOPT_GETARGS, 90 MOPT_NOATIME, 91 { NULL }, 92 }; 93 94 static struct disklabel *getdisklabel(char *, int); 95 static void rewritelabel(char *, int, struct disklabel *); 96 static gid_t mfs_group(const char *); 97 static uid_t mfs_user(const char *); 98 static int strsuftoi(const char *, const char *, int, int); 99 static void usage(void); 100 int main(int, char *[]); 101 102 #define COMPAT /* allow non-labeled disks */ 103 104 /* 105 * The following two constants set the default block and fragment sizes. 106 * Both constants must be a power of 2 and meet the following constraints: 107 * MINBSIZE <= DESBLKSIZE <= MAXBSIZE 108 * sectorsize <= DESFRAGSIZE <= DESBLKSIZE 109 * DESBLKSIZE / DESFRAGSIZE <= 8 110 */ 111 /* 112 * For file systems smaller than SMALL_FSSIZE we use the S_DFL_* defaults, 113 * otherwise if less than MEDIUM_FSSIZE use M_DFL_*, otherwise use 114 * L_DFL_*. 115 */ 116 #define SMALL_FSSIZE (20*1024*2) 117 #define S_DFL_FRAGSIZE 512 118 #define S_DFL_BLKSIZE 4096 119 #define MEDIUM_FSSIZE (1000*1024*2) 120 #define M_DFL_FRAGSIZE 1024 121 #define M_DFL_BLKSIZE 8192 122 #define L_DFL_FRAGSIZE 2048 123 #define L_DFL_BLKSIZE 16384 124 125 /* 126 * Default sector size. 127 */ 128 #define DFL_SECSIZE 512 129 130 /* 131 * Cylinder groups may have up to many cylinders. The actual 132 * number used depends upon how much information can be stored 133 * on a single cylinder. The default is to use 16 cylinders 134 * per group. 135 */ 136 #define DESCPG 65536 /* desired fs_cpg ("infinity") */ 137 138 /* 139 * ROTDELAY gives the minimum number of milliseconds to initiate 140 * another disk transfer on the same cylinder. It is used in 141 * determining the rotationally optimal layout for disk blocks 142 * within a file; the default of fs_rotdelay is 0ms. 143 */ 144 #define ROTDELAY 0 145 146 /* 147 * MAXBLKPG determines the maximum number of data blocks which are 148 * placed in a single cylinder group. The default is one indirect 149 * block worth of data blocks. 150 */ 151 #define MAXBLKPG(bsize) ((bsize) / sizeof(daddr_t)) 152 153 /* 154 * Each file system has a number of inodes statically allocated. 155 * We allocate one inode slot per NFPI fragments, expecting this 156 * to be far more than we will ever need. 157 */ 158 #define NFPI 4 159 160 /* 161 * For each cylinder we keep track of the availability of blocks at different 162 * rotational positions, so that we can lay out the data to be picked 163 * up with minimum rotational latency. NRPOS is the default number of 164 * rotational positions that we distinguish. With NRPOS of 8 the resolution 165 * of our summary information is 2ms for a typical 3600 rpm drive. Caching 166 * and zoning pretty much defeats rotational optimization, so we now use a 167 * default of 1. 168 */ 169 #define NRPOS 1 /* number distinct rotational positions */ 170 171 172 int mfs; /* run as the memory based filesystem */ 173 int Nflag; /* run without writing file system */ 174 int Oflag; /* format as an 4.3BSD file system */ 175 int fssize; /* file system size */ 176 int ntracks; /* # tracks/cylinder */ 177 int nsectors; /* # sectors/track */ 178 int nphyssectors; /* # sectors/track including spares */ 179 int secpercyl; /* sectors per cylinder */ 180 int trackspares = -1; /* spare sectors per track */ 181 int cylspares = -1; /* spare sectors per cylinder */ 182 int sectorsize; /* bytes/sector */ 183 int rpm; /* revolutions/minute of drive */ 184 int interleave; /* hardware sector interleave */ 185 int trackskew = -1; /* sector 0 skew, per track */ 186 int fsize = 0; /* fragment size */ 187 int bsize = 0; /* block size */ 188 int cpg = DESCPG; /* cylinders/cylinder group */ 189 int cpgflg; /* cylinders/cylinder group flag was given */ 190 int minfree = MINFREE; /* free space threshold */ 191 int opt = DEFAULTOPT; /* optimization preference (space or time) */ 192 int density; /* number of bytes per inode */ 193 int maxcontig = 0; /* max contiguous blocks to allocate */ 194 int rotdelay = ROTDELAY; /* rotational delay between blocks */ 195 int maxbpg; /* maximum blocks per file in a cyl group */ 196 int nrpos = NRPOS; /* # of distinguished rotational positions */ 197 int avgfilesize = AVFILESIZ;/* expected average file size */ 198 int avgfpdir = AFPDIR; /* expected number of files per directory */ 199 int bbsize = BBSIZE; /* boot block size */ 200 int sbsize = SBSIZE; /* superblock size */ 201 int mntflags = MNT_ASYNC; /* flags to be passed to mount */ 202 u_long memleft; /* virtual memory available */ 203 caddr_t membase; /* start address of memory based filesystem */ 204 int needswap; /* Filesystem not in native byte order */ 205 #ifdef COMPAT 206 char *disktype; 207 int unlabeled; 208 #endif 209 char *appleufs_volname = 0; /* Apple UFS volume name */ 210 int isappleufs = 0; 211 212 char device[MAXPATHLEN]; 213 214 int 215 main(int argc, char *argv[]) 216 { 217 struct partition *pp; 218 struct disklabel *lp; 219 struct disklabel mfsfakelabel; 220 struct partition oldpartition; 221 struct statfs *mp; 222 int ch, fsi, fso, len, maxpartitions, n, Fflag, Iflag, Zflag; 223 char *cp, *endp, *s1, *s2, *special; 224 const char *opstring; 225 long long llsize; 226 int dfl_fragsize, dfl_blksize; 227 #ifdef MFS 228 char mountfromname[100]; 229 pid_t pid, res; 230 struct statfs sf; 231 int status; 232 #endif 233 mode_t mfsmode; 234 uid_t mfsuid; 235 gid_t mfsgid; 236 237 cp = NULL; 238 fsi = fso = -1; 239 Fflag = Iflag = Zflag = 0; 240 if (strstr(getprogname(), "mfs")) { 241 mfs = 1; 242 mfsmode = 01777; /* default mode for a /tmp-type directory */ 243 mfsuid = 0; /* user root */ 244 mfsgid = 0; /* group wheel */ 245 Nflag++; 246 } 247 248 maxpartitions = getmaxpartitions(); 249 if (maxpartitions > 26) 250 errx(1, "insane maxpartitions value %d", maxpartitions); 251 252 opstring = mfs ? 253 "NT:a:b:c:d:e:f:g:h:i:m:o:p:s:u:" : 254 "B:FINOS:T:Za:b:c:d:e:f:g:h:i:k:l:m:n:o:p:r:s:t:u:v:x:"; 255 while ((ch = getopt(argc, argv, opstring)) != -1) 256 switch (ch) { 257 case 'B': 258 if (strcmp(optarg, "be") == 0) { 259 #if BYTE_ORDER == LITTLE_ENDIAN 260 needswap = 1; 261 #endif 262 } else if (strcmp(optarg, "le") == 0) { 263 #if BYTE_ORDER == BIG_ENDIAN 264 needswap = 1; 265 #endif 266 } else 267 usage(); 268 break; 269 case 'F': 270 Fflag = 1; 271 break; 272 case 'I': 273 Iflag = 1; 274 break; 275 case 'N': 276 Nflag = 1; 277 break; 278 case 'O': 279 Oflag = 1; 280 break; 281 case 'S': 282 sectorsize = strsuftoi("sector size", 283 optarg, 1, INT_MAX); 284 break; 285 #ifdef COMPAT 286 case 'T': 287 disktype = optarg; 288 break; 289 #endif 290 case 'Z': 291 Zflag = 1; 292 break; 293 case 'a': 294 maxcontig = strsuftoi("maximum contiguous blocks", 295 optarg, 1, INT_MAX); 296 break; 297 case 'b': 298 bsize = strsuftoi("block size", 299 optarg, MINBSIZE, MAXBSIZE); 300 break; 301 case 'c': 302 cpg = strsuftoi("cylinders per group", 303 optarg, 1, INT_MAX); 304 cpgflg++; 305 break; 306 case 'd': 307 rotdelay = strsuftoi("rotational delay", 308 optarg, 0, INT_MAX); 309 break; 310 case 'e': 311 maxbpg = strsuftoi( 312 "blocks per file in a cylinder group", 313 optarg, 1, INT_MAX); 314 break; 315 case 'f': 316 fsize = strsuftoi("fragment size", 317 optarg, 1, MAXBSIZE); 318 break; 319 case 'g': 320 if (mfs) 321 mfsgid = mfs_group(optarg); 322 else { 323 avgfilesize = strsuftoi("average file size", 324 optarg, 1, INT_MAX); 325 } 326 break; 327 case 'h': 328 avgfpdir = strsuftoi("expected files per directory", 329 optarg, 1, INT_MAX); 330 break; 331 case 'i': 332 density = strsuftoi("bytes per inode", 333 optarg, 1, INT_MAX); 334 break; 335 case 'k': 336 trackskew = strsuftoi("track skew", 337 optarg, 0, INT_MAX); 338 break; 339 case 'l': 340 interleave = strsuftoi("interleave", 341 optarg, 1, INT_MAX); 342 break; 343 case 'm': 344 minfree = strsuftoi("free space %", 345 optarg, 0, 99); 346 break; 347 case 'n': 348 nrpos = strsuftoi("rotational layout count", 349 optarg, 1, INT_MAX); 350 break; 351 case 'o': 352 if (mfs) 353 getmntopts(optarg, mopts, &mntflags, 0); 354 else { 355 if (strcmp(optarg, "space") == 0) 356 opt = FS_OPTSPACE; 357 else if (strcmp(optarg, "time") == 0) 358 opt = FS_OPTTIME; 359 else 360 errx(1, "%s %s", 361 "unknown optimization preference: ", 362 "use `space' or `time'."); 363 } 364 break; 365 case 'p': 366 if (mfs) { 367 if ((mfsmode = strtol(optarg, NULL, 8)) <= 0) 368 errx(1, "bad mode `%s'", optarg); 369 } else { 370 trackspares = strsuftoi( 371 "spare sectors per track", optarg, 0, 372 INT_MAX); 373 } 374 break; 375 case 'r': 376 rpm = strsuftoi("revolutions per minute", 377 optarg, 1, INT_MAX); 378 break; 379 case 's': 380 llsize = strtoll(optarg, &endp, 10); 381 if (endp[0] != '\0' && endp[1] != '\0') 382 llsize = -1; 383 else { 384 int ssiz; 385 386 ssiz = (sectorsize ? sectorsize : DFL_SECSIZE); 387 switch (tolower((unsigned char)endp[0])) { 388 case 'b': 389 llsize /= ssiz; 390 break; 391 case 'k': 392 llsize *= 1024 / ssiz; 393 break; 394 case 'm': 395 llsize *= 1024 * 1024 / ssiz; 396 break; 397 case 'g': 398 llsize *= 1024 * 1024 * 1024 / ssiz; 399 break; 400 case '\0': 401 case 's': 402 break; 403 default: 404 llsize = -1; 405 } 406 } 407 if (llsize > INT_MAX) 408 errx(1, "file system size `%s' is too large.", 409 optarg); 410 if (llsize <= 0) 411 errx(1, 412 "`%s' is not a valid number for file system size.", 413 optarg); 414 fssize = (int)llsize; 415 break; 416 case 't': 417 ntracks = strsuftoi("total tracks", 418 optarg, 1, INT_MAX); 419 break; 420 case 'u': 421 if (mfs) 422 mfsuid = mfs_user(optarg); 423 else { 424 nsectors = strsuftoi("sectors per track", 425 optarg, 1, INT_MAX); 426 } 427 break; 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 case 'x': 437 cylspares = strsuftoi("spare sectors per cylinder", 438 optarg, 0, INT_MAX); 439 break; 440 case '?': 441 default: 442 usage(); 443 } 444 argc -= optind; 445 argv += optind; 446 if (mntflags & MNT_GETARGS) 447 goto doit; 448 449 if (argc != 2 && (mfs || argc != 1)) 450 usage(); 451 452 special = argv[0]; 453 if (Fflag || mfs) { 454 /* 455 * it's a file system image or an MFS, so fake up a label. 456 * XXX 457 */ 458 if (!sectorsize) 459 sectorsize = DFL_SECSIZE; 460 461 if (Fflag && !Nflag) { /* creating image in a regular file */ 462 if (fssize == 0) 463 errx(1, "need to specify size when using -F"); 464 fso = open(special, O_RDWR | O_CREAT | O_TRUNC, 0777); 465 if (fso == -1) 466 err(1, "can't open file %s", special); 467 if ((fsi = dup(fso)) == -1) 468 err(1, "can't dup(2) image fd"); 469 /* XXXLUKEM: only ftruncate() regular files ? */ 470 if (ftruncate(fso, (off_t)fssize * sectorsize) == -1) 471 err(1, "can't resize %s to %d", 472 special, fssize); 473 474 if (Zflag) { /* pre-zero the file */ 475 char *buf; 476 int bufsize, i; 477 off_t bufrem; 478 struct statfs sfs; 479 480 if (fstatfs(fso, &sfs) == -1) { 481 warn("can't fstatfs `%s'", special); 482 bufsize = 8192; 483 } else 484 bufsize = sfs.f_iosize; 485 486 if ((buf = calloc(1, bufsize)) == NULL) 487 err(1, "can't malloc buffer of %d", 488 bufsize); 489 bufrem = fssize * sectorsize; 490 printf( 491 "Creating file system image in `%s', size %lld bytes, in %d byte chunks.\n", 492 special, (long long)bufrem, bufsize); 493 while (bufrem > 0) { 494 i = write(fso, buf, 495 MIN(bufsize, bufrem)); 496 if (i == -1) 497 err(1, "writing image"); 498 bufrem -= i; 499 } 500 } 501 502 } 503 504 memset(&mfsfakelabel, 0, sizeof(mfsfakelabel)); 505 mfsfakelabel.d_secsize = sectorsize; 506 mfsfakelabel.d_nsectors = 64; /* these 3 add up to 16MB */ 507 mfsfakelabel.d_ntracks = 16; 508 mfsfakelabel.d_ncylinders = 16; 509 mfsfakelabel.d_secpercyl = 510 mfsfakelabel.d_nsectors * mfsfakelabel.d_ntracks; 511 mfsfakelabel.d_secperunit = 512 mfsfakelabel.d_ncylinders * mfsfakelabel.d_secpercyl; 513 mfsfakelabel.d_rpm = 10000; 514 mfsfakelabel.d_interleave = 1; 515 mfsfakelabel.d_npartitions = 1; 516 mfsfakelabel.d_partitions[0].p_size = mfsfakelabel.d_secperunit; 517 mfsfakelabel.d_partitions[0].p_fsize = 1024; 518 mfsfakelabel.d_partitions[0].p_frag = 8; 519 mfsfakelabel.d_partitions[0].p_cpg = 16; 520 521 lp = &mfsfakelabel; 522 pp = &mfsfakelabel.d_partitions[0]; 523 } else { /* !Fflag && !mfs */ 524 fsi = opendisk(special, O_RDONLY, device, sizeof(device), 0); 525 special = device; 526 if (fsi < 0) 527 err(1, "%s: open for read", special); 528 529 if (Nflag) { 530 fso = -1; 531 } else { 532 fso = open(special, O_WRONLY); 533 if (fso < 0) 534 err(1, "%s: open for write", special); 535 536 /* Bail if target special is mounted */ 537 n = getmntinfo(&mp, MNT_NOWAIT); 538 if (n == 0) 539 err(1, "%s: getmntinfo", special); 540 541 len = sizeof(_PATH_DEV) - 1; 542 s1 = special; 543 if (strncmp(_PATH_DEV, s1, len) == 0) 544 s1 += len; 545 546 while (--n >= 0) { 547 s2 = mp->f_mntfromname; 548 if (strncmp(_PATH_DEV, s2, len) == 0) { 549 s2 += len - 1; 550 *s2 = 'r'; 551 } 552 if (strcmp(s1, s2) == 0 || 553 strcmp(s1, &s2[1]) == 0) 554 errx(1, "%s is mounted on %s", 555 special, mp->f_mntonname); 556 ++mp; 557 } 558 } 559 cp = strchr(argv[0], '\0') - 1; 560 if (cp == 0 || ((*cp < 'a' || *cp > ('a' + maxpartitions - 1)) 561 && !isdigit(*cp))) 562 errx(1, "can't figure out file system partition"); 563 #ifdef COMPAT 564 if (disktype == NULL) 565 disktype = argv[1]; 566 #endif 567 lp = getdisklabel(special, fsi); 568 if (isdigit(*cp)) 569 pp = &lp->d_partitions[0]; 570 else 571 pp = &lp->d_partitions[*cp - 'a']; 572 if (pp->p_size == 0) 573 errx(1, "`%c' partition is unavailable", *cp); 574 if (pp->p_fstype == FS_APPLEUFS) 575 isappleufs = 1; 576 if (isappleufs) { 577 if (!Iflag && (pp->p_fstype != FS_APPLEUFS)) 578 errx(1, "`%c' partition type is not `Apple UFS'", *cp); 579 } else { 580 if (!Iflag && (pp->p_fstype != FS_BSDFFS)) 581 errx(1, "`%c' partition type is not `4.2BSD'", *cp); 582 } 583 } /* !Fflag && !mfs */ 584 585 if (fssize == 0) 586 fssize = pp->p_size; 587 if (fssize > pp->p_size && !mfs && !Fflag) 588 errx(1, "maximum file system size on the `%c' partition is %d", 589 *cp, pp->p_size); 590 if (rpm == 0) { 591 rpm = lp->d_rpm; 592 if (rpm <= 0) 593 rpm = 3600; 594 } 595 if (ntracks == 0) { 596 ntracks = lp->d_ntracks; 597 if (ntracks <= 0) 598 errx(1, "no default #tracks"); 599 } 600 if (nsectors == 0) { 601 nsectors = lp->d_nsectors; 602 if (nsectors <= 0) 603 errx(1, "no default #sectors/track"); 604 } 605 if (sectorsize == 0) { 606 sectorsize = lp->d_secsize; 607 if (sectorsize <= 0) 608 errx(1, "no default sector size"); 609 } 610 if (trackskew == -1) { 611 trackskew = lp->d_trackskew; 612 if (trackskew < 0) 613 trackskew = 0; 614 } 615 if (interleave == 0) { 616 interleave = lp->d_interleave; 617 if (interleave <= 0) 618 interleave = 1; 619 } 620 621 if (fssize < SMALL_FSSIZE) { 622 dfl_fragsize = S_DFL_FRAGSIZE; 623 dfl_blksize = S_DFL_BLKSIZE; 624 } else if (fssize < MEDIUM_FSSIZE) { 625 dfl_fragsize = M_DFL_FRAGSIZE; 626 dfl_blksize = M_DFL_BLKSIZE; 627 } else { 628 dfl_fragsize = L_DFL_FRAGSIZE; 629 dfl_blksize = L_DFL_BLKSIZE; 630 } 631 632 if (fsize == 0) { 633 fsize = pp->p_fsize; 634 if (fsize <= 0) 635 fsize = MAX(dfl_fragsize, lp->d_secsize); 636 } 637 if (bsize == 0) { 638 bsize = pp->p_frag * pp->p_fsize; 639 if (bsize <= 0) 640 bsize = MIN(dfl_blksize, 8 * fsize); 641 } 642 /* 643 * Maxcontig sets the default for the maximum number of blocks 644 * that may be allocated sequentially. With filesystem clustering 645 * it is possible to allocate contiguous blocks up to the maximum 646 * transfer size permitted by the controller or buffering. 647 */ 648 if (maxcontig == 0) 649 maxcontig = MAX(1, MIN(MAXPHYS, MAXBSIZE) / bsize); 650 if (density == 0) 651 density = NFPI * fsize; 652 if (minfree < MINFREE && opt != FS_OPTSPACE) { 653 warnx("%s %s %d%%", "Warning: changing optimization to space", 654 "because minfree is less than", MINFREE); 655 opt = FS_OPTSPACE; 656 } 657 if (trackspares == -1) { 658 trackspares = lp->d_sparespertrack; 659 if (trackspares < 0) 660 trackspares = 0; 661 } 662 nphyssectors = nsectors + trackspares; 663 if (cylspares == -1) { 664 cylspares = lp->d_sparespercyl; 665 if (cylspares < 0) 666 cylspares = 0; 667 } 668 secpercyl = nsectors * ntracks - cylspares; 669 if (secpercyl != lp->d_secpercyl) 670 warnx("%s (%d) %s (%u)", 671 "Warning: calculated sectors per cylinder", secpercyl, 672 "disagrees with disk label", lp->d_secpercyl); 673 if (maxbpg == 0) 674 maxbpg = MAXBLKPG(bsize); 675 #ifdef notdef /* label may be 0 if faked up by kernel */ 676 bbsize = lp->d_bbsize; 677 sbsize = lp->d_sbsize; 678 #endif 679 oldpartition = *pp; 680 mkfs(pp, special, fsi, fso, mfsmode, mfsuid, mfsgid); 681 if (!Nflag && memcmp(pp, &oldpartition, sizeof(oldpartition)) && !Fflag) 682 rewritelabel(special, fso, lp); 683 if (!Nflag) 684 close(fso); 685 close(fsi); 686 #ifdef MFS 687 if (mfs) { 688 struct mfs_args args; 689 690 switch (pid = fork()) { 691 case -1: 692 perror("mfs"); 693 exit(10); 694 case 0: 695 (void)snprintf(mountfromname, sizeof(mountfromname), 696 "mfs:%d", getpid()); 697 break; 698 default: 699 (void)snprintf(mountfromname, sizeof(mountfromname), 700 "mfs:%d", pid); 701 for (;;) { 702 /* 703 * spin until the mount succeeds 704 * or the child exits 705 */ 706 usleep(1); 707 708 /* 709 * XXX Here is a race condition: another process 710 * can mount a filesystem which hides our 711 * ramdisk before we see the success. 712 */ 713 if (statfs(argv[1], &sf) < 0) 714 err(88, "statfs %s", argv[1]); 715 if (!strcmp(sf.f_mntfromname, mountfromname) && 716 !strncmp(sf.f_mntonname, argv[1], 717 MNAMELEN) && 718 !strcmp(sf.f_fstypename, "mfs")) 719 exit(0); 720 721 res = waitpid(pid, &status, WNOHANG); 722 if (res == -1) 723 err(11, "waitpid"); 724 if (res != pid) 725 continue; 726 if (WIFEXITED(status)) { 727 if (WEXITSTATUS(status) == 0) 728 exit(0); 729 errx(1, "%s: mount: %s", argv[1], 730 strerror(WEXITSTATUS(status))); 731 } else 732 errx(11, "abnormal termination"); 733 } 734 /* NOTREACHED */ 735 } 736 737 (void) setsid(); 738 (void) close(0); 739 (void) close(1); 740 (void) close(2); 741 (void) chdir("/"); 742 743 args.fspec = mountfromname; 744 args.export.ex_root = -2; 745 if (mntflags & MNT_RDONLY) 746 args.export.ex_flags = MNT_EXRDONLY; 747 else 748 args.export.ex_flags = 0; 749 args.base = membase; 750 args.size = fssize * sectorsize; 751 doit: 752 if (mount(MOUNT_MFS, argv[1], mntflags, &args) < 0) { 753 if (mntflags & MNT_GETARGS) 754 err(1, "mount `%s' failed", argv[1]); 755 exit(errno); /* parent prints message */ 756 } 757 if (mntflags & MNT_GETARGS) 758 printf("base=%p, size=%ld\n", args.base, args.size); 759 } 760 #endif 761 exit(0); 762 } 763 764 #ifdef COMPAT 765 const char lmsg[] = "%s: can't read disk label; disk type must be specified"; 766 #else 767 const char lmsg[] = "%s: can't read disk label"; 768 #endif 769 770 static struct disklabel * 771 getdisklabel(char *s, volatile int fd) 772 /* XXX why is fs volatile?! */ 773 { 774 static struct disklabel lab; 775 776 if (ioctl(fd, DIOCGDINFO, &lab) < 0) { 777 #ifdef COMPAT 778 if (disktype) { 779 struct disklabel *lp; 780 781 unlabeled++; 782 lp = getdiskbyname(disktype); 783 if (lp == NULL) 784 errx(1, "%s: unknown disk type", disktype); 785 return (lp); 786 } 787 #endif 788 warn("ioctl (GDINFO)"); 789 errx(1, lmsg, s); 790 } 791 return (&lab); 792 } 793 794 static void 795 rewritelabel(char *s, volatile int fd, struct disklabel *lp) 796 /* XXX why is fd volatile?! */ 797 { 798 #ifdef COMPAT 799 if (unlabeled) 800 return; 801 #endif 802 lp->d_checksum = 0; 803 lp->d_checksum = dkcksum(lp); 804 if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) { 805 if (errno == ESRCH) 806 return; 807 warn("ioctl (WDINFO)"); 808 errx(1, "%s: can't rewrite disk label", s); 809 } 810 #if __vax__ 811 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 812 int i; 813 int cfd; 814 daddr_t alt; 815 char specname[64]; 816 char blk[1024]; 817 char *cp; 818 819 /* 820 * Make name for 'c' partition. 821 */ 822 strcpy(specname, s); 823 cp = specname + strlen(specname) - 1; 824 if (!isdigit(*cp)) 825 *cp = 'c'; 826 cfd = open(specname, O_WRONLY); 827 if (cfd < 0) 828 err(1, "%s: open", specname); 829 memset(blk, 0, sizeof(blk)); 830 *(struct disklabel *)(blk + LABELOFFSET) = *lp; 831 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 832 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 833 off_t offset; 834 835 offset = alt + i; 836 offset *= lp->d_secsize; 837 if (lseek(cfd, offset, SEEK_SET) == -1) 838 err(1, "lseek to badsector area: "); 839 if (write(cfd, blk, lp->d_secsize) < lp->d_secsize) 840 warn("alternate label %d write", i/2); 841 } 842 close(cfd); 843 } 844 #endif 845 } 846 847 static gid_t 848 mfs_group(const char *gname) 849 { 850 struct group *gp; 851 852 if (!(gp = getgrnam(gname)) && !isdigit((unsigned char)*gname)) 853 errx(1, "unknown gname %s", gname); 854 return gp ? gp->gr_gid : atoi(gname); 855 } 856 857 static uid_t 858 mfs_user(const char *uname) 859 { 860 struct passwd *pp; 861 862 if (!(pp = getpwnam(uname)) && !isdigit((unsigned char)*uname)) 863 errx(1, "unknown user %s", uname); 864 return pp ? pp->pw_uid : atoi(uname); 865 } 866 867 static int 868 strsuftoi(const char *desc, const char *arg, int min, int max) 869 { 870 long long result; 871 char *ep; 872 873 errno = 0; 874 result = strtoll(arg, &ep, 10); 875 if (ep[0] != '\0' && ep[1] != '\0') 876 errx(1, "%s `%s' is not a valid number.", desc, arg); 877 switch (tolower((unsigned char)ep[0])) { 878 case '\0': 879 case 'b': 880 break; 881 case 'k': 882 result <<= 10; 883 break; 884 case 'm': 885 result <<= 20; 886 break; 887 case 'g': 888 result <<= 30; 889 break; 890 default: 891 errx(1, "`%s' is not a valid suffix for %s.", ep, desc); 892 } 893 if (result < min) 894 errx(1, "%s `%s' (%lld) is less than minimum (%d).", 895 desc, arg, result, min); 896 if (result > max) 897 errx(1, "%s `%s' (%lld) is greater than maximum (%d).", 898 desc, arg, result, max); 899 return ((int)result); 900 } 901 902 #define NEWFS 1 903 #define MFS_MOUNT 2 904 #define BOTH NEWFS | MFS_MOUNT 905 906 struct help_strings { 907 int flags; 908 const char *str; 909 } const help_strings[] = { 910 { NEWFS, "-B byteorder\tbyte order (`be' or `le')" }, 911 { NEWFS, "-F \t\tcreate file system image in regular file" }, 912 { NEWFS, "-I \t\tdo not check that the file system type is '4.2BSD'" }, 913 { BOTH, "-N \t\tdo not create file system, just print out " 914 "parameters" }, 915 { NEWFS, "-O \t\tcreate a 4.3BSD format filesystem" }, 916 { NEWFS, "-S secsize\tsector size" }, 917 #ifdef COMPAT 918 { NEWFS, "-T disktype\tdisk type" }, 919 #endif 920 { NEWFS, "-Z \t\tpre-zero the image file (with -F)" }, 921 { BOTH, "-a maxcontig\tmaximum contiguous blocks" }, 922 { BOTH, "-b bsize\tblock size" }, 923 { BOTH, "-c cpg\t\tcylinders/group" }, 924 { BOTH, "-d rotdelay\trotational delay between contiguous " 925 "blocks" }, 926 { BOTH, "-e maxbpg\tmaximum blocks per file in a cylinder group" 927 }, 928 { BOTH, "-f fsize\tfrag size" }, 929 { NEWFS, "-g avgfilesize\taverage file size" }, 930 { MFS_MOUNT, "-g groupname\tgroup name of mount point" }, 931 { BOTH, "-h avgfpdir\taverage files per directory" }, 932 { BOTH, "-i density\tnumber of bytes per inode" }, 933 { NEWFS, "-k trackskew\tsector 0 skew, per track" }, 934 { NEWFS, "-l interleave\thardware sector interleave" }, 935 { BOTH, "-m minfree\tminimum free space %%" }, 936 { NEWFS, "-n nrpos\tnumber of distinguished rotational " 937 "positions" }, 938 { BOTH, "-o optim\toptimization preference (`space' or `time')" 939 }, 940 { NEWFS, "-p tracksparse\tspare sectors per track" }, 941 { MFS_MOUNT, "-p perm\t\tpermissions (in octal)" }, 942 { BOTH, "-s fssize\tfile system size (sectors)" }, 943 { NEWFS, "-r rpm\t\trevolutions/minute" }, 944 { NEWFS, "-t ntracks\ttracks/cylinder" }, 945 { NEWFS, "-u nsectors\tsectors/track" }, 946 { MFS_MOUNT, "-u username\tuser name of mount point" }, 947 { NEWFS, "-v volname\tApple UFS volume name" }, 948 { NEWFS, "-x cylspares\tspare sectors per cylinder" }, 949 { 0, NULL } 950 }; 951 952 static void 953 usage(void) 954 { 955 int match; 956 const struct help_strings *hs; 957 958 if (mfs) { 959 fprintf(stderr, 960 "usage: %s [ fsoptions ] special-device mount-point\n", 961 getprogname()); 962 } else 963 fprintf(stderr, 964 "usage: %s [ fsoptions ] special-device%s\n", 965 getprogname(), 966 #ifdef COMPAT 967 " [device-type]"); 968 #else 969 ""); 970 #endif 971 fprintf(stderr, "where fsoptions are:\n"); 972 973 match = mfs ? MFS_MOUNT : NEWFS; 974 for (hs = help_strings; hs->flags != 0; hs++) 975 if (hs->flags & match) 976 fprintf(stderr, "\t%s\n", hs->str); 977 exit(1); 978 } 979