1/* $NetBSD: sgivol.c,v 1.22 2024/05/13 00:11:22 msaitoh Exp $ */ 2 3/*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Michael Hitch and Hubert Feyrer. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32#if HAVE_NBTOOL_CONFIG_H 33#include "nbtool_config.h" 34#endif 35 36#include <sys/types.h> 37#include <sys/ioctl.h> 38#include <sys/stat.h> 39 40#if HAVE_NBTOOL_CONFIG_H 41#include "../../../../../sys/sys/bootblock.h" 42/* Fictitious geometry for cross tool usage against a file image */ 43#define SGIVOL_NBTOOL_NSECS 32 44#define SGIVOL_NBTOOL_NTRACKS 64 45#else 46#include <sys/disklabel.h> 47#endif 48 49#include <errno.h> 50#include <stdio.h> 51#include <stdlib.h> 52#include <unistd.h> 53#include <string.h> 54#include <fcntl.h> 55#include <util.h> 56#include <err.h> 57#ifndef HAVE_NBTOOL_CONFIG_H 58#include <sys/endian.h> 59#endif 60 61int fd; 62int opt_i; /* Initialize volume header */ 63int opt_r; /* Read a file from volume header */ 64int opt_w; /* Write a file to volume header */ 65int opt_d; /* Delete a file from volume header */ 66int opt_m; /* Move (rename) a file in the volume header */ 67int opt_p; /* Modify a partition */ 68int opt_q; /* quiet mode */ 69int opt_f; /* Don't ask, just do what you're told */ 70int partno, partfirst, partblocks, parttype; 71struct sgi_boot_block *volhdr; 72int32_t checksum; 73u_int32_t volhdr_size = SGI_BOOT_BLOCK_SIZE_VOLHDR; 74 75const char *vfilename = ""; 76const char *ufilename = ""; 77 78#if HAVE_NBTOOL_CONFIG_H 79struct stat st; 80#else 81struct disklabel lbl; 82#endif 83 84char buf[512]; 85 86const char *sgi_types[] = { 87 "Volume Header", 88 "Repl Trks", 89 "Repl Secs", 90 "Raw", 91 "BSD4.2", 92 "SysV", 93 "Volume", 94 "EFS", 95 "LVol", 96 "RLVol", 97 "XFS", 98 "XSFLog", 99 "XLV", 100 "XVM" 101}; 102 103void display_vol(void); 104void init_volhdr(const char *); 105void read_file(void); 106void write_file(const char *); 107void delete_file(const char *); 108void move_file(const char *); 109void modify_partition(const char *); 110void write_volhdr(const char *); 111int allocate_space(int); 112void checksum_vol(void); 113int names_match(int, const char *); 114void usage(void) __dead; 115 116int 117main(int argc, char *argv[]) 118{ 119#define RESET_OPTS() opt_i = opt_m = opt_r = opt_w = opt_d = opt_p = 0 120 121 int ch; 122 while ((ch = getopt(argc, argv, "qfih:rwdmp?")) != -1) { 123 switch (ch) { 124 /* -i, -r, -w, -d, -m and -p override each other */ 125 /* -q implies -f */ 126 case 'q': 127 ++opt_q; 128 ++opt_f; 129 break; 130 case 'f': 131 ++opt_f; 132 break; 133 case 'i': 134 RESET_OPTS(); 135 ++opt_i; 136 break; 137 case 'h': 138 volhdr_size = atoi(optarg); 139 break; 140 case 'r': 141 RESET_OPTS(); 142 ++opt_r; 143 break; 144 case 'w': 145 RESET_OPTS(); 146 ++opt_w; 147 break; 148 case 'd': 149 RESET_OPTS(); 150 ++opt_d; 151 break; 152 case 'm': 153 RESET_OPTS(); 154 ++opt_m; 155 break; 156 case 'p': 157 RESET_OPTS(); 158 ++opt_p; 159 partno = atoi(argv[0]); 160 partfirst = atoi(argv[1]); 161 partblocks = atoi(argv[2]); 162 parttype = atoi(argv[3]); 163 break; 164 case '?': 165 default: 166 usage(); 167 } 168 } 169 argc -= optind; 170 argv += optind; 171 172 if (opt_m || opt_r || opt_w) { 173 if (argc != 3) 174 usage(); 175 vfilename = argv[0]; 176 ufilename = argv[1]; 177 argc -= 2; 178 argv += 2; 179 } 180 if (opt_d) { 181 if (argc != 2) 182 usage(); 183 vfilename = argv[0]; 184 argc--; 185 argv++; 186 } 187 188 if (opt_p) { 189 if (argc != 5) 190 usage(); 191 partno = atoi(argv[0]); 192 partfirst = atoi(argv[1]); 193 partblocks = atoi(argv[2]); 194 parttype = atoi(argv[3]); 195 argc -= 4; 196 argv += 4; 197 } 198 if (argc != 1) 199 usage(); 200 201 fd = open(argv[0], 202 (opt_i | opt_m | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY); 203 if (fd == -1) { 204#ifndef HAVE_NBTOOL_CONFIG_H 205 snprintf(buf, sizeof(buf), "/dev/r%s%c", argv[0], 206 'a' + getrawpartition()); 207 fd = open(buf, (opt_i | opt_w | opt_d | opt_p) 208 ? O_RDWR : O_RDONLY); 209 if (fd == -1) 210#endif 211 err(EXIT_FAILURE, "Error opening device `%s'", argv[0]); 212 } 213 214 if (read(fd, buf, sizeof(buf)) != sizeof(buf)) 215 err(EXIT_FAILURE, "Can't read volhdr from `%s'", argv[0]); 216 217#if HAVE_NBTOOL_CONFIG_H 218 if (fstat(fd, &st) == -1) 219 err(EXIT_FAILURE, "Can't stat `%s'", argv[0]); 220 if (!S_ISREG(st.st_mode)) 221 errx(EXIT_FAILURE, "Not a regular file `%s'", argv[0]); 222 223 if (st.st_size % SGI_BOOT_BLOCK_BLOCKSIZE) 224 errx(EXIT_FAILURE, "Size must be multiple of %d", 225 SGI_BOOT_BLOCK_BLOCKSIZE); 226 if (st.st_size < (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS)) 227 errx(EXIT_FAILURE, "Minimum size of %d required", 228 SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS); 229#else 230 if (ioctl(fd, DIOCGDINFO, &lbl) == -1) 231 err(EXIT_FAILURE, "ioctl DIOCGDINFO failed"); 232#endif 233 volhdr = (struct sgi_boot_block *) buf; 234 if (opt_i) { 235 init_volhdr(argv[0]); 236 return 0; 237 } 238 if (be32toh(volhdr->magic) != SGI_BOOT_BLOCK_MAGIC) 239 errx(EXIT_FAILURE, "No Volume Header found, magic=%x. " 240 "Use -i first.\n", be32toh(volhdr->magic)); 241 if (opt_r) { 242 read_file(); 243 return 0; 244 } 245 if (opt_w) { 246 write_file(argv[0]); 247 return 0; 248 } 249 if (opt_d) { 250 delete_file(argv[0]); 251 return 0; 252 } 253 if (opt_m) { 254 move_file(argv[0]); 255 return 0; 256 } 257 if (opt_p) { 258 modify_partition(argv[0]); 259 return 0; 260 } 261 262 if (!opt_q) 263 display_vol(); 264 265 return 0; 266} 267 268/* 269 * Compare the name in `slot' of voldir to `b'. Be careful, as the 270 * name in voldir need not be nul-terminated and `b' may be longer 271 * than the maximum (in which case it will never match). 272 * 273 * Returns non-0 if names are equal. 274 */ 275int 276names_match(int slot, const char *b) 277{ 278 int cmp; 279 280 if (slot < 0 || slot >= SGI_BOOT_BLOCK_MAXVOLDIRS) 281 errx(EXIT_FAILURE, "Internal error: bad slot in %s()", 282 __func__); 283 284 cmp = strncmp(volhdr->voldir[slot].name, b, 285 sizeof(volhdr->voldir[slot].name)); 286 287 return cmp == 0 && strlen(b) <= sizeof(volhdr->voldir[slot].name); 288} 289 290void 291display_vol(void) 292{ 293 int32_t *l; 294 int i; 295 296#if HAVE_NBTOOL_CONFIG_H 297 printf("disklabel shows %d sectors\n", 298 st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE); 299#else 300 printf("disklabel shows %d sectors\n", lbl.d_secperunit); 301#endif 302 l = (int32_t *)buf; 303 checksum = 0; 304 for (i = 0; i < 512 / 4; ++i) 305 checksum += be32toh(l[i]); 306 printf("checksum: %08x%s\n", checksum, checksum == 0 ? "" : " *ERROR*"); 307 printf("root part: %d\n", be16toh(volhdr->root)); 308 printf("swap part: %d\n", be16toh(volhdr->swap)); 309 printf("bootfile: %s\n", volhdr->bootfile); 310 /* volhdr->devparams[0..47] */ 311 printf("\nVolume header files:\n"); 312 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) 313 if (volhdr->voldir[i].name[0]) 314 printf("%-8s offset %4d blocks, length %8d bytes " 315 "(%d blocks)\n", 316 volhdr->voldir[i].name, 317 be32toh(volhdr->voldir[i].block), 318 be32toh(volhdr->voldir[i].bytes), 319 (be32toh(volhdr->voldir[i].bytes) + 511) / 512); 320 printf("\nSGI partitions:\n"); 321 for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; ++i) { 322 if (be32toh(volhdr->partitions[i].blocks)) { 323 printf("%2d:%c blocks %8d first %8d type %2d (%s)\n", 324 i, i + 'a', be32toh(volhdr->partitions[i].blocks), 325 be32toh(volhdr->partitions[i].first), 326 be32toh(volhdr->partitions[i].type), 327 be32toh(volhdr->partitions[i].type) > 13 ? "???" : 328 sgi_types[be32toh(volhdr->partitions[i].type)]); 329 } 330 } 331} 332 333void 334init_volhdr(const char *fname) 335{ 336 memset(buf, 0, sizeof(buf)); 337 volhdr->magic = htobe32(SGI_BOOT_BLOCK_MAGIC); 338 volhdr->root = htobe16(0); 339 volhdr->swap = htobe16(1); 340 strcpy(volhdr->bootfile, "/netbsd"); 341#if HAVE_NBTOOL_CONFIG_H 342 volhdr->dp.dp_skew = 0; 343#else 344 volhdr->dp.dp_skew = lbl.d_trackskew; 345#endif 346 volhdr->dp.dp_gap1 = 1; /* XXX */ 347 volhdr->dp.dp_gap2 = 1; /* XXX */ 348#if HAVE_NBTOOL_CONFIG_H 349 volhdr->dp.dp_cyls = 350 htobe16(st.st_size / (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS)); 351#else 352 volhdr->dp.dp_cyls = htobe16(lbl.d_ncylinders); 353#endif 354 volhdr->dp.dp_shd0 = 0; 355#if HAVE_NBTOOL_CONFIG_H 356 volhdr->dp.dp_trks0 = htobe16(SGIVOL_NBTOOL_NTRACKS); 357 volhdr->dp.dp_secs = htobe16(SGIVOL_NBTOOL_NSECS); 358 volhdr->dp.dp_secbytes = htobe16(SGI_BOOT_BLOCK_BLOCKSIZE); 359 volhdr->dp.dp_interleave = htobe16(1); 360#else 361 volhdr->dp.dp_trks0 = htobe16(lbl.d_ntracks); 362 volhdr->dp.dp_secs = htobe16(lbl.d_nsectors); 363 volhdr->dp.dp_secbytes = htobe16(lbl.d_secsize); 364 volhdr->dp.dp_interleave = htobe16(lbl.d_interleave); 365#endif 366 volhdr->dp.dp_nretries = htobe32(22); 367#if HAVE_NBTOOL_CONFIG_H 368 volhdr->partitions[10].blocks = 369 htobe32(st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE); 370#else 371 volhdr->partitions[10].blocks = htobe32(lbl.d_secperunit); 372#endif 373 volhdr->partitions[10].first = 0; 374 volhdr->partitions[10].type = htobe32(SGI_PTYPE_VOLUME); 375 volhdr->partitions[8].blocks = htobe32(volhdr_size); 376 volhdr->partitions[8].first = 0; 377 volhdr->partitions[8].type = htobe32(SGI_PTYPE_VOLHDR); 378#if HAVE_NBTOOL_CONFIG_H 379 volhdr->partitions[0].blocks = 380 htobe32((st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE) - volhdr_size); 381#else 382 volhdr->partitions[0].blocks = htobe32(lbl.d_secperunit - volhdr_size); 383#endif 384 volhdr->partitions[0].first = htobe32(volhdr_size); 385 volhdr->partitions[0].type = htobe32(SGI_PTYPE_BSD); 386 write_volhdr(fname); 387} 388 389void 390read_file(void) 391{ 392 FILE *fp; 393 int i; 394 395 if (!opt_q) 396 printf("Reading file %s\n", vfilename); 397 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) { 398 if (strncmp(vfilename, volhdr->voldir[i].name, 399 strlen(volhdr->voldir[i].name)) == 0) 400 break; 401 } 402 if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) 403 errx(EXIT_FAILURE, "File `%s' not found", vfilename); 404 /* XXX assumes volume header starts at 0? */ 405 lseek(fd, be32toh(volhdr->voldir[i].block) * 512, SEEK_SET); 406 fp = fopen(ufilename, "w"); 407 if (fp == NULL) 408 err(EXIT_FAILURE, "Can't open `%s'", ufilename); 409 i = be32toh(volhdr->voldir[i].bytes); 410 while (i > 0) { 411 if (read(fd, buf, sizeof(buf)) != sizeof(buf)) 412 err(EXIT_FAILURE, "Error reading from `%s'", ufilename); 413 fwrite(buf, 1, i > sizeof(buf) ? sizeof(buf) : i, fp); 414 i -= i > sizeof(buf) ? sizeof(buf) : i; 415 } 416 fclose(fp); 417} 418 419void 420write_file(const char *fname) 421{ 422 FILE *fp; 423 int slot; 424 size_t namelen; 425 int block, i; 426 off_t off; 427 struct stat st; 428 char fbuf[512]; 429 430 if (!opt_q) 431 printf("Writing file %s\n", ufilename); 432 if (stat(ufilename, &st) == -1) 433 err(EXIT_FAILURE, "Can't stat `%s'", ufilename); 434 if (!opt_q) 435 printf("File %s has %ju bytes\n", ufilename, 436 (uintmax_t)st.st_size); 437 slot = -1; 438 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) { 439 if (volhdr->voldir[i].name[0] == '\0' && slot < 0) 440 slot = i; 441 if (names_match(i, vfilename)) { 442 slot = i; 443 break; 444 } 445 } 446 if (slot == -1) 447 errx(EXIT_FAILURE, "No directory space for file %s", vfilename); 448 /* -w can overwrite, -a won't overwrite */ 449 if (be32toh(volhdr->voldir[slot].block) > 0) { 450 if (!opt_q) 451 printf("File %s exists, removing old file\n", 452 vfilename); 453 volhdr->voldir[slot].name[0] = 0; 454 volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0; 455 } 456 if (st.st_size == 0) { 457 errx(EXIT_FAILURE, "Empty file `%s'", ufilename); 458 exit(1); 459 } 460 /* XXX assumes volume header starts at 0? */ 461 block = allocate_space((int)st.st_size); 462 if (block < 0) 463 errx(EXIT_FAILURE, "No space for file `%s'", vfilename); 464 465 /* 466 * Make sure the name in the volume header is max. 8 chars, 467 * NOT including NUL. 468 */ 469 namelen = strlen(vfilename); 470 if (namelen > sizeof(volhdr->voldir[slot].name)) { 471 printf("Warning: '%s' is too long for volume header, ", 472 vfilename); 473 namelen = sizeof(volhdr->voldir[slot].name); 474 printf("truncating to '%.8s'\n", vfilename); 475 } 476 477 /* Populate it w/ NULs */ 478 memset(volhdr->voldir[slot].name, 0, 479 sizeof(volhdr->voldir[slot].name)); 480 /* Then copy the name */ 481 memcpy(volhdr->voldir[slot].name, vfilename, namelen); 482 483 volhdr->voldir[slot].block = htobe32(block); 484 volhdr->voldir[slot].bytes = htobe32(st.st_size); 485 486 write_volhdr(fname); 487 488 /* write the file itself */ 489 off = lseek(fd, block * 512, SEEK_SET); 490 if (off == -1) 491 err(EXIT_FAILURE, "Seek failed `%s'", fname); 492 i = st.st_size; 493 fp = fopen(ufilename, "r"); 494 if (fp == NULL) 495 err(EXIT_FAILURE, "Can't open `%s'", ufilename); 496 while (i > 0) { 497 int j = i > 512 ? 512 : i; 498 if (fread(fbuf, 1, j, fp) != j) 499 err(EXIT_FAILURE, "Can't read `%s'", ufilename); 500 if (write(fd, fbuf, 512) != 512) 501 err(EXIT_FAILURE, "Can't write `%s'", fname); 502 i -= j; 503 } 504 fclose(fp); 505} 506 507void 508delete_file(const char *fname) 509{ 510 int i; 511 512 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) { 513 if (names_match(i, vfilename)) { 514 break; 515 } 516 } 517 if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) 518 errx(EXIT_FAILURE, "File `%s' not found", vfilename); 519 520 /* XXX: we don't compact the file space, so get fragmentation */ 521 volhdr->voldir[i].name[0] = '\0'; 522 volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0; 523 write_volhdr(fname); 524} 525 526void 527move_file(const char *fname) 528{ 529 char dstfile[sizeof(volhdr->voldir[0].name) + 1]; 530 size_t namelen; 531 int i, slot = -1; 532 533 /* 534 * Make sure the name in the volume header is max. 8 chars, 535 * NOT including NUL. 536 */ 537 namelen = strlen(ufilename); 538 if (namelen > sizeof(volhdr->voldir[0].name)) { 539 printf("Warning: '%s' is too long for volume header, ", 540 ufilename); 541 namelen = sizeof(volhdr->voldir[0].name); 542 printf("truncating to '%.8s'\n", ufilename); 543 } 544 memset(dstfile, 0, sizeof(dstfile)); 545 memcpy(dstfile, ufilename, namelen); 546 547 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; i++) { 548 if (names_match(i, vfilename)) { 549 if (slot != -1) 550 errx(EXIT_FAILURE, 551 "Error: Cannot move '%s' to '%s' - " 552 "duplicate source files exist!", 553 vfilename, dstfile); 554 slot = i; 555 } 556 if (names_match(i, dstfile)) 557 errx(EXIT_FAILURE, "Error: Cannot move '%s' to '%s' - " 558 "destination file already exists!", 559 vfilename, dstfile); 560 } 561 if (slot == -1) 562 errx(EXIT_FAILURE, "File `%s' not found", vfilename); 563 564 /* `dstfile' is already padded with NULs */ 565 memcpy(volhdr->voldir[slot].name, dstfile, 566 sizeof(volhdr->voldir[slot].name)); 567 568 write_volhdr(fname); 569} 570 571void 572modify_partition(const char *fname) 573{ 574 if (!opt_q) 575 printf("Modify partition %d start %d length %d\n", 576 partno, partfirst, partblocks); 577 if (partno < 0 || partno >= SGI_BOOT_BLOCK_MAXPARTITIONS) 578 errx(EXIT_FAILURE, "Invalid partition number: %d", partno); 579 580 volhdr->partitions[partno].blocks = htobe32(partblocks); 581 volhdr->partitions[partno].first = htobe32(partfirst); 582 volhdr->partitions[partno].type = htobe32(parttype); 583 write_volhdr(fname); 584} 585 586void 587write_volhdr(const char *fname) 588{ 589 int i; 590 591 checksum_vol(); 592 593 if (!opt_q) 594 display_vol(); 595 if (!opt_f) { 596 printf("\nDo you want to update volume (y/n)? "); 597 i = getchar(); 598 if (i != 'Y' && i != 'y') 599 exit(1); 600 } 601 i = lseek(fd, 0, SEEK_SET); 602 if (i < 0) { 603 perror("lseek 0"); 604 exit(1); 605 } 606 i = write(fd, buf, 512); 607 if (i < 0) 608 errx(EXIT_FAILURE, "write volhdr `%s'", fname); 609} 610 611int 612allocate_space(int size) 613{ 614 int n, blocks; 615 int first; 616 617 blocks = (size + 511) / 512; 618 first = 2; 619 n = 0; 620 while (n < SGI_BOOT_BLOCK_MAXVOLDIRS) { 621 if (volhdr->voldir[n].name[0]) { 622 if (first < (be32toh(volhdr->voldir[n].block) + 623 (be32toh(volhdr->voldir[n].bytes) + 511) / 512) && 624 (first + blocks) > be32toh(volhdr->voldir[n].block)) { 625 first = be32toh(volhdr->voldir[n].block) + 626 (be32toh(volhdr->voldir[n].bytes) + 511) / 512; 627#if 0 628 printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size); 629 printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes); 630 printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block, 631 first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511) / 512); 632#endif 633 n = 0; 634 continue; 635 } 636 } 637 ++n; 638 } 639#if HAVE_NBTOOL_CONFIG_H 640 if (first + blocks > (st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE)) 641#else 642 if (first + blocks > lbl.d_secperunit) 643#endif 644 first = -1; 645 /* XXX assumes volume header is partition 8 */ 646 /* XXX assumes volume header starts at 0? */ 647 if (first + blocks >= be32toh(volhdr->partitions[8].blocks)) 648 first = -1; 649 return (first); 650} 651 652void 653checksum_vol(void) 654{ 655 int32_t *l; 656 int i; 657 658 volhdr->checksum = checksum = 0; 659 l = (int32_t *)buf; 660 for (i = 0; i < 512 / 4; ++i) 661 checksum += be32toh(l[i]); 662 volhdr->checksum = htobe32(-checksum); 663} 664 665void 666usage(void) 667{ 668 const char *p = getprogname(); 669 printf("Usage:\t%s [-qf] -i [-h vhsize] device\n" 670 "\t%s [-qf] -r vhfilename diskfilename device\n" 671 "\t%s [-qf] -w vhfilename diskfilename device\n" 672 "\t%s [-qf] -d vhfilename device\n" 673 "\t%s [-qf] -m vhfilename vhfilename device\n" 674 "\t%s [-qf] -p partno partfirst partblocks " 675 "parttype device\n", p, p, p, p, p, p); 676 exit(0); 677} 678