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