1 /* $NetBSD: inst.c,v 1.7 2002/03/16 06:20:08 gmcgarry 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 83 #include <hp300/stand/common/samachdep.h> 84 85 char line[100]; 86 87 extern u_int opendev; 88 extern char *lowram; 89 extern int noconsole; 90 extern int netio_ask; 91 92 char *kernel_name = "/netbsd"; 93 94 void dsklabel __P((void)); 95 void miniroot __P((void)); 96 void bootmini __P((void)); 97 void resetsys __P((void)); 98 void gethelp __P((void)); 99 int opendisk __P((char *, char *, int, char, int *)); 100 void disklabel_edit __P((struct disklabel *)); 101 void disklabel_show __P((struct disklabel *)); 102 int disklabel_write __P((char *, int, struct open_file *)); 103 void get_fstype __P((struct disklabel *lp, int)); 104 int a2int __P((char *)); 105 106 struct inst_command { 107 char *ic_cmd; /* command name */ 108 char *ic_desc; /* command description */ 109 void (*ic_func) __P((void)); /* handling function */ 110 } inst_commands[] = { 111 { "disklabel", "place partition map on disk", dsklabel }, 112 { "miniroot", "place miniroot on disk", miniroot }, 113 { "boot", "boot from miniroot", bootmini }, 114 { "reset", "reset the system", resetsys }, 115 { "help", "display command list", gethelp }, 116 }; 117 #define NCMDS (sizeof(inst_commands) / sizeof(inst_commands[0])) 118 119 main() 120 { 121 int i, currname = 0; 122 123 /* 124 * We want netopen() to ask for IP address, etc, rather 125 * that using bootparams. 126 */ 127 netio_ask = 1; 128 129 printf("\n"); 130 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev); 131 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date); 132 printf(">> HP 9000/%s SPU\n", getmachineid()); 133 gethelp(); 134 135 for (;;) { 136 printf("sys_inst> "); 137 bzero(line, sizeof(line)); 138 gets(line); 139 if (line[0] == '\n' || line[0] == '\0') 140 continue; 141 142 for (i = 0; i < NCMDS; ++i) 143 if (strcmp(line, inst_commands[i].ic_cmd) == 0) { 144 (*inst_commands[i].ic_func)(); 145 break; 146 } 147 148 149 if (i == NCMDS) 150 printf("unknown command: %s\n", line); 151 } 152 } 153 154 void 155 gethelp() 156 { 157 int i; 158 159 printf(">> Available commands:\n"); 160 for (i = 0; i < NCMDS; ++i) 161 printf(">> %s - %s\n", inst_commands[i].ic_cmd, 162 inst_commands[i].ic_desc); 163 } 164 165 /* 166 * Do all the steps necessary to place a disklabel on a disk. 167 * Note, this assumes 512 byte sectors. 168 */ 169 void 170 dsklabel() 171 { 172 struct disklabel *lp; 173 struct open_file *disk_ofp; 174 int dfd, error; 175 size_t xfersize; 176 char block[DEV_BSIZE], diskname[64]; 177 extern struct open_file files[]; 178 179 printf(" 180 You will be asked several questions about your disk, most of which 181 require prior knowledge of the disk's geometry. There is no easy way 182 for the system to provide this information for you. If you do not have 183 this information, please consult your disk's manual or another 184 informative source.\n\n"); 185 186 /* Error message printed by opendisk() */ 187 if (opendisk("Disk to label?", diskname, sizeof(diskname), 188 ('a' + RAW_PART), &dfd)) 189 return; 190 191 disk_ofp = &files[dfd]; 192 193 bzero(block, sizeof(block)); 194 if (error = (*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata, 195 F_READ, LABELSECTOR, sizeof(block), block, &xfersize)) { 196 printf("cannot read disk %s, errno = %d\n", diskname, error); 197 return; 198 } 199 200 printf("Sucessfully read %d bytes from %s\n", xfersize, diskname); 201 202 lp = (struct disklabel *)((void *)(&block[LABELOFFSET])); 203 204 disklabel_loop: 205 bzero(line, sizeof(line)); 206 printf("(z)ap, (e)dit, (s)how, (w)rite, (d)one > "); 207 gets(line); 208 if (line[0] == '\n' || line[0] == '\0') 209 goto disklabel_loop; 210 211 switch (line[0]) { 212 case 'z': 213 case 'Z': { 214 char zap[DEV_BSIZE]; 215 bzero(zap, sizeof(zap)); 216 (void)(*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata, 217 F_WRITE, LABELSECTOR, sizeof(zap), zap, &xfersize); 218 } 219 goto out; 220 /* NOTREACHED */ 221 222 case 'e': 223 case 'E': 224 disklabel_edit(lp); 225 break; 226 227 case 's': 228 case 'S': 229 disklabel_show(lp); 230 break; 231 232 case 'w': 233 case 'W': 234 /* 235 * Error message will be displayed by disklabel_write() 236 */ 237 if (disklabel_write(block, sizeof(block), disk_ofp)) 238 goto out; 239 else 240 printf("Sucessfully wrote label to %s\n", diskname); 241 break; 242 243 case 'd': 244 case 'D': 245 goto out; 246 /* NOTREACHED */ 247 248 default: 249 printf("unkown command: %s\n", line); 250 } 251 252 goto disklabel_loop; 253 /* NOTREACHED */ 254 255 out: 256 /* 257 * Close disk. Marks disk `not alive' so that partition 258 * information will be reloaded upon next open. 259 */ 260 (void)close(dfd); 261 } 262 263 #define GETNUM(out, num) \ 264 printf((out), (num)); \ 265 bzero(line, sizeof(line)); \ 266 gets(line); \ 267 if (line[0]) \ 268 (num) = atoi(line); 269 270 #define GETNUM2(out, num1, num2) \ 271 printf((out), (num1), (num2)); \ 272 bzero(line, sizeof(line)); \ 273 gets(line); \ 274 if (line[0]) \ 275 (num2) = atoi(line); 276 277 #define GETSTR(out, str) \ 278 printf((out), (str)); \ 279 bzero(line, sizeof(line)); \ 280 gets(line); \ 281 if (line[0]) \ 282 strcpy((str), line); 283 284 #define FLAGS(out, flag) \ 285 printf((out), lp->d_flags & (flag) ? 'y' : 'n'); \ 286 bzero(line, sizeof(line)); \ 287 gets(line); \ 288 if (line[0] == 'y' || line[0] == 'Y') \ 289 lp->d_flags |= (flag); \ 290 else \ 291 lp->d_flags &= ~(flag); 292 293 struct fsname_to_type { 294 const char *name; 295 u_int8_t type; 296 } n_to_t[] = { 297 { "unused", FS_UNUSED }, 298 { "ffs", FS_BSDFFS }, 299 { "swap", FS_SWAP }, 300 { "boot", FS_BOOT }, 301 { NULL, 0 }, 302 }; 303 304 void 305 get_fstype(lp, partno) 306 struct disklabel *lp; 307 int partno; 308 { 309 static int blocksize = 8192; /* XXX */ 310 struct partition *pp = &lp->d_partitions[partno]; 311 struct fsname_to_type *np; 312 int fragsize; 313 char line[80], str[80]; 314 315 if (pp->p_size == 0) { 316 /* 317 * No need to bother asking for a zero-sized partition. 318 */ 319 pp->p_fstype = FS_UNUSED; 320 return; 321 } 322 323 /* 324 * Select a default. 325 * XXX Should we check what might be in the label already? 326 */ 327 if (partno == 1) 328 strcpy(str, "swap"); 329 else if (partno == RAW_PART) 330 strcpy(str, "boot"); 331 else 332 strcpy(str, "ffs"); 333 334 again: 335 GETSTR(" fstype? [%s] ", str); 336 337 for (np = n_to_t; np->name != NULL; np++) 338 if (strcmp(str, np->name) == 0) 339 break; 340 341 if (np->name == NULL) { 342 printf("Please use one of: "); 343 for (np = n_to_t; np->name != NULL; np++) 344 printf(" %s", np->name); 345 printf(".\n"); 346 goto again; 347 } 348 349 pp->p_fstype = np->type; 350 351 if (pp->p_fstype != FS_BSDFFS) 352 return; 353 354 /* 355 * Get additional information needed for FFS. 356 */ 357 ffs_again: 358 GETNUM(" FFS block size? [%d] ", blocksize); 359 if (blocksize < NBPG || (blocksize % NBPG) != 0) { 360 printf("FFS block size must be a multiple of %d.\n", NBPG); 361 goto ffs_again; 362 } 363 364 fragsize = blocksize / 8; /* XXX */ 365 fragsize = max(fragsize, lp->d_secsize); 366 GETNUM(" FFS fragment size? [%d] ", fragsize); 367 if (fragsize < lp->d_secsize || (fragsize % lp->d_secsize) != 0) { 368 printf("FFS fragment size must be a multiple of sector size" 369 " (%d).\n", lp->d_secsize); 370 goto ffs_again; 371 } 372 if ((blocksize % fragsize) != 0) { 373 printf("FFS fragment size must be an even divisor of FFS" 374 " block size (%d).\n", blocksize); 375 goto ffs_again; 376 } 377 378 /* 379 * XXX Better sanity checking? 380 */ 381 382 pp->p_frag = blocksize / fragsize; 383 pp->p_fsize = fragsize; 384 } 385 386 void 387 disklabel_edit(lp) 388 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(lp) 452 struct disklabel *lp; 453 { 454 int i, npart; 455 struct partition *pp; 456 457 /* 458 * Check for valid disklabel. 459 */ 460 if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC) { 461 printf("No disklabel to show.\n"); 462 return; 463 } 464 465 if (lp->d_npartitions > MAXPARTITIONS || dkcksum(lp) != 0) { 466 printf("Corrupted disklabel.\n"); 467 return; 468 } 469 470 printf("\ndisk type %d (%s), %s: %s%s%s\n", lp->d_type, 471 lp->d_type < DKMAXTYPES ? dktypenames[lp->d_type] : 472 dktypenames[0], lp->d_typename, 473 (lp->d_flags & D_REMOVABLE) ? " removable" : "", 474 (lp->d_flags & D_ECC) ? " ecc" : "", 475 (lp->d_flags & D_BADSECT) ? " badsect" : ""); 476 477 printf("interleave %d, rpm %d, trackskew %d, cylinderskew %d\n", 478 lp->d_interleave, lp->d_rpm, lp->d_trackskew, lp->d_cylskew); 479 480 printf("headswitch %d, track-to-track %d, drivedata: %d %d %d %d %d\n", 481 lp->d_headswitch, lp->d_trkseek, lp->d_drivedata[0], 482 lp->d_drivedata[1], lp->d_drivedata[2], lp->d_drivedata[3], 483 lp->d_drivedata[4]); 484 485 printf("\nbytes/sector: %d\n", lp->d_secsize); 486 printf("sectors/track: %d\n", lp->d_nsectors); 487 printf("tracks/cylinder: %d\n", lp->d_ntracks); 488 printf("sectors/cylinder: %d\n", lp->d_secpercyl); 489 printf("cylinders: %d\n", lp->d_ncylinders); 490 printf("total sectors: %d\n", lp->d_secperunit); 491 492 printf("\n%d partitions:\n", lp->d_npartitions); 493 printf(" size offset\n"); 494 pp = lp->d_partitions; 495 for (i = 0; i < lp->d_npartitions; i++) { 496 printf("%c: %d, %d\n", 97 + i, lp->d_partitions[i].p_size, 497 lp->d_partitions[i].p_offset); 498 } 499 printf("\n"); 500 } 501 502 int 503 disklabel_write(block, len, ofp) 504 char *block; 505 int len; 506 struct open_file *ofp; 507 { 508 int error = 0; 509 size_t xfersize; 510 511 if (error = (*ofp->f_dev->dv_strategy)(ofp->f_devdata, F_WRITE, 512 LABELSECTOR, len, block, &xfersize)) 513 printf("cannot write disklabel, errno = %d\n", error); 514 515 return (error); 516 } 517 518 int 519 opendisk(question, diskname, len, partition, fdp) 520 char *question, *diskname; 521 int len; 522 char partition; 523 int *fdp; 524 { 525 char fulldiskname[64], *filename; 526 int i, error = 0; 527 528 getdiskname: 529 printf("%s ", question); 530 bzero(diskname, len); 531 bzero(fulldiskname, sizeof(fulldiskname)); 532 gets(diskname); 533 if (diskname[0] == '\n' || diskname[0] == '\0') 534 goto getdiskname; 535 536 /* 537 * devopen() is picky. Make sure it gets the sort of string it 538 * wants. 539 */ 540 bcopy(diskname, fulldiskname, 541 len < sizeof(fulldiskname) ? len : sizeof(fulldiskname)); 542 for (i = 0; fulldiskname[i + 1] != '\0'; ++i) 543 /* Nothing. */ ; 544 if (fulldiskname[i] < '0' || fulldiskname[i] > '9') { 545 printf("invalid disk name %s\n", diskname); 546 goto getdiskname; 547 } 548 fulldiskname[++i] = partition; fulldiskname[++i] = ':'; 549 550 /* 551 * We always open for writing. 552 */ 553 if ((*fdp = open(fulldiskname, 1)) < 0) { 554 printf("cannot open %s\n", diskname); 555 return (1); 556 } 557 558 return (0); 559 } 560 561 /* 562 * Copy a miniroot image from an NFS server or tape to the `b' partition 563 * of the specified disk. Note, this assumes 512 byte sectors. 564 */ 565 void 566 miniroot() 567 { 568 int sfd, dfd, i, nblks; 569 char diskname[64], minirootname[128]; 570 char block[DEV_BSIZE]; 571 char tapename[64]; 572 int fileno, ignoreshread, eof, len; 573 struct stat st; 574 size_t xfersize; 575 struct open_file *disk_ofp; 576 extern struct open_file files[]; 577 578 /* Error message printed by opendisk() */ 579 if (opendisk("Disk for miniroot?", diskname, sizeof(diskname), 580 'b', &dfd)) 581 return; 582 583 disk_ofp = &files[dfd]; 584 585 getsource: 586 printf("Source? (N)FS, (t)ape, (d)one > "); 587 bzero(line, sizeof(line)); 588 gets(line); 589 if (line[0] == '\0') 590 goto getsource; 591 592 switch (line[0]) { 593 case 'n': 594 case 'N': 595 name_of_nfs_miniroot: 596 printf("Name of miniroot file? "); 597 bzero(line, sizeof(line)); 598 bzero(minirootname, sizeof(minirootname)); 599 gets(line); 600 if (line[0] == '\0') 601 goto name_of_nfs_miniroot; 602 (void)strcat(minirootname, "le0a:"); 603 (void)strcat(minirootname, line); 604 if ((sfd = open(minirootname, 0)) < 0) { 605 printf("can't open %s\n", line); 606 return; 607 } 608 609 /* 610 * Find out how big the miniroot is... we can't 611 * check for size because it may be compressed. 612 */ 613 ignoreshread = 1; 614 if (fstat(sfd, &st) < 0) { 615 printf("can't stat %s\n", line); 616 goto done; 617 } 618 nblks = (int)(st.st_size / sizeof(block)); 619 620 printf("Copying miniroot from %s to %s...", line, 621 diskname); 622 break; 623 624 case 't': 625 case 'T': 626 name_of_tape_miniroot: 627 printf("Which tape device? "); 628 bzero(line, sizeof(line)); 629 bzero(minirootname, sizeof(minirootname)); 630 bzero(tapename, sizeof(tapename)); 631 gets(line); 632 if (line[0] == '\0') 633 goto name_of_tape_miniroot; 634 strcat(minirootname, line); 635 strcat(tapename, line); 636 637 printf("File number (first == 1)? "); 638 bzero(line, sizeof(line)); 639 gets(line); 640 fileno = a2int(line); 641 if (fileno < 1 || fileno > 8) { 642 printf("Invalid file number: %s\n", line); 643 goto getsource; 644 } 645 for (i = 0; i < sizeof(minirootname); ++i) { 646 if (minirootname[i] == '\0') 647 break; 648 } 649 if (i == sizeof(minirootname) || 650 (sizeof(minirootname) - i) < 8) { 651 printf("Invalid device name: %s\n", tapename); 652 goto getsource; 653 } 654 minirootname[i++] = 'a' + (fileno - 1); 655 minirootname[i++] = ':'; 656 strcat(minirootname, "XXX"); /* lameness in open() */ 657 658 ignoreshread = 0; 659 printf("Copy how many %d byte blocks? ", DEV_BSIZE); 660 bzero(line, sizeof(line)); 661 gets(line); 662 nblks = a2int(line); 663 if (nblks < 0) { 664 printf("Invalid block count: %s\n", line); 665 goto getsource; 666 } else if (nblks == 0) { 667 printf("Zero blocks? Ok, aborting.\n"); 668 return; 669 } 670 671 if ((sfd = open(minirootname, 0)) < 0) { 672 printf("can't open %s file %c\n", tapename, fileno); 673 return; 674 } 675 676 printf("Copying %s file %d to %s...", tapename, fileno, 677 diskname); 678 break; 679 680 case 'd': 681 case 'D': 682 return; 683 684 default: 685 printf("Unknown source: %s\n", line); 686 goto getsource; 687 } 688 689 /* 690 * Copy loop... 691 * This is fairly slow... if someone wants to speed it 692 * up, they'll get no complaints from me. 693 */ 694 for (i = 0, eof = 0; i < nblks || ignoreshread == 0; i++) { 695 if ((len = read(sfd, block, sizeof(block))) < 0) { 696 printf("Read error, errno = %d\n", errno); 697 goto out; 698 } 699 700 /* 701 * Check for end-of-file. 702 */ 703 if (len == 0) 704 goto done; 705 else if (len < sizeof(block)) 706 eof = 1; 707 708 if ((*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata, 709 F_WRITE, i, len, block, &xfersize) || xfersize != len) { 710 printf("Bad write at block %d, errno = %d\n", 711 i, errno); 712 goto out; 713 } 714 715 if (eof) 716 goto done; 717 } 718 done: 719 printf("done\n"); 720 721 printf("Successfully copied miniroot image.\n"); 722 723 out: 724 close(sfd); 725 close(dfd); 726 } 727 728 /* 729 * Boot the kernel from the miniroot image into single-user. 730 */ 731 void 732 bootmini() 733 { 734 char diskname[64], bootname[64]; 735 int i; 736 737 getdiskname: 738 printf("Disk to boot from? "); 739 bzero(diskname, sizeof(diskname)); 740 bzero(bootname, sizeof(bootname)); 741 gets(diskname); 742 if (diskname[0] == '\n' || diskname[0] == '\0') 743 goto getdiskname; 744 745 /* 746 * devopen() is picky. Make sure it gets the sort of string it 747 * wants. 748 */ 749 (void)strcat(bootname, diskname); 750 for (i = 0; bootname[i + 1] != '\0'; ++i) 751 /* Nothing. */ ; 752 if (bootname[i] < '0' || bootname[i] > '9') { 753 printf("invalid disk name %s\n", diskname); 754 goto getdiskname; 755 } 756 bootname[++i] = 'b'; bootname[++i] = ':'; 757 (void)strcat(bootname, kernel_name); 758 759 howto = RB_SINGLE; /* _Always_ */ 760 761 printf("booting: %s -s\n", bootname); 762 exec_hp300(bootname, (u_long)lowram, howto); 763 printf("boot: %s\n", strerror(errno)); 764 } 765 766 /* 767 * Reset the system. 768 */ 769 void 770 resetsys() 771 { 772 773 call_req_reboot(); 774 printf("panic: can't reboot, halting\n"); 775 asm("stop #0x2700"); 776 } 777 778 /* 779 * XXX Should have a generic atoi for libkern/libsa. 780 */ 781 int 782 a2int(cp) 783 char *cp; 784 { 785 int i = 0; 786 787 if (*cp == '\0') 788 return (-1); 789 790 while (*cp != '\0') 791 i = i * 10 + *cp++ - '0'; 792 return (i); 793 } 794