Home | History | Annotate | Line # | Download | only in sgivol
sgivol.c revision 1.2
      1 /*	$NetBSD: sgivol.c,v 1.2 2001/11/20 23:07:17 thorpej 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 <stdio.h>
     45 #include <stdlib.h>
     46 #include <unistd.h>
     47 #include <string.h>
     48 #include <fcntl.h>
     49 #include <util.h>
     50 
     51 #define SGI_SIZE_VOLHDR	3135	/* XXX Irix: 2592, NetBSD: 3753 */
     52 
     53 int	fd;
     54 int	opt_i;			/* Initialize volume header */
     55 int	opt_r;			/* Read a file from volume header */
     56 int	opt_w;			/* Write a file to volume header */
     57 int	opt_d;			/* Delete a file from volume header */
     58 int	opt_p;			/* Modify a partition */
     59 int	partno, partfirst, partblocks, parttype;
     60 struct sgilabel *volhdr;
     61 int32_t	checksum;
     62 
     63 const char *vfilename = "";
     64 const char *ufilename = "";
     65 
     66 struct disklabel lbl;
     67 
     68 unsigned char buf[512];
     69 
     70 const char *sgi_types[] = {
     71 	"Volume Header",
     72 	"Repl Trks",
     73 	"Repl Secs",
     74 	"Raw",
     75 	"BSD4.2",
     76 	"SysV",
     77 	"Volume",
     78 	"EFS",
     79 	"LVol",
     80 	"RLVol",
     81 	"XFS",
     82 	"XSFLog",
     83 	"XLV",
     84 	"XVM"
     85 };
     86 
     87 int	main(int, char *[]);
     88 
     89 void	display_vol(void);
     90 void	init_volhdr(void);
     91 void	read_file(void);
     92 void	write_file(void);
     93 void	delete_file(void);
     94 void	modify_partition(void);
     95 void	write_volhdr(void);
     96 int	allocate_space(int);
     97 void	checksum_vol(void);
     98 void	usage(void);
     99 
    100 int
    101 main(int argc, char *argv[])
    102 {
    103 	if (argc < 2)
    104 		usage();
    105 
    106 	if (argv[1][0] == '-') {
    107 		switch(argv[1][1]) {
    108 		case 'i':
    109 			++opt_i;
    110 			argv++;
    111 			argc--;
    112 			break;
    113 		case 'r':
    114 		case 'w':
    115 			if (argc < 4)
    116 				usage();
    117 			if (argv[1][1] == 'r')
    118 				++opt_r;
    119 			else
    120 				++opt_w;
    121 			vfilename = argv[2];
    122 			ufilename = argv[3];
    123 			argv += 3;
    124 			argc -= 3;
    125 			break;
    126 		case 'd':
    127 			if (argc < 3)
    128 				usage();
    129 			++opt_d;
    130 			vfilename = argv[2];
    131 			argv += 2;
    132 			argc -= 2;
    133 				break;
    134 		case 'p':
    135 			if (argc < 6)
    136 				usage();
    137 			++opt_p;
    138 			partno = atoi(argv[2]);
    139 			partfirst = atoi(argv[3]);
    140 			partblocks = atoi(argv[4]);
    141 			parttype = atoi(argv[5]);
    142 			argv += 5;
    143 			argc -= 5;
    144 			break;
    145 		default:
    146 			printf("-%c Invalid\n", argv[1][1]);
    147 			usage();
    148 		}
    149 	}
    150 
    151 	if (argc < 2)
    152 		usage();
    153 
    154 	fd = open(argv[1], (opt_i | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY);
    155 	if (fd < 0) {
    156 		sprintf(buf, "/dev/r%s%c", argv[1], 'a' + getrawpartition());
    157 		fd = open(buf,
    158 		    (opt_i | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY);
    159 		if (fd < 0) {
    160 			perror("open");
    161 			exit(1);
    162 		}
    163 	}
    164 	if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
    165 		perror("read volhdr");
    166 		exit(1);
    167 	}
    168 	if (ioctl(fd, DIOCGDINFO, &lbl) < 0) {
    169 		perror("DIOCGDINFO");
    170 		exit(1);
    171 	}
    172 	volhdr = (struct sgilabel *)buf;
    173 	if (opt_i) {
    174 		init_volhdr();
    175 		exit(0);
    176 	}
    177 	if (volhdr->magic != SGILABEL_MAGIC) {
    178 		printf("No SGI volume header found, magic=%x\n", volhdr->magic);
    179 		exit(1);
    180 	}
    181 	if (opt_r) {
    182 		read_file();
    183 		exit(0);
    184 	}
    185 	if (opt_w) {
    186 		write_file();
    187 		exit(0);
    188 	}
    189 	if (opt_d) {
    190 		delete_file();
    191 		exit(0);
    192 	}
    193 	if (opt_p) {
    194 		modify_partition();
    195 		exit(0);
    196 	}
    197 	display_vol();
    198 
    199 	return 0;
    200 }
    201 
    202 void
    203 display_vol(void)
    204 {
    205 	int32_t *l;
    206 	int i;
    207 
    208 	printf("disklabel shows %d sectors\n", lbl.d_secperunit);
    209 	l = (int32_t *)buf;
    210 	checksum = 0;
    211 	for (i = 0; i < 512 / 4; ++i)
    212 		checksum += l[i];
    213 	printf("checksum: %08x%s\n", checksum, checksum == 0 ? "" : " *ERROR*");
    214 	printf("root part: %d\n", volhdr->root);
    215 	printf("swap part: %d\n", volhdr->swap);
    216 	printf("bootfile: %s\n", volhdr->bootfile);
    217 	/* volhdr->devparams[0..47] */
    218 	printf("\nVolume header files:\n");
    219 	for (i = 0; i < 15; ++i)
    220 		if (volhdr->voldir[i].name[0])
    221 			printf("%-8s offset %4d blocks, length %8d bytes (%d blocks)\n",
    222 			    volhdr->voldir[i].name, volhdr->voldir[i].block,
    223 			    volhdr->voldir[i].bytes, (volhdr->voldir[i].bytes + 511 ) / 512);
    224 	printf("\nSGI partitions:\n");
    225 	for (i = 0; i < MAXPARTITIONS; ++i) {
    226 		if (volhdr->partitions[i].blocks) {
    227 			printf("%2d:%c blocks %8d first %8d type %2d (%s)\n",
    228 			    i, i + 'a', volhdr->partitions[i].blocks,
    229 			    volhdr->partitions[i].first,
    230 			    volhdr->partitions[i].type,
    231 			    volhdr->partitions[i].type > 13 ? "???" :
    232 			    sgi_types[volhdr->partitions[i].type]);
    233 		}
    234 	}
    235 }
    236 
    237 void
    238 init_volhdr(void)
    239 {
    240 	memset(buf, 0, sizeof(buf));
    241 	volhdr->magic = SGILABEL_MAGIC;
    242 	volhdr->root = 0;
    243 	volhdr->swap = 1;
    244 	strcpy(volhdr->bootfile, "/netbsd");
    245         volhdr->dp.dp_skew = lbl.d_trackskew;
    246         volhdr->dp.dp_gap1 = 1; /* XXX */
    247         volhdr->dp.dp_gap2 = 1; /* XXX */
    248         volhdr->dp.dp_cyls = lbl.d_ncylinders;
    249         volhdr->dp.dp_shd0 = 0;
    250         volhdr->dp.dp_trks0 = lbl.d_ntracks;
    251         volhdr->dp.dp_secs = lbl.d_nsectors;
    252         volhdr->dp.dp_secbytes = lbl.d_secsize;
    253         volhdr->dp.dp_interleave = lbl.d_interleave;
    254         volhdr->dp.dp_nretries = 22;
    255 	volhdr->partitions[10].blocks = lbl.d_secperunit;
    256 	volhdr->partitions[10].first = 0;
    257 	volhdr->partitions[10].type = SGI_PTYPE_VOLUME;
    258 	volhdr->partitions[8].blocks = SGI_SIZE_VOLHDR;
    259 	volhdr->partitions[8].first = 0;
    260 	volhdr->partitions[8].type = SGI_PTYPE_VOLHDR;
    261 	volhdr->partitions[0].blocks = lbl.d_secperunit - SGI_SIZE_VOLHDR;
    262 	volhdr->partitions[0].first = SGI_SIZE_VOLHDR;
    263 	volhdr->partitions[0].type = SGI_PTYPE_BSD;
    264 	write_volhdr();
    265 }
    266 
    267 void
    268 read_file(void)
    269 {
    270 	FILE *fp;
    271 	int i;
    272 
    273 	printf("Reading file %s\n", vfilename);
    274 	for (i = 0; i < 15; ++i) {
    275 		if (strcmp(vfilename, volhdr->voldir[i].name) == NULL)
    276 			break;
    277 	}
    278 	if (i >= 15) {
    279 		printf("file %s not found\n", vfilename);
    280 		exit(1);
    281 	}
    282 	/* XXX assumes volume header starts at 0? */
    283 	lseek(fd, volhdr->voldir[i].block * 512, SEEK_SET);
    284 	fp = fopen(ufilename, "w");
    285 	if (fp == NULL) {
    286 		perror("open write");
    287 		exit(1);
    288 	}
    289 	i = volhdr->voldir[i].bytes;
    290 	while (i > 0) {
    291 		if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
    292 			perror("read file");
    293 			exit(1);
    294 		}
    295 		fwrite(buf, 1, i > sizeof(buf) ? sizeof(buf) : i, fp);
    296 		i -= i > sizeof(buf) ? sizeof(buf) : i;
    297 	}
    298 	fclose(fp);
    299 }
    300 
    301 void
    302 write_file(void)
    303 {
    304 	FILE *fp;
    305 	int slot;
    306 	size_t namelen;
    307 	int block, i;
    308 	struct stat st;
    309 	char fbuf[512];
    310 
    311 	printf("Writing file %s\n", ufilename);
    312 	if (stat(ufilename, &st) < 0) {
    313 		perror("stat");
    314 		exit(1);
    315 	}
    316 	printf("File %s has %lld bytes\n", ufilename, st.st_size);
    317 	slot = -1;
    318 	for (i = 0; i < 15; ++i) {
    319 		if (volhdr->voldir[i].name[0] == '\0' && slot < 0)
    320 			slot = i;
    321 		if (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
    322 			slot = i;
    323 			break;
    324 		}
    325 	}
    326 	if (slot == -1) {
    327 		printf("No directory space for file %s\n", vfilename);
    328 		exit(1);
    329 	}
    330 	/* -w can overwrite, -a won't overwrite */
    331 	if (volhdr->voldir[slot].block > 0) {
    332 		printf("File %s exists, removing old file\n", vfilename);
    333 		volhdr->voldir[slot].name[0] = 0;
    334 		volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0;
    335 	}
    336 	if (st.st_size == 0) {
    337 		printf("bad file size?\n");
    338 		exit(1);
    339 	}
    340 	/* XXX assumes volume header starts at 0? */
    341 	block = allocate_space((int)st.st_size);
    342 	if (block < 0) {
    343 		printf("No space for file\n");
    344 		exit(1);
    345 	}
    346 
    347 	/*
    348 	 * Make sure the name in the volume header is max. 8 chars,
    349 	 * NOT including NUL.
    350 	 */
    351 	namelen = strlen(vfilename);
    352 	if (namelen > sizeof(volhdr->voldir[slot].name)) {
    353 		printf("Warning: '%s' is too long for volume header, ",
    354 		       vfilename);
    355 		namelen = sizeof(volhdr->voldir[slot].name);
    356 		printf("truncating to '%-8s'\n", vfilename);
    357 	}
    358 
    359 	/* Populate it w/ NULs */
    360 	memset(volhdr->voldir[slot].name, 0,
    361 	    sizeof(volhdr->voldir[slot].name));
    362 	/* Then copy the name */
    363 	memcpy(volhdr->voldir[slot].name, vfilename, namelen);
    364 
    365 	volhdr->voldir[slot].block = block;
    366 	volhdr->voldir[slot].bytes = st.st_size;
    367 
    368 	write_volhdr();
    369 
    370 	/* write the file itself */
    371 	i = lseek(fd, block * 512, SEEK_SET);
    372 	if (i < 0) {
    373 		perror("lseek write");
    374 		exit(1);
    375 	}
    376 	i = st.st_size;
    377 	fp = fopen(ufilename, "r");
    378 	while (i > 0) {
    379 		fread(fbuf, 1, i > 512 ? 512 : i, fp);
    380 		if (write(fd, fbuf, 512) != 512) {
    381 			perror("write file");
    382 			exit(1);
    383 		}
    384 		i -= i > 512 ? 512 : i;
    385 	}
    386 }
    387 
    388 void
    389 delete_file(void)
    390 {
    391 	int i;
    392 
    393 	for (i = 0; i < 15; ++i) {
    394 		if (strcmp(vfilename, volhdr->voldir[i].name) == NULL) {
    395 			break;
    396 		}
    397 	}
    398 	if (i >= 15) {
    399 		printf("File %s not found\n", vfilename);
    400 		exit(1);
    401 	}
    402 	volhdr->voldir[i].name[0] = '\0';
    403 	volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0;
    404 	write_volhdr();
    405 }
    406 
    407 void
    408 modify_partition(void)
    409 {
    410 	printf("Modify partition %d start %d length %d\n", partno, partfirst,
    411 	    partblocks);
    412 	if (partno < 0 || partno > 15) {
    413 		printf("Invalue partition number: %d\n", partno);
    414 		exit(1);
    415 	}
    416 	volhdr->partitions[partno].blocks = partblocks;
    417 	volhdr->partitions[partno].first = partfirst;
    418 	volhdr->partitions[partno].type = parttype;
    419 	write_volhdr();
    420 }
    421 
    422 void
    423 write_volhdr(void)
    424 {
    425 	int i;
    426 
    427 	checksum_vol();
    428 	display_vol();
    429 	printf("\nDo you want to update volume (y/n)? ");
    430 	i = getchar();
    431 	if (i != 'Y' && i != 'y')
    432 		exit(1);
    433 	i = lseek(fd, 0 , SEEK_SET);
    434 	if (i < 0) {
    435 		perror("lseek 0");
    436 		exit(1);
    437 	}
    438 	i = write(fd, buf, 512);
    439 	if (i < 0)
    440 		perror("write volhdr");
    441 }
    442 
    443 int
    444 allocate_space(int size)
    445 {
    446 	int n, blocks;
    447 	int first;
    448 
    449 	blocks = (size + 511) / 512;
    450 	first = 2;
    451 	n = 0;
    452 	while (n < 15) {
    453 		if (volhdr->voldir[n].name[0]) {
    454 			if (first < (volhdr->voldir[n].block +
    455 			    (volhdr->voldir[n].bytes + 511) / 512) &&
    456 			    (first + blocks) >= volhdr->voldir[n].block) {
    457 				first = volhdr->voldir[n].block +
    458 				    (volhdr->voldir[n].bytes + 511) / 512;
    459 #if 0
    460 printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size);
    461 printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes);
    462 printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block,
    463     first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511)/512);
    464 #endif
    465 				n = 0;
    466 				continue;
    467 			}
    468 		}
    469 		++n;
    470 	}
    471 	if (first + blocks > lbl.d_secperunit)
    472 		first = -1;
    473 	/* XXX assumes volume header is partition 8 */
    474 	/* XXX assumes volume header starts at 0? */
    475 	if (first + blocks >= volhdr->partitions[8].blocks)
    476 		first = -1;
    477 	return(first);
    478 }
    479 
    480 void
    481 checksum_vol(void)
    482 {
    483 	int32_t *l;
    484 	int i;
    485 
    486 	volhdr->checksum = checksum = 0;
    487 	l = (int32_t *)buf;
    488 	for (i = 0; i < 512 / 4; ++i)
    489 		checksum += l[i];
    490 	volhdr->checksum = -checksum;
    491 }
    492 
    493 void
    494 usage(void)
    495 {
    496 	printf("Usage:  sgivol [-i] device\n"
    497 	       "        sgivol [-r vhfilename diskfilename] device\n"
    498 	       "        sgivol [-w vhfilename diskfilename] device\n"
    499 	       "        sgivol [-d vhfilename] device\n"
    500 	       );
    501 	exit(0);
    502 }
    503