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