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