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