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