Home | History | Annotate | Line # | Download | only in sgivol
sgivol.c revision 1.7
      1 /*	$NetBSD: sgivol.c,v 1.7 2003/11/01 06:30:44 sekiya 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  * 3. All advertising materials mentioning features or use of this software
     19  *    must display the following acknowledgement:
     20  *        This product includes software developed by the NetBSD
     21  *        Foundation, Inc. and its contributors.
     22  * 4. Neither the name of The NetBSD Foundation nor the names of its
     23  *    contributors may be used to endorse or promote products derived
     24  *    from this software without specific prior written permission.
     25  *
     26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     36  * POSSIBILITY OF SUCH DAMAGE.
     37  */
     38 
     39 #include <sys/types.h>
     40 #include <sys/ioctl.h>
     41 #include <sys/disklabel.h>
     42 #include <sys/stat.h>
     43 
     44 #include <errno.h>
     45 #include <stdio.h>
     46 #include <stdlib.h>
     47 #include <unistd.h>
     48 #include <string.h>
     49 #include <fcntl.h>
     50 #include <util.h>
     51 #include <sys/endian.h>
     52 
     53 /*
     54  * Some IRIX man pages refer to the size being a multiple of whole cylinders.
     55  * Later ones only refer to the size being "typically" 2MB.  IRIX fx(1)
     56  * uses a default drive geometry if one can't be determined, suggesting
     57  * that "whole cylinder" multiples are not required.
     58  */
     59 
     60 #define SGI_SIZE_VOLHDR	3135	/* Can be overridden via -h parameter */
     61 
     62 struct devparms {
     63 	u_int8_t        dp_skew;
     64 	u_int8_t        dp_gap1;
     65 	u_int8_t        dp_gap2;
     66 	u_int8_t        dp_spares_cyl;
     67 	u_int16_t       dp_cyls;
     68 	u_int16_t       dp_shd0;
     69 	u_int16_t       dp_trks0;
     70 	u_int8_t        dp_ctq_depth;
     71 	u_int8_t        dp_cylshi;
     72 	u_int16_t       dp_unused;
     73 	u_int16_t       dp_secs;
     74 	u_int16_t       dp_secbytes;
     75 	u_int16_t       dp_interleave;
     76 	u_int32_t       dp_flags;
     77 	u_int32_t       dp_datarate;
     78 	u_int32_t       dp_nretries;
     79 	u_int32_t       dp_mspw;
     80 	u_int16_t       dp_xgap1;
     81 	u_int16_t       dp_xsync;
     82 	u_int16_t       dp_xrdly;
     83 	u_int16_t       dp_xgap2;
     84 	u_int16_t       dp_xrgate;
     85 	u_int16_t       dp_xwcont;
     86 }               __attribute__((__packed__));
     87 
     88 struct sgilabel {
     89 #define SGILABEL_MAGIC  0xbe5a941
     90 	u_int32_t       magic;
     91 	int16_t         root;
     92 	int16_t         swap;
     93 	char            bootfile[16];
     94 	struct devparms dp;
     95 	struct {
     96 		char            name[8];
     97 		int32_t         block;
     98 		int32_t         bytes;
     99 	}               voldir[15];
    100 	struct {
    101 		int32_t         blocks;
    102 		int32_t         first;
    103 		int32_t         type;
    104 	}               partitions[MAXPARTITIONS];
    105 	int32_t         checksum;
    106 	int32_t         _pad;
    107 }               __attribute__((__packed__));
    108 
    109 #define SGI_PTYPE_VOLHDR        0
    110 #define SGI_PTYPE_RAW           3
    111 #define SGI_PTYPE_BSD           4
    112 #define SGI_PTYPE_VOLUME        6
    113 #define SGI_PTYPE_EFS           7
    114 #define SGI_PTYPE_LVOL          8
    115 #define SGI_PTYPE_RLVOL         9
    116 #define SGI_PTYPE_XFS           10
    117 #define SGI_PTYPE_XFSLOG        11
    118 #define SGI_PTYPE_XLV           12
    119 #define SGI_PTYPE_XVM           13
    120 
    121 int	fd;
    122 int	opt_i;			/* Initialize volume header */
    123 int	opt_r;			/* Read a file from volume header */
    124 int	opt_w;			/* Write a file to volume header */
    125 int	opt_d;			/* Delete a file from volume header */
    126 int	opt_p;			/* Modify a partition */
    127 int	opt_q;			/* quiet mode */
    128 int	opt_f;			/* Don't ask, just do what you're told */
    129 int	partno, partfirst, partblocks, parttype;
    130 struct sgilabel *volhdr;
    131 int32_t	checksum;
    132 u_int32_t	volhdr_size = SGI_SIZE_VOLHDR;
    133 
    134 const char *vfilename = "";
    135 const char *ufilename = "";
    136 
    137 struct disklabel lbl;
    138 
    139 unsigned char buf[512];
    140 
    141 const char *sgi_types[] = {
    142 	"Volume Header",
    143 	"Repl Trks",
    144 	"Repl Secs",
    145 	"Raw",
    146 	"BSD4.2",
    147 	"SysV",
    148 	"Volume",
    149 	"EFS",
    150 	"LVol",
    151 	"RLVol",
    152 	"XFS",
    153 	"XSFLog",
    154 	"XLV",
    155 	"XVM"
    156 };
    157 
    158 int	main(int, char *[]);
    159 
    160 void	display_vol(void);
    161 void	init_volhdr(void);
    162 void	read_file(void);
    163 void	write_file(void);
    164 void	delete_file(void);
    165 void	modify_partition(void);
    166 void	write_volhdr(void);
    167 int	allocate_space(int);
    168 void	checksum_vol(void);
    169 void	usage(void);
    170 
    171 int
    172 main(int argc, char *argv[])
    173 {
    174 	int ch;
    175 	while ((ch = getopt(argc, argv, "irwpdqfh:")) != -1) {
    176 		switch (ch) {
    177 		/* -i, -r, -w, -d and -p override each other */
    178 		/* -q implies -f */
    179 		case 'q':
    180 			++opt_q;
    181 			++opt_f;
    182 			break;
    183 		case 'f':
    184 			++opt_f;
    185 			break;
    186 		case 'i':
    187 			++opt_i;
    188 			opt_r = opt_w = opt_d = opt_p = 0;
    189 			break;
    190 		case 'h':
    191 			volhdr_size = atoi(optarg);
    192 			break;
    193 		case 'r':
    194 			++opt_r;
    195 			opt_i = opt_w = opt_d = opt_p = 0;
    196 			break;
    197 		case 'w':
    198 			++opt_w;
    199 			opt_i = opt_r = opt_d = opt_p = 0;
    200 			break;
    201 		case 'd':
    202 			++opt_d;
    203 			opt_i = opt_r = opt_w = opt_p = 0;
    204 			break;
    205 		case 'p':
    206 			++opt_p;
    207 			opt_i = opt_r = opt_w = opt_d = 0;
    208 			partno = atoi(argv[0]);
    209 			partfirst = atoi(argv[1]);
    210 			partblocks = atoi(argv[2]);
    211 			parttype = atoi(argv[3]);
    212 			break;
    213 		case '?':
    214 		default:
    215 			usage();
    216 		}
    217 	}
    218 	argc -= optind;
    219 	argv += optind;
    220 
    221 	if (opt_r || opt_w) {
    222 		if (argc != 3)
    223 			usage();
    224 		vfilename = argv[0];
    225 		ufilename = argv[1];
    226 		argc -= 2;
    227 		argv += 2;
    228 	}
    229 	if (opt_d) {
    230 		if (argc != 2)
    231 			usage();
    232 		vfilename = argv[0];
    233 		argc--;
    234 		argv++;
    235 	}
    236 
    237 	if (opt_p) {
    238 		if (argc != 5)
    239 			usage();
    240 		partno = atoi(argv[0]);
    241 		partfirst = atoi(argv[1]);
    242 		partblocks = atoi(argv[2]);
    243 		parttype = atoi(argv[3]);
    244 		argc -= 4;
    245 		argv += 4;
    246 	}
    247 	if (argc != 1)
    248 		usage();
    249 
    250 	fd = open(argv[0], (opt_i | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY);
    251 	if (fd < 0) {
    252 		sprintf(buf, "/dev/r%s%c", argv[0], 'a' + getrawpartition());
    253 		fd = open(buf, (opt_i | opt_w | opt_d | opt_p)
    254 				? O_RDWR : O_RDONLY);
    255 		if (fd < 0) {
    256 			printf("Error opening device %s: %s\n",
    257 				argv[0], strerror(errno));
    258 			exit(1);
    259 		}
    260 	}
    261 	if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
    262 		perror("read volhdr");
    263 		exit(1);
    264 	}
    265 	if (ioctl(fd, DIOCGDINFO, &lbl) < 0) {
    266 		perror("DIOCGDINFO");
    267 		exit(1);
    268 	}
    269 	volhdr = (struct sgilabel *) buf;
    270 	if (opt_i) {
    271 		init_volhdr();
    272 		exit(0);
    273 	}
    274 	if (be32toh(volhdr->magic) != SGILABEL_MAGIC) {
    275 		printf("No Volume Header found, magic=%x.  Use -i first.\n",
    276 		       be32toh(volhdr->magic));
    277 		exit(1);
    278 	}
    279 	if (opt_r) {
    280 		read_file();
    281 		exit(0);
    282 	}
    283 	if (opt_w) {
    284 		write_file();
    285 		exit(0);
    286 	}
    287 	if (opt_d) {
    288 		delete_file();
    289 		exit(0);
    290 	}
    291 	if (opt_p) {
    292 		modify_partition();
    293 		exit(0);
    294 	}
    295 
    296 	if (!opt_q)
    297 		display_vol();
    298 
    299 	return 0;
    300 }
    301 
    302 void
    303 display_vol(void)
    304 {
    305 	int32_t *l;
    306 	int i;
    307 
    308 	printf("disklabel shows %d sectors\n", lbl.d_secperunit);
    309 	l = (int32_t *)buf;
    310 	checksum = 0;
    311 	for (i = 0; i < 512 / 4; ++i)
    312 		checksum += be32toh(l[i]);
    313 	printf("checksum: %08x%s\n", checksum, checksum == 0 ? "" : " *ERROR*");
    314 	printf("root part: %d\n", be16toh(volhdr->root));
    315 	printf("swap part: %d\n", be16toh(volhdr->swap));
    316 	printf("bootfile: %s\n", volhdr->bootfile);
    317 	/* volhdr->devparams[0..47] */
    318 	printf("\nVolume header files:\n");
    319 	for (i = 0; i < 15; ++i)
    320 		if (volhdr->voldir[i].name[0])
    321 			printf("%-8s offset %4d blocks, length %8d bytes (%d blocks)\n",
    322 			       volhdr->voldir[i].name, be32toh(volhdr->voldir[i].block),
    323 			       be32toh(volhdr->voldir[i].bytes), (be32toh(volhdr->voldir[i].bytes) + 511) / 512);
    324 	printf("\nSGI partitions:\n");
    325 	for (i = 0; i < MAXPARTITIONS; ++i) {
    326 		if (be32toh(volhdr->partitions[i].blocks)) {
    327 			printf("%2d:%c blocks %8d first %8d type %2d (%s)\n",
    328 			  i, i + 'a', be32toh(volhdr->partitions[i].blocks),
    329 			       be32toh(volhdr->partitions[i].first),
    330 			       be32toh(volhdr->partitions[i].type),
    331 			  be32toh(volhdr->partitions[i].type) > 13 ? "???" :
    332 			    sgi_types[be32toh(volhdr->partitions[i].type)]);
    333 		}
    334 	}
    335 }
    336 
    337 void
    338 init_volhdr(void)
    339 {
    340 	memset(buf, 0, sizeof(buf));
    341 	volhdr->magic = htobe32(SGILABEL_MAGIC);
    342 	volhdr->root = htobe16(0);
    343 	volhdr->swap = htobe16(1);
    344 	strcpy(volhdr->bootfile, "/netbsd");
    345 	volhdr->dp.dp_skew = lbl.d_trackskew;
    346 	volhdr->dp.dp_gap1 = 1; /* XXX */
    347 	volhdr->dp.dp_gap2 = 1; /* XXX */
    348 	volhdr->dp.dp_cyls = htobe16(lbl.d_ncylinders);
    349 	volhdr->dp.dp_shd0 = 0;
    350 	volhdr->dp.dp_trks0 = htobe16(lbl.d_ntracks);
    351 	volhdr->dp.dp_secs = htobe16(lbl.d_nsectors);
    352 	volhdr->dp.dp_secbytes = htobe16(lbl.d_secsize);
    353 	volhdr->dp.dp_interleave = htobe16(lbl.d_interleave);
    354 	volhdr->dp.dp_nretries = htobe32(22);
    355 	volhdr->partitions[10].blocks = htobe32(lbl.d_secperunit);
    356 	volhdr->partitions[10].first = 0;
    357 	volhdr->partitions[10].type = htobe32(SGI_PTYPE_VOLUME);
    358 	volhdr->partitions[8].blocks = htobe32(volhdr_size);
    359 	volhdr->partitions[8].first = 0;
    360 	volhdr->partitions[8].type = htobe32(SGI_PTYPE_VOLHDR);
    361 	volhdr->partitions[0].blocks = htobe32(lbl.d_secperunit - volhdr_size);
    362 	volhdr->partitions[0].first = htobe32(volhdr_size);
    363 	volhdr->partitions[0].type = htobe32(SGI_PTYPE_BSD);
    364 	write_volhdr();
    365 }
    366 
    367 void
    368 read_file(void)
    369 {
    370 	FILE *fp;
    371 	int i;
    372 
    373 	if (!opt_q)
    374 		printf("Reading file %s\n", vfilename);
    375 	for (i = 0; i < 15; ++i) {
    376 		if (strncmp(vfilename, volhdr->voldir[i].name,
    377 			    strlen(volhdr->voldir[i].name)) == 0)
    378 			break;
    379 	}
    380 	if (i >= 15) {
    381 		printf("file %s not found\n", vfilename);
    382 		exit(1);
    383 	}
    384 	/* XXX assumes volume header starts at 0? */
    385 	lseek(fd, be32toh(volhdr->voldir[i].block) * 512, SEEK_SET);
    386 	fp = fopen(ufilename, "w");
    387 	if (fp == NULL) {
    388 		perror("open write");
    389 		exit(1);
    390 	}
    391 	i = be32toh(volhdr->voldir[i].bytes);
    392 	while (i > 0) {
    393 		if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
    394 			perror("read file");
    395 			exit(1);
    396 		}
    397 		fwrite(buf, 1, i > sizeof(buf) ? sizeof(buf) : i, fp);
    398 		i -= i > sizeof(buf) ? sizeof(buf) : i;
    399 	}
    400 	fclose(fp);
    401 }
    402 
    403 void
    404 write_file(void)
    405 {
    406 	FILE *fp;
    407 	int slot;
    408 	size_t namelen;
    409 	int block, i;
    410 	struct stat st;
    411 	char fbuf[512];
    412 
    413 	if (!opt_q)
    414 		printf("Writing file %s\n", ufilename);
    415 	if (stat(ufilename, &st) < 0) {
    416 		perror("stat");
    417 		exit(1);
    418 	}
    419 	if (!opt_q)
    420 		printf("File %s has %lld bytes\n", ufilename, st.st_size);
    421 	slot = -1;
    422 	for (i = 0; i < 15; ++i) {
    423 		if (volhdr->voldir[i].name[0] == '\0' && slot < 0)
    424 			slot = i;
    425 		if (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
    426 			slot = i;
    427 			break;
    428 		}
    429 	}
    430 	if (slot == -1) {
    431 		printf("No directory space for file %s\n", vfilename);
    432 		exit(1);
    433 	}
    434 	/* -w can overwrite, -a won't overwrite */
    435 	if (be32toh(volhdr->voldir[slot].block) > 0) {
    436 		if (!opt_q)
    437 			printf("File %s exists, removing old file\n",
    438 				vfilename);
    439 		volhdr->voldir[slot].name[0] = 0;
    440 		volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0;
    441 	}
    442 	if (st.st_size == 0) {
    443 		printf("bad file size\n");
    444 		exit(1);
    445 	}
    446 	/* XXX assumes volume header starts at 0? */
    447 	block = allocate_space((int)st.st_size);
    448 	if (block < 0) {
    449 		printf("No space for file\n");
    450 		exit(1);
    451 	}
    452 
    453 	/*
    454 	 * Make sure the name in the volume header is max. 8 chars,
    455 	 * NOT including NUL.
    456 	 */
    457 	namelen = strlen(vfilename);
    458 	if (namelen > sizeof(volhdr->voldir[slot].name)) {
    459 		printf("Warning: '%s' is too long for volume header, ",
    460 		       vfilename);
    461 		namelen = sizeof(volhdr->voldir[slot].name);
    462 		printf("truncating to '%-8s'\n", vfilename);
    463 	}
    464 
    465 	/* Populate it w/ NULs */
    466 	memset(volhdr->voldir[slot].name, 0,
    467 	    sizeof(volhdr->voldir[slot].name));
    468 	/* Then copy the name */
    469 	memcpy(volhdr->voldir[slot].name, vfilename, namelen);
    470 
    471 	volhdr->voldir[slot].block = htobe32(block);
    472 	volhdr->voldir[slot].bytes = htobe32(st.st_size);
    473 
    474 	write_volhdr();
    475 
    476 	/* write the file itself */
    477 	i = lseek(fd, block * 512, SEEK_SET);
    478 	if (i < 0) {
    479 		perror("lseek write");
    480 		exit(1);
    481 	}
    482 	i = st.st_size;
    483 	fp = fopen(ufilename, "r");
    484 	while (i > 0) {
    485 		fread(fbuf, 1, i > 512 ? 512 : i, fp);
    486 		if (write(fd, fbuf, 512) != 512) {
    487 			perror("write file");
    488 			exit(1);
    489 		}
    490 		i -= i > 512 ? 512 : i;
    491 	}
    492 }
    493 
    494 void
    495 delete_file(void)
    496 {
    497 	int i;
    498 
    499 	for (i = 0; i < 15; ++i) {
    500 		if (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
    501 			break;
    502 		}
    503 	}
    504 	if (i >= 15) {
    505 		printf("File %s not found\n", vfilename);
    506 		exit(1);
    507 	}
    508 
    509 	/* XXX: we don't compact the file space, so get fragmentation */
    510 	volhdr->voldir[i].name[0] = '\0';
    511 	volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0;
    512 	write_volhdr();
    513 }
    514 
    515 void
    516 modify_partition(void)
    517 {
    518 	if (!opt_q)
    519 		printf("Modify partition %d start %d length %d\n",
    520 			partno, partfirst, partblocks);
    521 	if (partno < 0 || partno > 15) {
    522 		printf("Invalid partition number: %d\n", partno);
    523 		exit(1);
    524 	}
    525 	volhdr->partitions[partno].blocks = htobe32(partblocks);
    526 	volhdr->partitions[partno].first = htobe32(partfirst);
    527 	volhdr->partitions[partno].type = htobe32(parttype);
    528 	write_volhdr();
    529 }
    530 
    531 void
    532 write_volhdr(void)
    533 {
    534 	int i;
    535 
    536 	checksum_vol();
    537 
    538 	if (!opt_q)
    539 		display_vol();
    540 	if (!opt_f) {
    541 		printf("\nDo you want to update volume (y/n)? ");
    542 		i = getchar();
    543 		if (i != 'Y' && i != 'y')
    544 			exit(1);
    545 	}
    546 	i = lseek(fd, 0, SEEK_SET);
    547 	if (i < 0) {
    548 		perror("lseek 0");
    549 		exit(1);
    550 	}
    551 	i = write(fd, buf, 512);
    552 	if (i < 0)
    553 		perror("write volhdr");
    554 }
    555 
    556 int
    557 allocate_space(int size)
    558 {
    559 	int n, blocks;
    560 	int first;
    561 
    562 	blocks = (size + 511) / 512;
    563 	first = 2;
    564 	n = 0;
    565 	while (n < 15) {
    566 		if (volhdr->voldir[n].name[0]) {
    567 			if (first < (be32toh(volhdr->voldir[n].block) +
    568 			  (be32toh(volhdr->voldir[n].bytes) + 511) / 512) &&
    569 			    (first + blocks) > be32toh(volhdr->voldir[n].block)) {
    570 				first = be32toh(volhdr->voldir[n].block) +
    571 					(be32toh(volhdr->voldir[n].bytes) + 511) / 512;
    572 #if 0
    573 				printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size);
    574 				printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes);
    575 				printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block,
    576 				       first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511) / 512);
    577 #endif
    578 				n = 0;
    579 				continue;
    580 			}
    581 		}
    582 		++n;
    583 	}
    584 	if (first + blocks > lbl.d_secperunit)
    585 		first = -1;
    586 	/* XXX assumes volume header is partition 8 */
    587 	/* XXX assumes volume header starts at 0? */
    588 	if (first + blocks >= be32toh(volhdr->partitions[8].blocks))
    589 		first = -1;
    590 	return (first);
    591 }
    592 
    593 void
    594 checksum_vol(void)
    595 {
    596 	int32_t *l;
    597 	int i;
    598 
    599 	volhdr->checksum = checksum = 0;
    600 	l = (int32_t *)buf;
    601 	for (i = 0; i < 512 / 4; ++i)
    602 		checksum += be32toh(l[i]);
    603 	volhdr->checksum = htobe32(-checksum);
    604 }
    605 
    606 void
    607 usage(void)
    608 {
    609 	printf("Usage:	sgivol [-qf] [-i] [-h vhsize] device\n"
    610 	       "	sgivol [-qf] [-r vhfilename diskfilename] device\n"
    611 	       "	sgivol [-qf] [-w vhfilename diskfilename] device\n"
    612 	       "	sgivol [-qf] [-d vhfilename] device\n"
    613 	       );
    614 	exit(0);
    615 }
    616