xref: /netbsd/sys/arch/sgimips/stand/sgivol/sgivol.c (revision bf9ec67e)
1 /*	$NetBSD: sgivol.c,v 1.4 2002/03/13 13:12:30 simonb 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 (strncmp(vfilename, volhdr->voldir[i].name,
276 		    sizeof(volhdr->voldir[i].name)) == NULL)
277 			break;
278 	}
279 	if (i >= 15) {
280 		printf("file %s not found\n", vfilename);
281 		exit(1);
282 	}
283 	/* XXX assumes volume header starts at 0? */
284 	lseek(fd, volhdr->voldir[i].block * 512, SEEK_SET);
285 	fp = fopen(ufilename, "w");
286 	if (fp == NULL) {
287 		perror("open write");
288 		exit(1);
289 	}
290 	i = volhdr->voldir[i].bytes;
291 	while (i > 0) {
292 		if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
293 			perror("read file");
294 			exit(1);
295 		}
296 		fwrite(buf, 1, i > sizeof(buf) ? sizeof(buf) : i, fp);
297 		i -= i > sizeof(buf) ? sizeof(buf) : i;
298 	}
299 	fclose(fp);
300 }
301 
302 void
303 write_file(void)
304 {
305 	FILE *fp;
306 	int slot;
307 	size_t namelen;
308 	int block, i;
309 	struct stat st;
310 	char fbuf[512];
311 
312 	printf("Writing file %s\n", ufilename);
313 	if (stat(ufilename, &st) < 0) {
314 		perror("stat");
315 		exit(1);
316 	}
317 	printf("File %s has %lld bytes\n", ufilename, st.st_size);
318 	slot = -1;
319 	for (i = 0; i < 15; ++i) {
320 		if (volhdr->voldir[i].name[0] == '\0' && slot < 0)
321 			slot = i;
322 		if (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
323 			slot = i;
324 			break;
325 		}
326 	}
327 	if (slot == -1) {
328 		printf("No directory space for file %s\n", vfilename);
329 		exit(1);
330 	}
331 	/* -w can overwrite, -a won't overwrite */
332 	if (volhdr->voldir[slot].block > 0) {
333 		printf("File %s exists, removing old file\n", vfilename);
334 		volhdr->voldir[slot].name[0] = 0;
335 		volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0;
336 	}
337 	if (st.st_size == 0) {
338 		printf("bad file size?\n");
339 		exit(1);
340 	}
341 	/* XXX assumes volume header starts at 0? */
342 	block = allocate_space((int)st.st_size);
343 	if (block < 0) {
344 		printf("No space for file\n");
345 		exit(1);
346 	}
347 
348 	/*
349 	 * Make sure the name in the volume header is max. 8 chars,
350 	 * NOT including NUL.
351 	 */
352 	namelen = strlen(vfilename);
353 	if (namelen > sizeof(volhdr->voldir[slot].name)) {
354 		printf("Warning: '%s' is too long for volume header, ",
355 		       vfilename);
356 		namelen = sizeof(volhdr->voldir[slot].name);
357 		printf("truncating to '%-8s'\n", vfilename);
358 	}
359 
360 	/* Populate it w/ NULs */
361 	memset(volhdr->voldir[slot].name, 0,
362 	    sizeof(volhdr->voldir[slot].name));
363 	/* Then copy the name */
364 	memcpy(volhdr->voldir[slot].name, vfilename, namelen);
365 
366 	volhdr->voldir[slot].block = block;
367 	volhdr->voldir[slot].bytes = st.st_size;
368 
369 	write_volhdr();
370 
371 	/* write the file itself */
372 	i = lseek(fd, block * 512, SEEK_SET);
373 	if (i < 0) {
374 		perror("lseek write");
375 		exit(1);
376 	}
377 	i = st.st_size;
378 	fp = fopen(ufilename, "r");
379 	while (i > 0) {
380 		fread(fbuf, 1, i > 512 ? 512 : i, fp);
381 		if (write(fd, fbuf, 512) != 512) {
382 			perror("write file");
383 			exit(1);
384 		}
385 		i -= i > 512 ? 512 : i;
386 	}
387 }
388 
389 void
390 delete_file(void)
391 {
392 	int i;
393 
394 	for (i = 0; i < 15; ++i) {
395 		if (strcmp(vfilename, volhdr->voldir[i].name) == NULL) {
396 			break;
397 		}
398 	}
399 	if (i >= 15) {
400 		printf("File %s not found\n", vfilename);
401 		exit(1);
402 	}
403 	volhdr->voldir[i].name[0] = '\0';
404 	volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0;
405 	write_volhdr();
406 }
407 
408 void
409 modify_partition(void)
410 {
411 	printf("Modify partition %d start %d length %d\n", partno, partfirst,
412 	    partblocks);
413 	if (partno < 0 || partno > 15) {
414 		printf("Invalue partition number: %d\n", partno);
415 		exit(1);
416 	}
417 	volhdr->partitions[partno].blocks = partblocks;
418 	volhdr->partitions[partno].first = partfirst;
419 	volhdr->partitions[partno].type = parttype;
420 	write_volhdr();
421 }
422 
423 void
424 write_volhdr(void)
425 {
426 	int i;
427 
428 	checksum_vol();
429 	display_vol();
430 	printf("\nDo you want to update volume (y/n)? ");
431 	i = getchar();
432 	if (i != 'Y' && i != 'y')
433 		exit(1);
434 	i = lseek(fd, 0 , SEEK_SET);
435 	if (i < 0) {
436 		perror("lseek 0");
437 		exit(1);
438 	}
439 	i = write(fd, buf, 512);
440 	if (i < 0)
441 		perror("write volhdr");
442 }
443 
444 int
445 allocate_space(int size)
446 {
447 	int n, blocks;
448 	int first;
449 
450 	blocks = (size + 511) / 512;
451 	first = 2;
452 	n = 0;
453 	while (n < 15) {
454 		if (volhdr->voldir[n].name[0]) {
455 			if (first < (volhdr->voldir[n].block +
456 			    (volhdr->voldir[n].bytes + 511) / 512) &&
457 			    (first + blocks) >= volhdr->voldir[n].block) {
458 				first = volhdr->voldir[n].block +
459 				    (volhdr->voldir[n].bytes + 511) / 512;
460 #if 0
461 printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size);
462 printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes);
463 printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block,
464     first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511)/512);
465 #endif
466 				n = 0;
467 				continue;
468 			}
469 		}
470 		++n;
471 	}
472 	if (first + blocks > lbl.d_secperunit)
473 		first = -1;
474 	/* XXX assumes volume header is partition 8 */
475 	/* XXX assumes volume header starts at 0? */
476 	if (first + blocks >= volhdr->partitions[8].blocks)
477 		first = -1;
478 	return(first);
479 }
480 
481 void
482 checksum_vol(void)
483 {
484 	int32_t *l;
485 	int i;
486 
487 	volhdr->checksum = checksum = 0;
488 	l = (int32_t *)buf;
489 	for (i = 0; i < 512 / 4; ++i)
490 		checksum += l[i];
491 	volhdr->checksum = -checksum;
492 }
493 
494 void
495 usage(void)
496 {
497 	printf("Usage:	sgivol [-i] device\n"
498 	       "	sgivol [-r vhfilename diskfilename] device\n"
499 	       "	sgivol [-w vhfilename diskfilename] device\n"
500 	       "	sgivol [-d vhfilename] device\n"
501 	       );
502 	exit(0);
503 }
504