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