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