sgivol.c revision 1.20 1 1.20 christos /* $NetBSD: sgivol.c,v 1.20 2014/03/26 16:16:06 christos 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 *
19 1.1 soren * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 1.1 soren * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 1.1 soren * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 1.1 soren * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 1.1 soren * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 1.1 soren * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 1.1 soren * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 1.1 soren * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 1.1 soren * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 1.1 soren * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 1.1 soren * POSSIBILITY OF SUCH DAMAGE.
30 1.1 soren */
31 1.1 soren
32 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
33 1.9 jmc #include "nbtool_config.h"
34 1.9 jmc #endif
35 1.9 jmc
36 1.2 thorpej #include <sys/types.h>
37 1.2 thorpej #include <sys/ioctl.h>
38 1.8 sekiya #include <sys/stat.h>
39 1.9 jmc
40 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
41 1.9 jmc #include "../../../../../sys/sys/bootblock.h"
42 1.9 jmc /* Ficticious geometry for cross tool usage against a file image */
43 1.9 jmc #define SGIVOL_NBTOOL_NSECS 32
44 1.9 jmc #define SGIVOL_NBTOOL_NTRACKS 64
45 1.9 jmc #else
46 1.2 thorpej #include <sys/disklabel.h>
47 1.9 jmc #endif
48 1.2 thorpej
49 1.5 rafal #include <errno.h>
50 1.1 soren #include <stdio.h>
51 1.2 thorpej #include <stdlib.h>
52 1.1 soren #include <unistd.h>
53 1.1 soren #include <string.h>
54 1.1 soren #include <fcntl.h>
55 1.1 soren #include <util.h>
56 1.12 thorpej #ifndef HAVE_NBTOOL_CONFIG_H
57 1.7 sekiya #include <sys/endian.h>
58 1.12 thorpej #endif
59 1.1 soren
60 1.1 soren int fd;
61 1.1 soren int opt_i; /* Initialize volume header */
62 1.1 soren int opt_r; /* Read a file from volume header */
63 1.1 soren int opt_w; /* Write a file to volume header */
64 1.1 soren int opt_d; /* Delete a file from volume header */
65 1.17 rumble int opt_m; /* Move (rename) a file in the volume header */
66 1.1 soren int opt_p; /* Modify a partition */
67 1.5 rafal int opt_q; /* quiet mode */
68 1.5 rafal int opt_f; /* Don't ask, just do what you're told */
69 1.1 soren int partno, partfirst, partblocks, parttype;
70 1.9 jmc struct sgi_boot_block *volhdr;
71 1.2 thorpej int32_t checksum;
72 1.9 jmc u_int32_t volhdr_size = SGI_BOOT_BLOCK_SIZE_VOLHDR;
73 1.2 thorpej
74 1.2 thorpej const char *vfilename = "";
75 1.2 thorpej const char *ufilename = "";
76 1.1 soren
77 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
78 1.9 jmc struct stat st;
79 1.9 jmc #else
80 1.1 soren struct disklabel lbl;
81 1.9 jmc #endif
82 1.1 soren
83 1.1 soren unsigned char buf[512];
84 1.1 soren
85 1.2 thorpej const char *sgi_types[] = {
86 1.1 soren "Volume Header",
87 1.1 soren "Repl Trks",
88 1.1 soren "Repl Secs",
89 1.1 soren "Raw",
90 1.1 soren "BSD4.2",
91 1.1 soren "SysV",
92 1.1 soren "Volume",
93 1.1 soren "EFS",
94 1.1 soren "LVol",
95 1.1 soren "RLVol",
96 1.1 soren "XFS",
97 1.1 soren "XSFLog",
98 1.1 soren "XLV",
99 1.1 soren "XVM"
100 1.1 soren };
101 1.1 soren
102 1.2 thorpej int main(int, char *[]);
103 1.2 thorpej
104 1.2 thorpej void display_vol(void);
105 1.2 thorpej void init_volhdr(void);
106 1.2 thorpej void read_file(void);
107 1.2 thorpej void write_file(void);
108 1.2 thorpej void delete_file(void);
109 1.17 rumble void move_file(void);
110 1.2 thorpej void modify_partition(void);
111 1.2 thorpej void write_volhdr(void);
112 1.2 thorpej int allocate_space(int);
113 1.2 thorpej void checksum_vol(void);
114 1.18 rumble int names_match(int, const char *);
115 1.2 thorpej void usage(void);
116 1.2 thorpej
117 1.2 thorpej int
118 1.2 thorpej main(int argc, char *argv[])
119 1.1 soren {
120 1.17 rumble #define RESET_OPTS() opt_i = opt_m = opt_r = opt_w = opt_d = opt_p = 0
121 1.17 rumble
122 1.5 rafal int ch;
123 1.17 rumble while ((ch = getopt(argc, argv, "qfih:rwdmp?")) != -1) {
124 1.5 rafal switch (ch) {
125 1.17 rumble /* -i, -r, -w, -d, -m 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.17 rumble RESET_OPTS();
136 1.1 soren ++opt_i;
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.17 rumble RESET_OPTS();
143 1.5 rafal ++opt_r;
144 1.5 rafal break;
145 1.1 soren case 'w':
146 1.17 rumble RESET_OPTS();
147 1.5 rafal ++opt_w;
148 1.1 soren break;
149 1.1 soren case 'd':
150 1.17 rumble RESET_OPTS();
151 1.1 soren ++opt_d;
152 1.17 rumble break;
153 1.17 rumble case 'm':
154 1.17 rumble RESET_OPTS();
155 1.17 rumble ++opt_m;
156 1.5 rafal break;
157 1.1 soren case 'p':
158 1.17 rumble RESET_OPTS();
159 1.1 soren ++opt_p;
160 1.5 rafal partno = atoi(argv[0]);
161 1.5 rafal partfirst = atoi(argv[1]);
162 1.5 rafal partblocks = atoi(argv[2]);
163 1.5 rafal parttype = atoi(argv[3]);
164 1.1 soren break;
165 1.5 rafal case '?':
166 1.1 soren default:
167 1.1 soren usage();
168 1.1 soren }
169 1.1 soren }
170 1.5 rafal argc -= optind;
171 1.5 rafal argv += optind;
172 1.5 rafal
173 1.17 rumble if (opt_m || opt_r || opt_w) {
174 1.5 rafal if (argc != 3)
175 1.5 rafal usage();
176 1.5 rafal vfilename = argv[0];
177 1.5 rafal ufilename = argv[1];
178 1.5 rafal argc -= 2;
179 1.5 rafal argv += 2;
180 1.5 rafal }
181 1.5 rafal if (opt_d) {
182 1.5 rafal if (argc != 2)
183 1.5 rafal usage();
184 1.5 rafal vfilename = argv[0];
185 1.5 rafal argc--;
186 1.5 rafal argv++;
187 1.5 rafal }
188 1.1 soren
189 1.5 rafal if (opt_p) {
190 1.5 rafal if (argc != 5)
191 1.5 rafal usage();
192 1.5 rafal partno = atoi(argv[0]);
193 1.5 rafal partfirst = atoi(argv[1]);
194 1.5 rafal partblocks = atoi(argv[2]);
195 1.5 rafal parttype = atoi(argv[3]);
196 1.5 rafal argc -= 4;
197 1.5 rafal argv += 4;
198 1.5 rafal }
199 1.5 rafal if (argc != 1)
200 1.1 soren usage();
201 1.5 rafal
202 1.17 rumble fd = open(argv[0],
203 1.17 rumble (opt_i | opt_m | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY);
204 1.1 soren if (fd < 0) {
205 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
206 1.9 jmc perror("File open");
207 1.9 jmc exit(1);
208 1.9 jmc #else
209 1.20 christos snprintf(buf, sizeof(buf), "/dev/r%s%c", argv[0],
210 1.20 christos 'a' + getrawpartition());
211 1.13 mrg fd = open((char *)buf, (opt_i | opt_w | opt_d | opt_p)
212 1.5 rafal ? O_RDWR : O_RDONLY);
213 1.1 soren if (fd < 0) {
214 1.5 rafal printf("Error opening device %s: %s\n",
215 1.5 rafal argv[0], strerror(errno));
216 1.1 soren exit(1);
217 1.1 soren }
218 1.9 jmc #endif
219 1.1 soren }
220 1.2 thorpej if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
221 1.1 soren perror("read volhdr");
222 1.1 soren exit(1);
223 1.1 soren }
224 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
225 1.9 jmc if (fstat(fd, &st) < 0) {
226 1.9 jmc perror("stat error");
227 1.9 jmc exit(1);
228 1.9 jmc }
229 1.9 jmc if (!S_ISREG(st.st_mode)) {
230 1.9 jmc printf("Must be regular file\n");
231 1.9 jmc exit(1);
232 1.9 jmc }
233 1.9 jmc if (st.st_size % SGI_BOOT_BLOCK_BLOCKSIZE) {
234 1.9 jmc printf("Size must be multiple of %d\n",
235 1.9 jmc SGI_BOOT_BLOCK_BLOCKSIZE);
236 1.9 jmc exit(1);
237 1.9 jmc }
238 1.9 jmc if (st.st_size < (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS)) {
239 1.9 jmc printf("Minimum size of %d required\n",
240 1.9 jmc SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS);
241 1.9 jmc exit(1);
242 1.9 jmc }
243 1.9 jmc #else
244 1.10 sekiya if (ioctl(fd, DIOCGDINFO, &lbl) < 0) {
245 1.1 soren perror("DIOCGDINFO");
246 1.1 soren exit(1);
247 1.1 soren }
248 1.9 jmc #endif
249 1.9 jmc volhdr = (struct sgi_boot_block *) buf;
250 1.1 soren if (opt_i) {
251 1.1 soren init_volhdr();
252 1.1 soren exit(0);
253 1.1 soren }
254 1.9 jmc if (be32toh(volhdr->magic) != SGI_BOOT_BLOCK_MAGIC) {
255 1.5 rafal printf("No Volume Header found, magic=%x. Use -i first.\n",
256 1.7 sekiya be32toh(volhdr->magic));
257 1.1 soren exit(1);
258 1.1 soren }
259 1.1 soren if (opt_r) {
260 1.1 soren read_file();
261 1.1 soren exit(0);
262 1.1 soren }
263 1.1 soren if (opt_w) {
264 1.1 soren write_file();
265 1.1 soren exit(0);
266 1.1 soren }
267 1.1 soren if (opt_d) {
268 1.1 soren delete_file();
269 1.1 soren exit(0);
270 1.1 soren }
271 1.17 rumble if (opt_m) {
272 1.17 rumble move_file();
273 1.17 rumble exit(0);
274 1.17 rumble }
275 1.1 soren if (opt_p) {
276 1.1 soren modify_partition();
277 1.1 soren exit(0);
278 1.1 soren }
279 1.5 rafal
280 1.5 rafal if (!opt_q)
281 1.5 rafal display_vol();
282 1.1 soren
283 1.1 soren return 0;
284 1.1 soren }
285 1.1 soren
286 1.18 rumble /*
287 1.18 rumble * Compare the name in `slot' of voldir to `b'. Be careful, as the
288 1.18 rumble * name in voldir need not be nul-terminated and `b' may be longer
289 1.18 rumble * than the maximum (in which case it will never match).
290 1.18 rumble *
291 1.18 rumble * Returns non-0 if names are equal.
292 1.18 rumble */
293 1.18 rumble int
294 1.18 rumble names_match(int slot, const char *b)
295 1.18 rumble {
296 1.18 rumble int cmp;
297 1.18 rumble
298 1.18 rumble if (slot < 0 || slot >= SGI_BOOT_BLOCK_MAXVOLDIRS) {
299 1.18 rumble printf("Internal error: bad slot in %s()\n", __func__);
300 1.18 rumble exit(1);
301 1.18 rumble }
302 1.18 rumble
303 1.18 rumble cmp = strncmp(volhdr->voldir[slot].name, b,
304 1.18 rumble sizeof(volhdr->voldir[slot].name));
305 1.18 rumble
306 1.18 rumble return (cmp == 0 && strlen(b) <= sizeof(volhdr->voldir[slot].name));
307 1.18 rumble }
308 1.18 rumble
309 1.2 thorpej void
310 1.2 thorpej display_vol(void)
311 1.1 soren {
312 1.2 thorpej int32_t *l;
313 1.2 thorpej int i;
314 1.2 thorpej
315 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
316 1.9 jmc printf("disklabel shows %d sectors\n",
317 1.9 jmc st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
318 1.9 jmc #else
319 1.1 soren printf("disklabel shows %d sectors\n", lbl.d_secperunit);
320 1.9 jmc #endif
321 1.2 thorpej l = (int32_t *)buf;
322 1.1 soren checksum = 0;
323 1.2 thorpej for (i = 0; i < 512 / 4; ++i)
324 1.7 sekiya checksum += be32toh(l[i]);
325 1.1 soren printf("checksum: %08x%s\n", checksum, checksum == 0 ? "" : " *ERROR*");
326 1.7 sekiya printf("root part: %d\n", be16toh(volhdr->root));
327 1.7 sekiya printf("swap part: %d\n", be16toh(volhdr->swap));
328 1.2 thorpej printf("bootfile: %s\n", volhdr->bootfile);
329 1.1 soren /* volhdr->devparams[0..47] */
330 1.1 soren printf("\nVolume header files:\n");
331 1.17 rumble for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i)
332 1.2 thorpej if (volhdr->voldir[i].name[0])
333 1.9 jmc printf("%-8s offset %4d blocks, length %8d bytes "
334 1.9 jmc "(%d blocks)\n",
335 1.9 jmc volhdr->voldir[i].name,
336 1.9 jmc be32toh(volhdr->voldir[i].block),
337 1.9 jmc be32toh(volhdr->voldir[i].bytes),
338 1.9 jmc (be32toh(volhdr->voldir[i].bytes) + 511) / 512);
339 1.1 soren printf("\nSGI partitions:\n");
340 1.9 jmc for (i = 0; i < SGI_BOOT_BLOCK_MAXPARTITIONS; ++i) {
341 1.7 sekiya if (be32toh(volhdr->partitions[i].blocks)) {
342 1.2 thorpej printf("%2d:%c blocks %8d first %8d type %2d (%s)\n",
343 1.7 sekiya i, i + 'a', be32toh(volhdr->partitions[i].blocks),
344 1.7 sekiya be32toh(volhdr->partitions[i].first),
345 1.7 sekiya be32toh(volhdr->partitions[i].type),
346 1.7 sekiya be32toh(volhdr->partitions[i].type) > 13 ? "???" :
347 1.7 sekiya sgi_types[be32toh(volhdr->partitions[i].type)]);
348 1.2 thorpej }
349 1.2 thorpej }
350 1.1 soren }
351 1.1 soren
352 1.2 thorpej void
353 1.2 thorpej init_volhdr(void)
354 1.1 soren {
355 1.1 soren memset(buf, 0, sizeof(buf));
356 1.9 jmc volhdr->magic = htobe32(SGI_BOOT_BLOCK_MAGIC);
357 1.7 sekiya volhdr->root = htobe16(0);
358 1.7 sekiya volhdr->swap = htobe16(1);
359 1.2 thorpej strcpy(volhdr->bootfile, "/netbsd");
360 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
361 1.9 jmc volhdr->dp.dp_skew = 0;
362 1.9 jmc #else
363 1.4 simonb volhdr->dp.dp_skew = lbl.d_trackskew;
364 1.9 jmc #endif
365 1.4 simonb volhdr->dp.dp_gap1 = 1; /* XXX */
366 1.4 simonb volhdr->dp.dp_gap2 = 1; /* XXX */
367 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
368 1.9 jmc volhdr->dp.dp_cyls =
369 1.9 jmc htobe16(st.st_size / (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS));
370 1.9 jmc #else
371 1.7 sekiya volhdr->dp.dp_cyls = htobe16(lbl.d_ncylinders);
372 1.9 jmc #endif
373 1.4 simonb volhdr->dp.dp_shd0 = 0;
374 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
375 1.9 jmc volhdr->dp.dp_trks0 = htobe16(SGIVOL_NBTOOL_NTRACKS);
376 1.9 jmc volhdr->dp.dp_secs = htobe16(SGIVOL_NBTOOL_NSECS);
377 1.9 jmc volhdr->dp.dp_secbytes = htobe16(SGI_BOOT_BLOCK_BLOCKSIZE);
378 1.9 jmc volhdr->dp.dp_interleave = htobe16(1);
379 1.9 jmc #else
380 1.7 sekiya volhdr->dp.dp_trks0 = htobe16(lbl.d_ntracks);
381 1.7 sekiya volhdr->dp.dp_secs = htobe16(lbl.d_nsectors);
382 1.7 sekiya volhdr->dp.dp_secbytes = htobe16(lbl.d_secsize);
383 1.7 sekiya volhdr->dp.dp_interleave = htobe16(lbl.d_interleave);
384 1.9 jmc #endif
385 1.7 sekiya volhdr->dp.dp_nretries = htobe32(22);
386 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
387 1.9 jmc volhdr->partitions[10].blocks =
388 1.9 jmc htobe32(st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE);
389 1.9 jmc #else
390 1.7 sekiya volhdr->partitions[10].blocks = htobe32(lbl.d_secperunit);
391 1.9 jmc #endif
392 1.1 soren volhdr->partitions[10].first = 0;
393 1.7 sekiya volhdr->partitions[10].type = htobe32(SGI_PTYPE_VOLUME);
394 1.7 sekiya volhdr->partitions[8].blocks = htobe32(volhdr_size);
395 1.1 soren volhdr->partitions[8].first = 0;
396 1.7 sekiya volhdr->partitions[8].type = htobe32(SGI_PTYPE_VOLHDR);
397 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
398 1.9 jmc volhdr->partitions[0].blocks =
399 1.9 jmc htobe32((st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE) - volhdr_size);
400 1.9 jmc #else
401 1.7 sekiya volhdr->partitions[0].blocks = htobe32(lbl.d_secperunit - volhdr_size);
402 1.9 jmc #endif
403 1.7 sekiya volhdr->partitions[0].first = htobe32(volhdr_size);
404 1.7 sekiya volhdr->partitions[0].type = htobe32(SGI_PTYPE_BSD);
405 1.1 soren write_volhdr();
406 1.1 soren }
407 1.1 soren
408 1.2 thorpej void
409 1.2 thorpej read_file(void)
410 1.1 soren {
411 1.1 soren FILE *fp;
412 1.2 thorpej int i;
413 1.1 soren
414 1.5 rafal if (!opt_q)
415 1.5 rafal printf("Reading file %s\n", vfilename);
416 1.17 rumble for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) {
417 1.3 thorpej if (strncmp(vfilename, volhdr->voldir[i].name,
418 1.7 sekiya strlen(volhdr->voldir[i].name)) == 0)
419 1.1 soren break;
420 1.1 soren }
421 1.17 rumble if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) {
422 1.17 rumble printf("File '%s' not found\n", vfilename);
423 1.1 soren exit(1);
424 1.1 soren }
425 1.1 soren /* XXX assumes volume header starts at 0? */
426 1.7 sekiya lseek(fd, be32toh(volhdr->voldir[i].block) * 512, SEEK_SET);
427 1.1 soren fp = fopen(ufilename, "w");
428 1.1 soren if (fp == NULL) {
429 1.1 soren perror("open write");
430 1.1 soren exit(1);
431 1.1 soren }
432 1.7 sekiya i = be32toh(volhdr->voldir[i].bytes);
433 1.2 thorpej while (i > 0) {
434 1.1 soren if (read(fd, buf, sizeof(buf)) != sizeof(buf)) {
435 1.1 soren perror("read file");
436 1.1 soren exit(1);
437 1.1 soren }
438 1.2 thorpej fwrite(buf, 1, i > sizeof(buf) ? sizeof(buf) : i, fp);
439 1.2 thorpej i -= i > sizeof(buf) ? sizeof(buf) : i;
440 1.1 soren }
441 1.1 soren fclose(fp);
442 1.1 soren }
443 1.1 soren
444 1.2 thorpej void
445 1.2 thorpej write_file(void)
446 1.1 soren {
447 1.1 soren FILE *fp;
448 1.2 thorpej int slot;
449 1.2 thorpej size_t namelen;
450 1.2 thorpej int block, i;
451 1.1 soren struct stat st;
452 1.1 soren char fbuf[512];
453 1.1 soren
454 1.5 rafal if (!opt_q)
455 1.5 rafal printf("Writing file %s\n", ufilename);
456 1.1 soren if (stat(ufilename, &st) < 0) {
457 1.1 soren perror("stat");
458 1.1 soren exit(1);
459 1.1 soren }
460 1.5 rafal if (!opt_q)
461 1.5 rafal printf("File %s has %lld bytes\n", ufilename, st.st_size);
462 1.2 thorpej slot = -1;
463 1.17 rumble for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) {
464 1.2 thorpej if (volhdr->voldir[i].name[0] == '\0' && slot < 0)
465 1.2 thorpej slot = i;
466 1.18 rumble if (names_match(i, vfilename)) {
467 1.2 thorpej slot = i;
468 1.1 soren break;
469 1.1 soren }
470 1.1 soren }
471 1.2 thorpej if (slot == -1) {
472 1.2 thorpej printf("No directory space for file %s\n", vfilename);
473 1.1 soren exit(1);
474 1.1 soren }
475 1.1 soren /* -w can overwrite, -a won't overwrite */
476 1.7 sekiya if (be32toh(volhdr->voldir[slot].block) > 0) {
477 1.5 rafal if (!opt_q)
478 1.5 rafal printf("File %s exists, removing old file\n",
479 1.5 rafal vfilename);
480 1.2 thorpej volhdr->voldir[slot].name[0] = 0;
481 1.2 thorpej volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0;
482 1.1 soren }
483 1.1 soren if (st.st_size == 0) {
484 1.5 rafal printf("bad file size\n");
485 1.1 soren exit(1);
486 1.1 soren }
487 1.1 soren /* XXX assumes volume header starts at 0? */
488 1.1 soren block = allocate_space((int)st.st_size);
489 1.1 soren if (block < 0) {
490 1.1 soren printf("No space for file\n");
491 1.1 soren exit(1);
492 1.1 soren }
493 1.1 soren
494 1.2 thorpej /*
495 1.2 thorpej * Make sure the name in the volume header is max. 8 chars,
496 1.2 thorpej * NOT including NUL.
497 1.2 thorpej */
498 1.2 thorpej namelen = strlen(vfilename);
499 1.2 thorpej if (namelen > sizeof(volhdr->voldir[slot].name)) {
500 1.1 soren printf("Warning: '%s' is too long for volume header, ",
501 1.1 soren vfilename);
502 1.2 thorpej namelen = sizeof(volhdr->voldir[slot].name);
503 1.17 rumble printf("truncating to '%.8s'\n", vfilename);
504 1.1 soren }
505 1.4 simonb
506 1.2 thorpej /* Populate it w/ NULs */
507 1.2 thorpej memset(volhdr->voldir[slot].name, 0,
508 1.2 thorpej sizeof(volhdr->voldir[slot].name));
509 1.2 thorpej /* Then copy the name */
510 1.2 thorpej memcpy(volhdr->voldir[slot].name, vfilename, namelen);
511 1.2 thorpej
512 1.7 sekiya volhdr->voldir[slot].block = htobe32(block);
513 1.7 sekiya volhdr->voldir[slot].bytes = htobe32(st.st_size);
514 1.1 soren
515 1.1 soren write_volhdr();
516 1.1 soren
517 1.1 soren /* write the file itself */
518 1.2 thorpej i = lseek(fd, block * 512, SEEK_SET);
519 1.2 thorpej if (i < 0) {
520 1.1 soren perror("lseek write");
521 1.1 soren exit(1);
522 1.1 soren }
523 1.2 thorpej i = st.st_size;
524 1.1 soren fp = fopen(ufilename, "r");
525 1.2 thorpej while (i > 0) {
526 1.2 thorpej fread(fbuf, 1, i > 512 ? 512 : i, fp);
527 1.1 soren if (write(fd, fbuf, 512) != 512) {
528 1.1 soren perror("write file");
529 1.1 soren exit(1);
530 1.1 soren }
531 1.2 thorpej i -= i > 512 ? 512 : i;
532 1.1 soren }
533 1.19 christos fclose(fp);
534 1.1 soren }
535 1.1 soren
536 1.2 thorpej void
537 1.2 thorpej delete_file(void)
538 1.1 soren {
539 1.2 thorpej int i;
540 1.2 thorpej
541 1.17 rumble for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; ++i) {
542 1.18 rumble if (names_match(i, vfilename)) {
543 1.1 soren break;
544 1.1 soren }
545 1.1 soren }
546 1.17 rumble if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) {
547 1.17 rumble printf("File '%s' not found\n", vfilename);
548 1.1 soren exit(1);
549 1.1 soren }
550 1.5 rafal
551 1.5 rafal /* XXX: we don't compact the file space, so get fragmentation */
552 1.2 thorpej volhdr->voldir[i].name[0] = '\0';
553 1.2 thorpej volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0;
554 1.1 soren write_volhdr();
555 1.1 soren }
556 1.1 soren
557 1.2 thorpej void
558 1.17 rumble move_file(void)
559 1.17 rumble {
560 1.17 rumble char dstfile[sizeof(volhdr->voldir[0].name) + 1];
561 1.17 rumble size_t namelen;
562 1.17 rumble int i, slot = -1;
563 1.17 rumble
564 1.17 rumble /*
565 1.17 rumble * Make sure the name in the volume header is max. 8 chars,
566 1.17 rumble * NOT including NUL.
567 1.17 rumble */
568 1.17 rumble namelen = strlen(ufilename);
569 1.17 rumble if (namelen > sizeof(volhdr->voldir[0].name)) {
570 1.17 rumble printf("Warning: '%s' is too long for volume header, ",
571 1.17 rumble ufilename);
572 1.17 rumble namelen = sizeof(volhdr->voldir[0].name);
573 1.17 rumble printf("truncating to '%.8s'\n", ufilename);
574 1.17 rumble }
575 1.17 rumble memset(dstfile, 0, sizeof(dstfile));
576 1.17 rumble memcpy(dstfile, ufilename, namelen);
577 1.17 rumble
578 1.17 rumble for (i = 0; i < SGI_BOOT_BLOCK_MAXVOLDIRS; i++) {
579 1.18 rumble if (names_match(i, vfilename)) {
580 1.17 rumble if (slot != -1) {
581 1.17 rumble printf("Error: Cannot move '%s' to '%s' - "
582 1.17 rumble "duplicate source files exist!\n",
583 1.17 rumble vfilename, dstfile);
584 1.17 rumble exit(1);
585 1.17 rumble }
586 1.17 rumble slot = i;
587 1.17 rumble }
588 1.18 rumble if (names_match(i, dstfile)) {
589 1.17 rumble printf("Error: Cannot move '%s' to '%s' - "
590 1.17 rumble "destination file already exists!\n",
591 1.17 rumble vfilename, dstfile);
592 1.17 rumble exit(1);
593 1.17 rumble }
594 1.17 rumble }
595 1.17 rumble if (slot == -1) {
596 1.17 rumble printf("File '%s' not found\n", vfilename);
597 1.17 rumble exit(1);
598 1.17 rumble }
599 1.17 rumble
600 1.17 rumble /* `dstfile' is already padded with NULs */
601 1.17 rumble memcpy(volhdr->voldir[slot].name, dstfile,
602 1.17 rumble sizeof(volhdr->voldir[slot].name));
603 1.17 rumble
604 1.17 rumble write_volhdr();
605 1.17 rumble }
606 1.17 rumble
607 1.17 rumble void
608 1.2 thorpej modify_partition(void)
609 1.1 soren {
610 1.5 rafal if (!opt_q)
611 1.5 rafal printf("Modify partition %d start %d length %d\n",
612 1.5 rafal partno, partfirst, partblocks);
613 1.17 rumble if (partno < 0 || partno >= SGI_BOOT_BLOCK_MAXPARTITIONS) {
614 1.5 rafal printf("Invalid partition number: %d\n", partno);
615 1.1 soren exit(1);
616 1.1 soren }
617 1.7 sekiya volhdr->partitions[partno].blocks = htobe32(partblocks);
618 1.7 sekiya volhdr->partitions[partno].first = htobe32(partfirst);
619 1.7 sekiya volhdr->partitions[partno].type = htobe32(parttype);
620 1.1 soren write_volhdr();
621 1.1 soren }
622 1.1 soren
623 1.2 thorpej void
624 1.2 thorpej write_volhdr(void)
625 1.1 soren {
626 1.2 thorpej int i;
627 1.2 thorpej
628 1.1 soren checksum_vol();
629 1.5 rafal
630 1.5 rafal if (!opt_q)
631 1.5 rafal display_vol();
632 1.5 rafal if (!opt_f) {
633 1.5 rafal printf("\nDo you want to update volume (y/n)? ");
634 1.5 rafal i = getchar();
635 1.5 rafal if (i != 'Y' && i != 'y')
636 1.5 rafal exit(1);
637 1.5 rafal }
638 1.7 sekiya i = lseek(fd, 0, SEEK_SET);
639 1.2 thorpej if (i < 0) {
640 1.1 soren perror("lseek 0");
641 1.1 soren exit(1);
642 1.1 soren }
643 1.2 thorpej i = write(fd, buf, 512);
644 1.2 thorpej if (i < 0)
645 1.1 soren perror("write volhdr");
646 1.1 soren }
647 1.1 soren
648 1.2 thorpej int
649 1.2 thorpej allocate_space(int size)
650 1.1 soren {
651 1.1 soren int n, blocks;
652 1.1 soren int first;
653 1.1 soren
654 1.1 soren blocks = (size + 511) / 512;
655 1.1 soren first = 2;
656 1.1 soren n = 0;
657 1.17 rumble while (n < SGI_BOOT_BLOCK_MAXVOLDIRS) {
658 1.1 soren if (volhdr->voldir[n].name[0]) {
659 1.7 sekiya if (first < (be32toh(volhdr->voldir[n].block) +
660 1.7 sekiya (be32toh(volhdr->voldir[n].bytes) + 511) / 512) &&
661 1.7 sekiya (first + blocks) > be32toh(volhdr->voldir[n].block)) {
662 1.7 sekiya first = be32toh(volhdr->voldir[n].block) +
663 1.7 sekiya (be32toh(volhdr->voldir[n].bytes) + 511) / 512;
664 1.1 soren #if 0
665 1.7 sekiya printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size);
666 1.7 sekiya printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes);
667 1.7 sekiya printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block,
668 1.7 sekiya first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511) / 512);
669 1.1 soren #endif
670 1.1 soren n = 0;
671 1.1 soren continue;
672 1.1 soren }
673 1.1 soren }
674 1.1 soren ++n;
675 1.1 soren }
676 1.9 jmc #if HAVE_NBTOOL_CONFIG_H
677 1.9 jmc if (first + blocks > (st.st_size / SGI_BOOT_BLOCK_BLOCKSIZE))
678 1.9 jmc #else
679 1.1 soren if (first + blocks > lbl.d_secperunit)
680 1.9 jmc #endif
681 1.1 soren first = -1;
682 1.1 soren /* XXX assumes volume header is partition 8 */
683 1.1 soren /* XXX assumes volume header starts at 0? */
684 1.7 sekiya if (first + blocks >= be32toh(volhdr->partitions[8].blocks))
685 1.1 soren first = -1;
686 1.7 sekiya return (first);
687 1.1 soren }
688 1.1 soren
689 1.2 thorpej void
690 1.2 thorpej checksum_vol(void)
691 1.1 soren {
692 1.2 thorpej int32_t *l;
693 1.2 thorpej int i;
694 1.2 thorpej
695 1.1 soren volhdr->checksum = checksum = 0;
696 1.2 thorpej l = (int32_t *)buf;
697 1.2 thorpej for (i = 0; i < 512 / 4; ++i)
698 1.7 sekiya checksum += be32toh(l[i]);
699 1.7 sekiya volhdr->checksum = htobe32(-checksum);
700 1.1 soren }
701 1.1 soren
702 1.2 thorpej void
703 1.2 thorpej usage(void)
704 1.1 soren {
705 1.15 rumble printf("Usage: sgivol [-qf] -i [-h vhsize] device\n"
706 1.15 rumble " sgivol [-qf] -r vhfilename diskfilename device\n"
707 1.15 rumble " sgivol [-qf] -w vhfilename diskfilename device\n"
708 1.15 rumble " sgivol [-qf] -d vhfilename device\n"
709 1.18 rumble " sgivol [-qf] -m vhfilename vhfilename device\n"
710 1.15 rumble " sgivol [-qf] -p partno partfirst partblocks "
711 1.15 rumble "parttype device\n"
712 1.1 soren );
713 1.1 soren exit(0);
714 1.1 soren }
715