sgivol.c revision 1.1 1 1.1 soren /* $NetBSD: sgivol.c,v 1.1 2001/11/20 18:35:22 soren Exp $ */
2 1.1 soren
3 1.1 soren /*-
4 1.1 soren * Copyright (c) 2001 The NetBSD Foundation, Inc.
5 1.1 soren * All rights reserved.
6 1.1 soren *
7 1.1 soren * This code is derived from software contributed to The NetBSD Foundation
8 1.1 soren * by Michael Hitch and Hubert Feyrer.
9 1.1 soren *
10 1.1 soren * Redistribution and use in source and binary forms, with or without
11 1.1 soren * modification, are permitted provided that the following conditions
12 1.1 soren * are met:
13 1.1 soren * 1. Redistributions of source code must retain the above copyright
14 1.1 soren * notice, this list of conditions and the following disclaimer.
15 1.1 soren * 2. Redistributions in binary form must reproduce the above copyright
16 1.1 soren * notice, this list of conditions and the following disclaimer in the
17 1.1 soren * documentation and/or other materials provided with the distribution.
18 1.1 soren * 3. All advertising materials mentioning features or use of this software
19 1.1 soren * must display the following acknowledgement:
20 1.1 soren * This product includes software developed by the NetBSD
21 1.1 soren * Foundation, Inc. and its contributors.
22 1.1 soren * 4. Neither the name of The NetBSD Foundation nor the names of its
23 1.1 soren * contributors may be used to endorse or promote products derived
24 1.1 soren * from this software without specific prior written permission.
25 1.1 soren *
26 1.1 soren * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 1.1 soren * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 1.1 soren * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 1.1 soren * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 1.1 soren * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 1.1 soren * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 1.1 soren * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 1.1 soren * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 1.1 soren * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 1.1 soren * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 1.1 soren * POSSIBILITY OF SUCH DAMAGE.
37 1.1 soren */
38 1.1 soren
39 1.1 soren #include <stdio.h>
40 1.1 soren #include <unistd.h>
41 1.1 soren #include <string.h>
42 1.1 soren #include <fcntl.h>
43 1.1 soren #include <util.h>
44 1.1 soren
45 1.1 soren #include <sys/types.h>
46 1.1 soren #include <sys/ioctl.h>
47 1.1 soren #include <sys/disklabel.h>
48 1.1 soren #include <sys/stat.h>
49 1.1 soren
50 1.1 soren #define SGI_SIZE_VOLHDR 3135 /* XXX Irix: 2592, NetBSD: 3753 */
51 1.1 soren
52 1.1 soren int fd;
53 1.1 soren int n;
54 1.1 soren int opt_i; /* Initialize volume header */
55 1.1 soren int opt_r; /* Read a file from volume header */
56 1.1 soren int opt_w; /* Write a file to volume header */
57 1.1 soren int opt_d; /* Delete a file from volume header */
58 1.1 soren int opt_p; /* Modify a partition */
59 1.1 soren char *vfilename = "";
60 1.1 soren char *ufilename = "";
61 1.1 soren int partno, partfirst, partblocks, parttype;
62 1.1 soren struct sgilabel *volhdr;
63 1.1 soren long *l;
64 1.1 soren long checksum;
65 1.1 soren
66 1.1 soren struct disklabel lbl;
67 1.1 soren
68 1.1 soren unsigned char buf[512];
69 1.1 soren
70 1.1 soren char *sgi_types[] = {
71 1.1 soren "Volume Header",
72 1.1 soren "Repl Trks",
73 1.1 soren "Repl Secs",
74 1.1 soren "Raw",
75 1.1 soren "BSD4.2",
76 1.1 soren "SysV",
77 1.1 soren "Volume",
78 1.1 soren "EFS",
79 1.1 soren "LVol",
80 1.1 soren "RLVol",
81 1.1 soren "XFS",
82 1.1 soren "XSFLog",
83 1.1 soren "XLV",
84 1.1 soren "XVM"
85 1.1 soren };
86 1.1 soren
87 1.1 soren main(argc, argv)
88 1.1 soren int argc;
89 1.1 soren char *argv[];
90 1.1 soren {
91 1.1 soren if (argc < 2)
92 1.1 soren usage();
93 1.1 soren
94 1.1 soren if (argv[1][0] == '-') {
95 1.1 soren switch(argv[1][1]) {
96 1.1 soren case 'i':
97 1.1 soren ++opt_i;
98 1.1 soren argv++;
99 1.1 soren argc--;
100 1.1 soren break;
101 1.1 soren case 'r':
102 1.1 soren case 'w':
103 1.1 soren if (argc < 4)
104 1.1 soren usage();
105 1.1 soren if (argv[1][1] == 'r')
106 1.1 soren ++opt_r;
107 1.1 soren else
108 1.1 soren ++opt_w;
109 1.1 soren vfilename = argv[2];
110 1.1 soren ufilename = argv[3];
111 1.1 soren argv += 3;
112 1.1 soren argc -= 3;
113 1.1 soren break;
114 1.1 soren case 'd':
115 1.1 soren if (argc < 3)
116 1.1 soren usage();
117 1.1 soren ++opt_d;
118 1.1 soren vfilename = argv[2];
119 1.1 soren argv += 2;
120 1.1 soren argc -= 2;
121 1.1 soren break;
122 1.1 soren case 'p':
123 1.1 soren if (argc < 6)
124 1.1 soren usage();
125 1.1 soren ++opt_p;
126 1.1 soren partno = atoi(argv[2]);
127 1.1 soren partfirst = atoi(argv[3]);
128 1.1 soren partblocks = atoi(argv[4]);
129 1.1 soren parttype = atoi(argv[5]);
130 1.1 soren argv += 5;
131 1.1 soren argc -= 5;
132 1.1 soren break;
133 1.1 soren default:
134 1.1 soren printf("-%c Invalid\n", argv[1][1]);
135 1.1 soren usage();
136 1.1 soren }
137 1.1 soren }
138 1.1 soren
139 1.1 soren if (argc < 2)
140 1.1 soren usage();
141 1.1 soren
142 1.1 soren fd = open(argv[1], (opt_i | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY);
143 1.1 soren if (fd < 0) {
144 1.1 soren sprintf(buf, "/dev/r%s%c", argv[1], 'a' + getrawpartition());
145 1.1 soren fd = open(buf, (opt_i | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY);
146 1.1 soren if (fd < 0) {
147 1.1 soren perror("open");
148 1.1 soren exit(1);
149 1.1 soren }
150 1.1 soren }
151 1.1 soren n = read(fd, buf, sizeof(buf));
152 1.1 soren if (n != sizeof(buf)) {
153 1.1 soren perror("read volhdr");
154 1.1 soren exit(1);
155 1.1 soren }
156 1.1 soren n = ioctl(fd, DIOCGDINFO, &lbl);
157 1.1 soren if (n < 0) {
158 1.1 soren perror("DIOCGDINFO");
159 1.1 soren exit(1);
160 1.1 soren }
161 1.1 soren volhdr = (struct sgilabel *)buf;
162 1.1 soren if (opt_i) {
163 1.1 soren init_volhdr();
164 1.1 soren exit(0);
165 1.1 soren }
166 1.1 soren if (volhdr->magic != SGILABEL_MAGIC) {
167 1.1 soren printf("No SGI volumn header found, magic=%x\n", volhdr->magic);
168 1.1 soren exit(1);
169 1.1 soren }
170 1.1 soren if (opt_r) {
171 1.1 soren read_file();
172 1.1 soren exit(0);
173 1.1 soren }
174 1.1 soren if (opt_w) {
175 1.1 soren write_file();
176 1.1 soren exit(0);
177 1.1 soren }
178 1.1 soren if (opt_d) {
179 1.1 soren delete_file();
180 1.1 soren exit(0);
181 1.1 soren }
182 1.1 soren if (opt_p) {
183 1.1 soren modify_partition();
184 1.1 soren exit(0);
185 1.1 soren }
186 1.1 soren display_vol();
187 1.1 soren
188 1.1 soren return 0;
189 1.1 soren }
190 1.1 soren
191 1.1 soren display_vol()
192 1.1 soren {
193 1.1 soren printf("disklabel shows %d sectors\n", lbl.d_secperunit);
194 1.1 soren l = (long *)buf;
195 1.1 soren checksum = 0;
196 1.1 soren for (n = 0; n < 512 / 4; ++n)
197 1.1 soren checksum += l[n];
198 1.1 soren printf("checksum: %08x%s\n", checksum, checksum == 0 ? "" : " *ERROR*");
199 1.1 soren printf("root part: %d\n", volhdr->root);
200 1.1 soren printf("swap part: %d\n", volhdr->swap);
201 1.1 soren printf("bootfile: %\n", volhdr->bootfile);
202 1.1 soren /* volhdr->devparams[0..47] */
203 1.1 soren printf("\nVolume header files:\n");
204 1.1 soren for (n = 0; n < 15; ++n)
205 1.1 soren if (volhdr->voldir[n].name[0])
206 1.1 soren printf("%-8s offset %4d blocks, length %8d bytes (%d blocks)\n",
207 1.1 soren volhdr->voldir[n].name, volhdr->voldir[n].block,
208 1.1 soren volhdr->voldir[n].bytes, (volhdr->voldir[n].bytes + 511 ) / 512);
209 1.1 soren printf("\nSGI partitions:\n");
210 1.1 soren for (n = 0; n < MAXPARTITIONS; ++n)
211 1.1 soren if (volhdr->partitions[n].blocks)
212 1.1 soren printf("%2d:%c blocks %8d first %8d type %2d (%s)\n", n, n + 'a',
213 1.1 soren volhdr->partitions[n].blocks, volhdr->partitions[n].first,
214 1.1 soren volhdr->partitions[n].type,
215 1.1 soren volhdr->partitions[n].type > 13 ? "???" :
216 1.1 soren sgi_types[volhdr->partitions[n].type]);
217 1.1 soren }
218 1.1 soren
219 1.1 soren init_volhdr()
220 1.1 soren {
221 1.1 soren memset(buf, 0, sizeof(buf));
222 1.1 soren volhdr->magic = SGILABEL_MAGIC;
223 1.1 soren volhdr->root = 0;
224 1.1 soren volhdr->swap = 1;
225 1.1 soren strcpy(volhdr->bootfile, "netbsd");
226 1.1 soren volhdr->dp.dp_skew = lbl.d_trackskew;
227 1.1 soren volhdr->dp.dp_gap1 = 1; /* XXX */
228 1.1 soren volhdr->dp.dp_gap2 = 1; /* XXX */
229 1.1 soren volhdr->dp.dp_cyls = lbl.d_ncylinders;
230 1.1 soren volhdr->dp.dp_shd0 = 0;
231 1.1 soren volhdr->dp.dp_trks0 = lbl.d_ntracks;
232 1.1 soren volhdr->dp.dp_secs = lbl.d_nsectors;
233 1.1 soren volhdr->dp.dp_secbytes = lbl.d_secsize;
234 1.1 soren volhdr->dp.dp_interleave = lbl.d_interleave;
235 1.1 soren volhdr->dp.dp_nretries = 22;
236 1.1 soren volhdr->partitions[10].blocks = lbl.d_secperunit;
237 1.1 soren volhdr->partitions[10].first = 0;
238 1.1 soren volhdr->partitions[10].type = SGI_PTYPE_VOLUME;
239 1.1 soren volhdr->partitions[8].blocks = SGI_SIZE_VOLHDR;
240 1.1 soren volhdr->partitions[8].first = 0;
241 1.1 soren volhdr->partitions[8].type = SGI_PTYPE_VOLHDR;
242 1.1 soren volhdr->partitions[0].blocks = lbl.d_secperunit - SGI_SIZE_VOLHDR;
243 1.1 soren volhdr->partitions[0].first = SGI_SIZE_VOLHDR;
244 1.1 soren volhdr->partitions[0].type = SGI_PTYPE_EFS;
245 1.1 soren write_volhdr();
246 1.1 soren }
247 1.1 soren
248 1.1 soren read_file()
249 1.1 soren {
250 1.1 soren FILE *fp;
251 1.1 soren
252 1.1 soren printf("Reading file %s\n", vfilename);
253 1.1 soren for (n = 0; n < 15; ++n) {
254 1.1 soren if (strcmp(vfilename, volhdr->voldir[n].name) == NULL)
255 1.1 soren break;
256 1.1 soren }
257 1.1 soren if (n >= 15) {
258 1.1 soren printf("file %s not found\n", vfilename);
259 1.1 soren exit(1);
260 1.1 soren }
261 1.1 soren /* XXX assumes volume header starts at 0? */
262 1.1 soren lseek(fd, volhdr->voldir[n].block * 512, SEEK_SET);
263 1.1 soren fp = fopen(ufilename, "w");
264 1.1 soren if (fp == NULL) {
265 1.1 soren perror("open write");
266 1.1 soren exit(1);
267 1.1 soren }
268 1.1 soren n = volhdr->voldir[n].bytes;
269 1.1 soren while (n > 0) {
270 1.1 soren if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
271 1.1 soren perror("read file");
272 1.1 soren exit(1);
273 1.1 soren }
274 1.1 soren fwrite(buf, 1, n > sizeof(buf) ? sizeof(buf) : n, fp);
275 1.1 soren n -= n > sizeof(buf) ? sizeof(buf) : n;
276 1.1 soren }
277 1.1 soren fclose(fp);
278 1.1 soren }
279 1.1 soren
280 1.1 soren write_file()
281 1.1 soren {
282 1.1 soren FILE *fp;
283 1.1 soren int fileno;
284 1.1 soren int block, bytes;
285 1.1 soren struct stat st;
286 1.1 soren char fbuf[512];
287 1.1 soren
288 1.1 soren printf("Writing file %s\n", ufilename);
289 1.1 soren if (stat(ufilename, &st) < 0) {
290 1.1 soren perror("stat");
291 1.1 soren exit(1);
292 1.1 soren }
293 1.1 soren printf("File %s has %lld bytes\n", ufilename, st.st_size);
294 1.1 soren fileno = -1;
295 1.1 soren for (n = 0; n < 15; ++n) {
296 1.1 soren if (volhdr->voldir[n].name[0] == '\0' && fileno < 0)
297 1.1 soren fileno = n;
298 1.1 soren if (strcmp(vfilename, volhdr->voldir[n].name) == 0) {
299 1.1 soren fileno = n;
300 1.1 soren break;
301 1.1 soren }
302 1.1 soren }
303 1.1 soren if (fileno == -1) {
304 1.1 soren printf("No directory space for file %\n", vfilename);
305 1.1 soren exit(1);
306 1.1 soren }
307 1.1 soren /* -w can overwrite, -a won't overwrite */
308 1.1 soren if (volhdr->voldir[fileno].block > 0) {
309 1.1 soren printf("File %s exists, removing old file\n", vfilename);
310 1.1 soren volhdr->voldir[fileno].name[0] = 0;
311 1.1 soren volhdr->voldir[fileno].block = volhdr->voldir[fileno].bytes = 0;
312 1.1 soren }
313 1.1 soren if (st.st_size == 0) {
314 1.1 soren printf("bad file size?\n");
315 1.1 soren exit(1);
316 1.1 soren }
317 1.1 soren /* XXX assumes volume header starts at 0? */
318 1.1 soren block = allocate_space((int)st.st_size);
319 1.1 soren if (block < 0) {
320 1.1 soren printf("No space for file\n");
321 1.1 soren exit(1);
322 1.1 soren }
323 1.1 soren
324 1.1 soren /* Make sure name in volume header is max. 8 chars including NUL */
325 1.1 soren if (strlen(vfilename) > sizeof(volhdr->voldir[fileno].name) - 1) {
326 1.1 soren printf("Warning: '%s' is too long for volume header, ",
327 1.1 soren vfilename);
328 1.1 soren vfilename[sizeof(volhdr->voldir[fileno].name) - 1] = '\0';
329 1.1 soren printf("truncating to '%s'\n", vfilename);
330 1.1 soren }
331 1.1 soren
332 1.1 soren strcpy(volhdr->voldir[fileno].name, vfilename);
333 1.1 soren volhdr->voldir[fileno].block = block;
334 1.1 soren volhdr->voldir[fileno].bytes = st.st_size;
335 1.1 soren
336 1.1 soren write_volhdr();
337 1.1 soren
338 1.1 soren /* write the file itself */
339 1.1 soren n = lseek(fd, block * 512, SEEK_SET);
340 1.1 soren if (n < 0) {
341 1.1 soren perror("lseek write");
342 1.1 soren exit(1);
343 1.1 soren }
344 1.1 soren n = st.st_size;
345 1.1 soren fp = fopen(ufilename, "r");
346 1.1 soren while (n > 0) {
347 1.1 soren fread(fbuf, 1, n > 512 ? 512 : n, fp);
348 1.1 soren if (write(fd, fbuf, 512) != 512) {
349 1.1 soren perror("write file");
350 1.1 soren exit(1);
351 1.1 soren }
352 1.1 soren n -= n > 512 ? 512 : n;
353 1.1 soren }
354 1.1 soren }
355 1.1 soren
356 1.1 soren delete_file()
357 1.1 soren {
358 1.1 soren for (n = 0; n < 15; ++n) {
359 1.1 soren if (strcmp(vfilename, volhdr->voldir[n].name) == NULL) {
360 1.1 soren break;
361 1.1 soren }
362 1.1 soren }
363 1.1 soren if (n >= 15) {
364 1.1 soren printf("File %s not found\n", vfilename);
365 1.1 soren exit(1);
366 1.1 soren }
367 1.1 soren volhdr->voldir[n].name[0] = '\0';
368 1.1 soren volhdr->voldir[n].block = volhdr->voldir[n].bytes = 0;
369 1.1 soren write_volhdr();
370 1.1 soren }
371 1.1 soren
372 1.1 soren modify_partition()
373 1.1 soren {
374 1.1 soren printf("Modify partition %d start %d length %d\n", partno, partfirst, partblocks);
375 1.1 soren if (partno < 0 || partno > 15) {
376 1.1 soren printf("Invalue partition number: %d\n", partno);
377 1.1 soren exit(1);
378 1.1 soren }
379 1.1 soren volhdr->partitions[partno].blocks = partblocks;
380 1.1 soren volhdr->partitions[partno].first = partfirst;
381 1.1 soren volhdr->partitions[partno].type = parttype;
382 1.1 soren write_volhdr();
383 1.1 soren }
384 1.1 soren
385 1.1 soren write_volhdr()
386 1.1 soren {
387 1.1 soren checksum_vol();
388 1.1 soren display_vol();
389 1.1 soren printf("\nDo you want to update volume (y/n)? ");
390 1.1 soren n = getchar();
391 1.1 soren if (n != 'Y' && n != 'y')
392 1.1 soren exit(1);
393 1.1 soren n = lseek(fd, 0 , SEEK_SET);
394 1.1 soren if (n < 0) {
395 1.1 soren perror("lseek 0");
396 1.1 soren exit(1);
397 1.1 soren }
398 1.1 soren n = write(fd, buf, 512);
399 1.1 soren if (n < 0)
400 1.1 soren perror("write volhdr");
401 1.1 soren }
402 1.1 soren
403 1.1 soren /*
404 1.1 soren */
405 1.1 soren allocate_space(size)
406 1.1 soren int size;
407 1.1 soren {
408 1.1 soren int n, blocks;
409 1.1 soren int first;
410 1.1 soren
411 1.1 soren blocks = (size + 511) / 512;
412 1.1 soren first = 2;
413 1.1 soren n = 0;
414 1.1 soren while (n < 15) {
415 1.1 soren if (volhdr->voldir[n].name[0]) {
416 1.1 soren if (first < (volhdr->voldir[n].block +
417 1.1 soren (volhdr->voldir[n].bytes + 511) / 512) &&
418 1.1 soren (first + blocks) >= volhdr->voldir[n].block) {
419 1.1 soren first = volhdr->voldir[n].block +
420 1.1 soren (volhdr->voldir[n].bytes + 511) / 512;
421 1.1 soren #if 0
422 1.1 soren printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size);
423 1.1 soren printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes);
424 1.1 soren printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block,
425 1.1 soren first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511)/512);
426 1.1 soren #endif
427 1.1 soren n = 0;
428 1.1 soren continue;
429 1.1 soren }
430 1.1 soren }
431 1.1 soren ++n;
432 1.1 soren }
433 1.1 soren if (first + blocks > lbl.d_secperunit)
434 1.1 soren first = -1;
435 1.1 soren /* XXX assumes volume header is partition 8 */
436 1.1 soren /* XXX assumes volume header starts at 0? */
437 1.1 soren if (first + blocks >= volhdr->partitions[8].blocks)
438 1.1 soren first = -1;
439 1.1 soren return(first);
440 1.1 soren }
441 1.1 soren
442 1.1 soren checksum_vol()
443 1.1 soren {
444 1.1 soren volhdr->checksum = checksum = 0;
445 1.1 soren l = (long *)buf;
446 1.1 soren for (n = 0; n < 512 / 4; ++n)
447 1.1 soren checksum += l[n];
448 1.1 soren volhdr->checksum = -checksum;
449 1.1 soren }
450 1.1 soren
451 1.1 soren usage()
452 1.1 soren {
453 1.1 soren printf("Usage: sgivol [-i] device\n"
454 1.1 soren " sgivol [-r vhfilename diskfilename] device\n"
455 1.1 soren " sgivol [-w vhfilename diskfilename] device\n"
456 1.1 soren " sgivol [-d vhfilename] device\n"
457 1.1 soren );
458 1.1 soren exit(0);
459 1.1 soren }
460