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