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