sgivol.c revision 1.9 1 1.9 jmc /* $NetBSD: sgivol.c,v 1.9 2004/11/24 22:01:21 jmc 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.9 jmc #if HAVE_NBTOOL_CONFIG_H
40 1.9 jmc #include "nbtool_config.h"
41 1.9 jmc #endif
42 1.9 jmc
43 1.2 thorpej #include <sys/types.h>
44 1.2 thorpej #include <sys/ioctl.h>
45 1.8 sekiya #include <sys/stat.h>
46 1.9 jmc
47 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
48 1.9 jmc #include "../../../../../sys/sys/bootblock.h"
49 1.9 jmc /* Ficticious geometry for cross tool usage against a file image */
50 1.9 jmc #define SGIVOL_NBTOOL_NSECS 32
51 1.9 jmc #define SGIVOL_NBTOOL_NTRACKS 64
52 1.9 jmc #else
53 1.2 thorpej #include <sys/disklabel.h>
54 1.9 jmc #endif
55 1.2 thorpej
56 1.5 rafal #include <errno.h>
57 1.1 soren #include <stdio.h>
58 1.2 thorpej #include <stdlib.h>
59 1.1 soren #include <unistd.h>
60 1.1 soren #include <string.h>
61 1.1 soren #include <fcntl.h>
62 1.1 soren #include <util.h>
63 1.7 sekiya #include <sys/endian.h>
64 1.1 soren
65 1.1 soren int fd;
66 1.1 soren int opt_i; /* Initialize volume header */
67 1.1 soren int opt_r; /* Read a file from volume header */
68 1.1 soren int opt_w; /* Write a file to volume header */
69 1.1 soren int opt_d; /* Delete a file from volume header */
70 1.1 soren int opt_p; /* Modify a partition */
71 1.5 rafal int opt_q; /* quiet mode */
72 1.5 rafal int opt_f; /* Don't ask, just do what you're told */
73 1.1 soren int partno, partfirst, partblocks, parttype;
74 1.9 jmc struct sgi_boot_block *volhdr;
75 1.2 thorpej int32_t checksum;
76 1.9 jmc u_int32_t volhdr_size = SGI_BOOT_BLOCK_SIZE_VOLHDR;
77 1.2 thorpej
78 1.2 thorpej const char *vfilename = "";
79 1.2 thorpej const char *ufilename = "";
80 1.1 soren
81 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
82 1.9 jmc struct stat st;
83 1.9 jmc #else
84 1.1 soren struct disklabel lbl;
85 1.9 jmc #endif
86 1.1 soren
87 1.1 soren unsigned char buf[512];
88 1.1 soren
89 1.2 thorpej const char *sgi_types[] = {
90 1.1 soren "Volume Header",
91 1.1 soren "Repl Trks",
92 1.1 soren "Repl Secs",
93 1.1 soren "Raw",
94 1.1 soren "BSD4.2",
95 1.1 soren "SysV",
96 1.1 soren "Volume",
97 1.1 soren "EFS",
98 1.1 soren "LVol",
99 1.1 soren "RLVol",
100 1.1 soren "XFS",
101 1.1 soren "XSFLog",
102 1.1 soren "XLV",
103 1.1 soren "XVM"
104 1.1 soren };
105 1.1 soren
106 1.2 thorpej int main(int, char *[]);
107 1.2 thorpej
108 1.2 thorpej void display_vol(void);
109 1.2 thorpej void init_volhdr(void);
110 1.2 thorpej void read_file(void);
111 1.2 thorpej void write_file(void);
112 1.2 thorpej void delete_file(void);
113 1.2 thorpej void modify_partition(void);
114 1.2 thorpej void write_volhdr(void);
115 1.2 thorpej int allocate_space(int);
116 1.2 thorpej void checksum_vol(void);
117 1.2 thorpej void usage(void);
118 1.2 thorpej
119 1.2 thorpej int
120 1.2 thorpej main(int argc, char *argv[])
121 1.1 soren {
122 1.5 rafal int ch;
123 1.7 sekiya while ((ch = getopt(argc, argv, "irwpdqfh:")) != -1) {
124 1.5 rafal switch (ch) {
125 1.5 rafal /* -i, -r, -w, -d and -p override each other */
126 1.5 rafal /* -q implies -f */
127 1.5 rafal case 'q':
128 1.5 rafal ++opt_q;
129 1.5 rafal ++opt_f;
130 1.5 rafal break;
131 1.5 rafal case 'f':
132 1.5 rafal ++opt_f;
133 1.5 rafal break;
134 1.1 soren case 'i':
135 1.1 soren ++opt_i;
136 1.5 rafal opt_r = opt_w = opt_d = opt_p = 0;
137 1.1 soren break;
138 1.7 sekiya case 'h':
139 1.7 sekiya volhdr_size = atoi(optarg);
140 1.7 sekiya break;
141 1.1 soren case 'r':
142 1.5 rafal ++opt_r;
143 1.5 rafal opt_i = opt_w = opt_d = opt_p = 0;
144 1.5 rafal break;
145 1.1 soren case 'w':
146 1.5 rafal ++opt_w;
147 1.5 rafal opt_i = opt_r = opt_d = opt_p = 0;
148 1.1 soren break;
149 1.1 soren case 'd':
150 1.1 soren ++opt_d;
151 1.5 rafal opt_i = opt_r = opt_w = opt_p = 0;
152 1.5 rafal break;
153 1.1 soren case 'p':
154 1.1 soren ++opt_p;
155 1.5 rafal opt_i = opt_r = opt_w = opt_d = 0;
156 1.5 rafal partno = atoi(argv[0]);
157 1.5 rafal partfirst = atoi(argv[1]);
158 1.5 rafal partblocks = atoi(argv[2]);
159 1.5 rafal parttype = atoi(argv[3]);
160 1.1 soren break;
161 1.5 rafal case '?':
162 1.1 soren default:
163 1.1 soren usage();
164 1.1 soren }
165 1.1 soren }
166 1.5 rafal argc -= optind;
167 1.5 rafal argv += optind;
168 1.5 rafal
169 1.5 rafal if (opt_r || opt_w) {
170 1.5 rafal if (argc != 3)
171 1.5 rafal usage();
172 1.5 rafal vfilename = argv[0];
173 1.5 rafal ufilename = argv[1];
174 1.5 rafal argc -= 2;
175 1.5 rafal argv += 2;
176 1.5 rafal }
177 1.5 rafal if (opt_d) {
178 1.5 rafal if (argc != 2)
179 1.5 rafal usage();
180 1.5 rafal vfilename = argv[0];
181 1.5 rafal argc--;
182 1.5 rafal argv++;
183 1.5 rafal }
184 1.1 soren
185 1.5 rafal if (opt_p) {
186 1.5 rafal if (argc != 5)
187 1.5 rafal usage();
188 1.5 rafal partno = atoi(argv[0]);
189 1.5 rafal partfirst = atoi(argv[1]);
190 1.5 rafal partblocks = atoi(argv[2]);
191 1.5 rafal parttype = atoi(argv[3]);
192 1.5 rafal argc -= 4;
193 1.5 rafal argv += 4;
194 1.5 rafal }
195 1.5 rafal if (argc != 1)
196 1.1 soren usage();
197 1.5 rafal
198 1.5 rafal fd = open(argv[0], (opt_i | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY);
199 1.1 soren if (fd < 0) {
200 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
201 1.9 jmc perror("File open");
202 1.9 jmc exit(1);
203 1.9 jmc #else
204 1.5 rafal sprintf(buf, "/dev/r%s%c", argv[0], 'a' + getrawpartition());
205 1.5 rafal fd = open(buf, (opt_i | opt_w | opt_d | opt_p)
206 1.5 rafal ? O_RDWR : O_RDONLY);
207 1.1 soren if (fd < 0) {
208 1.5 rafal printf("Error opening device %s: %s\n",
209 1.5 rafal argv[0], strerror(errno));
210 1.1 soren exit(1);
211 1.1 soren }
212 1.9 jmc #endif
213 1.1 soren }
214 1.2 thorpej if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
215 1.1 soren perror("read volhdr");
216 1.1 soren exit(1);
217 1.1 soren }
218 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
219 1.9 jmc if (fstat(fd, &st) < 0) {
220 1.9 jmc perror("stat error");
221 1.9 jmc exit(1);
222 1.9 jmc }
223 1.9 jmc if (!S_ISREG(st.st_mode)) {
224 1.9 jmc printf("Must be regular file\n");
225 1.9 jmc exit(1);
226 1.9 jmc }
227 1.9 jmc if (st.st_size % SGI_BOOT_BLOCK_BLOCKSIZE) {
228 1.9 jmc printf("Size must be multiple of %d\n",
229 1.9 jmc SGI_BOOT_BLOCK_BLOCKSIZE);
230 1.9 jmc exit(1);
231 1.9 jmc }
232 1.9 jmc if (st.st_size < (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS)) {
233 1.9 jmc printf("Minimum size of %d required\n",
234 1.9 jmc SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS);
235 1.9 jmc exit(1);
236 1.9 jmc }
237 1.9 jmc #else
238 1.9 jmc if (ioctl(fd, DIOCGDINFO, &lbl) < 1) {
239 1.1 soren perror("DIOCGDINFO");
240 1.1 soren exit(1);
241 1.1 soren }
242 1.9 jmc #endif
243 1.9 jmc volhdr = (struct sgi_boot_block *) buf;
244 1.1 soren if (opt_i) {
245 1.1 soren init_volhdr();
246 1.1 soren exit(0);
247 1.1 soren }
248 1.9 jmc if (be32toh(volhdr->magic) != SGI_BOOT_BLOCK_MAGIC) {
249 1.5 rafal printf("No Volume Header found, magic=%x. Use -i first.\n",
250 1.7 sekiya be32toh(volhdr->magic));
251 1.1 soren exit(1);
252 1.1 soren }
253 1.1 soren if (opt_r) {
254 1.1 soren read_file();
255 1.1 soren exit(0);
256 1.1 soren }
257 1.1 soren if (opt_w) {
258 1.1 soren write_file();
259 1.1 soren exit(0);
260 1.1 soren }
261 1.1 soren if (opt_d) {
262 1.1 soren delete_file();
263 1.1 soren exit(0);
264 1.1 soren }
265 1.1 soren if (opt_p) {
266 1.1 soren modify_partition();
267 1.1 soren exit(0);
268 1.1 soren }
269 1.5 rafal
270 1.5 rafal if (!opt_q)
271 1.5 rafal display_vol();
272 1.1 soren
273 1.1 soren return 0;
274 1.1 soren }
275 1.1 soren
276 1.2 thorpej void
277 1.2 thorpej display_vol(void)
278 1.1 soren {
279 1.2 thorpej int32_t *l;
280 1.2 thorpej int i;
281 1.2 thorpej
282 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
283 1.9 jmc printf("disklabel shows %d sectors\n",
284 1.9 jmc st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
285 1.9 jmc #else
286 1.1 soren printf("disklabel shows %d sectors\n", lbl.d_secperunit);
287 1.9 jmc #endif
288 1.2 thorpej l = (int32_t *)buf;
289 1.1 soren checksum = 0;
290 1.2 thorpej for (i = 0; i < 512 / 4; ++i)
291 1.7 sekiya checksum += be32toh(l[i]);
292 1.1 soren printf("checksum: %08x%s\n", checksum, checksum == 0 ? "" : " *ERROR*");
293 1.7 sekiya printf("root part: %d\n", be16toh(volhdr->root));
294 1.7 sekiya printf("swap part: %d\n", be16toh(volhdr->swap));
295 1.2 thorpej printf("bootfile: %s\n", volhdr->bootfile);
296 1.1 soren /* volhdr->devparams[0..47] */
297 1.1 soren printf("\nVolume header files:\n");
298 1.2 thorpej for (i = 0; i < 15; ++i)
299 1.2 thorpej if (volhdr->voldir[i].name[0])
300 1.9 jmc printf("%-8s offset %4d blocks, length %8d bytes "
301 1.9 jmc "(%d blocks)\n",
302 1.9 jmc volhdr->voldir[i].name,
303 1.9 jmc be32toh(volhdr->voldir[i].block),
304 1.9 jmc be32toh(volhdr->voldir[i].bytes),
305 1.9 jmc (be32toh(volhdr->voldir[i].bytes) + 511) / 512);
306 1.1 soren printf("\nSGI partitions:\n");
307 1.9 jmc for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; ++i) {
308 1.7 sekiya if (be32toh(volhdr->partitions[i].blocks)) {
309 1.2 thorpej printf("%2d:%c blocks %8d first %8d type %2d (%s)\n",
310 1.7 sekiya i, i + 'a', be32toh(volhdr->partitions[i].blocks),
311 1.7 sekiya be32toh(volhdr->partitions[i].first),
312 1.7 sekiya be32toh(volhdr->partitions[i].type),
313 1.7 sekiya be32toh(volhdr->partitions[i].type) > 13 ? "???" :
314 1.7 sekiya sgi_types[be32toh(volhdr->partitions[i].type)]);
315 1.2 thorpej }
316 1.2 thorpej }
317 1.1 soren }
318 1.1 soren
319 1.2 thorpej void
320 1.2 thorpej init_volhdr(void)
321 1.1 soren {
322 1.1 soren memset(buf, 0, sizeof(buf));
323 1.9 jmc volhdr->magic = htobe32(SGI_BOOT_BLOCK_MAGIC);
324 1.7 sekiya volhdr->root = htobe16(0);
325 1.7 sekiya volhdr->swap = htobe16(1);
326 1.2 thorpej strcpy(volhdr->bootfile, "/netbsd");
327 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
328 1.9 jmc volhdr->dp.dp_skew = 0;
329 1.9 jmc #else
330 1.4 simonb volhdr->dp.dp_skew = lbl.d_trackskew;
331 1.9 jmc #endif
332 1.4 simonb volhdr->dp.dp_gap1 = 1; /* XXX */
333 1.4 simonb volhdr->dp.dp_gap2 = 1; /* XXX */
334 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
335 1.9 jmc volhdr->dp.dp_cyls =
336 1.9 jmc htobe16(st.st_size / (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS));
337 1.9 jmc #else
338 1.7 sekiya volhdr->dp.dp_cyls = htobe16(lbl.d_ncylinders);
339 1.9 jmc #endif
340 1.4 simonb volhdr->dp.dp_shd0 = 0;
341 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
342 1.9 jmc volhdr->dp.dp_trks0 = htobe16(SGIVOL_NBTOOL_NTRACKS);
343 1.9 jmc volhdr->dp.dp_secs = htobe16(SGIVOL_NBTOOL_NSECS);
344 1.9 jmc volhdr->dp.dp_secbytes = htobe16(SGI_BOOT_BLOCK_BLOCKSIZE);
345 1.9 jmc volhdr->dp.dp_interleave = htobe16(1);
346 1.9 jmc #else
347 1.7 sekiya volhdr->dp.dp_trks0 = htobe16(lbl.d_ntracks);
348 1.7 sekiya volhdr->dp.dp_secs = htobe16(lbl.d_nsectors);
349 1.7 sekiya volhdr->dp.dp_secbytes = htobe16(lbl.d_secsize);
350 1.7 sekiya volhdr->dp.dp_interleave = htobe16(lbl.d_interleave);
351 1.9 jmc #endif
352 1.7 sekiya volhdr->dp.dp_nretries = htobe32(22);
353 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
354 1.9 jmc volhdr->partitions[10].blocks =
355 1.9 jmc htobe32(st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
356 1.9 jmc #else
357 1.7 sekiya volhdr->partitions[10].blocks = htobe32(lbl.d_secperunit);
358 1.9 jmc #endif
359 1.1 soren volhdr->partitions[10].first = 0;
360 1.7 sekiya volhdr->partitions[10].type = htobe32(SGI_PTYPE_VOLUME);
361 1.7 sekiya volhdr->partitions[8].blocks = htobe32(volhdr_size);
362 1.1 soren volhdr->partitions[8].first = 0;
363 1.7 sekiya volhdr->partitions[8].type = htobe32(SGI_PTYPE_VOLHDR);
364 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
365 1.9 jmc volhdr->partitions[0].blocks =
366 1.9 jmc htobe32((st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE) - volhdr_size);
367 1.9 jmc #else
368 1.7 sekiya volhdr->partitions[0].blocks = htobe32(lbl.d_secperunit - volhdr_size);
369 1.9 jmc #endif
370 1.7 sekiya volhdr->partitions[0].first = htobe32(volhdr_size);
371 1.7 sekiya volhdr->partitions[0].type = htobe32(SGI_PTYPE_BSD);
372 1.1 soren write_volhdr();
373 1.1 soren }
374 1.1 soren
375 1.2 thorpej void
376 1.2 thorpej read_file(void)
377 1.1 soren {
378 1.1 soren FILE *fp;
379 1.2 thorpej int i;
380 1.1 soren
381 1.5 rafal if (!opt_q)
382 1.5 rafal printf("Reading file %s\n", vfilename);
383 1.2 thorpej for (i = 0; i < 15; ++i) {
384 1.3 thorpej if (strncmp(vfilename, volhdr->voldir[i].name,
385 1.7 sekiya strlen(volhdr->voldir[i].name)) == 0)
386 1.1 soren break;
387 1.1 soren }
388 1.2 thorpej if (i >= 15) {
389 1.1 soren printf("file %s not found\n", vfilename);
390 1.1 soren exit(1);
391 1.1 soren }
392 1.1 soren /* XXX assumes volume header starts at 0? */
393 1.7 sekiya lseek(fd, be32toh(volhdr->voldir[i].block) * 512, SEEK_SET);
394 1.1 soren fp = fopen(ufilename, "w");
395 1.1 soren if (fp == NULL) {
396 1.1 soren perror("open write");
397 1.1 soren exit(1);
398 1.1 soren }
399 1.7 sekiya i = be32toh(volhdr->voldir[i].bytes);
400 1.2 thorpej while (i > 0) {
401 1.1 soren if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
402 1.1 soren perror("read file");
403 1.1 soren exit(1);
404 1.1 soren }
405 1.2 thorpej fwrite(buf, 1, i > sizeof(buf) ? sizeof(buf) : i, fp);
406 1.2 thorpej i -= i > sizeof(buf) ? sizeof(buf) : i;
407 1.1 soren }
408 1.1 soren fclose(fp);
409 1.1 soren }
410 1.1 soren
411 1.2 thorpej void
412 1.2 thorpej write_file(void)
413 1.1 soren {
414 1.1 soren FILE *fp;
415 1.2 thorpej int slot;
416 1.2 thorpej size_t namelen;
417 1.2 thorpej int block, i;
418 1.1 soren struct stat st;
419 1.1 soren char fbuf[512];
420 1.1 soren
421 1.5 rafal if (!opt_q)
422 1.5 rafal printf("Writing file %s\n", ufilename);
423 1.1 soren if (stat(ufilename, &st) < 0) {
424 1.1 soren perror("stat");
425 1.1 soren exit(1);
426 1.1 soren }
427 1.5 rafal if (!opt_q)
428 1.5 rafal printf("File %s has %lld bytes\n", ufilename, st.st_size);
429 1.2 thorpej slot = -1;
430 1.2 thorpej for (i = 0; i < 15; ++i) {
431 1.2 thorpej if (volhdr->voldir[i].name[0] == '\0' && slot < 0)
432 1.2 thorpej slot = i;
433 1.2 thorpej if (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
434 1.2 thorpej slot = i;
435 1.1 soren break;
436 1.1 soren }
437 1.1 soren }
438 1.2 thorpej if (slot == -1) {
439 1.2 thorpej printf("No directory space for file %s\n", vfilename);
440 1.1 soren exit(1);
441 1.1 soren }
442 1.1 soren /* -w can overwrite, -a won't overwrite */
443 1.7 sekiya if (be32toh(volhdr->voldir[slot].block) > 0) {
444 1.5 rafal if (!opt_q)
445 1.5 rafal printf("File %s exists, removing old file\n",
446 1.5 rafal vfilename);
447 1.2 thorpej volhdr->voldir[slot].name[0] = 0;
448 1.2 thorpej volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0;
449 1.1 soren }
450 1.1 soren if (st.st_size == 0) {
451 1.5 rafal printf("bad file size\n");
452 1.1 soren exit(1);
453 1.1 soren }
454 1.1 soren /* XXX assumes volume header starts at 0? */
455 1.1 soren block = allocate_space((int)st.st_size);
456 1.1 soren if (block < 0) {
457 1.1 soren printf("No space for file\n");
458 1.1 soren exit(1);
459 1.1 soren }
460 1.1 soren
461 1.2 thorpej /*
462 1.2 thorpej * Make sure the name in the volume header is max. 8 chars,
463 1.2 thorpej * NOT including NUL.
464 1.2 thorpej */
465 1.2 thorpej namelen = strlen(vfilename);
466 1.2 thorpej if (namelen > sizeof(volhdr->voldir[slot].name)) {
467 1.1 soren printf("Warning: '%s' is too long for volume header, ",
468 1.1 soren vfilename);
469 1.2 thorpej namelen = sizeof(volhdr->voldir[slot].name);
470 1.2 thorpej printf("truncating to '%-8s'\n", vfilename);
471 1.1 soren }
472 1.4 simonb
473 1.2 thorpej /* Populate it w/ NULs */
474 1.2 thorpej memset(volhdr->voldir[slot].name, 0,
475 1.2 thorpej sizeof(volhdr->voldir[slot].name));
476 1.2 thorpej /* Then copy the name */
477 1.2 thorpej memcpy(volhdr->voldir[slot].name, vfilename, namelen);
478 1.2 thorpej
479 1.7 sekiya volhdr->voldir[slot].block = htobe32(block);
480 1.7 sekiya volhdr->voldir[slot].bytes = htobe32(st.st_size);
481 1.1 soren
482 1.1 soren write_volhdr();
483 1.1 soren
484 1.1 soren /* write the file itself */
485 1.2 thorpej i = lseek(fd, block * 512, SEEK_SET);
486 1.2 thorpej if (i < 0) {
487 1.1 soren perror("lseek write");
488 1.1 soren exit(1);
489 1.1 soren }
490 1.2 thorpej i = st.st_size;
491 1.1 soren fp = fopen(ufilename, "r");
492 1.2 thorpej while (i > 0) {
493 1.2 thorpej fread(fbuf, 1, i > 512 ? 512 : i, fp);
494 1.1 soren if (write(fd, fbuf, 512) != 512) {
495 1.1 soren perror("write file");
496 1.1 soren exit(1);
497 1.1 soren }
498 1.2 thorpej i -= i > 512 ? 512 : i;
499 1.1 soren }
500 1.1 soren }
501 1.1 soren
502 1.2 thorpej void
503 1.2 thorpej delete_file(void)
504 1.1 soren {
505 1.2 thorpej int i;
506 1.2 thorpej
507 1.2 thorpej for (i = 0; i < 15; ++i) {
508 1.6 sekiya if (strcmp(vfilename, volhdr->voldir[i].name) == 0) {
509 1.1 soren break;
510 1.1 soren }
511 1.1 soren }
512 1.2 thorpej if (i >= 15) {
513 1.1 soren printf("File %s not found\n", vfilename);
514 1.1 soren exit(1);
515 1.1 soren }
516 1.5 rafal
517 1.5 rafal /* XXX: we don't compact the file space, so get fragmentation */
518 1.2 thorpej volhdr->voldir[i].name[0] = '\0';
519 1.2 thorpej volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0;
520 1.1 soren write_volhdr();
521 1.1 soren }
522 1.1 soren
523 1.2 thorpej void
524 1.2 thorpej modify_partition(void)
525 1.1 soren {
526 1.5 rafal if (!opt_q)
527 1.5 rafal printf("Modify partition %d start %d length %d\n",
528 1.5 rafal partno, partfirst, partblocks);
529 1.1 soren if (partno < 0 || partno > 15) {
530 1.5 rafal printf("Invalid partition number: %d\n", partno);
531 1.1 soren exit(1);
532 1.1 soren }
533 1.7 sekiya volhdr->partitions[partno].blocks = htobe32(partblocks);
534 1.7 sekiya volhdr->partitions[partno].first = htobe32(partfirst);
535 1.7 sekiya volhdr->partitions[partno].type = htobe32(parttype);
536 1.1 soren write_volhdr();
537 1.1 soren }
538 1.1 soren
539 1.2 thorpej void
540 1.2 thorpej write_volhdr(void)
541 1.1 soren {
542 1.2 thorpej int i;
543 1.2 thorpej
544 1.1 soren checksum_vol();
545 1.5 rafal
546 1.5 rafal if (!opt_q)
547 1.5 rafal display_vol();
548 1.5 rafal if (!opt_f) {
549 1.5 rafal printf("\nDo you want to update volume (y/n)? ");
550 1.5 rafal i = getchar();
551 1.5 rafal if (i != 'Y' && i != 'y')
552 1.5 rafal exit(1);
553 1.5 rafal }
554 1.7 sekiya i = lseek(fd, 0, SEEK_SET);
555 1.2 thorpej if (i < 0) {
556 1.1 soren perror("lseek 0");
557 1.1 soren exit(1);
558 1.1 soren }
559 1.2 thorpej i = write(fd, buf, 512);
560 1.2 thorpej if (i < 0)
561 1.1 soren perror("write volhdr");
562 1.1 soren }
563 1.1 soren
564 1.2 thorpej int
565 1.2 thorpej allocate_space(int size)
566 1.1 soren {
567 1.1 soren int n, blocks;
568 1.1 soren int first;
569 1.1 soren
570 1.1 soren blocks = (size + 511) / 512;
571 1.1 soren first = 2;
572 1.1 soren n = 0;
573 1.1 soren while (n < 15) {
574 1.1 soren if (volhdr->voldir[n].name[0]) {
575 1.7 sekiya if (first < (be32toh(volhdr->voldir[n].block) +
576 1.7 sekiya (be32toh(volhdr->voldir[n].bytes) + 511) / 512) &&
577 1.7 sekiya (first + blocks) > be32toh(volhdr->voldir[n].block)) {
578 1.7 sekiya first = be32toh(volhdr->voldir[n].block) +
579 1.7 sekiya (be32toh(volhdr->voldir[n].bytes) + 511) / 512;
580 1.1 soren #if 0
581 1.7 sekiya printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size);
582 1.7 sekiya printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes);
583 1.7 sekiya printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block,
584 1.7 sekiya first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511) / 512);
585 1.1 soren #endif
586 1.1 soren n = 0;
587 1.1 soren continue;
588 1.1 soren }
589 1.1 soren }
590 1.1 soren ++n;
591 1.1 soren }
592 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
593 1.9 jmc if (first + blocks > (st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE))
594 1.9 jmc #else
595 1.1 soren if (first + blocks > lbl.d_secperunit)
596 1.9 jmc #endif
597 1.1 soren first = -1;
598 1.1 soren /* XXX assumes volume header is partition 8 */
599 1.1 soren /* XXX assumes volume header starts at 0? */
600 1.7 sekiya if (first + blocks >= be32toh(volhdr->partitions[8].blocks))
601 1.1 soren first = -1;
602 1.7 sekiya return (first);
603 1.1 soren }
604 1.1 soren
605 1.2 thorpej void
606 1.2 thorpej checksum_vol(void)
607 1.1 soren {
608 1.2 thorpej int32_t *l;
609 1.2 thorpej int i;
610 1.2 thorpej
611 1.1 soren volhdr->checksum = checksum = 0;
612 1.2 thorpej l = (int32_t *)buf;
613 1.2 thorpej for (i = 0; i < 512 / 4; ++i)
614 1.7 sekiya checksum += be32toh(l[i]);
615 1.7 sekiya volhdr->checksum = htobe32(-checksum);
616 1.1 soren }
617 1.1 soren
618 1.2 thorpej void
619 1.2 thorpej usage(void)
620 1.1 soren {
621 1.7 sekiya printf("Usage: sgivol [-qf] [-i] [-h vhsize] device\n"
622 1.5 rafal " sgivol [-qf] [-r vhfilename diskfilename] device\n"
623 1.5 rafal " sgivol [-qf] [-w vhfilename diskfilename] device\n"
624 1.5 rafal " sgivol [-qf] [-d vhfilename] device\n"
625 1.1 soren );
626 1.1 soren exit(0);
627 1.1 soren }
628