xref: /netbsd/sys/arch/sgimips/stand/sgivol/sgivol.c (revision 8b377fc2)
1 /*	$NetBSD: sgivol.c,v 1.21 2014/03/28 15:00:53 christos 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 #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
main(int argc,char * argv[])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
names_match(int slot,const char * b)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
display_vol(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
init_volhdr(const char * fname)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
read_file(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
write_file(const char * fname)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
delete_file(const char * fname)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
move_file(const char * fname)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
modify_partition(const char * fname)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
write_volhdr(const char * fname)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
allocate_space(int size)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
checksum_vol(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
usage(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