Home | History | Annotate | Line # | Download | only in sgivol
sgivol.c revision 1.18
      1 /*	$NetBSD: sgivol.c,v 1.18 2008/08/03 17:42:34 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 int	names_match(int, const char *);
    115 void	usage(void);
    116 
    117 int
    118 main(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  */
    292 int
    293 names_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 
    308 void
    309 display_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 
    351 void
    352 init_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 
    407 void
    408 read_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 
    443 void
    444 write_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 
    534 void
    535 delete_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 
    555 void
    556 move_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 
    605 void
    606 modify_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 
    621 void
    622 write_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 
    646 int
    647 allocate_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 
    687 void
    688 checksum_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 
    700 void
    701 usage(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