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