1 /* $NetBSD: sgivol.c,v 1.4 2002/03/13 13:12:30 simonb Exp $ */ 2 3 /*- 4 * Copyright (c) 2001 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Michael Hitch and Hubert Feyrer. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/types.h> 40 #include <sys/ioctl.h> 41 #include <sys/disklabel.h> 42 #include <sys/stat.h> 43 44 #include <stdio.h> 45 #include <stdlib.h> 46 #include <unistd.h> 47 #include <string.h> 48 #include <fcntl.h> 49 #include <util.h> 50 51 #define SGI_SIZE_VOLHDR 3135 /* XXX Irix: 2592, NetBSD: 3753 */ 52 53 int fd; 54 int opt_i; /* Initialize volume header */ 55 int opt_r; /* Read a file from volume header */ 56 int opt_w; /* Write a file to volume header */ 57 int opt_d; /* Delete a file from volume header */ 58 int opt_p; /* Modify a partition */ 59 int partno, partfirst, partblocks, parttype; 60 struct sgilabel *volhdr; 61 int32_t checksum; 62 63 const char *vfilename = ""; 64 const char *ufilename = ""; 65 66 struct disklabel lbl; 67 68 unsigned char buf[512]; 69 70 const char *sgi_types[] = { 71 "Volume Header", 72 "Repl Trks", 73 "Repl Secs", 74 "Raw", 75 "BSD4.2", 76 "SysV", 77 "Volume", 78 "EFS", 79 "LVol", 80 "RLVol", 81 "XFS", 82 "XSFLog", 83 "XLV", 84 "XVM" 85 }; 86 87 int main(int, char *[]); 88 89 void display_vol(void); 90 void init_volhdr(void); 91 void read_file(void); 92 void write_file(void); 93 void delete_file(void); 94 void modify_partition(void); 95 void write_volhdr(void); 96 int allocate_space(int); 97 void checksum_vol(void); 98 void usage(void); 99 100 int 101 main(int argc, char *argv[]) 102 { 103 if (argc < 2) 104 usage(); 105 106 if (argv[1][0] == '-') { 107 switch(argv[1][1]) { 108 case 'i': 109 ++opt_i; 110 argv++; 111 argc--; 112 break; 113 case 'r': 114 case 'w': 115 if (argc < 4) 116 usage(); 117 if (argv[1][1] == 'r') 118 ++opt_r; 119 else 120 ++opt_w; 121 vfilename = argv[2]; 122 ufilename = argv[3]; 123 argv += 3; 124 argc -= 3; 125 break; 126 case 'd': 127 if (argc < 3) 128 usage(); 129 ++opt_d; 130 vfilename = argv[2]; 131 argv += 2; 132 argc -= 2; 133 break; 134 case 'p': 135 if (argc < 6) 136 usage(); 137 ++opt_p; 138 partno = atoi(argv[2]); 139 partfirst = atoi(argv[3]); 140 partblocks = atoi(argv[4]); 141 parttype = atoi(argv[5]); 142 argv += 5; 143 argc -= 5; 144 break; 145 default: 146 printf("-%c Invalid\n", argv[1][1]); 147 usage(); 148 } 149 } 150 151 if (argc < 2) 152 usage(); 153 154 fd = open(argv[1], (opt_i | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY); 155 if (fd < 0) { 156 sprintf(buf, "/dev/r%s%c", argv[1], 'a' + getrawpartition()); 157 fd = open(buf, 158 (opt_i | opt_w | opt_d | opt_p) ? O_RDWR : O_RDONLY); 159 if (fd < 0) { 160 perror("open"); 161 exit(1); 162 } 163 } 164 if (read(fd, buf, sizeof(buf)) != sizeof(buf)) { 165 perror("read volhdr"); 166 exit(1); 167 } 168 if (ioctl(fd, DIOCGDINFO, &lbl) < 0) { 169 perror("DIOCGDINFO"); 170 exit(1); 171 } 172 volhdr = (struct sgilabel *)buf; 173 if (opt_i) { 174 init_volhdr(); 175 exit(0); 176 } 177 if (volhdr->magic != SGILABEL_MAGIC) { 178 printf("No SGI volume header found, magic=%x\n", volhdr->magic); 179 exit(1); 180 } 181 if (opt_r) { 182 read_file(); 183 exit(0); 184 } 185 if (opt_w) { 186 write_file(); 187 exit(0); 188 } 189 if (opt_d) { 190 delete_file(); 191 exit(0); 192 } 193 if (opt_p) { 194 modify_partition(); 195 exit(0); 196 } 197 display_vol(); 198 199 return 0; 200 } 201 202 void 203 display_vol(void) 204 { 205 int32_t *l; 206 int i; 207 208 printf("disklabel shows %d sectors\n", lbl.d_secperunit); 209 l = (int32_t *)buf; 210 checksum = 0; 211 for (i = 0; i < 512 / 4; ++i) 212 checksum += l[i]; 213 printf("checksum: %08x%s\n", checksum, checksum == 0 ? "" : " *ERROR*"); 214 printf("root part: %d\n", volhdr->root); 215 printf("swap part: %d\n", volhdr->swap); 216 printf("bootfile: %s\n", volhdr->bootfile); 217 /* volhdr->devparams[0..47] */ 218 printf("\nVolume header files:\n"); 219 for (i = 0; i < 15; ++i) 220 if (volhdr->voldir[i].name[0]) 221 printf("%-8s offset %4d blocks, length %8d bytes (%d blocks)\n", 222 volhdr->voldir[i].name, volhdr->voldir[i].block, 223 volhdr->voldir[i].bytes, (volhdr->voldir[i].bytes + 511 ) / 512); 224 printf("\nSGI partitions:\n"); 225 for (i = 0; i < MAXPARTITIONS; ++i) { 226 if (volhdr->partitions[i].blocks) { 227 printf("%2d:%c blocks %8d first %8d type %2d (%s)\n", 228 i, i + 'a', volhdr->partitions[i].blocks, 229 volhdr->partitions[i].first, 230 volhdr->partitions[i].type, 231 volhdr->partitions[i].type > 13 ? "???" : 232 sgi_types[volhdr->partitions[i].type]); 233 } 234 } 235 } 236 237 void 238 init_volhdr(void) 239 { 240 memset(buf, 0, sizeof(buf)); 241 volhdr->magic = SGILABEL_MAGIC; 242 volhdr->root = 0; 243 volhdr->swap = 1; 244 strcpy(volhdr->bootfile, "/netbsd"); 245 volhdr->dp.dp_skew = lbl.d_trackskew; 246 volhdr->dp.dp_gap1 = 1; /* XXX */ 247 volhdr->dp.dp_gap2 = 1; /* XXX */ 248 volhdr->dp.dp_cyls = lbl.d_ncylinders; 249 volhdr->dp.dp_shd0 = 0; 250 volhdr->dp.dp_trks0 = lbl.d_ntracks; 251 volhdr->dp.dp_secs = lbl.d_nsectors; 252 volhdr->dp.dp_secbytes = lbl.d_secsize; 253 volhdr->dp.dp_interleave = lbl.d_interleave; 254 volhdr->dp.dp_nretries = 22; 255 volhdr->partitions[10].blocks = lbl.d_secperunit; 256 volhdr->partitions[10].first = 0; 257 volhdr->partitions[10].type = SGI_PTYPE_VOLUME; 258 volhdr->partitions[8].blocks = SGI_SIZE_VOLHDR; 259 volhdr->partitions[8].first = 0; 260 volhdr->partitions[8].type = SGI_PTYPE_VOLHDR; 261 volhdr->partitions[0].blocks = lbl.d_secperunit - SGI_SIZE_VOLHDR; 262 volhdr->partitions[0].first = SGI_SIZE_VOLHDR; 263 volhdr->partitions[0].type = SGI_PTYPE_BSD; 264 write_volhdr(); 265 } 266 267 void 268 read_file(void) 269 { 270 FILE *fp; 271 int i; 272 273 printf("Reading file %s\n", vfilename); 274 for (i = 0; i < 15; ++i) { 275 if (strncmp(vfilename, volhdr->voldir[i].name, 276 sizeof(volhdr->voldir[i].name)) == NULL) 277 break; 278 } 279 if (i >= 15) { 280 printf("file %s not found\n", vfilename); 281 exit(1); 282 } 283 /* XXX assumes volume header starts at 0? */ 284 lseek(fd, volhdr->voldir[i].block * 512, SEEK_SET); 285 fp = fopen(ufilename, "w"); 286 if (fp == NULL) { 287 perror("open write"); 288 exit(1); 289 } 290 i = volhdr->voldir[i].bytes; 291 while (i > 0) { 292 if (read(fd, buf, sizeof(buf)) != sizeof(buf)) { 293 perror("read file"); 294 exit(1); 295 } 296 fwrite(buf, 1, i > sizeof(buf) ? sizeof(buf) : i, fp); 297 i -= i > sizeof(buf) ? sizeof(buf) : i; 298 } 299 fclose(fp); 300 } 301 302 void 303 write_file(void) 304 { 305 FILE *fp; 306 int slot; 307 size_t namelen; 308 int block, i; 309 struct stat st; 310 char fbuf[512]; 311 312 printf("Writing file %s\n", ufilename); 313 if (stat(ufilename, &st) < 0) { 314 perror("stat"); 315 exit(1); 316 } 317 printf("File %s has %lld bytes\n", ufilename, st.st_size); 318 slot = -1; 319 for (i = 0; i < 15; ++i) { 320 if (volhdr->voldir[i].name[0] == '\0' && slot < 0) 321 slot = i; 322 if (strcmp(vfilename, volhdr->voldir[i].name) == 0) { 323 slot = i; 324 break; 325 } 326 } 327 if (slot == -1) { 328 printf("No directory space for file %s\n", vfilename); 329 exit(1); 330 } 331 /* -w can overwrite, -a won't overwrite */ 332 if (volhdr->voldir[slot].block > 0) { 333 printf("File %s exists, removing old file\n", vfilename); 334 volhdr->voldir[slot].name[0] = 0; 335 volhdr->voldir[slot].block = volhdr->voldir[slot].bytes = 0; 336 } 337 if (st.st_size == 0) { 338 printf("bad file size?\n"); 339 exit(1); 340 } 341 /* XXX assumes volume header starts at 0? */ 342 block = allocate_space((int)st.st_size); 343 if (block < 0) { 344 printf("No space for file\n"); 345 exit(1); 346 } 347 348 /* 349 * Make sure the name in the volume header is max. 8 chars, 350 * NOT including NUL. 351 */ 352 namelen = strlen(vfilename); 353 if (namelen > sizeof(volhdr->voldir[slot].name)) { 354 printf("Warning: '%s' is too long for volume header, ", 355 vfilename); 356 namelen = sizeof(volhdr->voldir[slot].name); 357 printf("truncating to '%-8s'\n", vfilename); 358 } 359 360 /* Populate it w/ NULs */ 361 memset(volhdr->voldir[slot].name, 0, 362 sizeof(volhdr->voldir[slot].name)); 363 /* Then copy the name */ 364 memcpy(volhdr->voldir[slot].name, vfilename, namelen); 365 366 volhdr->voldir[slot].block = block; 367 volhdr->voldir[slot].bytes = st.st_size; 368 369 write_volhdr(); 370 371 /* write the file itself */ 372 i = lseek(fd, block * 512, SEEK_SET); 373 if (i < 0) { 374 perror("lseek write"); 375 exit(1); 376 } 377 i = st.st_size; 378 fp = fopen(ufilename, "r"); 379 while (i > 0) { 380 fread(fbuf, 1, i > 512 ? 512 : i, fp); 381 if (write(fd, fbuf, 512) != 512) { 382 perror("write file"); 383 exit(1); 384 } 385 i -= i > 512 ? 512 : i; 386 } 387 } 388 389 void 390 delete_file(void) 391 { 392 int i; 393 394 for (i = 0; i < 15; ++i) { 395 if (strcmp(vfilename, volhdr->voldir[i].name) == NULL) { 396 break; 397 } 398 } 399 if (i >= 15) { 400 printf("File %s not found\n", vfilename); 401 exit(1); 402 } 403 volhdr->voldir[i].name[0] = '\0'; 404 volhdr->voldir[i].block = volhdr->voldir[i].bytes = 0; 405 write_volhdr(); 406 } 407 408 void 409 modify_partition(void) 410 { 411 printf("Modify partition %d start %d length %d\n", partno, partfirst, 412 partblocks); 413 if (partno < 0 || partno > 15) { 414 printf("Invalue partition number: %d\n", partno); 415 exit(1); 416 } 417 volhdr->partitions[partno].blocks = partblocks; 418 volhdr->partitions[partno].first = partfirst; 419 volhdr->partitions[partno].type = parttype; 420 write_volhdr(); 421 } 422 423 void 424 write_volhdr(void) 425 { 426 int i; 427 428 checksum_vol(); 429 display_vol(); 430 printf("\nDo you want to update volume (y/n)? "); 431 i = getchar(); 432 if (i != 'Y' && i != 'y') 433 exit(1); 434 i = lseek(fd, 0 , SEEK_SET); 435 if (i < 0) { 436 perror("lseek 0"); 437 exit(1); 438 } 439 i = write(fd, buf, 512); 440 if (i < 0) 441 perror("write volhdr"); 442 } 443 444 int 445 allocate_space(int size) 446 { 447 int n, blocks; 448 int first; 449 450 blocks = (size + 511) / 512; 451 first = 2; 452 n = 0; 453 while (n < 15) { 454 if (volhdr->voldir[n].name[0]) { 455 if (first < (volhdr->voldir[n].block + 456 (volhdr->voldir[n].bytes + 511) / 512) && 457 (first + blocks) >= volhdr->voldir[n].block) { 458 first = volhdr->voldir[n].block + 459 (volhdr->voldir[n].bytes + 511) / 512; 460 #if 0 461 printf("allocate: n=%d first=%d blocks=%d size=%d\n", n, first, blocks, size); 462 printf("%s %d %d\n", volhdr->voldir[n].name, volhdr->voldir[n].block, volhdr->voldir[n].bytes); 463 printf("first=%d block=%d last=%d end=%d\n", first, volhdr->voldir[n].block, 464 first + blocks - 1, volhdr->voldir[n].block + (volhdr->voldir[n].bytes + 511)/512); 465 #endif 466 n = 0; 467 continue; 468 } 469 } 470 ++n; 471 } 472 if (first + blocks > lbl.d_secperunit) 473 first = -1; 474 /* XXX assumes volume header is partition 8 */ 475 /* XXX assumes volume header starts at 0? */ 476 if (first + blocks >= volhdr->partitions[8].blocks) 477 first = -1; 478 return(first); 479 } 480 481 void 482 checksum_vol(void) 483 { 484 int32_t *l; 485 int i; 486 487 volhdr->checksum = checksum = 0; 488 l = (int32_t *)buf; 489 for (i = 0; i < 512 / 4; ++i) 490 checksum += l[i]; 491 volhdr->checksum = -checksum; 492 } 493 494 void 495 usage(void) 496 { 497 printf("Usage: sgivol [-i] device\n" 498 " sgivol [-r vhfilename diskfilename] device\n" 499 " sgivol [-w vhfilename diskfilename] device\n" 500 " sgivol [-d vhfilename] device\n" 501 ); 502 exit(0); 503 } 504