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