1 /* $NetBSD: sgivol.c,v 1.17 2008/08/03 16:09:20 rumble Exp $ */
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Michael Hitch and Hubert Feyrer.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
36 #include <sys/types.h>
37 #include <sys/ioctl.h>
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
46 #include <sys/disklabel.h>
56 #ifndef HAVE_NBTOOL_CONFIG_H
57 #include <sys/endian.h>
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
;
72 u_int32_t volhdr_size
= SGI_BOOT_BLOCK_SIZE_VOLHDR
;
74 const char *vfilename
= "";
75 const char *ufilename
= "";
77 #if HAVE_NBTOOL_CONFIG_H
83 unsigned char buf
[512];
85 const char *sgi_types
[] = {
102 int main(int, char *[]);
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 *);
118 main(int argc
, char *argv
[])
120 #define RESET_OPTS() opt_i = opt_m = opt_r = opt_w = opt_d = opt_p = 0
123 while ((ch
= getopt(argc
, argv
, "qfih:rwdmp?")) != -1) {
125 /* -i, -r, -w, -d, -m and -p override each other */
139 volhdr_size
= atoi(optarg
);
160 partno
= atoi(argv
[0]);
161 partfirst
= atoi(argv
[1]);
162 partblocks
= atoi(argv
[2]);
163 parttype
= atoi(argv
[3]);
173 if (opt_m
|| opt_r
|| opt_w
) {
192 partno
= atoi(argv
[0]);
193 partfirst
= atoi(argv
[1]);
194 partblocks
= atoi(argv
[2]);
195 parttype
= atoi(argv
[3]);
203 (opt_i
| opt_m
| opt_w
| opt_d
| opt_p
) ? O_RDWR
: O_RDONLY
);
205 #if HAVE_NBTOOL_CONFIG_H
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
);
213 printf("Error opening device %s: %s\n",
214 argv
[0], strerror(errno
));
219 if (read(fd
, buf
, sizeof(buf
)) != sizeof(buf
)) {
220 perror("read volhdr");
223 #if HAVE_NBTOOL_CONFIG_H
224 if (fstat(fd
, &st
) < 0) {
225 perror("stat error");
228 if (!S_ISREG(st
.st_mode
)) {
229 printf("Must be regular file\n");
232 if (st
.st_size
% SGI_BOOT_BLOCK_BLOCKSIZE
) {
233 printf("Size must be multiple of %d\n",
234 SGI_BOOT_BLOCK_BLOCKSIZE
);
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
);
243 if (ioctl(fd
, DIOCGDINFO
, &lbl
) < 0) {
244 perror("DIOCGDINFO");
248 volhdr
= (struct sgi_boot_block
*) buf
;
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
));
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).
290 * Returns non-0 if names are equal.
293 names_match(int slot
, const char *b
)
297 if (slot
< 0 || slot
>= SGI_BOOT_BLOCK_MAXVOLDIRS
) {
298 printf("Internal error: bad slot in %s()\n", __func__
);
302 cmp
= strncmp(volhdr
->voldir
[slot
].name
, b
,
303 sizeof(volhdr
->voldir
[slot
].name
));
305 return (cmp
== 0 && strlen(b
) <= sizeof(volhdr
->voldir
[slot
].name
));
314 #if HAVE_NBTOOL_CONFIG_H
315 printf("disklabel shows %d sectors\n",
316 st
.st_size
/ SGI_BOOT_BLOCK_BLOCKSIZE
);
318 printf("disklabel shows %d sectors\n", lbl
.d_secperunit
);
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 "
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
)]);
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;
362 volhdr
->dp
.dp_skew
= lbl
.d_trackskew
;
364 volhdr
->dp
.dp_gap1
= 1; /* XXX */
365 volhdr
->dp
.dp_gap2
= 1; /* XXX */
366 #if HAVE_NBTOOL_CONFIG_H
368 htobe16(st
.st_size
/ (SGIVOL_NBTOOL_NSECS
* SGIVOL_NBTOOL_NTRACKS
));
370 volhdr
->dp
.dp_cyls
= htobe16(lbl
.d_ncylinders
);
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);
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
);
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
);
389 volhdr
->partitions
[10].blocks
= htobe32(lbl
.d_secperunit
);
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
);
400 volhdr
->partitions
[0].blocks
= htobe32(lbl
.d_secperunit
- volhdr_size
);
402 volhdr
->partitions
[0].first
= htobe32(volhdr_size
);
403 volhdr
->partitions
[0].type
= htobe32(SGI_PTYPE_BSD
);
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)
420 if (i
>= SGI_BOOT_BLOCK_MAXVOLDIRS
) {
421 printf("File '%s' not found\n", vfilename
);
424 /* XXX assumes volume header starts at 0? */
425 lseek(fd
, be32toh(volhdr
->voldir
[i
].block
) * 512, SEEK_SET
);
426 fp
= fopen(ufilename
, "w");
428 perror("open write");
431 i
= be32toh(volhdr
->voldir
[i
].bytes
);
433 if (read(fd
, buf
, sizeof(buf
)) != sizeof(buf
)) {
437 fwrite(buf
, 1, i
> sizeof(buf
) ? sizeof(buf
) : i
, fp
);
438 i
-= i
> sizeof(buf
) ? sizeof(buf
) : i
;
454 printf("Writing file %s\n", ufilename
);
455 if (stat(ufilename
, &st
) < 0) {
460 printf("File %s has %lld bytes\n", ufilename
, st
.st_size
);
462 for (i
= 0; i
< SGI_BOOT_BLOCK_MAXVOLDIRS
; ++i
) {
463 if (volhdr
->voldir
[i
].name
[0] == '\0' && slot
< 0)
465 if (names_match(i
, vfilename
)) {
471 printf("No directory space for file %s\n", vfilename
);
474 /* -w can overwrite, -a won't overwrite */
475 if (be32toh(volhdr
->voldir
[slot
].block
) > 0) {
477 printf("File %s exists, removing old file\n",
479 volhdr
->voldir
[slot
].name
[0] = 0;
480 volhdr
->voldir
[slot
].block
= volhdr
->voldir
[slot
].bytes
= 0;
482 if (st
.st_size
== 0) {
483 printf("bad file size\n");
486 /* XXX assumes volume header starts at 0? */
487 block
= allocate_space((int)st
.st_size
);
489 printf("No space for file\n");
494 * Make sure the name in the volume header is max. 8 chars,
497 namelen
= strlen(vfilename
);
498 if (namelen
> sizeof(volhdr
->voldir
[slot
].name
)) {
499 printf("Warning: '%s' is too long for volume header, ",
501 namelen
= sizeof(volhdr
->voldir
[slot
].name
);
502 printf("truncating to '%.8s'\n", vfilename
);
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
);
511 volhdr
->voldir
[slot
].block
= htobe32(block
);
512 volhdr
->voldir
[slot
].bytes
= htobe32(st
.st_size
);
516 /* write the file itself */
517 i
= lseek(fd
, block
* 512, SEEK_SET
);
519 perror("lseek write");
523 fp
= fopen(ufilename
, "r");
525 fread(fbuf
, 1, i
> 512 ? 512 : i
, fp
);
526 if (write(fd
, fbuf
, 512) != 512) {
527 perror("write file");
530 i
-= i
> 512 ? 512 : i
;
539 for (i
= 0; i
< SGI_BOOT_BLOCK_MAXVOLDIRS
; ++i
) {
540 if (names_match(i
, vfilename
)) {
544 if (i
>= SGI_BOOT_BLOCK_MAXVOLDIRS
) {
545 printf("File '%s' not found\n", vfilename
);
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;
558 char dstfile
[sizeof(volhdr
->voldir
[0].name
) + 1];
563 * Make sure the name in the volume header is max. 8 chars,
566 namelen
= strlen(ufilename
);
567 if (namelen
> sizeof(volhdr
->voldir
[0].name
)) {
568 printf("Warning: '%s' is too long for volume header, ",
570 namelen
= sizeof(volhdr
->voldir
[0].name
);
571 printf("truncating to '%.8s'\n", ufilename
);
573 memset(dstfile
, 0, sizeof(dstfile
));
574 memcpy(dstfile
, ufilename
, namelen
);
576 for (i
= 0; i
< SGI_BOOT_BLOCK_MAXVOLDIRS
; i
++) {
577 if (names_match(i
, vfilename
)) {
579 printf("Error: Cannot move '%s' to '%s' - "
580 "duplicate source files exist!\n",
586 if (names_match(i
, dstfile
)) {
587 printf("Error: Cannot move '%s' to '%s' - "
588 "destination file already exists!\n",
594 printf("File '%s' not found\n", vfilename
);
598 /* `dstfile' is already padded with NULs */
599 memcpy(volhdr
->voldir
[slot
].name
, dstfile
,
600 sizeof(volhdr
->voldir
[slot
].name
));
606 modify_partition(void)
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
);
615 volhdr
->partitions
[partno
].blocks
= htobe32(partblocks
);
616 volhdr
->partitions
[partno
].first
= htobe32(partfirst
);
617 volhdr
->partitions
[partno
].type
= htobe32(parttype
);
631 printf("\nDo you want to update volume (y/n)? ");
633 if (i
!= 'Y' && i
!= 'y')
636 i
= lseek(fd
, 0, SEEK_SET
);
641 i
= write(fd
, buf
, 512);
643 perror("write volhdr");
647 allocate_space(int size
)
652 blocks
= (size
+ 511) / 512;
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;
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);
674 #if HAVE_NBTOOL_CONFIG_H
675 if (first
+ blocks
> (st
.st_size
/ SGI_BOOT_BLOCK_BLOCKSIZE
))
677 if (first
+ blocks
> lbl
.d_secperunit
)
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
))
693 volhdr
->checksum
= checksum
= 0;
695 for (i
= 0; i
< 512 / 4; ++i
)
696 checksum
+= be32toh(l
[i
]);
697 volhdr
->checksum
= htobe32(-checksum
);
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 "