1 /* $NetBSD: tunefs.c,v 1.52 2020/05/16 18:31:47 christos Exp $ */ 2 3 /* 4 * Copyright (c) 1983, 1993 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 #include <sys/cdefs.h> 33 #ifndef lint 34 __COPYRIGHT("@(#) Copyright (c) 1983, 1993\ 35 The Regents of the University of California. All rights reserved."); 36 #endif /* not lint */ 37 38 #ifndef lint 39 #if 0 40 static char sccsid[] = "@(#)tunefs.c 8.3 (Berkeley) 5/3/95"; 41 #else 42 __RCSID("$NetBSD: tunefs.c,v 1.52 2020/05/16 18:31:47 christos Exp $"); 43 #endif 44 #endif /* not lint */ 45 46 /* 47 * tunefs: change layout parameters to an existing file system. 48 */ 49 #include <sys/param.h> 50 #include <sys/statvfs.h> 51 52 #include <ufs/ffs/fs.h> 53 #include <ufs/ffs/ffs_extern.h> 54 #include <ufs/ufs/ufs_wapbl.h> 55 #include <ufs/ufs/ufsmount.h> 56 #include <ufs/ufs/quota2.h> 57 58 #include <machine/bswap.h> 59 60 #include <err.h> 61 #include <errno.h> 62 #include <fcntl.h> 63 #include <fstab.h> 64 #include <paths.h> 65 #include <stdio.h> 66 #include <stdlib.h> 67 #include <string.h> 68 #include <unistd.h> 69 #include <util.h> 70 71 /* the optimization warning string template */ 72 #define OPTWARN "should optimize for %s with minfree %s %d%%" 73 74 union { 75 struct fs sb; 76 char data[MAXBSIZE]; 77 } sbun, buf; 78 #define sblock sbun.sb 79 80 int fi; 81 long dev_bsize = 512; 82 int needswap = 0; 83 int is_ufs2 = 0; 84 off_t sblockloc; 85 int userquota = 0; 86 int groupquota = 0; 87 #define Q2_EN (1) 88 #define Q2_IGN (0) 89 #define Q2_DIS (-1) 90 91 static off_t sblock_try[] = SBLOCKSEARCH; 92 93 static void bwrite(daddr_t, char *, int, const char *); 94 static void bread(daddr_t, char *, int, const char *); 95 static void change_log_info(long long); 96 static void getsb(struct fs *, const char *); 97 static int openpartition(const char *, int, char *, size_t); 98 static void show_log_info(void); 99 __dead static void usage(void); 100 101 int 102 main(int argc, char *argv[]) 103 { 104 int i, ch, aflag, pflag, Aflag, Fflag, Nflag, openflags; 105 const char *special, *chg[2]; 106 char device[MAXPATHLEN]; 107 int maxbpg, minfree, optim, secsize; 108 int avgfilesize, avgfpdir, active; 109 long long logfilesize; 110 int secshift, fsbtodb; 111 const char *avalue, *pvalue, *name; 112 struct statvfs sfs; 113 114 aflag = pflag = Aflag = Fflag = Nflag = 0; 115 avalue = pvalue = NULL; 116 maxbpg = minfree = optim = secsize = -1; 117 avgfilesize = avgfpdir = -1; 118 logfilesize = -1; 119 secshift = 0; 120 chg[FS_OPTSPACE] = "space"; 121 chg[FS_OPTTIME] = "time"; 122 123 while ((ch = getopt(argc, argv, "AFNa:e:g:h:l:m:o:p:q:S:")) != -1) { 124 switch (ch) { 125 126 case 'A': 127 Aflag++; 128 break; 129 130 case 'F': 131 Fflag++; 132 break; 133 134 case 'N': 135 Nflag++; 136 break; 137 138 case 'a': 139 name = "ACLs"; 140 avalue = optarg; 141 if (strcmp(avalue, "enable") && 142 strcmp(avalue, "disable")) { 143 errx(10, "bad %s (options are %s)", 144 name, "`enable' or `disable'"); 145 } 146 aflag = 1; 147 break; 148 149 case 'e': 150 maxbpg = strsuftoll( 151 "maximum blocks per file in a cylinder group", 152 optarg, 1, INT_MAX); 153 break; 154 155 case 'g': 156 avgfilesize = strsuftoll("average file size", optarg, 157 1, INT_MAX); 158 break; 159 160 case 'h': 161 avgfpdir = strsuftoll( 162 "expected number of files per directory", 163 optarg, 1, INT_MAX); 164 break; 165 166 case 'l': 167 logfilesize = strsuftoll("journal log file size", 168 optarg, 0, INT_MAX); 169 break; 170 171 case 'm': 172 minfree = strsuftoll("minimum percentage of free space", 173 optarg, 0, 99); 174 break; 175 176 case 'o': 177 if (strcmp(optarg, chg[FS_OPTSPACE]) == 0) 178 optim = FS_OPTSPACE; 179 else if (strcmp(optarg, chg[FS_OPTTIME]) == 0) 180 optim = FS_OPTTIME; 181 else 182 errx(10, 183 "bad %s (options are `space' or `time')", 184 "optimization preference"); 185 break; 186 187 case 'p': 188 name = "POSIX1e ACLs"; 189 pvalue = optarg; 190 if (strcmp(pvalue, "enable") && 191 strcmp(pvalue, "disable")) { 192 errx(10, "bad %s (options are %s)", 193 name, "`enable' or `disable'"); 194 } 195 pflag = 1; 196 break; 197 198 case 'q': 199 if (strcmp(optarg, "user") == 0) 200 userquota = Q2_EN; 201 else if (strcmp(optarg, "group") == 0) 202 groupquota = Q2_EN; 203 else if (strcmp(optarg, "nouser") == 0) 204 userquota = Q2_DIS; 205 else if (strcmp(optarg, "nogroup") == 0) 206 groupquota = Q2_DIS; 207 else 208 errx(11, "invalid quota type %s", optarg); 209 break; 210 211 case 'S': 212 secsize = strsuftoll("physical sector size", 213 optarg, 0, INT_MAX); 214 secshift = ffs(secsize) - 1; 215 if (secsize != 0 && 1 << secshift != secsize) 216 errx(12, "sector size %d is not a power of two", secsize); 217 break; 218 219 default: 220 usage(); 221 } 222 } 223 argc -= optind; 224 argv += optind; 225 if (argc != 1) 226 usage(); 227 228 special = argv[0]; 229 openflags = Nflag ? O_RDONLY : O_RDWR; 230 if (Fflag) 231 fi = open(special, openflags); 232 else { 233 fi = openpartition(special, openflags, device, sizeof(device)); 234 special = device; 235 } 236 active = fstatvfs(fi, &sfs) != -1; 237 if (fi == -1) 238 err(1, "%s", special); 239 getsb(&sblock, special); 240 241 #define CHANGEVAL(old, new, type, suffix) do \ 242 if ((new) != -1) { \ 243 if ((new) == (old)) \ 244 warnx("%s remains unchanged at %d%s", \ 245 (type), (old), (suffix)); \ 246 else { \ 247 warnx("%s changes from %d%s to %d%s", \ 248 (type), (old), (suffix), (new), (suffix)); \ 249 (old) = (new); \ 250 } \ 251 } while (/* CONSTCOND */0) 252 253 warnx("tuning %s", special); 254 CHANGEVAL(sblock.fs_maxbpg, maxbpg, 255 "maximum blocks per file in a cylinder group", ""); 256 CHANGEVAL(sblock.fs_minfree, minfree, 257 "minimum percentage of free space", "%"); 258 if (minfree != -1) { 259 if (minfree >= MINFREE && 260 sblock.fs_optim == FS_OPTSPACE) 261 warnx(OPTWARN, "time", ">=", MINFREE); 262 if (minfree < MINFREE && 263 sblock.fs_optim == FS_OPTTIME) 264 warnx(OPTWARN, "space", "<", MINFREE); 265 } 266 if (optim != -1) { 267 if (sblock.fs_optim == optim) { 268 warnx("%s remains unchanged as %s", 269 "optimization preference", 270 chg[optim]); 271 } else { 272 warnx("%s changes from %s to %s", 273 "optimization preference", 274 chg[sblock.fs_optim], chg[optim]); 275 sblock.fs_optim = optim; 276 if (sblock.fs_minfree >= MINFREE && 277 optim == FS_OPTSPACE) 278 warnx(OPTWARN, "time", ">=", MINFREE); 279 if (sblock.fs_minfree < MINFREE && 280 optim == FS_OPTTIME) 281 warnx(OPTWARN, "space", "<", MINFREE); 282 } 283 } 284 if (secsize != -1) { 285 if (secsize == 0) { 286 secsize = sblock.fs_fsize / FFS_FSBTODB(&sblock, 1); 287 secshift = ffs(secsize) - 1; 288 } 289 290 if (secshift < DEV_BSHIFT) 291 warnx("sector size must be at least %d", DEV_BSIZE); 292 else if (secshift > sblock.fs_fshift) 293 warnx("sector size %d cannot be larger than fragment size %d", 294 secsize, sblock.fs_fsize); 295 else { 296 fsbtodb = sblock.fs_fshift - secshift; 297 if (fsbtodb == sblock.fs_fsbtodb) { 298 warnx("sector size remains unchanged as %d", 299 sblock.fs_fsize / FFS_FSBTODB(&sblock, 1)); 300 } else { 301 warnx("sector size changed from %d to %d", 302 sblock.fs_fsize / FFS_FSBTODB(&sblock, 1), 303 secsize); 304 sblock.fs_fsbtodb = fsbtodb; 305 } 306 } 307 } 308 CHANGEVAL(sblock.fs_avgfilesize, avgfilesize, 309 "average file size", ""); 310 CHANGEVAL(sblock.fs_avgfpdir, avgfpdir, 311 "expected number of files per directory", ""); 312 313 if (logfilesize >= 0) 314 change_log_info(logfilesize); 315 if (userquota == Q2_EN || groupquota == Q2_EN) 316 sblock.fs_flags |= FS_DOQUOTA2; 317 if (sblock.fs_flags & FS_DOQUOTA2) { 318 sblock.fs_quota_magic = Q2_HEAD_MAGIC; 319 switch(userquota) { 320 case Q2_EN: 321 if ((sblock.fs_quota_flags & FS_Q2_DO_TYPE(USRQUOTA)) 322 == 0) { 323 printf("enabling user quotas\n"); 324 sblock.fs_quota_flags |= 325 FS_Q2_DO_TYPE(USRQUOTA); 326 sblock.fs_quotafile[USRQUOTA] = 0; 327 } 328 break; 329 case Q2_DIS: 330 if ((sblock.fs_quota_flags & FS_Q2_DO_TYPE(USRQUOTA)) 331 != 0) { 332 printf("disabling user quotas\n"); 333 sblock.fs_quota_flags &= 334 ~FS_Q2_DO_TYPE(USRQUOTA); 335 } 336 } 337 switch(groupquota) { 338 case Q2_EN: 339 if ((sblock.fs_quota_flags & FS_Q2_DO_TYPE(GRPQUOTA)) 340 == 0) { 341 printf("enabling group quotas\n"); 342 sblock.fs_quota_flags |= 343 FS_Q2_DO_TYPE(GRPQUOTA); 344 sblock.fs_quotafile[GRPQUOTA] = 0; 345 } 346 break; 347 case Q2_DIS: 348 if ((sblock.fs_quota_flags & FS_Q2_DO_TYPE(GRPQUOTA)) 349 != 0) { 350 printf("disabling group quotas\n"); 351 sblock.fs_quota_flags &= 352 ~FS_Q2_DO_TYPE(GRPQUOTA); 353 } 354 } 355 } 356 /* 357 * if we disabled all quotas, FS_DOQUOTA2 and associated inode(s) will 358 * be cleared by kernel or fsck. 359 */ 360 if (aflag) { 361 name = "ACLs"; 362 if (strcmp(avalue, "enable") == 0) { 363 if (sblock.fs_flags & FS_ACLS) { 364 warnx("%s remains unchanged as enabled", name); 365 } else if (sblock.fs_flags & FS_POSIX1EACLS) { 366 warnx("%s and POSIX.1e ACLs are mutually " 367 "exclusive", name); 368 } else { 369 sblock.fs_flags |= FS_ACLS; 370 printf("%s set\n", name); 371 } 372 } else if (strcmp(avalue, "disable") == 0) { 373 if ((~sblock.fs_flags & FS_ACLS) == FS_ACLS) { 374 warnx("%s remains unchanged as disabled", 375 name); 376 } else { 377 sblock.fs_flags &= ~FS_ACLS; 378 printf("%s cleared\n", name); 379 } 380 } 381 } 382 383 if (pflag) { 384 name = "POSIX1e ACLs"; 385 if (strcmp(pvalue, "enable") == 0) { 386 if (sblock.fs_flags & FS_POSIX1EACLS) { 387 warnx("%s remains unchanged as enabled", name); 388 } else if (sblock.fs_flags & FS_ACLS) { 389 warnx("%s and ACLs are mutually " 390 "exclusive", name); 391 } else { 392 sblock.fs_flags |= FS_POSIX1EACLS; 393 printf("%s set", name); 394 } 395 } else if (strcmp(pvalue, "disable") == 0) { 396 if ((~sblock.fs_flags & FS_POSIX1EACLS) == 397 FS_POSIX1EACLS) { 398 warnx("%s remains unchanged as disabled", 399 name); 400 } else { 401 sblock.fs_flags &= ~FS_POSIX1EACLS; 402 printf("%s cleared", name); 403 } 404 } 405 } 406 407 if (Nflag) { 408 printf("%s: current settings of %s\n", getprogname(), special); 409 printf("\tmaximum contiguous block count %d\n", 410 sblock.fs_maxcontig); 411 printf("\tmaximum blocks per file in a cylinder group %d\n", 412 sblock.fs_maxbpg); 413 printf("\tminimum percentage of free space %d%%\n", 414 sblock.fs_minfree); 415 printf("\toptimization preference: %s\n", chg[sblock.fs_optim]); 416 printf("\taverage file size: %d\n", sblock.fs_avgfilesize); 417 printf("\texpected number of files per directory: %d\n", 418 sblock.fs_avgfpdir); 419 show_log_info(); 420 printf("\tquotas"); 421 if (sblock.fs_flags & FS_DOQUOTA2) { 422 if (sblock.fs_quota_flags & FS_Q2_DO_TYPE(USRQUOTA)) { 423 printf(" user"); 424 if (sblock.fs_quota_flags & 425 FS_Q2_DO_TYPE(GRPQUOTA)) 426 printf(","); 427 } 428 if (sblock.fs_quota_flags & FS_Q2_DO_TYPE(GRPQUOTA)) 429 printf(" group"); 430 printf(" enabled\n"); 431 } else { 432 printf(" disabled\n"); 433 } 434 printf("\tPOSIX.1e ACLs %s\n", 435 (sblock.fs_flags & FS_POSIX1EACLS) ? "enabled" : "disabled"); 436 printf("\tACLs %s\n", 437 (sblock.fs_flags & FS_ACLS) ? "enabled" : "disabled"); 438 printf("%s: no changes made\n", getprogname()); 439 return 0; 440 } 441 442 memcpy(&buf, (char *)&sblock, SBLOCKSIZE); 443 if (needswap) 444 ffs_sb_swap((struct fs*)&buf, (struct fs*)&buf); 445 446 /* write superblock to original coordinates (use old dev_bsize!) */ 447 bwrite(sblockloc, buf.data, SBLOCKSIZE, special); 448 449 if (active) { 450 struct ufs_args args; 451 args.fspec = sfs.f_mntfromname; 452 if (mount(MOUNT_FFS, sfs.f_mntonname, sfs.f_flag | MNT_UPDATE, 453 &args, sizeof args) == -1) 454 warn("mount"); 455 else 456 printf("%s: mount of %s on %s updated\n", 457 getprogname(), sfs.f_mntfromname, sfs.f_mntonname); 458 } 459 460 461 /* correct dev_bsize from possibly changed superblock data */ 462 dev_bsize = sblock.fs_fsize / FFS_FSBTODB(&sblock, 1); 463 464 if (Aflag) 465 for (i = 0; i < sblock.fs_ncg; i++) 466 bwrite(FFS_FSBTODB(&sblock, cgsblock(&sblock, i)), 467 buf.data, SBLOCKSIZE, special); 468 close(fi); 469 exit(0); 470 } 471 472 static void 473 show_log_info(void) 474 { 475 const char *loc; 476 uint64_t size, blksize, logsize; 477 int print; 478 479 switch (sblock.fs_journal_location) { 480 case UFS_WAPBL_JOURNALLOC_NONE: 481 print = blksize = 0; 482 /* nothing */ 483 break; 484 case UFS_WAPBL_JOURNALLOC_END_PARTITION: 485 loc = "end of partition"; 486 size = sblock.fs_journallocs[UFS_WAPBL_EPART_COUNT]; 487 blksize = sblock.fs_journallocs[UFS_WAPBL_EPART_BLKSZ]; 488 print = 1; 489 break; 490 case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM: 491 loc = "in filesystem"; 492 size = sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT]; 493 blksize = sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ]; 494 print = 1; 495 break; 496 default: 497 loc = "unknown"; 498 size = blksize = 0; 499 print = 1; 500 break; 501 } 502 503 if (print) { 504 logsize = size * blksize; 505 506 printf("\tjournal log file location: %s\n", loc); 507 printf("\tjournal log file size: "); 508 if (logsize == 0) 509 printf("0\n"); 510 else { 511 char sizebuf[8]; 512 humanize_number(sizebuf, 6, size * blksize, "B", 513 HN_AUTOSCALE, HN_B | HN_NOSPACE | HN_DECIMAL); 514 printf("%s (%" PRId64 " bytes)", sizebuf, logsize); 515 } 516 printf("\n"); 517 printf("\tjournal log flags:"); 518 if (sblock.fs_journal_flags & UFS_WAPBL_FLAGS_CREATE_LOG) 519 printf(" create-log"); 520 if (sblock.fs_journal_flags & UFS_WAPBL_FLAGS_CLEAR_LOG) 521 printf(" clear-log"); 522 printf("\n"); 523 } 524 } 525 526 static void 527 change_log_info(long long logfilesize) 528 { 529 /* 530 * NOTES: 531 * - only operate on in-filesystem log sizes 532 * - can't change size of existing log 533 * - if current is same, no action 534 * - if current is zero and new is non-zero, set flag to create log 535 * on next mount 536 * - if current is non-zero and new is zero, set flag to clear log 537 * on next mount 538 */ 539 int in_fs_log; 540 uint64_t old_size; 541 542 old_size = 0; 543 switch (sblock.fs_journal_location) { 544 case UFS_WAPBL_JOURNALLOC_END_PARTITION: 545 in_fs_log = 0; 546 old_size = sblock.fs_journallocs[UFS_WAPBL_EPART_COUNT] * 547 sblock.fs_journallocs[UFS_WAPBL_EPART_BLKSZ]; 548 break; 549 550 case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM: 551 in_fs_log = 1; 552 old_size = sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT] * 553 sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ]; 554 break; 555 556 case UFS_WAPBL_JOURNALLOC_NONE: 557 default: 558 in_fs_log = 0; 559 old_size = 0; 560 break; 561 } 562 563 if (logfilesize == 0) { 564 /* 565 * Don't clear out the locators - the kernel might need 566 * these to find the log! Just set the "clear the log" 567 * flag and let the kernel do the rest. 568 */ 569 sblock.fs_journal_flags |= UFS_WAPBL_FLAGS_CLEAR_LOG; 570 sblock.fs_journal_flags &= ~UFS_WAPBL_FLAGS_CREATE_LOG; 571 warnx("log file size cleared from %" PRIu64 "", old_size); 572 return; 573 } 574 575 if (!in_fs_log && logfilesize > 0 && old_size > 0) 576 errx(1, "Can't change size of non-in-filesystem log"); 577 578 if (old_size == (uint64_t)logfilesize && logfilesize > 0) { 579 /* no action */ 580 warnx("log file size remains unchanged at %lld", logfilesize); 581 return; 582 } 583 584 if (old_size == 0) { 585 /* create new log of desired size next mount */ 586 sblock.fs_journal_location = UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM; 587 sblock.fs_journallocs[UFS_WAPBL_INFS_ADDR] = 0; 588 sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT] = logfilesize; 589 sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ] = 0; 590 sblock.fs_journallocs[UFS_WAPBL_INFS_INO] = 0; 591 sblock.fs_journal_flags |= UFS_WAPBL_FLAGS_CREATE_LOG; 592 sblock.fs_journal_flags &= ~UFS_WAPBL_FLAGS_CLEAR_LOG; 593 warnx("log file size set to %lld", logfilesize); 594 } else { 595 errx(1, 596 "Can't change existing log size from %" PRIu64 " to %lld", 597 old_size, logfilesize); 598 } 599 } 600 601 static void 602 usage(void) 603 { 604 605 fprintf(stderr, "usage: tunefs [-AFN] tuneup-options special-device\n"); 606 fprintf(stderr, "where tuneup-options are:\n"); 607 fprintf(stderr, "\t-a ACLS: `enable' or `disable'\n"); 608 fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n"); 609 fprintf(stderr, "\t-g average file size\n"); 610 fprintf(stderr, "\t-h expected number of files per directory\n"); 611 fprintf(stderr, "\t-l journal log file size (`0' to clear journal)\n"); 612 fprintf(stderr, "\t-m minimum percentage of free space\n"); 613 fprintf(stderr, "\t-p POSIX.1e ACLS: `enable' or `disable'\n"); 614 fprintf(stderr, "\t-o optimization preference (`space' or `time')\n"); 615 fprintf(stderr, "\t-q quota type (`[no]user' or `[no]group')\n"); 616 fprintf(stderr, "\t-S sector size\n"); 617 exit(2); 618 } 619 620 static void 621 getsb(struct fs *fs, const char *file) 622 { 623 int i; 624 625 for (i = 0; ; i++) { 626 if (sblock_try[i] == -1) 627 errx(5, "cannot find filesystem superblock"); 628 bread(sblock_try[i] / dev_bsize, (char *)fs, SBLOCKSIZE, file); 629 switch(fs->fs_magic) { 630 case FS_UFS2_MAGIC: 631 is_ufs2 = 1; 632 /*FALLTHROUGH*/ 633 case FS_UFS1_MAGIC: 634 break; 635 case FS_UFS2_MAGIC_SWAPPED: 636 is_ufs2 = 1; 637 /*FALLTHROUGH*/ 638 case FS_UFS1_MAGIC_SWAPPED: 639 warnx("%s: swapping byte order", file); 640 needswap = 1; 641 ffs_sb_swap(fs, fs); 642 break; 643 default: 644 continue; 645 } 646 if (!is_ufs2 && sblock_try[i] == SBLOCK_UFS2) 647 continue; 648 if ((is_ufs2 || fs->fs_old_flags & FS_FLAGS_UPDATED) 649 && fs->fs_sblockloc != sblock_try[i]) 650 continue; 651 break; 652 } 653 654 dev_bsize = fs->fs_fsize / FFS_FSBTODB(fs, 1); 655 sblockloc = sblock_try[i] / dev_bsize; 656 } 657 658 static void 659 bwrite(daddr_t blk, char *buffer, int size, const char *file) 660 { 661 off_t offset; 662 663 offset = (off_t)blk * dev_bsize; 664 if (lseek(fi, offset, SEEK_SET) == -1) 665 err(6, "%s: seeking to %lld", file, (long long)offset); 666 if (write(fi, buffer, size) != size) 667 err(7, "%s: writing %d bytes", file, size); 668 } 669 670 static void 671 bread(daddr_t blk, char *buffer, int cnt, const char *file) 672 { 673 off_t offset; 674 int i; 675 676 offset = (off_t)blk * dev_bsize; 677 if (lseek(fi, offset, SEEK_SET) == -1) 678 err(4, "%s: seeking to %lld", file, (long long)offset); 679 if ((i = read(fi, buffer, cnt)) != cnt) 680 errx(5, "%s: short read", file); 681 } 682 683 static int 684 openpartition(const char *name, int flags, char *device, size_t devicelen) 685 { 686 char specname[MAXPATHLEN]; 687 char rawname[MAXPATHLEN]; 688 const char *special, *raw; 689 struct fstab *fs; 690 int fd, oerrno; 691 692 fs = getfsfile(name); 693 special = fs ? fs->fs_spec : name; 694 695 raw = getfsspecname(specname, sizeof(specname), special); 696 if (raw == NULL) 697 err(1, "%s: %s", name, specname); 698 special = getdiskrawname(rawname, sizeof(rawname), raw); 699 if (special == NULL) 700 special = raw; 701 702 fd = opendisk(special, flags, device, devicelen, 0); 703 if (fd == -1 && errno == ENOENT) { 704 oerrno = errno; 705 strlcpy(device, special, devicelen); 706 errno = oerrno; 707 } 708 return (fd); 709 } 710