xref: /netbsd-src/sys/arch/hp300/stand/inst/inst.c (revision b7b7574d3bf8eeb51a1fa3977b59142ec6434a55)
1 /*	$NetBSD: inst.c,v 1.19 2014/06/21 02:01:21 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 extern	u_int opendev;
82 extern	char *lowram;
83 extern	int noconsole;
84 extern	int netio_ask;
85 
86 char	*kernel_name = "/netbsd";
87 
88 void	main(void);
89 void	dsklabel(void);
90 void	miniroot(void);
91 void	bootmini(void);
92 void	resetsys(void);
93 void	gethelp(void);
94 int	opendisk(char *, char *, int, char, int *);
95 void	disklabel_edit(struct disklabel *);
96 void	disklabel_show(struct disklabel *);
97 int	disklabel_write(char *, int, struct open_file *);
98 void	get_fstype(struct disklabel *lp, int);
99 int	a2int(char *);
100 
101 struct	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 
114 void
115 main(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 
150 void
151 gethelp(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  */
165 void
166 dsklabel(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 
289 struct 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 
300 void
301 get_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 
380 void
381 disklabel_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 
443 void
444 disklabel_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", 'a' + i, pp[i].p_size,
489 		    pp[i].p_offset);
490 	}
491 	printf("\n");
492 }
493 
494 int
495 disklabel_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 
507 int
508 opendisk(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  */
550 void
551 miniroot(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  */
716 void
717 bootmini(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  */
754 void
755 resetsys(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  */
766 int
767 a2int(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