Home | History | Annotate | Line # | Download | only in sgivol
sgivol.c revision 1.17
      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 
     60 int	fd;
     61 int	opt_i;			/* Initialize volume header */
     62 int	opt_r;			/* Read a file from volume header */
     63 int	opt_w;			/* Write a file to volume header */
     64 int	opt_d;			/* Delete a file from volume header */
     65 int	opt_m;			/* Move (rename) a file in the volume header */
     66 int	opt_p;			/* Modify a partition */
     67 int	opt_q;			/* quiet mode */
     68 int	opt_f;			/* Don't ask, just do what you're told */
     69 int	partno, partfirst, partblocks, parttype;
     70 struct sgi_boot_block *volhdr;
     71 int32_t	checksum;
     72 u_int32_t	volhdr_size = SGI_BOOT_BLOCK_SIZE_VOLHDR;
     73 
     74 const char *vfilename = "";
     75 const char *ufilename = "";
     76 
     77 #if HAVE_NBTOOL_CONFIG_H
     78 struct stat st;
     79 #else
     80 struct disklabel lbl;
     81 #endif
     82 
     83 unsigned char buf[512];
     84 
     85 const 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 
    102 int	main(int, char *[]);
    103 
    104 void	display_vol(void);
    105 void	init_volhdr(void);
    106 void	read_file(void);
    107 void	write_file(void);
    108 void	delete_file(void);
    109 void	move_file(void);
    110 void	modify_partition(void);
    111 void	write_volhdr(void);
    112 int	allocate_space(int);
    113 void	checksum_vol(void);
    114 void	usage(void);
    115 
    116 int
    117 main(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 < 0) {
    204 #if HAVE_NBTOOL_CONFIG_H
    205 		perror("File open");
    206 		exit(1);
    207 #else
    208 		sprintf((char *)buf, "/dev/r%s%c", argv[0], 'a' + getrawpartition());
    209 		fd = open((char *)buf, (opt_i | opt_w | opt_d | opt_p)
    210 				? O_RDWR : O_RDONLY);
    211 		if (fd < 0) {
    212 			printf("Error opening device %s: %s\n",
    213 				argv[0], strerror(errno));
    214 			exit(1);
    215 		}
    216 #endif
    217 	}
    218 	if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
    219 		perror("read volhdr");
    220 		exit(1);
    221 	}
    222 #if HAVE_NBTOOL_CONFIG_H
    223 	if (fstat(fd, &st) < 0) {
    224 		perror("stat error");
    225 		exit(1);
    226 	}
    227 	if (!S_ISREG(st.st_mode)) {
    228 		printf("Must be regular file\n");
    229 		exit(1);
    230 	}
    231 	if (st.st_size % SGI_BOOT_BLOCK_BLOCKSIZE) {
    232 		printf("Size must be multiple of %d\n",
    233 		    SGI_BOOT_BLOCK_BLOCKSIZE);
    234 		exit(1);
    235 	}
    236 	if (st.st_size < (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS)) {
    237 		printf("Minimum size of %d required\n",
    238 		    SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS);
    239 		exit(1);
    240 	}
    241 #else
    242 	if (ioctl(fd, DIOCGDINFO, &lbl) < 0) {
    243 		perror("DIOCGDINFO");
    244 		exit(1);
    245 	}
    246 #endif
    247 	volhdr = (struct sgi_boot_block *) buf;
    248 	if (opt_i) {
    249 		init_volhdr();
    250 		exit(0);
    251 	}
    252 	if (be32toh(volhdr->magic) != SGI_BOOT_BLOCK_MAGIC) {
    253 		printf("No Volume Header found, magic=%x.  Use -i first.\n",
    254 		       be32toh(volhdr->magic));
    255 		exit(1);
    256 	}
    257 	if (opt_r) {
    258 		read_file();
    259 		exit(0);
    260 	}
    261 	if (opt_w) {
    262 		write_file();
    263 		exit(0);
    264 	}
    265 	if (opt_d) {
    266 		delete_file();
    267 		exit(0);
    268 	}
    269 	if (opt_m) {
    270 		move_file();
    271 		exit(0);
    272 	}
    273 	if (opt_p) {
    274 		modify_partition();
    275 		exit(0);
    276 	}
    277 
    278 	if (!opt_q)
    279 		display_vol();
    280 
    281 	return 0;
    282 }
    283 
    284 void
    285 display_vol(void)
    286 {
    287 	int32_t *l;
    288 	int i;
    289 
    290 #if HAVE_NBTOOL_CONFIG_H
    291 	printf("disklabel shows %d sectors\n",
    292 	    st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
    293 #else
    294 	printf("disklabel shows %d sectors\n", lbl.d_secperunit);
    295 #endif
    296 	l = (int32_t *)buf;
    297 	checksum = 0;
    298 	for (i = 0; i < 512 / 4; ++i)
    299 		checksum += be32toh(l[i]);
    300 	printf("checksum: %08x%s\n", checksum, checksum == 0 ? "" : " *ERROR*");
    301 	printf("root part: %d\n", be16toh(volhdr->root));
    302 	printf("swap part: %d\n", be16toh(volhdr->swap));
    303 	printf("bootfile: %s\n", volhdr->bootfile);
    304 	/* volhdr->devparams[0..47] */
    305 	printf("\nVolume header files:\n");
    306 	for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i)
    307 		if (volhdr->voldir[i].name[0])
    308 			printf("%-8s offset %4d blocks, length %8d bytes "
    309 			    "(%d blocks)\n",
    310 			    volhdr->voldir[i].name,
    311                             be32toh(volhdr->voldir[i].block),
    312 			    be32toh(volhdr->voldir[i].bytes),
    313                             (be32toh(volhdr->voldir[i].bytes) + 511) / 512);
    314 	printf("\nSGI partitions:\n");
    315 	for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; ++i) {
    316 		if (be32toh(volhdr->partitions[i].blocks)) {
    317 			printf("%2d:%c blocks %8d first %8d type %2d (%s)\n",
    318 			  i, i + 'a', be32toh(volhdr->partitions[i].blocks),
    319 			       be32toh(volhdr->partitions[i].first),
    320 			       be32toh(volhdr->partitions[i].type),
    321 			  be32toh(volhdr->partitions[i].type) > 13 ? "???" :
    322 			    sgi_types[be32toh(volhdr->partitions[i].type)]);
    323 		}
    324 	}
    325 }
    326 
    327 void
    328 init_volhdr(void)
    329 {
    330 	memset(buf, 0, sizeof(buf));
    331 	volhdr->magic = htobe32(SGI_BOOT_BLOCK_MAGIC);
    332 	volhdr->root = htobe16(0);
    333 	volhdr->swap = htobe16(1);
    334 	strcpy(volhdr->bootfile, "/netbsd");
    335 #if HAVE_NBTOOL_CONFIG_H
    336 	volhdr->dp.dp_skew = 0;
    337 #else
    338 	volhdr->dp.dp_skew = lbl.d_trackskew;
    339 #endif
    340 	volhdr->dp.dp_gap1 = 1; /* XXX */
    341 	volhdr->dp.dp_gap2 = 1; /* XXX */
    342 #if HAVE_NBTOOL_CONFIG_H
    343 	volhdr->dp.dp_cyls =
    344 	    htobe16(st.st_size / (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS));
    345 #else
    346 	volhdr->dp.dp_cyls = htobe16(lbl.d_ncylinders);
    347 #endif
    348 	volhdr->dp.dp_shd0 = 0;
    349 #if HAVE_NBTOOL_CONFIG_H
    350 	volhdr->dp.dp_trks0 = htobe16(SGIVOL_NBTOOL_NTRACKS);
    351 	volhdr->dp.dp_secs = htobe16(SGIVOL_NBTOOL_NSECS);
    352 	volhdr->dp.dp_secbytes = htobe16(SGI_BOOT_BLOCK_BLOCKSIZE);
    353 	volhdr->dp.dp_interleave = htobe16(1);
    354 #else
    355 	volhdr->dp.dp_trks0 = htobe16(lbl.d_ntracks);
    356 	volhdr->dp.dp_secs = htobe16(lbl.d_nsectors);
    357 	volhdr->dp.dp_secbytes = htobe16(lbl.d_secsize);
    358 	volhdr->dp.dp_interleave = htobe16(lbl.d_interleave);
    359 #endif
    360 	volhdr->dp.dp_nretries = htobe32(22);
    361 #if HAVE_NBTOOL_CONFIG_H
    362 	volhdr->partitions[10].blocks =
    363 	    htobe32(st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
    364 #else
    365 	volhdr->partitions[10].blocks = htobe32(lbl.d_secperunit);
    366 #endif
    367 	volhdr->partitions[10].first = 0;
    368 	volhdr->partitions[10].type = htobe32(SGI_PTYPE_VOLUME);
    369 	volhdr->partitions[8].blocks = htobe32(volhdr_size);
    370 	volhdr->partitions[8].first = 0;
    371 	volhdr->partitions[8].type = htobe32(SGI_PTYPE_VOLHDR);
    372 #if HAVE_NBTOOL_CONFIG_H
    373 	volhdr->partitions[0].blocks =
    374 	    htobe32((st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE) - volhdr_size);
    375 #else
    376 	volhdr->partitions[0].blocks = htobe32(lbl.d_secperunit - volhdr_size);
    377 #endif
    378 	volhdr->partitions[0].first = htobe32(volhdr_size);
    379 	volhdr->partitions[0].type = htobe32(SGI_PTYPE_BSD);
    380 	write_volhdr();
    381 }
    382 
    383 void
    384 read_file(void)
    385 {
    386 	FILE *fp;
    387 	int i;
    388 
    389 	if (!opt_q)
    390 		printf("Reading file %s\n", vfilename);
    391 	for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) {
    392 		if (strncmp(vfilename, volhdr->voldir[i].name,
    393 			    strlen(volhdr->voldir[i].name)) == 0)
    394 			break;
    395 	}
    396 	if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) {
    397 		printf("File '%s' not found\n", vfilename);
    398 		exit(1);
    399 	}
    400 	/* XXX assumes volume header starts at 0? */
    401 	lseek(fd, be32toh(volhdr->voldir[i].block) * 512, SEEK_SET);
    402 	fp = fopen(ufilename, "w");
    403 	if (fp == NULL) {
    404 		perror("open write");
    405 		exit(1);
    406 	}
    407 	i = be32toh(volhdr->voldir[i].bytes);
    408 	while (i > 0) {
    409 		if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
    410 			perror("read file");
    411 			exit(1);
    412 		}
    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 
    419 void
    420 write_file(void)
    421 {
    422 	FILE *fp;
    423 	int slot;
    424 	size_t namelen;
    425 	int block, i;
    426 	struct stat st;
    427 	char fbuf[512];
    428 
    429 	if (!opt_q)
    430 		printf("Writing file %s\n", ufilename);
    431 	if (stat(ufilename, &st) < 0) {
    432 		perror("stat");
    433 		exit(1);
    434 	}
    435 	if (!opt_q)
    436 		printf("File %s has %lld bytes\n", ufilename, 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 (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
    442 			slot = i;
    443 			break;
    444 		}
    445 	}
    446 	if (slot == -1) {
    447 		printf("No directory space for file %s\n", vfilename);
    448 		exit(1);
    449 	}
    450 	/* -w can overwrite, -a won't overwrite */
    451 	if (be32toh(volhdr->voldir[slot].block) > 0) {
    452 		if (!opt_q)
    453 			printf("File %s exists, removing old file\n",
    454 				vfilename);
    455 		volhdr->voldir[slot].name[0] = 0;
    456 		volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0;
    457 	}
    458 	if (st.st_size == 0) {
    459 		printf("bad file size\n");
    460 		exit(1);
    461 	}
    462 	/* XXX assumes volume header starts at 0? */
    463 	block = allocate_space((int)st.st_size);
    464 	if (block < 0) {
    465 		printf("No space for file\n");
    466 		exit(1);
    467 	}
    468 
    469 	/*
    470 	 * Make sure the name in the volume header is max. 8 chars,
    471 	 * NOT including NUL.
    472 	 */
    473 	namelen = strlen(vfilename);
    474 	if (namelen > sizeof(volhdr->voldir[slot].name)) {
    475 		printf("Warning: '%s' is too long for volume header, ",
    476 		       vfilename);
    477 		namelen = sizeof(volhdr->voldir[slot].name);
    478 		printf("truncating to '%.8s'\n", vfilename);
    479 	}
    480 
    481 	/* Populate it w/ NULs */
    482 	memset(volhdr->voldir[slot].name, 0,
    483 	    sizeof(volhdr->voldir[slot].name));
    484 	/* Then copy the name */
    485 	memcpy(volhdr->voldir[slot].name, vfilename, namelen);
    486 
    487 	volhdr->voldir[slot].block = htobe32(block);
    488 	volhdr->voldir[slot].bytes = htobe32(st.st_size);
    489 
    490 	write_volhdr();
    491 
    492 	/* write the file itself */
    493 	i = lseek(fd, block * 512, SEEK_SET);
    494 	if (i < 0) {
    495 		perror("lseek write");
    496 		exit(1);
    497 	}
    498 	i = st.st_size;
    499 	fp = fopen(ufilename, "r");
    500 	while (i > 0) {
    501 		fread(fbuf, 1, i > 512 ? 512 : i, fp);
    502 		if (write(fd, fbuf, 512) != 512) {
    503 			perror("write file");
    504 			exit(1);
    505 		}
    506 		i -= i > 512 ? 512 : i;
    507 	}
    508 }
    509 
    510 void
    511 delete_file(void)
    512 {
    513 	int i;
    514 
    515 	for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) {
    516 		if (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
    517 			break;
    518 		}
    519 	}
    520 	if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) {
    521 		printf("File '%s' not found\n", vfilename);
    522 		exit(1);
    523 	}
    524 
    525 	/* XXX: we don't compact the file space, so get fragmentation */
    526 	volhdr->voldir[i].name[0] = '\0';
    527 	volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0;
    528 	write_volhdr();
    529 }
    530 
    531 void
    532 move_file(void)
    533 {
    534 	char dstfile[sizeof(volhdr->voldir[0].name) + 1];
    535 	size_t namelen;
    536 	int i, slot = -1;
    537 
    538 	/*
    539 	 * Make sure the name in the volume header is max. 8 chars,
    540 	 * NOT including NUL.
    541 	 */
    542 	namelen = strlen(ufilename);
    543 	if (namelen > sizeof(volhdr->voldir[0].name)) {
    544 		printf("Warning: '%s' is too long for volume header, ",
    545 		       ufilename);
    546 		namelen = sizeof(volhdr->voldir[0].name);
    547 		printf("truncating to '%.8s'\n", ufilename);
    548 	}
    549 	memset(dstfile, 0, sizeof(dstfile));
    550 	memcpy(dstfile, ufilename, namelen);
    551 
    552 	for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; i++) {
    553 		if (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
    554 			if (slot != -1) {
    555 				printf("Error: Cannot move '%s' to '%s' - "
    556 				    "duplicate source files exist!\n",
    557 				    vfilename, dstfile);
    558 				exit(1);
    559 			}
    560 			slot = i;
    561 		}
    562 		if (strcmp(dstfile, volhdr->voldir[i].name) == 0) {
    563 			printf("Error: Cannot move '%s' to '%s' - "
    564 			    "destination file already exists!\n",
    565 			    vfilename, dstfile);
    566 			exit(1);
    567 		}
    568 	}
    569 	if (slot == -1) {
    570 		printf("File '%s' not found\n", vfilename);
    571 		exit(1);
    572 	}
    573 
    574 	/* `dstfile' is already padded with NULs */
    575 	memcpy(volhdr->voldir[slot].name, dstfile,
    576 	    sizeof(volhdr->voldir[slot].name));
    577 
    578 	write_volhdr();
    579 }
    580 
    581 void
    582 modify_partition(void)
    583 {
    584 	if (!opt_q)
    585 		printf("Modify partition %d start %d length %d\n",
    586 			partno, partfirst, partblocks);
    587 	if (partno < 0 || partno >= SGI_BOOT_BLOCK_MAXPARTITIONS) {
    588 		printf("Invalid partition number: %d\n", partno);
    589 		exit(1);
    590 	}
    591 	volhdr->partitions[partno].blocks = htobe32(partblocks);
    592 	volhdr->partitions[partno].first = htobe32(partfirst);
    593 	volhdr->partitions[partno].type = htobe32(parttype);
    594 	write_volhdr();
    595 }
    596 
    597 void
    598 write_volhdr(void)
    599 {
    600 	int i;
    601 
    602 	checksum_vol();
    603 
    604 	if (!opt_q)
    605 		display_vol();
    606 	if (!opt_f) {
    607 		printf("\nDo you want to update volume (y/n)? ");
    608 		i = getchar();
    609 		if (i != 'Y' && i != 'y')
    610 			exit(1);
    611 	}
    612 	i = lseek(fd, 0, SEEK_SET);
    613 	if (i < 0) {
    614 		perror("lseek 0");
    615 		exit(1);
    616 	}
    617 	i = write(fd, buf, 512);
    618 	if (i < 0)
    619 		perror("write volhdr");
    620 }
    621 
    622 int
    623 allocate_space(int size)
    624 {
    625 	int n, blocks;
    626 	int first;
    627 
    628 	blocks = (size + 511) / 512;
    629 	first = 2;
    630 	n = 0;
    631 	while (n < SGI_BOOT_BLOCK_MAXVOLDIRS) {
    632 		if (volhdr->voldir[n].name[0]) {
    633 			if (first < (be32toh(volhdr->voldir[n].block) +
    634 			  (be32toh(volhdr->voldir[n].bytes) + 511) / 512) &&
    635 			    (first + blocks) > be32toh(volhdr->voldir[n].block)) {
    636 				first = be32toh(volhdr->voldir[n].block) +
    637 					(be32toh(volhdr->voldir[n].bytes) + 511) / 512;
    638 #if 0
    639 				printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size);
    640 				printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes);
    641 				printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block,
    642 				       first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511) / 512);
    643 #endif
    644 				n = 0;
    645 				continue;
    646 			}
    647 		}
    648 		++n;
    649 	}
    650 #if HAVE_NBTOOL_CONFIG_H
    651 	if (first + blocks > (st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE))
    652 #else
    653 	if (first + blocks > lbl.d_secperunit)
    654 #endif
    655 		first = -1;
    656 	/* XXX assumes volume header is partition 8 */
    657 	/* XXX assumes volume header starts at 0? */
    658 	if (first + blocks >= be32toh(volhdr->partitions[8].blocks))
    659 		first = -1;
    660 	return (first);
    661 }
    662 
    663 void
    664 checksum_vol(void)
    665 {
    666 	int32_t *l;
    667 	int i;
    668 
    669 	volhdr->checksum = checksum = 0;
    670 	l = (int32_t *)buf;
    671 	for (i = 0; i < 512 / 4; ++i)
    672 		checksum += be32toh(l[i]);
    673 	volhdr->checksum = htobe32(-checksum);
    674 }
    675 
    676 void
    677 usage(void)
    678 {
    679 	printf("Usage:	sgivol [-qf] -i [-h vhsize] device\n"
    680 	       "	sgivol [-qf] -r vhfilename diskfilename device\n"
    681 	       "	sgivol [-qf] -w vhfilename diskfilename device\n"
    682 	       "	sgivol [-qf] -d vhfilename device\n"
    683 	       "	sgivol [-qf] -p partno partfirst partblocks "
    684 	       "parttype device\n"
    685 	       );
    686 	exit(0);
    687 }
    688