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