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