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