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