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