Expand PMF_FN_* macros.
[netbsd-mini2440.git] / sys / arch / sgimips / stand / sgivol / sgivol.c
blob487c1901ebbb66d33857128b55b8af49a326bbf7
1 /* $NetBSD: sgivol.c,v 1.17 2008/08/03 16:09:20 rumble Exp $ */
3 /*-
4 * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 * All rights reserved.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Michael Hitch and Hubert Feyrer.
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.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #if HAVE_NBTOOL_CONFIG_H
33 #include "nbtool_config.h"
34 #endif
36 #include <sys/types.h>
37 #include <sys/ioctl.h>
38 #include <sys/stat.h>
40 #if HAVE_NBTOOL_CONFIG_H
41 #include "../../../../../sys/sys/bootblock.h"
42 /* Ficticious geometry for cross tool usage against a file image */
43 #define SGIVOL_NBTOOL_NSECS 32
44 #define SGIVOL_NBTOOL_NTRACKS 64
45 #else
46 #include <sys/disklabel.h>
47 #endif
49 #include <errno.h>
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <string.h>
54 #include <fcntl.h>
55 #include <util.h>
56 #ifndef HAVE_NBTOOL_CONFIG_H
57 #include <sys/endian.h>
58 #endif
60 int fd;
61 int opt_i; /* Initialize volume header */
62 int opt_r; /* Read a file from volume header */
63 int opt_w; /* Write a file to volume header */
64 int opt_d; /* Delete a file from volume header */
65 int opt_m; /* Move (rename) a file in the 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 sgi_boot_block *volhdr;
71 int32_t checksum;
72 u_int32_t volhdr_size = SGI_BOOT_BLOCK_SIZE_VOLHDR;
74 const char *vfilename = "";
75 const char *ufilename = "";
77 #if HAVE_NBTOOL_CONFIG_H
78 struct stat st;
79 #else
80 struct disklabel lbl;
81 #endif
83 unsigned char buf[512];
85 const char *sgi_types[] = {
86 "Volume Header",
87 "Repl Trks",
88 "Repl Secs",
89 "Raw",
90 "BSD4.2",
91 "SysV",
92 "Volume",
93 "EFS",
94 "LVol",
95 "RLVol",
96 "XFS",
97 "XSFLog",
98 "XLV",
99 "XVM"
102 int main(int, char *[]);
104 void display_vol(void);
105 void init_volhdr(void);
106 void read_file(void);
107 void write_file(void);
108 void delete_file(void);
109 void move_file(void);
110 void modify_partition(void);
111 void write_volhdr(void);
112 int allocate_space(int);
113 void checksum_vol(void);
114 int names_match(int, const char *);
115 void usage(void);
118 main(int argc, char *argv[])
120 #define RESET_OPTS() opt_i = opt_m = opt_r = opt_w = opt_d = opt_p = 0
122 int ch;
123 while ((ch = getopt(argc, argv, "qfih:rwdmp?")) != -1) {
124 switch (ch) {
125 /* -i, -r, -w, -d, -m 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 RESET_OPTS();
136 ++opt_i;
137 break;
138 case 'h':
139 volhdr_size = atoi(optarg);
140 break;
141 case 'r':
142 RESET_OPTS();
143 ++opt_r;
144 break;
145 case 'w':
146 RESET_OPTS();
147 ++opt_w;
148 break;
149 case 'd':
150 RESET_OPTS();
151 ++opt_d;
152 break;
153 case 'm':
154 RESET_OPTS();
155 ++opt_m;
156 break;
157 case 'p':
158 RESET_OPTS();
159 ++opt_p;
160 partno = atoi(argv[0]);
161 partfirst = atoi(argv[1]);
162 partblocks = atoi(argv[2]);
163 parttype = atoi(argv[3]);
164 break;
165 case '?':
166 default:
167 usage();
170 argc -= optind;
171 argv += optind;
173 if (opt_m || opt_r || opt_w) {
174 if (argc != 3)
175 usage();
176 vfilename = argv[0];
177 ufilename = argv[1];
178 argc -= 2;
179 argv += 2;
181 if (opt_d) {
182 if (argc != 2)
183 usage();
184 vfilename = argv[0];
185 argc--;
186 argv++;
189 if (opt_p) {
190 if (argc != 5)
191 usage();
192 partno = atoi(argv[0]);
193 partfirst = atoi(argv[1]);
194 partblocks = atoi(argv[2]);
195 parttype = atoi(argv[3]);
196 argc -= 4;
197 argv += 4;
199 if (argc != 1)
200 usage();
202 fd = open(argv[0],
203 (opt_i | opt_m | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY);
204 if (fd < 0) {
205 #if HAVE_NBTOOL_CONFIG_H
206 perror("File open");
207 exit(1);
208 #else
209 sprintf((char *)buf, "/dev/r%s%c", argv[0], 'a' + getrawpartition());
210 fd = open((char *)buf, (opt_i | opt_w | opt_d | opt_p)
211 ? O_RDWR : O_RDONLY);
212 if (fd < 0) {
213 printf("Error opening device %s: %s\n",
214 argv[0], strerror(errno));
215 exit(1);
217 #endif
219 if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
220 perror("read volhdr");
221 exit(1);
223 #if HAVE_NBTOOL_CONFIG_H
224 if (fstat(fd, &st) < 0) {
225 perror("stat error");
226 exit(1);
228 if (!S_ISREG(st.st_mode)) {
229 printf("Must be regular file\n");
230 exit(1);
232 if (st.st_size % SGI_BOOT_BLOCK_BLOCKSIZE) {
233 printf("Size must be multiple of %d\n",
234 SGI_BOOT_BLOCK_BLOCKSIZE);
235 exit(1);
237 if (st.st_size < (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS)) {
238 printf("Minimum size of %d required\n",
239 SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS);
240 exit(1);
242 #else
243 if (ioctl(fd, DIOCGDINFO, &lbl) < 0) {
244 perror("DIOCGDINFO");
245 exit(1);
247 #endif
248 volhdr = (struct sgi_boot_block *) buf;
249 if (opt_i) {
250 init_volhdr();
251 exit(0);
253 if (be32toh(volhdr->magic) != SGI_BOOT_BLOCK_MAGIC) {
254 printf("No Volume Header found, magic=%x. Use -i first.\n",
255 be32toh(volhdr->magic));
256 exit(1);
258 if (opt_r) {
259 read_file();
260 exit(0);
262 if (opt_w) {
263 write_file();
264 exit(0);
266 if (opt_d) {
267 delete_file();
268 exit(0);
270 if (opt_m) {
271 move_file();
272 exit(0);
274 if (opt_p) {
275 modify_partition();
276 exit(0);
279 if (!opt_q)
280 display_vol();
282 return 0;
286 * Compare the name in `slot' of voldir to `b'. Be careful, as the
287 * name in voldir need not be nul-terminated and `b' may be longer
288 * than the maximum (in which case it will never match).
290 * Returns non-0 if names are equal.
293 names_match(int slot, const char *b)
295 int cmp;
297 if (slot < 0 || slot >= SGI_BOOT_BLOCK_MAXVOLDIRS) {
298 printf("Internal error: bad slot in %s()\n", __func__);
299 exit(1);
302 cmp = strncmp(volhdr->voldir[slot].name, b,
303 sizeof(volhdr->voldir[slot].name));
305 return (cmp == 0 && strlen(b) <= sizeof(volhdr->voldir[slot].name));
308 void
309 display_vol(void)
311 int32_t *l;
312 int i;
314 #if HAVE_NBTOOL_CONFIG_H
315 printf("disklabel shows %d sectors\n",
316 st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
317 #else
318 printf("disklabel shows %d sectors\n", lbl.d_secperunit);
319 #endif
320 l = (int32_t *)buf;
321 checksum = 0;
322 for (i = 0; i < 512 / 4; ++i)
323 checksum += be32toh(l[i]);
324 printf("checksum: %08x%s\n", checksum, checksum == 0 ? "" : " *ERROR*");
325 printf("root part: %d\n", be16toh(volhdr->root));
326 printf("swap part: %d\n", be16toh(volhdr->swap));
327 printf("bootfile: %s\n", volhdr->bootfile);
328 /* volhdr->devparams[0..47] */
329 printf("\nVolume header files:\n");
330 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i)
331 if (volhdr->voldir[i].name[0])
332 printf("%-8s offset %4d blocks, length %8d bytes "
333 "(%d blocks)\n",
334 volhdr->voldir[i].name,
335 be32toh(volhdr->voldir[i].block),
336 be32toh(volhdr->voldir[i].bytes),
337 (be32toh(volhdr->voldir[i].bytes) + 511) / 512);
338 printf("\nSGI partitions:\n");
339 for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; ++i) {
340 if (be32toh(volhdr->partitions[i].blocks)) {
341 printf("%2d:%c blocks %8d first %8d type %2d (%s)\n",
342 i, i + 'a', be32toh(volhdr->partitions[i].blocks),
343 be32toh(volhdr->partitions[i].first),
344 be32toh(volhdr->partitions[i].type),
345 be32toh(volhdr->partitions[i].type) > 13 ? "???" :
346 sgi_types[be32toh(volhdr->partitions[i].type)]);
351 void
352 init_volhdr(void)
354 memset(buf, 0, sizeof(buf));
355 volhdr->magic = htobe32(SGI_BOOT_BLOCK_MAGIC);
356 volhdr->root = htobe16(0);
357 volhdr->swap = htobe16(1);
358 strcpy(volhdr->bootfile, "/netbsd");
359 #if HAVE_NBTOOL_CONFIG_H
360 volhdr->dp.dp_skew = 0;
361 #else
362 volhdr->dp.dp_skew = lbl.d_trackskew;
363 #endif
364 volhdr->dp.dp_gap1 = 1; /* XXX */
365 volhdr->dp.dp_gap2 = 1; /* XXX */
366 #if HAVE_NBTOOL_CONFIG_H
367 volhdr->dp.dp_cyls =
368 htobe16(st.st_size / (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS));
369 #else
370 volhdr->dp.dp_cyls = htobe16(lbl.d_ncylinders);
371 #endif
372 volhdr->dp.dp_shd0 = 0;
373 #if HAVE_NBTOOL_CONFIG_H
374 volhdr->dp.dp_trks0 = htobe16(SGIVOL_NBTOOL_NTRACKS);
375 volhdr->dp.dp_secs = htobe16(SGIVOL_NBTOOL_NSECS);
376 volhdr->dp.dp_secbytes = htobe16(SGI_BOOT_BLOCK_BLOCKSIZE);
377 volhdr->dp.dp_interleave = htobe16(1);
378 #else
379 volhdr->dp.dp_trks0 = htobe16(lbl.d_ntracks);
380 volhdr->dp.dp_secs = htobe16(lbl.d_nsectors);
381 volhdr->dp.dp_secbytes = htobe16(lbl.d_secsize);
382 volhdr->dp.dp_interleave = htobe16(lbl.d_interleave);
383 #endif
384 volhdr->dp.dp_nretries = htobe32(22);
385 #if HAVE_NBTOOL_CONFIG_H
386 volhdr->partitions[10].blocks =
387 htobe32(st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
388 #else
389 volhdr->partitions[10].blocks = htobe32(lbl.d_secperunit);
390 #endif
391 volhdr->partitions[10].first = 0;
392 volhdr->partitions[10].type = htobe32(SGI_PTYPE_VOLUME);
393 volhdr->partitions[8].blocks = htobe32(volhdr_size);
394 volhdr->partitions[8].first = 0;
395 volhdr->partitions[8].type = htobe32(SGI_PTYPE_VOLHDR);
396 #if HAVE_NBTOOL_CONFIG_H
397 volhdr->partitions[0].blocks =
398 htobe32((st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE) - volhdr_size);
399 #else
400 volhdr->partitions[0].blocks = htobe32(lbl.d_secperunit - volhdr_size);
401 #endif
402 volhdr->partitions[0].first = htobe32(volhdr_size);
403 volhdr->partitions[0].type = htobe32(SGI_PTYPE_BSD);
404 write_volhdr();
407 void
408 read_file(void)
410 FILE *fp;
411 int i;
413 if (!opt_q)
414 printf("Reading file %s\n", vfilename);
415 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) {
416 if (strncmp(vfilename, volhdr->voldir[i].name,
417 strlen(volhdr->voldir[i].name)) == 0)
418 break;
420 if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) {
421 printf("File '%s' not found\n", vfilename);
422 exit(1);
424 /* XXX assumes volume header starts at 0? */
425 lseek(fd, be32toh(volhdr->voldir[i].block) * 512, SEEK_SET);
426 fp = fopen(ufilename, "w");
427 if (fp == NULL) {
428 perror("open write");
429 exit(1);
431 i = be32toh(volhdr->voldir[i].bytes);
432 while (i > 0) {
433 if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
434 perror("read file");
435 exit(1);
437 fwrite(buf, 1, i > sizeof(buf) ? sizeof(buf) : i, fp);
438 i -= i > sizeof(buf) ? sizeof(buf) : i;
440 fclose(fp);
443 void
444 write_file(void)
446 FILE *fp;
447 int slot;
448 size_t namelen;
449 int block, i;
450 struct stat st;
451 char fbuf[512];
453 if (!opt_q)
454 printf("Writing file %s\n", ufilename);
455 if (stat(ufilename, &st) < 0) {
456 perror("stat");
457 exit(1);
459 if (!opt_q)
460 printf("File %s has %lld bytes\n", ufilename, st.st_size);
461 slot = -1;
462 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) {
463 if (volhdr->voldir[i].name[0] == '\0' && slot < 0)
464 slot = i;
465 if (names_match(i, vfilename)) {
466 slot = i;
467 break;
470 if (slot == -1) {
471 printf("No directory space for file %s\n", vfilename);
472 exit(1);
474 /* -w can overwrite, -a won't overwrite */
475 if (be32toh(volhdr->voldir[slot].block) > 0) {
476 if (!opt_q)
477 printf("File %s exists, removing old file\n",
478 vfilename);
479 volhdr->voldir[slot].name[0] = 0;
480 volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0;
482 if (st.st_size == 0) {
483 printf("bad file size\n");
484 exit(1);
486 /* XXX assumes volume header starts at 0? */
487 block = allocate_space((int)st.st_size);
488 if (block < 0) {
489 printf("No space for file\n");
490 exit(1);
494 * Make sure the name in the volume header is max. 8 chars,
495 * NOT including NUL.
497 namelen = strlen(vfilename);
498 if (namelen > sizeof(volhdr->voldir[slot].name)) {
499 printf("Warning: '%s' is too long for volume header, ",
500 vfilename);
501 namelen = sizeof(volhdr->voldir[slot].name);
502 printf("truncating to '%.8s'\n", vfilename);
505 /* Populate it w/ NULs */
506 memset(volhdr->voldir[slot].name, 0,
507 sizeof(volhdr->voldir[slot].name));
508 /* Then copy the name */
509 memcpy(volhdr->voldir[slot].name, vfilename, namelen);
511 volhdr->voldir[slot].block = htobe32(block);
512 volhdr->voldir[slot].bytes = htobe32(st.st_size);
514 write_volhdr();
516 /* write the file itself */
517 i = lseek(fd, block * 512, SEEK_SET);
518 if (i < 0) {
519 perror("lseek write");
520 exit(1);
522 i = st.st_size;
523 fp = fopen(ufilename, "r");
524 while (i > 0) {
525 fread(fbuf, 1, i > 512 ? 512 : i, fp);
526 if (write(fd, fbuf, 512) != 512) {
527 perror("write file");
528 exit(1);
530 i -= i > 512 ? 512 : i;
534 void
535 delete_file(void)
537 int i;
539 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) {
540 if (names_match(i, vfilename)) {
541 break;
544 if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) {
545 printf("File '%s' not found\n", vfilename);
546 exit(1);
549 /* XXX: we don't compact the file space, so get fragmentation */
550 volhdr->voldir[i].name[0] = '\0';
551 volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0;
552 write_volhdr();
555 void
556 move_file(void)
558 char dstfile[sizeof(volhdr->voldir[0].name) + 1];
559 size_t namelen;
560 int i, slot = -1;
563 * Make sure the name in the volume header is max. 8 chars,
564 * NOT including NUL.
566 namelen = strlen(ufilename);
567 if (namelen > sizeof(volhdr->voldir[0].name)) {
568 printf("Warning: '%s' is too long for volume header, ",
569 ufilename);
570 namelen = sizeof(volhdr->voldir[0].name);
571 printf("truncating to '%.8s'\n", ufilename);
573 memset(dstfile, 0, sizeof(dstfile));
574 memcpy(dstfile, ufilename, namelen);
576 for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; i++) {
577 if (names_match(i, vfilename)) {
578 if (slot != -1) {
579 printf("Error: Cannot move '%s' to '%s' - "
580 "duplicate source files exist!\n",
581 vfilename, dstfile);
582 exit(1);
584 slot = i;
586 if (names_match(i, dstfile)) {
587 printf("Error: Cannot move '%s' to '%s' - "
588 "destination file already exists!\n",
589 vfilename, dstfile);
590 exit(1);
593 if (slot == -1) {
594 printf("File '%s' not found\n", vfilename);
595 exit(1);
598 /* `dstfile' is already padded with NULs */
599 memcpy(volhdr->voldir[slot].name, dstfile,
600 sizeof(volhdr->voldir[slot].name));
602 write_volhdr();
605 void
606 modify_partition(void)
608 if (!opt_q)
609 printf("Modify partition %d start %d length %d\n",
610 partno, partfirst, partblocks);
611 if (partno < 0 || partno >= SGI_BOOT_BLOCK_MAXPARTITIONS) {
612 printf("Invalid partition number: %d\n", partno);
613 exit(1);
615 volhdr->partitions[partno].blocks = htobe32(partblocks);
616 volhdr->partitions[partno].first = htobe32(partfirst);
617 volhdr->partitions[partno].type = htobe32(parttype);
618 write_volhdr();
621 void
622 write_volhdr(void)
624 int i;
626 checksum_vol();
628 if (!opt_q)
629 display_vol();
630 if (!opt_f) {
631 printf("\nDo you want to update volume (y/n)? ");
632 i = getchar();
633 if (i != 'Y' && i != 'y')
634 exit(1);
636 i = lseek(fd, 0, SEEK_SET);
637 if (i < 0) {
638 perror("lseek 0");
639 exit(1);
641 i = write(fd, buf, 512);
642 if (i < 0)
643 perror("write volhdr");
647 allocate_space(int size)
649 int n, blocks;
650 int first;
652 blocks = (size + 511) / 512;
653 first = 2;
654 n = 0;
655 while (n < SGI_BOOT_BLOCK_MAXVOLDIRS) {
656 if (volhdr->voldir[n].name[0]) {
657 if (first < (be32toh(volhdr->voldir[n].block) +
658 (be32toh(volhdr->voldir[n].bytes) + 511) / 512) &&
659 (first + blocks) > be32toh(volhdr->voldir[n].block)) {
660 first = be32toh(volhdr->voldir[n].block) +
661 (be32toh(volhdr->voldir[n].bytes) + 511) / 512;
662 #if 0
663 printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size);
664 printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes);
665 printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block,
666 first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511) / 512);
667 #endif
668 n = 0;
669 continue;
672 ++n;
674 #if HAVE_NBTOOL_CONFIG_H
675 if (first + blocks > (st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE))
676 #else
677 if (first + blocks > lbl.d_secperunit)
678 #endif
679 first = -1;
680 /* XXX assumes volume header is partition 8 */
681 /* XXX assumes volume header starts at 0? */
682 if (first + blocks >= be32toh(volhdr->partitions[8].blocks))
683 first = -1;
684 return (first);
687 void
688 checksum_vol(void)
690 int32_t *l;
691 int i;
693 volhdr->checksum = checksum = 0;
694 l = (int32_t *)buf;
695 for (i = 0; i < 512 / 4; ++i)
696 checksum += be32toh(l[i]);
697 volhdr->checksum = htobe32(-checksum);
700 void
701 usage(void)
703 printf("Usage: sgivol [-qf] -i [-h vhsize] device\n"
704 " sgivol [-qf] -r vhfilename diskfilename device\n"
705 " sgivol [-qf] -w vhfilename diskfilename device\n"
706 " sgivol [-qf] -d vhfilename device\n"
707 " sgivol [-qf] -m vhfilename vhfilename device\n"
708 " sgivol [-qf] -p partno partfirst partblocks "
709 "parttype device\n"
711 exit(0);