inst.c revision 1.15 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