1 /* $NetBSD: inst.c,v 1.15 2005/12/24 22:45:35 perry Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Jason R. Thorpe. 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 /* 40 * Portions of this program are inspired by (and have borrowed code from) 41 * the `editlabel' program that accompanies NetBSD/vax, which carries 42 * the following notice: 43 * 44 * Copyright (c) 1995 Ludd, University of Lule}, Sweden. 45 * All rights reserved. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. All advertising materials mentioning features or use of this software 56 * must display the following acknowledgement: 57 * This product includes software developed at Ludd, University of 58 * Lule}, Sweden and its contributors. 59 * 4. The name of the author may not be used to endorse or promote products 60 * derived from this software without specific prior written permission 61 * 62 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 63 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 64 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 65 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 66 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 67 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 68 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 69 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 70 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 71 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 72 * SUCH DAMAGE. 73 */ 74 75 #define DKTYPENAMES 76 77 #include <sys/param.h> 78 #include <sys/reboot.h> 79 #include <sys/disklabel.h> 80 81 #include <lib/libsa/stand.h> 82 #include <lib/libkern/libkern.h> 83 84 #include <hp300/stand/common/samachdep.h> 85 86 char line[100]; 87 88 extern u_int opendev; 89 extern char *lowram; 90 extern int noconsole; 91 extern int netio_ask; 92 93 char *kernel_name = "/netbsd"; 94 95 void main(void); 96 void dsklabel(void); 97 void miniroot(void); 98 void bootmini(void); 99 void resetsys(void); 100 void gethelp(void); 101 int opendisk(char *, char *, int, char, int *); 102 void disklabel_edit(struct disklabel *); 103 void disklabel_show(struct disklabel *); 104 int disklabel_write(char *, int, struct open_file *); 105 void get_fstype(struct disklabel *lp, int); 106 int a2int(char *); 107 108 struct inst_command { 109 char *ic_cmd; /* command name */ 110 char *ic_desc; /* command description */ 111 void (*ic_func) __P((void)); /* handling function */ 112 } inst_commands[] = { 113 { "disklabel", "place partition map on disk", dsklabel }, 114 { "miniroot", "place miniroot on disk", miniroot }, 115 { "boot", "boot from miniroot", bootmini }, 116 { "reset", "reset the system", resetsys }, 117 { "help", "display command list", gethelp }, 118 }; 119 #define NCMDS (sizeof(inst_commands) / sizeof(inst_commands[0])) 120 121 void 122 main(void) 123 { 124 int i; 125 126 /* 127 * We want netopen() to ask for IP address, etc, rather 128 * that using bootparams. 129 */ 130 netio_ask = 1; 131 132 printf("\n"); 133 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 134 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 135 printf(">> HP 9000/%s SPU\n", getmachineid()); 136 gethelp(); 137 138 for (;;) { 139 printf("sys_inst> "); 140 memset(line, 0, sizeof(line)); 141 gets(line); 142 if (line[0] == '\n' || line[0] == '\0') 143 continue; 144 145 for (i = 0; i < NCMDS; ++i) 146 if (strcmp(line, inst_commands[i].ic_cmd) == 0) { 147 (*inst_commands[i].ic_func)(); 148 break; 149 } 150 151 152 if (i == NCMDS) 153 printf("unknown command: %s\n", line); 154 } 155 } 156 157 void 158 gethelp(void) 159 { 160 int i; 161 162 printf(">> Available commands:\n"); 163 for (i = 0; i < NCMDS; ++i) 164 printf(">> %s - %s\n", inst_commands[i].ic_cmd, 165 inst_commands[i].ic_desc); 166 } 167 168 /* 169 * Do all the steps necessary to place a disklabel on a disk. 170 * Note, this assumes 512 byte sectors. 171 */ 172 void 173 dsklabel(void) 174 { 175 struct disklabel *lp; 176 struct open_file *disk_ofp; 177 int dfd, error; 178 size_t xfersize; 179 char block[DEV_BSIZE], diskname[64]; 180 extern struct open_file files[]; 181 182 printf( 183 "You will be asked several questions about your disk, most of which\n" 184 "require prior knowledge of the disk's geometry. There is no easy way\n" 185 "for the system to provide this information for you. If you do not have\n" 186 "this information, please consult your disk's manual or another\n" 187 "informative source.\n\n"); 188 189 /* Error message printed by opendisk() */ 190 if (opendisk("Disk to label?", diskname, sizeof(diskname), 191 ('a' + RAW_PART), &dfd)) 192 return; 193 194 disk_ofp = &files[dfd]; 195 196 memset(block, 0, sizeof(block)); 197 if ((error = (*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata, 198 F_READ, LABELSECTOR, sizeof(block), block, &xfersize)) != 0) { 199 printf("cannot read disk %s, errno = %d\n", diskname, error); 200 return; 201 } 202 203 printf("Successfully read %d bytes from %s\n", xfersize, diskname); 204 205 lp = (struct disklabel *)((void *)(&block[LABELOFFSET])); 206 207 disklabel_loop: 208 memset(line, 0, sizeof(line)); 209 printf("(z)ap, (e)dit, (s)how, (w)rite, (d)one > "); 210 gets(line); 211 if (line[0] == '\n' || line[0] == '\0') 212 goto disklabel_loop; 213 214 switch (line[0]) { 215 case 'z': 216 case 'Z': { 217 char zap[DEV_BSIZE]; 218 memset(zap, 0, sizeof(zap)); 219 (void)(*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata, 220 F_WRITE, LABELSECTOR, sizeof(zap), zap, &xfersize); 221 } 222 goto out; 223 /* NOTREACHED */ 224 225 case 'e': 226 case 'E': 227 disklabel_edit(lp); 228 break; 229 230 case 's': 231 case 'S': 232 disklabel_show(lp); 233 break; 234 235 case 'w': 236 case 'W': 237 /* 238 * Error message will be displayed by disklabel_write() 239 */ 240 if (disklabel_write(block, sizeof(block), disk_ofp)) 241 goto out; 242 else 243 printf("Successfully wrote label to %s\n", diskname); 244 break; 245 246 case 'd': 247 case 'D': 248 goto out; 249 /* NOTREACHED */ 250 251 default: 252 printf("unknown command: %s\n", line); 253 } 254 255 goto disklabel_loop; 256 /* NOTREACHED */ 257 258 out: 259 /* 260 * Close disk. Marks disk `not alive' so that partition 261 * information will be reloaded upon next open. 262 */ 263 (void)close(dfd); 264 } 265 266 #define GETNUM(out, num) \ 267 printf((out), (num)); \ 268 memset(line, 0, sizeof(line)); \ 269 gets(line); \ 270 if (line[0]) \ 271 (num) = atoi(line); 272 273 #define GETNUM2(out, num1, num2) \ 274 printf((out), (num1), (num2)); \ 275 memset(line, 0, sizeof(line)); \ 276 gets(line); \ 277 if (line[0]) \ 278 (num2) = atoi(line); 279 280 #define GETSTR(out, str) \ 281 printf((out), (str)); \ 282 memset(line, 0, sizeof(line)); \ 283 gets(line); \ 284 if (line[0]) \ 285 strcpy((str), line); 286 287 #define FLAGS(out, flag) \ 288 printf((out), lp->d_flags & (flag) ? 'y' : 'n'); \ 289 memset(line, 0, sizeof(line)); \ 290 gets(line); \ 291 if (line[0] == 'y' || line[0] == 'Y') \ 292 lp->d_flags |= (flag); \ 293 else \ 294 lp->d_flags &= ~(flag); 295 296 struct fsname_to_type { 297 const char *name; 298 uint8_t type; 299 } n_to_t[] = { 300 { "unused", FS_UNUSED }, 301 { "ffs", FS_BSDFFS }, 302 { "swap", FS_SWAP }, 303 { "boot", FS_BOOT }, 304 { NULL, 0 }, 305 }; 306 307 void 308 get_fstype(struct disklabel *lp, int partno) 309 { 310 static int blocksize = 8192; /* XXX */ 311 struct partition *pp = &lp->d_partitions[partno]; 312 struct fsname_to_type *np; 313 int fragsize; 314 char line[80], str[80]; 315 316 if (pp->p_size == 0) { 317 /* 318 * No need to bother asking for a zero-sized partition. 319 */ 320 pp->p_fstype = FS_UNUSED; 321 return; 322 } 323 324 /* 325 * Select a default. 326 * XXX Should we check what might be in the label already? 327 */ 328 if (partno == 1) 329 strcpy(str, "swap"); 330 else if (partno == RAW_PART) 331 strcpy(str, "boot"); 332 else 333 strcpy(str, "ffs"); 334 335 again: 336 GETSTR(" fstype? [%s] ", str); 337 338 for (np = n_to_t; np->name != NULL; np++) 339 if (strcmp(str, np->name) == 0) 340 break; 341 342 if (np->name == NULL) { 343 printf("Please use one of: "); 344 for (np = n_to_t; np->name != NULL; np++) 345 printf(" %s", np->name); 346 printf(".\n"); 347 goto again; 348 } 349 350 pp->p_fstype = np->type; 351 352 if (pp->p_fstype != FS_BSDFFS) 353 return; 354 355 /* 356 * Get additional information needed for FFS. 357 */ 358 ffs_again: 359 GETNUM(" FFS block size? [%d] ", blocksize); 360 if (blocksize < NBPG || (blocksize % NBPG) != 0) { 361 printf("FFS block size must be a multiple of %d.\n", NBPG); 362 goto ffs_again; 363 } 364 365 fragsize = blocksize / 8; /* XXX */ 366 fragsize = max(fragsize, lp->d_secsize); 367 GETNUM(" FFS fragment size? [%d] ", fragsize); 368 if (fragsize < lp->d_secsize || (fragsize % lp->d_secsize) != 0) { 369 printf("FFS fragment size must be a multiple of sector size" 370 " (%d).\n", lp->d_secsize); 371 goto ffs_again; 372 } 373 if ((blocksize % fragsize) != 0) { 374 printf("FFS fragment size must be an even divisor of FFS" 375 " block size (%d).\n", blocksize); 376 goto ffs_again; 377 } 378 379 /* 380 * XXX Better sanity checking? 381 */ 382 383 pp->p_frag = blocksize / fragsize; 384 pp->p_fsize = fragsize; 385 } 386 387 void 388 disklabel_edit(struct disklabel *lp) 389 { 390 int i; 391 392 printf("Select disk type. Valid types:\n"); 393 for (i = 0; i < DKMAXTYPES; i++) 394 printf("%d %s\n", i, dktypenames[i]); 395 printf("\n"); 396 397 GETNUM("Disk type (number)? [%d] ", lp->d_type); 398 GETSTR("Disk model name? [%s] ", lp->d_typename); 399 GETSTR("Disk pack name? [%s] ", lp->d_packname); 400 FLAGS("Bad sectoring? [%c] ", D_BADSECT); 401 FLAGS("Ecc? [%c] ", D_ECC); 402 FLAGS("Removable? [%c] ", D_REMOVABLE); 403 404 printf("\n"); 405 406 GETNUM("Interleave? [%d] ", lp->d_interleave); 407 GETNUM("Rpm? [%d] ", lp->d_rpm); 408 GETNUM("Trackskew? [%d] ", lp->d_trackskew); 409 GETNUM("Cylinderskew? [%d] ", lp->d_cylskew); 410 GETNUM("Headswitch? [%d] ", lp->d_headswitch); 411 GETNUM("Track-to-track? [%d] ", lp->d_trkseek); 412 GETNUM("Drivedata 0? [%d] ", lp->d_drivedata[0]); 413 GETNUM("Drivedata 1? [%d] ", lp->d_drivedata[1]); 414 GETNUM("Drivedata 2? [%d] ", lp->d_drivedata[2]); 415 GETNUM("Drivedata 3? [%d] ", lp->d_drivedata[3]); 416 GETNUM("Drivedata 4? [%d] ", lp->d_drivedata[4]); 417 418 printf("\n"); 419 420 GETNUM("Bytes/sector? [%d] ", lp->d_secsize); 421 GETNUM("Sectors/track? [%d] ", lp->d_nsectors); 422 GETNUM("Tracks/cylinder? [%d] ", lp->d_ntracks); 423 if (lp->d_secpercyl == 0) 424 lp->d_secpercyl = lp->d_ntracks * lp->d_nsectors; 425 GETNUM("Sectors/cylinder? [%d] ", lp->d_secpercyl); 426 GETNUM("Cylinders? [%d] ", lp->d_ncylinders); 427 if (lp->d_secperunit == 0) 428 lp->d_secperunit = lp->d_ncylinders * lp->d_secpercyl; 429 GETNUM("Total sectors? [%d] ", lp->d_secperunit); 430 431 printf( 432 "Enter partition table. Note, sizes and offsets are in sectors.\n\n"); 433 434 lp->d_npartitions = MAXPARTITIONS; 435 for (i = 0; i < lp->d_npartitions; ++i) { 436 GETNUM2("%c partition: offset? [%d] ", ('a' + i), 437 lp->d_partitions[i].p_offset); 438 GETNUM(" size? [%d] ", lp->d_partitions[i].p_size); 439 get_fstype(lp, i); 440 } 441 442 /* Perform magic. */ 443 lp->d_magic = lp->d_magic2 = DISKMAGIC; 444 445 /* Calculate disklabel checksum. */ 446 lp->d_checksum = 0; 447 lp->d_checksum = dkcksum(lp); 448 } 449 450 void 451 disklabel_show(struct disklabel *lp) 452 { 453 int i; 454 struct partition *pp; 455 456 /* 457 * Check for valid disklabel. 458 */ 459 if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC) { 460 printf("No disklabel to show.\n"); 461 return; 462 } 463 464 if (lp->d_npartitions > MAXPARTITIONS || dkcksum(lp) != 0) { 465 printf("Corrupted disklabel.\n"); 466 return; 467 } 468 469 printf("\ndisk type %d (%s), %s: %s%s%s\n", lp->d_type, 470 lp->d_type < DKMAXTYPES ? dktypenames[lp->d_type] : 471 dktypenames[0], lp->d_typename, 472 (lp->d_flags & D_REMOVABLE) ? " removable" : "", 473 (lp->d_flags & D_ECC) ? " ecc" : "", 474 (lp->d_flags & D_BADSECT) ? " badsect" : ""); 475 476 printf("interleave %d, rpm %d, trackskew %d, cylinderskew %d\n", 477 lp->d_interleave, lp->d_rpm, lp->d_trackskew, lp->d_cylskew); 478 479 printf("headswitch %d, track-to-track %d, drivedata: %d %d %d %d %d\n", 480 lp->d_headswitch, lp->d_trkseek, lp->d_drivedata[0], 481 lp->d_drivedata[1], lp->d_drivedata[2], lp->d_drivedata[3], 482 lp->d_drivedata[4]); 483 484 printf("\nbytes/sector: %d\n", lp->d_secsize); 485 printf("sectors/track: %d\n", lp->d_nsectors); 486 printf("tracks/cylinder: %d\n", lp->d_ntracks); 487 printf("sectors/cylinder: %d\n", lp->d_secpercyl); 488 printf("cylinders: %d\n", lp->d_ncylinders); 489 printf("total sectors: %d\n", lp->d_secperunit); 490 491 printf("\n%d partitions:\n", lp->d_npartitions); 492 printf(" size offset\n"); 493 pp = lp->d_partitions; 494 for (i = 0; i < lp->d_npartitions; i++) { 495 printf("%c: %d, %d\n", 97 + i, lp->d_partitions[i].p_size, 496 lp->d_partitions[i].p_offset); 497 } 498 printf("\n"); 499 } 500 501 int 502 disklabel_write(char *block, int len, struct open_file *ofp) 503 { 504 int error = 0; 505 size_t xfersize; 506 507 if ((error = (*ofp->f_dev->dv_strategy)(ofp->f_devdata, F_WRITE, 508 LABELSECTOR, len, block, &xfersize)) != 0) 509 printf("cannot write disklabel, errno = %d\n", error); 510 511 return (error); 512 } 513 514 int 515 opendisk(char *question, char *diskname, int len, char partition, int *fdp) 516 { 517 char fulldiskname[64]; 518 int i; 519 520 getdiskname: 521 printf("%s ", question); 522 memset(diskname, 0, len); 523 memset(fulldiskname, 0, sizeof(fulldiskname)); 524 gets(diskname); 525 if (diskname[0] == '\n' || diskname[0] == '\0') 526 goto getdiskname; 527 528 /* 529 * devopen() is picky. Make sure it gets the sort of string it 530 * wants. 531 */ 532 memcpy(fulldiskname, diskname, 533 len < sizeof(fulldiskname) ? len : sizeof(fulldiskname)); 534 for (i = 0; fulldiskname[i + 1] != '\0'; ++i) 535 /* Nothing. */ ; 536 if (fulldiskname[i] < '0' || fulldiskname[i] > '9') { 537 printf("invalid disk name %s\n", diskname); 538 goto getdiskname; 539 } 540 fulldiskname[++i] = partition; fulldiskname[++i] = ':'; 541 542 /* 543 * We always open for writing. 544 */ 545 if ((*fdp = open(fulldiskname, 1)) < 0) { 546 printf("cannot open %s\n", diskname); 547 return 1; 548 } 549 550 return 0; 551 } 552 553 /* 554 * Copy a miniroot image from an NFS server or tape to the `b' partition 555 * of the specified disk. Note, this assumes 512 byte sectors. 556 */ 557 void 558 miniroot(void) 559 { 560 int sfd, dfd, i, nblks; 561 char diskname[64], minirootname[128]; 562 char block[DEV_BSIZE]; 563 char tapename[64]; 564 int fileno, ignoreshread, eof, len; 565 struct stat st; 566 size_t xfersize; 567 struct open_file *disk_ofp; 568 extern struct open_file files[]; 569 570 /* Error message printed by opendisk() */ 571 if (opendisk("Disk for miniroot?", diskname, sizeof(diskname), 572 'b', &dfd)) 573 return; 574 575 disk_ofp = &files[dfd]; 576 577 getsource: 578 printf("Source? (N)FS, (t)ape, (d)one > "); 579 memset(line, 0, sizeof(line)); 580 gets(line); 581 if (line[0] == '\0') 582 goto getsource; 583 584 switch (line[0]) { 585 case 'n': 586 case 'N': 587 name_of_nfs_miniroot: 588 printf("Name of miniroot file? "); 589 memset(line, 0, sizeof(line)); 590 memset(minirootname, 0, sizeof(minirootname)); 591 gets(line); 592 if (line[0] == '\0') 593 goto name_of_nfs_miniroot; 594 (void)strcat(minirootname, "le0a:"); 595 (void)strcat(minirootname, line); 596 if ((sfd = open(minirootname, 0)) < 0) { 597 printf("can't open %s\n", line); 598 return; 599 } 600 601 /* 602 * Find out how big the miniroot is... we can't 603 * check for size because it may be compressed. 604 */ 605 ignoreshread = 1; 606 if (fstat(sfd, &st) < 0) { 607 printf("can't stat %s\n", line); 608 goto done; 609 } 610 nblks = (int)(st.st_size / sizeof(block)); 611 612 printf("Copying miniroot from %s to %s...", line, 613 diskname); 614 break; 615 616 case 't': 617 case 'T': 618 name_of_tape_miniroot: 619 printf("Which tape device? "); 620 memset(line, 0, sizeof(line)); 621 memset(minirootname, 0, sizeof(minirootname)); 622 memset(tapename, 0, sizeof(tapename)); 623 gets(line); 624 if (line[0] == '\0') 625 goto name_of_tape_miniroot; 626 strcat(minirootname, line); 627 strcat(tapename, line); 628 629 printf("File number (first == 1)? "); 630 memset(line, 0, sizeof(line)); 631 gets(line); 632 fileno = a2int(line); 633 if (fileno < 1 || fileno > 8) { 634 printf("Invalid file number: %s\n", line); 635 goto getsource; 636 } 637 for (i = 0; i < sizeof(minirootname); ++i) { 638 if (minirootname[i] == '\0') 639 break; 640 } 641 if (i == sizeof(minirootname) || 642 (sizeof(minirootname) - i) < 8) { 643 printf("Invalid device name: %s\n", tapename); 644 goto getsource; 645 } 646 minirootname[i++] = 'a' + (fileno - 1); 647 minirootname[i++] = ':'; 648 strcat(minirootname, "XXX"); /* lameness in open() */ 649 650 ignoreshread = 0; 651 printf("Copy how many %d byte blocks? ", DEV_BSIZE); 652 memset(line, 0, sizeof(line)); 653 gets(line); 654 nblks = a2int(line); 655 if (nblks < 0) { 656 printf("Invalid block count: %s\n", line); 657 goto getsource; 658 } else if (nblks == 0) { 659 printf("Zero blocks? Ok, aborting.\n"); 660 return; 661 } 662 663 if ((sfd = open(minirootname, 0)) < 0) { 664 printf("can't open %s file %c\n", tapename, fileno); 665 return; 666 } 667 668 printf("Copying %s file %d to %s...", tapename, fileno, 669 diskname); 670 break; 671 672 case 'd': 673 case 'D': 674 return; 675 676 default: 677 printf("Unknown source: %s\n", line); 678 goto getsource; 679 } 680 681 /* 682 * Copy loop... 683 * This is fairly slow... if someone wants to speed it 684 * up, they'll get no complaints from me. 685 */ 686 for (i = 0, eof = 0; i < nblks || ignoreshread == 0; i++) { 687 if ((len = read(sfd, block, sizeof(block))) < 0) { 688 printf("Read error, errno = %d\n", errno); 689 goto out; 690 } 691 692 /* 693 * Check for end-of-file. 694 */ 695 if (len == 0) 696 goto done; 697 else if (len < sizeof(block)) 698 eof = 1; 699 700 if ((*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata, 701 F_WRITE, i, len, block, &xfersize) || xfersize != len) { 702 printf("Bad write at block %d, errno = %d\n", 703 i, errno); 704 goto out; 705 } 706 707 if (eof) 708 goto done; 709 } 710 done: 711 printf("done\n"); 712 713 printf("Successfully copied miniroot image.\n"); 714 715 out: 716 close(sfd); 717 close(dfd); 718 } 719 720 /* 721 * Boot the kernel from the miniroot image into single-user. 722 */ 723 void 724 bootmini(void) 725 { 726 char diskname[64], bootname[64]; 727 int i; 728 729 getdiskname: 730 printf("Disk to boot from? "); 731 memset(diskname, 0, sizeof(diskname)); 732 memset(bootname, 0, sizeof(bootname)); 733 gets(diskname); 734 if (diskname[0] == '\n' || diskname[0] == '\0') 735 goto getdiskname; 736 737 /* 738 * devopen() is picky. Make sure it gets the sort of string it 739 * wants. 740 */ 741 (void)strcat(bootname, diskname); 742 for (i = 0; bootname[i + 1] != '\0'; ++i) 743 /* Nothing. */ ; 744 if (bootname[i] < '0' || bootname[i] > '9') { 745 printf("invalid disk name %s\n", diskname); 746 goto getdiskname; 747 } 748 bootname[++i] = 'b'; bootname[++i] = ':'; 749 (void)strcat(bootname, kernel_name); 750 751 howto = RB_SINGLE; /* _Always_ */ 752 753 printf("booting: %s -s\n", bootname); 754 exec_hp300(bootname, (u_long)lowram, howto); 755 printf("boot: %s\n", strerror(errno)); 756 } 757 758 /* 759 * Reset the system. 760 */ 761 void 762 resetsys(void) 763 { 764 765 call_req_reboot(); 766 printf("panic: can't reboot, halting\n"); 767 __asm("stop #0x2700"); 768 } 769 770 /* 771 * XXX Should have a generic atoi for libkern/libsa. 772 */ 773 int 774 a2int(char *cp) 775 { 776 int i = 0; 777 778 if (*cp == '\0') 779 return (-1); 780 781 while (*cp != '\0') 782 i = i * 10 + *cp++ - '0'; 783 return (i); 784 } 785