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