1 1.22 msaitoh /* $NetBSD: sgivol.c,v 1.22 2024/05/13 00:11:22 msaitoh 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.22 msaitoh /* Fictitious 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.21 christos #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.21 christos 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.21 christos void init_volhdr(const char *); 105 1.2 thorpej void read_file(void); 106 1.21 christos void write_file(const char *); 107 1.21 christos void delete_file(const char *); 108 1.21 christos void move_file(const char *); 109 1.21 christos void modify_partition(const char *); 110 1.21 christos 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.21 christos 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.21 christos if (fd == -1) { 204 1.21 christos #ifndef HAVE_NBTOOL_CONFIG_H 205 1.20 christos snprintf(buf, sizeof(buf), "/dev/r%s%c", argv[0], 206 1.20 christos 'a' + getrawpartition()); 207 1.21 christos fd = open(buf, (opt_i | opt_w | opt_d | opt_p) 208 1.21 christos ? O_RDWR : O_RDONLY); 209 1.21 christos if (fd == -1) 210 1.9 jmc #endif 211 1.21 christos err(EXIT_FAILURE, "Error opening device `%s'", argv[0]); 212 1.1 soren } 213 1.21 christos 214 1.21 christos if (read(fd, buf, sizeof(buf)) != sizeof(buf)) 215 1.21 christos err(EXIT_FAILURE, "Can't read volhdr from `%s'", argv[0]); 216 1.21 christos 217 1.9 jmc #if HAVE_NBTOOL_CONFIG_H 218 1.21 christos if (fstat(fd, &st) == -1) 219 1.21 christos err(EXIT_FAILURE, "Can't stat `%s'", argv[0]); 220 1.21 christos if (!S_ISREG(st.st_mode)) 221 1.21 christos errx(EXIT_FAILURE, "Not a regular file `%s'", argv[0]); 222 1.21 christos 223 1.21 christos if (st.st_size % SGI_BOOT_BLOCK_BLOCKSIZE) 224 1.21 christos errx(EXIT_FAILURE, "Size must be multiple of %d", 225 1.9 jmc SGI_BOOT_BLOCK_BLOCKSIZE); 226 1.21 christos if (st.st_size < (SGIVOL_NBTOOL_NSECS * SGIVOL_NBTOOL_NTRACKS)) 227 1.21 christos 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.21 christos if (ioctl(fd, DIOCGDINFO, &lbl) == -1) 231 1.21 christos 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.21 christos init_volhdr(argv[0]); 236 1.21 christos return 0; 237 1.1 soren } 238 1.21 christos if (be32toh(volhdr->magic) != SGI_BOOT_BLOCK_MAGIC) 239 1.21 christos errx(EXIT_FAILURE, "No Volume Header found, magic=%x. " 240 1.21 christos "Use -i first.\n", be32toh(volhdr->magic)); 241 1.1 soren if (opt_r) { 242 1.1 soren read_file(); 243 1.21 christos return 0; 244 1.1 soren } 245 1.1 soren if (opt_w) { 246 1.21 christos write_file(argv[0]); 247 1.21 christos return 0; 248 1.1 soren } 249 1.1 soren if (opt_d) { 250 1.21 christos delete_file(argv[0]); 251 1.21 christos return 0; 252 1.1 soren } 253 1.17 rumble if (opt_m) { 254 1.21 christos move_file(argv[0]); 255 1.21 christos return 0; 256 1.17 rumble } 257 1.1 soren if (opt_p) { 258 1.21 christos modify_partition(argv[0]); 259 1.21 christos 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.21 christos if (slot < 0 || slot >= SGI_BOOT_BLOCK_MAXVOLDIRS) 281 1.21 christos errx(EXIT_FAILURE, "Internal error: bad slot in %s()", 282 1.21 christos __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.21 christos 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.21 christos 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.21 christos 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.21 christos if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) 403 1.21 christos 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.21 christos if (fp == NULL) 408 1.21 christos 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.21 christos if (read(fd, buf, sizeof(buf)) != sizeof(buf)) 412 1.21 christos 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.21 christos 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.21 christos 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.21 christos if (stat(ufilename, &st) == -1) 433 1.21 christos err(EXIT_FAILURE, "Can't stat `%s'", ufilename); 434 1.5 rafal if (!opt_q) 435 1.21 christos printf("File %s has %ju bytes\n", ufilename, 436 1.21 christos (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.21 christos if (slot == -1) 447 1.21 christos 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.21 christos 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.21 christos if (block < 0) 463 1.21 christos 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.21 christos write_volhdr(fname); 487 1.1 soren 488 1.1 soren /* write the file itself */ 489 1.21 christos off = lseek(fd, block * 512, SEEK_SET); 490 1.21 christos if (off == -1) 491 1.21 christos 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.21 christos if (fp == NULL) 495 1.21 christos err(EXIT_FAILURE, "Can't open `%s'", ufilename); 496 1.2 thorpej while (i > 0) { 497 1.21 christos int j = i > 512 ? 512 : i; 498 1.21 christos if (fread(fbuf, 1, j, fp) != j) 499 1.21 christos err(EXIT_FAILURE, "Can't read `%s'", ufilename); 500 1.21 christos if (write(fd, fbuf, 512) != 512) 501 1.21 christos err(EXIT_FAILURE, "Can't write `%s'", fname); 502 1.21 christos 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.21 christos 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.21 christos if (i >= SGI_BOOT_BLOCK_MAXVOLDIRS) 518 1.21 christos 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.21 christos write_volhdr(fname); 524 1.1 soren } 525 1.1 soren 526 1.2 thorpej void 527 1.21 christos 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.21 christos if (slot != -1) 550 1.21 christos errx(EXIT_FAILURE, 551 1.21 christos "Error: Cannot move '%s' to '%s' - " 552 1.21 christos "duplicate source files exist!", 553 1.17 rumble vfilename, dstfile); 554 1.17 rumble slot = i; 555 1.17 rumble } 556 1.21 christos if (names_match(i, dstfile)) 557 1.21 christos errx(EXIT_FAILURE, "Error: Cannot move '%s' to '%s' - " 558 1.21 christos "destination file already exists!", 559 1.17 rumble vfilename, dstfile); 560 1.17 rumble } 561 1.21 christos if (slot == -1) 562 1.21 christos 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.21 christos write_volhdr(fname); 569 1.17 rumble } 570 1.17 rumble 571 1.17 rumble void 572 1.21 christos 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.21 christos if (partno < 0 || partno >= SGI_BOOT_BLOCK_MAXPARTITIONS) 578 1.21 christos errx(EXIT_FAILURE, "Invalid partition number: %d", partno); 579 1.21 christos 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.21 christos write_volhdr(fname); 584 1.1 soren } 585 1.1 soren 586 1.2 thorpej void 587 1.21 christos 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.21 christos 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.21 christos const char *p = getprogname(); 669 1.21 christos printf("Usage:\t%s [-qf] -i [-h vhsize] device\n" 670 1.21 christos "\t%s [-qf] -r vhfilename diskfilename device\n" 671 1.21 christos "\t%s [-qf] -w vhfilename diskfilename device\n" 672 1.21 christos "\t%s [-qf] -d vhfilename device\n" 673 1.21 christos "\t%s [-qf] -m vhfilename vhfilename device\n" 674 1.21 christos "\t%s [-qf] -p partno partfirst partblocks " 675 1.21 christos "parttype device\n", p, p, p, p, p, p); 676 1.1 soren exit(0); 677 1.1 soren } 678