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