| @@ -0,0 +1,527 @@ | | | @@ -0,0 +1,527 @@ |
| | | 1 | /* $NetBSD: tunefs.c,v 1.34.2.2 2008/07/28 12:40:06 simonb 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.34.2.2 2008/07/28 12:40:06 simonb 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 | |
| | | 51 | #include <ufs/ffs/fs.h> |
| | | 52 | #include <ufs/ffs/ffs_extern.h> |
| | | 53 | #include <ufs/ufs/ufs_wapbl.h> |
| | | 54 | |
| | | 55 | #include <machine/bswap.h> |
| | | 56 | |
| | | 57 | #include <err.h> |
| | | 58 | #include <errno.h> |
| | | 59 | #include <fcntl.h> |
| | | 60 | #include <fstab.h> |
| | | 61 | #include <paths.h> |
| | | 62 | #include <stdio.h> |
| | | 63 | #include <stdlib.h> |
| | | 64 | #include <string.h> |
| | | 65 | #include <unistd.h> |
| | | 66 | #include <util.h> |
| | | 67 | |
| | | 68 | /* the optimization warning string template */ |
| | | 69 | #define OPTWARN "should optimize for %s with minfree %s %d%%" |
| | | 70 | |
| | | 71 | union { |
| | | 72 | struct fs sb; |
| | | 73 | char pad[MAXBSIZE]; |
| | | 74 | } sbun; |
| | | 75 | #define sblock sbun.sb |
| | | 76 | char buf[MAXBSIZE]; |
| | | 77 | |
| | | 78 | int fi; |
| | | 79 | long dev_bsize = 512; |
| | | 80 | int needswap = 0; |
| | | 81 | int is_ufs2 = 0; |
| | | 82 | off_t sblockloc; |
| | | 83 | |
| | | 84 | static off_t sblock_try[] = SBLOCKSEARCH; |
| | | 85 | |
| | | 86 | static void bwrite(daddr_t, char *, int, const char *); |
| | | 87 | static void bread(daddr_t, char *, int, const char *); |
| | | 88 | static void change_log_info(long long); |
| | | 89 | static void getsb(struct fs *, const char *); |
| | | 90 | static int openpartition(const char *, int, char *, size_t); |
| | | 91 | static void show_log_info(void); |
| | | 92 | static void usage(void); |
| | | 93 | |
| | | 94 | int |
| | | 95 | main(int argc, char *argv[]) |
| | | 96 | { |
| | | 97 | #define OPTSTRINGBASE "AFNe:g:h:l:m:o:" |
| | | 98 | #ifdef TUNEFS_SOFTDEP |
| | | 99 | int softdep; |
| | | 100 | #define OPTSTRING OPTSTRINGBASE ## "n:" |
| | | 101 | #else |
| | | 102 | #define OPTSTRING OPTSTRINGBASE |
| | | 103 | #endif |
| | | 104 | int i, ch, Aflag, Fflag, Nflag, openflags; |
| | | 105 | const char *special, *chg[2]; |
| | | 106 | char device[MAXPATHLEN]; |
| | | 107 | int maxbpg, minfree, optim; |
| | | 108 | int avgfilesize, avgfpdir; |
| | | 109 | long long logfilesize; |
| | | 110 | |
| | | 111 | Aflag = Fflag = Nflag = 0; |
| | | 112 | maxbpg = minfree = optim = -1; |
| | | 113 | avgfilesize = avgfpdir = -1; |
| | | 114 | logfilesize = -1; |
| | | 115 | #ifdef TUNEFS_SOFTDEP |
| | | 116 | softdep = -1; |
| | | 117 | #endif |
| | | 118 | chg[FS_OPTSPACE] = "space"; |
| | | 119 | chg[FS_OPTTIME] = "time"; |
| | | 120 | |
| | | 121 | while ((ch = getopt(argc, argv, OPTSTRING)) != -1) { |
| | | 122 | switch (ch) { |
| | | 123 | |
| | | 124 | case 'A': |
| | | 125 | Aflag++; |
| | | 126 | break; |
| | | 127 | |
| | | 128 | case 'F': |
| | | 129 | Fflag++; |
| | | 130 | break; |
| | | 131 | |
| | | 132 | case 'N': |
| | | 133 | Nflag++; |
| | | 134 | break; |
| | | 135 | |
| | | 136 | case 'e': |
| | | 137 | maxbpg = strsuftoll( |
| | | 138 | "maximum blocks per file in a cylinder group", |
| | | 139 | optarg, 1, INT_MAX); |
| | | 140 | break; |
| | | 141 | |
| | | 142 | case 'g': |
| | | 143 | avgfilesize = strsuftoll("average file size", optarg, |
| | | 144 | 1, INT_MAX); |
| | | 145 | break; |
| | | 146 | |
| | | 147 | case 'h': |
| | | 148 | avgfpdir = strsuftoll( |
| | | 149 | "expected number of files per directory", |
| | | 150 | optarg, 1, INT_MAX); |
| | | 151 | break; |
| | | 152 | |
| | | 153 | case 'l': |
| | | 154 | logfilesize = strsuftoll("journal log file size", |
| | | 155 | optarg, 0, INT_MAX); |
| | | 156 | break; |
| | | 157 | |
| | | 158 | case 'm': |
| | | 159 | minfree = strsuftoll("minimum percentage of free space", |
| | | 160 | optarg, 0, 99); |
| | | 161 | break; |
| | | 162 | |
| | | 163 | #ifdef TUNEFS_SOFTDEP |
| | | 164 | case 'n': |
| | | 165 | if (strcmp(optarg, "enable") == 0) |
| | | 166 | softdep = 1; |
| | | 167 | else if (strcmp(optarg, "disable") == 0) |
| | | 168 | softdep = 0; |
| | | 169 | else { |
| | | 170 | errx(10, "bad soft dependencies " |
| | | 171 | "(options are `enable' or `disable')"); |
| | | 172 | } |
| | | 173 | break; |
| | | 174 | #endif |
| | | 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 | default: |
| | | 188 | usage(); |
| | | 189 | } |
| | | 190 | } |
| | | 191 | argc -= optind; |
| | | 192 | argv += optind; |
| | | 193 | if (argc != 1) |
| | | 194 | usage(); |
| | | 195 | |
| | | 196 | special = argv[0]; |
| | | 197 | openflags = Nflag ? O_RDONLY : O_RDWR; |
| | | 198 | if (Fflag) |
| | | 199 | fi = open(special, openflags); |
| | | 200 | else { |
| | | 201 | fi = openpartition(special, openflags, device, sizeof(device)); |
| | | 202 | special = device; |
| | | 203 | } |
| | | 204 | if (fi == -1) |
| | | 205 | err(1, "%s", special); |
| | | 206 | getsb(&sblock, special); |
| | | 207 | |
| | | 208 | #define CHANGEVAL(old, new, type, suffix) do \ |
| | | 209 | if ((new) != -1) { \ |
| | | 210 | if ((new) == (old)) \ |
| | | 211 | warnx("%s remains unchanged at %d%s", \ |
| | | 212 | (type), (old), (suffix)); \ |
| | | 213 | else { \ |
| | | 214 | warnx("%s changes from %d%s to %d%s", \ |
| | | 215 | (type), (old), (suffix), (new), (suffix)); \ |
| | | 216 | (old) = (new); \ |
| | | 217 | } \ |
| | | 218 | } while (/* CONSTCOND */0) |
| | | 219 | |
| | | 220 | warnx("tuning %s", special); |
| | | 221 | CHANGEVAL(sblock.fs_maxbpg, maxbpg, |
| | | 222 | "maximum blocks per file in a cylinder group", ""); |
| | | 223 | CHANGEVAL(sblock.fs_minfree, minfree, |
| | | 224 | "minimum percentage of free space", "%"); |
| | | 225 | if (minfree != -1) { |
| | | 226 | if (minfree >= MINFREE && |
| | | 227 | sblock.fs_optim == FS_OPTSPACE) |
| | | 228 | warnx(OPTWARN, "time", ">=", MINFREE); |
| | | 229 | if (minfree < MINFREE && |
| | | 230 | sblock.fs_optim == FS_OPTTIME) |
| | | 231 | warnx(OPTWARN, "space", "<", MINFREE); |
| | | 232 | } |
| | | 233 | #ifdef TUNEFS_SOFTDEP |
| | | 234 | if (softdep == 1) { |
| | | 235 | sblock.fs_flags |= FS_DOSOFTDEP; |
| | | 236 | warnx("soft dependencies set"); |
| | | 237 | } else if (softdep == 0) { |
| | | 238 | sblock.fs_flags &= ~FS_DOSOFTDEP; |
| | | 239 | warnx("soft dependencies cleared"); |
| | | 240 | } |
| | | 241 | #endif |
| | | 242 | if (optim != -1) { |
| | | 243 | if (sblock.fs_optim == optim) { |
| | | 244 | warnx("%s remains unchanged as %s", |
| | | 245 | "optimization preference", |
| | | 246 | chg[optim]); |
| | | 247 | } else { |
| | | 248 | warnx("%s changes from %s to %s", |
| | | 249 | "optimization preference", |
| | | 250 | chg[sblock.fs_optim], chg[optim]); |
| | | 251 | sblock.fs_optim = optim; |
| | | 252 | if (sblock.fs_minfree >= MINFREE && |
| | | 253 | optim == FS_OPTSPACE) |
| | | 254 | warnx(OPTWARN, "time", ">=", MINFREE); |
| | | 255 | if (sblock.fs_minfree < MINFREE && |
| | | 256 | optim == FS_OPTTIME) |
| | | 257 | warnx(OPTWARN, "space", "<", MINFREE); |
| | | 258 | } |
| | | 259 | } |
| | | 260 | CHANGEVAL(sblock.fs_avgfilesize, avgfilesize, |
| | | 261 | "average file size", ""); |
| | | 262 | CHANGEVAL(sblock.fs_avgfpdir, avgfpdir, |
| | | 263 | "expected number of files per directory", ""); |
| | | 264 | |
| | | 265 | if (logfilesize >= 0) |
| | | 266 | change_log_info(logfilesize); |
| | | 267 | |
| | | 268 | if (Nflag) { |
| | | 269 | fprintf(stdout, "tunefs: current settings of %s\n", special); |
| | | 270 | fprintf(stdout, "\tmaximum contiguous block count %d\n", |
| | | 271 | sblock.fs_maxcontig); |
| | | 272 | fprintf(stdout, |
| | | 273 | "\tmaximum blocks per file in a cylinder group %d\n", |
| | | 274 | sblock.fs_maxbpg); |
| | | 275 | fprintf(stdout, "\tminimum percentage of free space %d%%\n", |
| | | 276 | sblock.fs_minfree); |
| | | 277 | #ifdef TUNEFS_SOFTDEP |
| | | 278 | fprintf(stdout, "\tsoft dependencies: %s\n", |
| | | 279 | (sblock.fs_flags & FS_DOSOFTDEP) ? "on" : "off"); |
| | | 280 | #endif |
| | | 281 | fprintf(stdout, "\toptimization preference: %s\n", |
| | | 282 | chg[sblock.fs_optim]); |
| | | 283 | fprintf(stdout, "\taverage file size: %d\n", |
| | | 284 | sblock.fs_avgfilesize); |
| | | 285 | fprintf(stdout, |
| | | 286 | "\texpected number of files per directory: %d\n", |
| | | 287 | sblock.fs_avgfpdir); |
| | | 288 | show_log_info(); |
| | | 289 | fprintf(stdout, "tunefs: no changes made\n"); |
| | | 290 | exit(0); |
| | | 291 | } |
| | | 292 | |
| | | 293 | memcpy(buf, (char *)&sblock, SBLOCKSIZE); |
| | | 294 | if (needswap) |
| | | 295 | ffs_sb_swap((struct fs*)buf, (struct fs*)buf); |
| | | 296 | bwrite(sblockloc, buf, SBLOCKSIZE, special); |
| | | 297 | if (Aflag) |
| | | 298 | for (i = 0; i < sblock.fs_ncg; i++) |
| | | 299 | bwrite(fsbtodb(&sblock, cgsblock(&sblock, i)), |
| | | 300 | buf, SBLOCKSIZE, special); |
| | | 301 | close(fi); |
| | | 302 | exit(0); |
| | | 303 | } |
| | | 304 | |
| | | 305 | static void |
| | | 306 | show_log_info(void) |
| | | 307 | { |
| | | 308 | const char *loc; |
| | | 309 | uint64_t size, blksize; |
| | | 310 | int print; |
| | | 311 | |
| | | 312 | switch (sblock.fs_journal_location) { |
| | | 313 | case UFS_WAPBL_JOURNALLOC_NONE: |
| | | 314 | print = blksize = 0; |
| | | 315 | /* nothing */ |
| | | 316 | break; |
| | | 317 | case UFS_WAPBL_JOURNALLOC_END_PARTITION: |
| | | 318 | loc = "end of partition"; |
| | | 319 | size = sblock.fs_journallocs[UFS_WAPBL_EPART_COUNT]; |
| | | 320 | blksize = sblock.fs_journallocs[UFS_WAPBL_EPART_BLKSZ]; |
| | | 321 | print = 1; |
| | | 322 | break; |
| | | 323 | case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM: |
| | | 324 | loc = "in filesystem"; |
| | | 325 | size = sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT]; |
| | | 326 | blksize = sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ]; |
| | | 327 | print = 1; |
| | | 328 | break; |
| | | 329 | default: |
| | | 330 | loc = "unknown"; |
| | | 331 | size = blksize = 0; |
| | | 332 | print = 1; |
| | | 333 | break; |
| | | 334 | } |
| | | 335 | |
| | | 336 | if (print) { |
| | | 337 | fprintf(stdout, "\tjournal log file location: %s\n", loc); |
| | | 338 | fprintf(stdout, "\tjournal log file size: %" PRIu64 "\n", |
| | | 339 | size * blksize); |
| | | 340 | fprintf(stdout, "\tjournal log flags:"); |
| | | 341 | if (sblock.fs_journal_flags & UFS_WAPBL_FLAGS_CREATE_LOG) |
| | | 342 | fprintf(stdout, " clear-log"); |
| | | 343 | if (sblock.fs_journal_flags & UFS_WAPBL_FLAGS_CLEAR_LOG) |
| | | 344 | fprintf(stdout, " clear-log"); |
| | | 345 | fprintf(stdout, "\n"); |
| | | 346 | } |
| | | 347 | } |
| | | 348 | |
| | | 349 | static void |
| | | 350 | change_log_info(long long logfilesize) |
| | | 351 | { |
| | | 352 | /* |
| | | 353 | * NOTES: |
| | | 354 | * - only operate on in-filesystem log sizes |
| | | 355 | * - can't change size of existing log |
| | | 356 | * - if current is same, no action |
| | | 357 | * - if current is zero and new is non-zero, set flag to create log |
| | | 358 | * on next mount |
| | | 359 | * - if current is non-zero and new is zero, set flag to clear log |
| | | 360 | * on next mount |
| | | 361 | */ |
| | | 362 | int in_fs_log; |
| | | 363 | uint64_t old_size; |
| | | 364 | |
| | | 365 | old_size = 0; |
| | | 366 | switch (sblock.fs_journal_location) { |
| | | 367 | case UFS_WAPBL_JOURNALLOC_END_PARTITION: |
| | | 368 | in_fs_log = 0; |
| | | 369 | old_size = sblock.fs_journallocs[UFS_WAPBL_EPART_COUNT] * |
| | | 370 | sblock.fs_journallocs[UFS_WAPBL_EPART_BLKSZ]; |
| | | 371 | break; |
| | | 372 | |
| | | 373 | case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM: |
| | | 374 | in_fs_log = 1; |
| | | 375 | old_size = sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT] * |
| | | 376 | sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ]; |
| | | 377 | break; |
| | | 378 | |
| | | 379 | case UFS_WAPBL_JOURNALLOC_NONE: |
| | | 380 | default: |
| | | 381 | in_fs_log = 0; |
| | | 382 | old_size = 0; |
| | | 383 | break; |
| | | 384 | } |
| | | 385 | |
| | | 386 | if (!in_fs_log) |
| | | 387 | errx(1, "Can't change size of non-in-filesystem log"); |
| | | 388 | |
| | | 389 | if (old_size == logfilesize && logfilesize > 0) { |
| | | 390 | /* no action */ |
| | | 391 | warnx("log file size remains unchanged at %lld", logfilesize); |
| | | 392 | return; |
| | | 393 | } |
| | | 394 | |
| | | 395 | if (logfilesize == 0) { |
| | | 396 | /* |
| | | 397 | * Don't clear out the locators - the kernel might need |
| | | 398 | * these to find the log! Just set the "clear the log" |
| | | 399 | * flag and let the kernel do the rest. |
| | | 400 | */ |
| | | 401 | sblock.fs_journal_flags |= UFS_WAPBL_FLAGS_CLEAR_LOG; |
| | | 402 | sblock.fs_journal_flags &= ~UFS_WAPBL_FLAGS_CREATE_LOG; |
| | | 403 | warnx("log file size cleared from %" PRIu64 "", old_size); |
| | | 404 | return; |
| | | 405 | } |
| | | 406 | |
| | | 407 | if (old_size == 0) { |
| | | 408 | /* create new log of desired size next mount */ |
| | | 409 | sblock.fs_journal_location = UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM; |
| | | 410 | sblock.fs_journallocs[UFS_WAPBL_INFS_ADDR] = 0; |
| | | 411 | sblock.fs_journallocs[UFS_WAPBL_INFS_COUNT] = logfilesize; |
| | | 412 | sblock.fs_journallocs[UFS_WAPBL_INFS_BLKSZ] = 0; |
| | | 413 | sblock.fs_journallocs[UFS_WAPBL_INFS_INO] = 0; |
| | | 414 | sblock.fs_journal_flags |= UFS_WAPBL_FLAGS_CREATE_LOG; |
| | | 415 | sblock.fs_journal_flags &= ~UFS_WAPBL_FLAGS_CLEAR_LOG; |
| | | 416 | warnx("log file size set to %lld", logfilesize); |
| | | 417 | } else { |
| | | 418 | errx(1, "Can't change existing log size from %" PRIu64 " to %d", |
| | | 419 | old_size, logfilesize); |
| | | 420 | } |
| | | 421 | } |
| | | 422 | |
| | | 423 | static void |
| | | 424 | usage(void) |
| | | 425 | { |
| | | 426 | |
| | | 427 | fprintf(stderr, "usage: tunefs [-AFN] tuneup-options special-device\n"); |
| | | 428 | fprintf(stderr, "where tuneup-options are:\n"); |
| | | 429 | fprintf(stderr, "\t-e maximum blocks per file in a cylinder group\n"); |
| | | 430 | fprintf(stderr, "\t-g average file size\n"); |
| | | 431 | fprintf(stderr, "\t-h expected number of files per directory\n"); |
| | | 432 | fprintf(stderr, "\t-l journal log file size (`0' to clear journal)\n"); |
| | | 433 | fprintf(stderr, "\t-m minimum percentage of free space\n"); |
| | | 434 | #ifdef TUNEFS_SOFTDEP |
| | | 435 | fprintf(stderr, "\t-n soft dependencies (`enable' or `disable')\n"); |
| | | 436 | #endif |
| | | 437 | fprintf(stderr, "\t-o optimization preference (`space' or `time')\n"); |
| | | 438 | exit(2); |
| | | 439 | } |
| | | 440 | |
| | | 441 | static void |
| | | 442 | getsb(struct fs *fs, const char *file) |
| | | 443 | { |
| | | 444 | int i; |
| | | 445 | |
| | | 446 | for (i = 0; ; i++) { |
| | | 447 | if (sblock_try[i] == -1) |
| | | 448 | errx(5, "cannot find filesystem superblock"); |
| | | 449 | bread(sblock_try[i] / dev_bsize, (char *)fs, SBLOCKSIZE, file); |
| | | 450 | switch(fs->fs_magic) { |
| | | 451 | case FS_UFS2_MAGIC: |
| | | 452 | is_ufs2 = 1; |
| | | 453 | /*FALLTHROUGH*/ |
| | | 454 | case FS_UFS1_MAGIC: |
| | | 455 | break; |
| | | 456 | case FS_UFS2_MAGIC_SWAPPED: |
| | | 457 | is_ufs2 = 1; |
| | | 458 | /*FALLTHROUGH*/ |
| | | 459 | case FS_UFS1_MAGIC_SWAPPED: |
| | | 460 | warnx("%s: swapping byte order", file); |
| | | 461 | needswap = 1; |
| | | 462 | ffs_sb_swap(fs, fs); |
| | | 463 | break; |
| | | 464 | default: |
| | | 465 | continue; |
| | | 466 | } |
| | | 467 | if (!is_ufs2 && sblock_try[i] == SBLOCK_UFS2) |
| | | 468 | continue; |
| | | 469 | if ((is_ufs2 || fs->fs_old_flags & FS_FLAGS_UPDATED) |
| | | 470 | && fs->fs_sblockloc != sblock_try[i]) |
| | | 471 | continue; |
| | | 472 | break; |
| | | 473 | } |
| | | 474 | |
| | | 475 | dev_bsize = fs->fs_fsize / fsbtodb(fs, 1); |
| | | 476 | sblockloc = sblock_try[i] / dev_bsize; |
| | | 477 | } |
| | | 478 | |
| | | 479 | static void |
| | | 480 | bwrite(daddr_t blk, char *buffer, int size, const char *file) |
| | | 481 | { |
| | | 482 | off_t offset; |
| | | 483 | |
| | | 484 | offset = (off_t)blk * dev_bsize; |
| | | 485 | if (lseek(fi, offset, SEEK_SET) == -1) |
| | | 486 | err(6, "%s: seeking to %lld", file, (long long)offset); |
| | | 487 | if (write(fi, buffer, size) != size) |
| | | 488 | err(7, "%s: writing %d bytes", file, size); |
| | | 489 | } |
| | | 490 | |
| | | 491 | static void |
| | | 492 | bread(daddr_t blk, char *buffer, int cnt, const char *file) |
| | | 493 | { |
| | | 494 | off_t offset; |
| | | 495 | int i; |
| | | 496 | |
| | | 497 | offset = (off_t)blk * dev_bsize; |
| | | 498 | if (lseek(fi, offset, SEEK_SET) == -1) |
| | | 499 | err(4, "%s: seeking to %lld", file, (long long)offset); |
| | | 500 | if ((i = read(fi, buffer, cnt)) != cnt) |
| | | 501 | errx(5, "%s: short read", file); |
| | | 502 | } |
| | | 503 | |
| | | 504 | static int |
| | | 505 | openpartition(const char *name, int flags, char *device, size_t devicelen) |
| | | 506 | { |
| | | 507 | char rawspec[MAXPATHLEN], *p; |
| | | 508 | struct fstab *fs; |
| | | 509 | int fd, oerrno; |
| | | 510 | |
| | | 511 | fs = getfsfile(name); |
| | | 512 | if (fs) { |
| | | 513 | if ((p = strrchr(fs->fs_spec, '/')) != NULL) { |
| | | 514 | snprintf(rawspec, sizeof(rawspec), "%.*s/r%s", |
| | | 515 | (int)(p - fs->fs_spec), fs->fs_spec, p + 1); |
| | | 516 | name = rawspec; |
| | | 517 | } else |
| | | 518 | name = fs->fs_spec; |
| | | 519 | } |
| | | 520 | fd = opendisk(name, flags, device, devicelen, 0); |
| | | 521 | if (fd == -1 && errno == ENOENT) { |
| | | 522 | oerrno = errno; |
| | | 523 | strlcpy(device, name, devicelen); |
| | | 524 | errno = oerrno; |
| | | 525 | } |
| | | 526 | return (fd); |
| | | 527 | } |