sgivol.c revision 1.2 1 /* $NetBSD: sgivol.c,v 1.2 2001/11/20 23:07:17 thorpej 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 (strcmp(vfilename, volhdr->voldir[i].name) == NULL)
276 break;
277 }
278 if (i >= 15) {
279 printf("file %s not found\n", vfilename);
280 exit(1);
281 }
282 /* XXX assumes volume header starts at 0? */
283 lseek(fd, volhdr->voldir[i].block * 512, SEEK_SET);
284 fp = fopen(ufilename, "w");
285 if (fp == NULL) {
286 perror("open write");
287 exit(1);
288 }
289 i = volhdr->voldir[i].bytes;
290 while (i > 0) {
291 if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
292 perror("read file");
293 exit(1);
294 }
295 fwrite(buf, 1, i > sizeof(buf) ? sizeof(buf) : i, fp);
296 i -= i > sizeof(buf) ? sizeof(buf) : i;
297 }
298 fclose(fp);
299 }
300
301 void
302 write_file(void)
303 {
304 FILE *fp;
305 int slot;
306 size_t namelen;
307 int block, i;
308 struct stat st;
309 char fbuf[512];
310
311 printf("Writing file %s\n", ufilename);
312 if (stat(ufilename, &st) < 0) {
313 perror("stat");
314 exit(1);
315 }
316 printf("File %s has %lld bytes\n", ufilename, st.st_size);
317 slot = -1;
318 for (i = 0; i < 15; ++i) {
319 if (volhdr->voldir[i].name[0] == '\0' && slot < 0)
320 slot = i;
321 if (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
322 slot = i;
323 break;
324 }
325 }
326 if (slot == -1) {
327 printf("No directory space for file %s\n", vfilename);
328 exit(1);
329 }
330 /* -w can overwrite, -a won't overwrite */
331 if (volhdr->voldir[slot].block > 0) {
332 printf("File %s exists, removing old file\n", vfilename);
333 volhdr->voldir[slot].name[0] = 0;
334 volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0;
335 }
336 if (st.st_size == 0) {
337 printf("bad file size?\n");
338 exit(1);
339 }
340 /* XXX assumes volume header starts at 0? */
341 block = allocate_space((int)st.st_size);
342 if (block < 0) {
343 printf("No space for file\n");
344 exit(1);
345 }
346
347 /*
348 * Make sure the name in the volume header is max. 8 chars,
349 * NOT including NUL.
350 */
351 namelen = strlen(vfilename);
352 if (namelen > sizeof(volhdr->voldir[slot].name)) {
353 printf("Warning: '%s' is too long for volume header, ",
354 vfilename);
355 namelen = sizeof(volhdr->voldir[slot].name);
356 printf("truncating to '%-8s'\n", vfilename);
357 }
358
359 /* Populate it w/ NULs */
360 memset(volhdr->voldir[slot].name, 0,
361 sizeof(volhdr->voldir[slot].name));
362 /* Then copy the name */
363 memcpy(volhdr->voldir[slot].name, vfilename, namelen);
364
365 volhdr->voldir[slot].block = block;
366 volhdr->voldir[slot].bytes = st.st_size;
367
368 write_volhdr();
369
370 /* write the file itself */
371 i = lseek(fd, block * 512, SEEK_SET);
372 if (i < 0) {
373 perror("lseek write");
374 exit(1);
375 }
376 i = st.st_size;
377 fp = fopen(ufilename, "r");
378 while (i > 0) {
379 fread(fbuf, 1, i > 512 ? 512 : i, fp);
380 if (write(fd, fbuf, 512) != 512) {
381 perror("write file");
382 exit(1);
383 }
384 i -= i > 512 ? 512 : i;
385 }
386 }
387
388 void
389 delete_file(void)
390 {
391 int i;
392
393 for (i = 0; i < 15; ++i) {
394 if (strcmp(vfilename, volhdr->voldir[i].name) == NULL) {
395 break;
396 }
397 }
398 if (i >= 15) {
399 printf("File %s not found\n", vfilename);
400 exit(1);
401 }
402 volhdr->voldir[i].name[0] = '\0';
403 volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0;
404 write_volhdr();
405 }
406
407 void
408 modify_partition(void)
409 {
410 printf("Modify partition %d start %d length %d\n", partno, partfirst,
411 partblocks);
412 if (partno < 0 || partno > 15) {
413 printf("Invalue partition number: %d\n", partno);
414 exit(1);
415 }
416 volhdr->partitions[partno].blocks = partblocks;
417 volhdr->partitions[partno].first = partfirst;
418 volhdr->partitions[partno].type = parttype;
419 write_volhdr();
420 }
421
422 void
423 write_volhdr(void)
424 {
425 int i;
426
427 checksum_vol();
428 display_vol();
429 printf("\nDo you want to update volume (y/n)? ");
430 i = getchar();
431 if (i != 'Y' && i != 'y')
432 exit(1);
433 i = lseek(fd, 0 , SEEK_SET);
434 if (i < 0) {
435 perror("lseek 0");
436 exit(1);
437 }
438 i = write(fd, buf, 512);
439 if (i < 0)
440 perror("write volhdr");
441 }
442
443 int
444 allocate_space(int size)
445 {
446 int n, blocks;
447 int first;
448
449 blocks = (size + 511) / 512;
450 first = 2;
451 n = 0;
452 while (n < 15) {
453 if (volhdr->voldir[n].name[0]) {
454 if (first < (volhdr->voldir[n].block +
455 (volhdr->voldir[n].bytes + 511) / 512) &&
456 (first + blocks) >= volhdr->voldir[n].block) {
457 first = volhdr->voldir[n].block +
458 (volhdr->voldir[n].bytes + 511) / 512;
459 #if 0
460 printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size);
461 printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes);
462 printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block,
463 first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511)/512);
464 #endif
465 n = 0;
466 continue;
467 }
468 }
469 ++n;
470 }
471 if (first + blocks > lbl.d_secperunit)
472 first = -1;
473 /* XXX assumes volume header is partition 8 */
474 /* XXX assumes volume header starts at 0? */
475 if (first + blocks >= volhdr->partitions[8].blocks)
476 first = -1;
477 return(first);
478 }
479
480 void
481 checksum_vol(void)
482 {
483 int32_t *l;
484 int i;
485
486 volhdr->checksum = checksum = 0;
487 l = (int32_t *)buf;
488 for (i = 0; i < 512 / 4; ++i)
489 checksum += l[i];
490 volhdr->checksum = -checksum;
491 }
492
493 void
494 usage(void)
495 {
496 printf("Usage: sgivol [-i] device\n"
497 " sgivol [-r vhfilename diskfilename] device\n"
498 " sgivol [-w vhfilename diskfilename] device\n"
499 " sgivol [-d vhfilename] device\n"
500 );
501 exit(0);
502 }
503