sgivol.c revision 1.12 1 /* $NetBSD: sgivol.c,v 1.12 2006/05/05 17:59:41 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 #if HAVE_NBTOOL_CONFIG_H
40 #include "nbtool_config.h"
41 #endif
42
43 #include <sys/types.h>
44 #include <sys/ioctl.h>
45 #include <sys/stat.h>
46
47 #if HAVE_NBTOOL_CONFIG_H
48 #include "../../../../../sys/sys/bootblock.h"
49 /* Ficticious geometry for cross tool usage against a file image */
50 #define SGIVOL_NBTOOL_NSECS 32
51 #define SGIVOL_NBTOOL_NTRACKS 64
52 #else
53 #include <sys/disklabel.h>
54 #endif
55
56 #include <errno.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <unistd.h>
60 #include <string.h>
61 #include <fcntl.h>
62 #include <util.h>
63 #ifndef HAVE_NBTOOL_CONFIG_H
64 #include <sys/endian.h>
65 #endif
66
67 int fd;
68 int opt_i; /* Initialize volume header */
69 int opt_r; /* Read a file from volume header */
70 int opt_w; /* Write a file to volume header */
71 int opt_d; /* Delete a file from volume header */
72 int opt_p; /* Modify a partition */
73 int opt_q; /* quiet mode */
74 int opt_f; /* Don't ask, just do what you're told */
75 int partno, partfirst, partblocks, parttype;
76 struct sgi_boot_block *volhdr;
77 int32_t checksum;
78 u_int32_t volhdr_size = SGI_BOOT_BLOCK_SIZE_VOLHDR;
79
80 const char *vfilename = "";
81 const char *ufilename = "";
82
83 #if HAVE_NBTOOL_CONFIG_H
84 struct stat st;
85 #else
86 struct disklabel lbl;
87 #endif
88
89 unsigned char buf[512];
90
91 const char *sgi_types[] = {
92 "Volume Header",
93 "Repl Trks",
94 "Repl Secs",
95 "Raw",
96 "BSD4.2",
97 "SysV",
98 "Volume",
99 "EFS",
100 "LVol",
101 "RLVol",
102 "XFS",
103 "XSFLog",
104 "XLV",
105 "XVM"
106 };
107
108 int main(int, char *[]);
109
110 void display_vol(void);
111 void init_volhdr(void);
112 void read_file(void);
113 void write_file(void);
114 void delete_file(void);
115 void modify_partition(void);
116 void write_volhdr(void);
117 int allocate_space(int);
118 void checksum_vol(void);
119 void usage(void);
120
121 int
122 main(int argc, char *argv[])
123 {
124 int ch;
125 while ((ch = getopt(argc, argv, "irwpdqfh:")) != -1) {
126 switch (ch) {
127 /* -i, -r, -w, -d and -p override each other */
128 /* -q implies -f */
129 case 'q':
130 ++opt_q;
131 ++opt_f;
132 break;
133 case 'f':
134 ++opt_f;
135 break;
136 case 'i':
137 ++opt_i;
138 opt_r = opt_w = opt_d = opt_p = 0;
139 break;
140 case 'h':
141 volhdr_size = atoi(optarg);
142 break;
143 case 'r':
144 ++opt_r;
145 opt_i = opt_w = opt_d = opt_p = 0;
146 break;
147 case 'w':
148 ++opt_w;
149 opt_i = opt_r = opt_d = opt_p = 0;
150 break;
151 case 'd':
152 ++opt_d;
153 opt_i = opt_r = opt_w = opt_p = 0;
154 break;
155 case 'p':
156 ++opt_p;
157 opt_i = opt_r = opt_w = opt_d = 0;
158 partno = atoi(argv[0]);
159 partfirst = atoi(argv[1]);
160 partblocks = atoi(argv[2]);
161 parttype = atoi(argv[3]);
162 break;
163 case '?':
164 default:
165 usage();
166 }
167 }
168 argc -= optind;
169 argv += optind;
170
171 if (opt_r || opt_w) {
172 if (argc != 3)
173 usage();
174 vfilename = argv[0];
175 ufilename = argv[1];
176 argc -= 2;
177 argv += 2;
178 }
179 if (opt_d) {
180 if (argc != 2)
181 usage();
182 vfilename = argv[0];
183 argc--;
184 argv++;
185 }
186
187 if (opt_p) {
188 if (argc != 5)
189 usage();
190 partno = atoi(argv[0]);
191 partfirst = atoi(argv[1]);
192 partblocks = atoi(argv[2]);
193 parttype = atoi(argv[3]);
194 argc -= 4;
195 argv += 4;
196 }
197 if (argc != 1)
198 usage();
199
200 fd = open(argv[0], (opt_i | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY);
201 if (fd < 0) {
202 #if HAVE_NBTOOL_CONFIG_H
203 perror("File open");
204 exit(1);
205 #else
206 sprintf(buf, "/dev/r%s%c", argv[0], 'a' + getrawpartition());
207 fd = open(buf, (opt_i | opt_w | opt_d | opt_p)
208 ? O_RDWR : O_RDONLY);
209 if (fd < 0) {
210 printf("Error opening device %s: %s\n",
211 argv[0], strerror(errno));
212 exit(1);
213 }
214 #endif
215 }
216 if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
217 perror("read volhdr");
218 exit(1);
219 }
220 #if HAVE_NBTOOL_CONFIG_H
221 if (fstat(fd, &st) < 0) {
222 perror("stat error");
223 exit(1);
224 }
225 if (!S_ISREG(st.st_mode)) {
226 printf("Must be regular file\n");
227 exit(1);
228 }
229 if (st.st_size % SGI_BOOT_BLOCK_BLOCKSIZE) {
230 printf("Size must be multiple of %d\n",
231 SGI_BOOT_BLOCK_BLOCKSIZE);
232 exit(1);
233 }
234 if (st.st_size < (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS)) {
235 printf("Minimum size of %d required\n",
236 SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS);
237 exit(1);
238 }
239 #else
240 if (ioctl(fd, DIOCGDINFO, &lbl) < 0) {
241 perror("DIOCGDINFO");
242 exit(1);
243 }
244 #endif
245 volhdr = (struct sgi_boot_block *) buf;
246 if (opt_i) {
247 init_volhdr();
248 exit(0);
249 }
250 if (be32toh(volhdr->magic) != SGI_BOOT_BLOCK_MAGIC) {
251 printf("No Volume Header found, magic=%x. Use -i first.\n",
252 be32toh(volhdr->magic));
253 exit(1);
254 }
255 if (opt_r) {
256 read_file();
257 exit(0);
258 }
259 if (opt_w) {
260 write_file();
261 exit(0);
262 }
263 if (opt_d) {
264 delete_file();
265 exit(0);
266 }
267 if (opt_p) {
268 modify_partition();
269 exit(0);
270 }
271
272 if (!opt_q)
273 display_vol();
274
275 return 0;
276 }
277
278 void
279 display_vol(void)
280 {
281 int32_t *l;
282 int i;
283
284 #if HAVE_NBTOOL_CONFIG_H
285 printf("disklabel shows %d sectors\n",
286 st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
287 #else
288 printf("disklabel shows %d sectors\n", lbl.d_secperunit);
289 #endif
290 l = (int32_t *)buf;
291 checksum = 0;
292 for (i = 0; i < 512 / 4; ++i)
293 checksum += be32toh(l[i]);
294 printf("checksum: %08x%s\n", checksum, checksum == 0 ? "" : " *ERROR*");
295 printf("root part: %d\n", be16toh(volhdr->root));
296 printf("swap part: %d\n", be16toh(volhdr->swap));
297 printf("bootfile: %s\n", volhdr->bootfile);
298 /* volhdr->devparams[0..47] */
299 printf("\nVolume header files:\n");
300 for (i = 0; i < 15; ++i)
301 if (volhdr->voldir[i].name[0])
302 printf("%-8s offset %4d blocks, length %8d bytes "
303 "(%d blocks)\n",
304 volhdr->voldir[i].name,
305 be32toh(volhdr->voldir[i].block),
306 be32toh(volhdr->voldir[i].bytes),
307 (be32toh(volhdr->voldir[i].bytes) + 511) / 512);
308 printf("\nSGI partitions:\n");
309 for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; ++i) {
310 if (be32toh(volhdr->partitions[i].blocks)) {
311 printf("%2d:%c blocks %8d first %8d type %2d (%s)\n",
312 i, i + 'a', be32toh(volhdr->partitions[i].blocks),
313 be32toh(volhdr->partitions[i].first),
314 be32toh(volhdr->partitions[i].type),
315 be32toh(volhdr->partitions[i].type) > 13 ? "???" :
316 sgi_types[be32toh(volhdr->partitions[i].type)]);
317 }
318 }
319 }
320
321 void
322 init_volhdr(void)
323 {
324 memset(buf, 0, sizeof(buf));
325 volhdr->magic = htobe32(SGI_BOOT_BLOCK_MAGIC);
326 volhdr->root = htobe16(0);
327 volhdr->swap = htobe16(1);
328 strcpy(volhdr->bootfile, "/netbsd");
329 #if HAVE_NBTOOL_CONFIG_H
330 volhdr->dp.dp_skew = 0;
331 #else
332 volhdr->dp.dp_skew = lbl.d_trackskew;
333 #endif
334 volhdr->dp.dp_gap1 = 1; /* XXX */
335 volhdr->dp.dp_gap2 = 1; /* XXX */
336 #if HAVE_NBTOOL_CONFIG_H
337 volhdr->dp.dp_cyls =
338 htobe16(st.st_size / (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS));
339 #else
340 volhdr->dp.dp_cyls = htobe16(lbl.d_ncylinders);
341 #endif
342 volhdr->dp.dp_shd0 = 0;
343 #if HAVE_NBTOOL_CONFIG_H
344 volhdr->dp.dp_trks0 = htobe16(SGIVOL_NBTOOL_NTRACKS);
345 volhdr->dp.dp_secs = htobe16(SGIVOL_NBTOOL_NSECS);
346 volhdr->dp.dp_secbytes = htobe16(SGI_BOOT_BLOCK_BLOCKSIZE);
347 volhdr->dp.dp_interleave = htobe16(1);
348 #else
349 volhdr->dp.dp_trks0 = htobe16(lbl.d_ntracks);
350 volhdr->dp.dp_secs = htobe16(lbl.d_nsectors);
351 volhdr->dp.dp_secbytes = htobe16(lbl.d_secsize);
352 volhdr->dp.dp_interleave = htobe16(lbl.d_interleave);
353 #endif
354 volhdr->dp.dp_nretries = htobe32(22);
355 #if HAVE_NBTOOL_CONFIG_H
356 volhdr->partitions[10].blocks =
357 htobe32(st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
358 #else
359 volhdr->partitions[10].blocks = htobe32(lbl.d_secperunit);
360 #endif
361 volhdr->partitions[10].first = 0;
362 volhdr->partitions[10].type = htobe32(SGI_PTYPE_VOLUME);
363 volhdr->partitions[8].blocks = htobe32(volhdr_size);
364 volhdr->partitions[8].first = 0;
365 volhdr->partitions[8].type = htobe32(SGI_PTYPE_VOLHDR);
366 #if HAVE_NBTOOL_CONFIG_H
367 volhdr->partitions[0].blocks =
368 htobe32((st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE) - volhdr_size);
369 #else
370 volhdr->partitions[0].blocks = htobe32(lbl.d_secperunit - volhdr_size);
371 #endif
372 volhdr->partitions[0].first = htobe32(volhdr_size);
373 volhdr->partitions[0].type = htobe32(SGI_PTYPE_BSD);
374 write_volhdr();
375 }
376
377 void
378 read_file(void)
379 {
380 FILE *fp;
381 int i;
382
383 if (!opt_q)
384 printf("Reading file %s\n", vfilename);
385 for (i = 0; i < 15; ++i) {
386 if (strncmp(vfilename, volhdr->voldir[i].name,
387 strlen(volhdr->voldir[i].name)) == 0)
388 break;
389 }
390 if (i >= 15) {
391 printf("file %s not found\n", vfilename);
392 exit(1);
393 }
394 /* XXX assumes volume header starts at 0? */
395 lseek(fd, be32toh(volhdr->voldir[i].block) * 512, SEEK_SET);
396 fp = fopen(ufilename, "w");
397 if (fp == NULL) {
398 perror("open write");
399 exit(1);
400 }
401 i = be32toh(volhdr->voldir[i].bytes);
402 while (i > 0) {
403 if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
404 perror("read file");
405 exit(1);
406 }
407 fwrite(buf, 1, i > sizeof(buf) ? sizeof(buf) : i, fp);
408 i -= i > sizeof(buf) ? sizeof(buf) : i;
409 }
410 fclose(fp);
411 }
412
413 void
414 write_file(void)
415 {
416 FILE *fp;
417 int slot;
418 size_t namelen;
419 int block, i;
420 struct stat st;
421 char fbuf[512];
422
423 if (!opt_q)
424 printf("Writing file %s\n", ufilename);
425 if (stat(ufilename, &st) < 0) {
426 perror("stat");
427 exit(1);
428 }
429 if (!opt_q)
430 printf("File %s has %lld bytes\n", ufilename, st.st_size);
431 slot = -1;
432 for (i = 0; i < 15; ++i) {
433 if (volhdr->voldir[i].name[0] == '\0' && slot < 0)
434 slot = i;
435 if (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
436 slot = i;
437 break;
438 }
439 }
440 if (slot == -1) {
441 printf("No directory space for file %s\n", vfilename);
442 exit(1);
443 }
444 /* -w can overwrite, -a won't overwrite */
445 if (be32toh(volhdr->voldir[slot].block) > 0) {
446 if (!opt_q)
447 printf("File %s exists, removing old file\n",
448 vfilename);
449 volhdr->voldir[slot].name[0] = 0;
450 volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0;
451 }
452 if (st.st_size == 0) {
453 printf("bad file size\n");
454 exit(1);
455 }
456 /* XXX assumes volume header starts at 0? */
457 block = allocate_space((int)st.st_size);
458 if (block < 0) {
459 printf("No space for file\n");
460 exit(1);
461 }
462
463 /*
464 * Make sure the name in the volume header is max. 8 chars,
465 * NOT including NUL.
466 */
467 namelen = strlen(vfilename);
468 if (namelen > sizeof(volhdr->voldir[slot].name)) {
469 printf("Warning: '%s' is too long for volume header, ",
470 vfilename);
471 namelen = sizeof(volhdr->voldir[slot].name);
472 printf("truncating to '%-8s'\n", vfilename);
473 }
474
475 /* Populate it w/ NULs */
476 memset(volhdr->voldir[slot].name, 0,
477 sizeof(volhdr->voldir[slot].name));
478 /* Then copy the name */
479 memcpy(volhdr->voldir[slot].name, vfilename, namelen);
480
481 volhdr->voldir[slot].block = htobe32(block);
482 volhdr->voldir[slot].bytes = htobe32(st.st_size);
483
484 write_volhdr();
485
486 /* write the file itself */
487 i = lseek(fd, block * 512, SEEK_SET);
488 if (i < 0) {
489 perror("lseek write");
490 exit(1);
491 }
492 i = st.st_size;
493 fp = fopen(ufilename, "r");
494 while (i > 0) {
495 fread(fbuf, 1, i > 512 ? 512 : i, fp);
496 if (write(fd, fbuf, 512) != 512) {
497 perror("write file");
498 exit(1);
499 }
500 i -= i > 512 ? 512 : i;
501 }
502 }
503
504 void
505 delete_file(void)
506 {
507 int i;
508
509 for (i = 0; i < 15; ++i) {
510 if (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
511 break;
512 }
513 }
514 if (i >= 15) {
515 printf("File %s not found\n", vfilename);
516 exit(1);
517 }
518
519 /* XXX: we don't compact the file space, so get fragmentation */
520 volhdr->voldir[i].name[0] = '\0';
521 volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0;
522 write_volhdr();
523 }
524
525 void
526 modify_partition(void)
527 {
528 if (!opt_q)
529 printf("Modify partition %d start %d length %d\n",
530 partno, partfirst, partblocks);
531 if (partno < 0 || partno > 15) {
532 printf("Invalid partition number: %d\n", partno);
533 exit(1);
534 }
535 volhdr->partitions[partno].blocks = htobe32(partblocks);
536 volhdr->partitions[partno].first = htobe32(partfirst);
537 volhdr->partitions[partno].type = htobe32(parttype);
538 write_volhdr();
539 }
540
541 void
542 write_volhdr(void)
543 {
544 int i;
545
546 checksum_vol();
547
548 if (!opt_q)
549 display_vol();
550 if (!opt_f) {
551 printf("\nDo you want to update volume (y/n)? ");
552 i = getchar();
553 if (i != 'Y' && i != 'y')
554 exit(1);
555 }
556 i = lseek(fd, 0, SEEK_SET);
557 if (i < 0) {
558 perror("lseek 0");
559 exit(1);
560 }
561 i = write(fd, buf, 512);
562 if (i < 0)
563 perror("write volhdr");
564 }
565
566 int
567 allocate_space(int size)
568 {
569 int n, blocks;
570 int first;
571
572 blocks = (size + 511) / 512;
573 first = 2;
574 n = 0;
575 while (n < 15) {
576 if (volhdr->voldir[n].name[0]) {
577 if (first < (be32toh(volhdr->voldir[n].block) +
578 (be32toh(volhdr->voldir[n].bytes) + 511) / 512) &&
579 (first + blocks) > be32toh(volhdr->voldir[n].block)) {
580 first = be32toh(volhdr->voldir[n].block) +
581 (be32toh(volhdr->voldir[n].bytes) + 511) / 512;
582 #if 0
583 printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size);
584 printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes);
585 printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block,
586 first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511) / 512);
587 #endif
588 n = 0;
589 continue;
590 }
591 }
592 ++n;
593 }
594 #if HAVE_NBTOOL_CONFIG_H
595 if (first + blocks > (st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE))
596 #else
597 if (first + blocks > lbl.d_secperunit)
598 #endif
599 first = -1;
600 /* XXX assumes volume header is partition 8 */
601 /* XXX assumes volume header starts at 0? */
602 if (first + blocks >= be32toh(volhdr->partitions[8].blocks))
603 first = -1;
604 return (first);
605 }
606
607 void
608 checksum_vol(void)
609 {
610 int32_t *l;
611 int i;
612
613 volhdr->checksum = checksum = 0;
614 l = (int32_t *)buf;
615 for (i = 0; i < 512 / 4; ++i)
616 checksum += be32toh(l[i]);
617 volhdr->checksum = htobe32(-checksum);
618 }
619
620 void
621 usage(void)
622 {
623 printf("Usage: sgivol [-qf] [-i] [-h vhsize] device\n"
624 " sgivol [-qf] [-r vhfilename diskfilename] device\n"
625 " sgivol [-qf] [-w vhfilename diskfilename] device\n"
626 " sgivol [-qf] [-d vhfilename] device\n"
627 );
628 exit(0);
629 }
630