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