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