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