xref: /netbsd/sys/arch/hp300/stand/inst/inst.c (revision 15805031)
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