1 /* $NetBSD: inst.c,v 1.17 2008/04/28 20:23:19 martin Exp $ */
4 * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
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.
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.
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:
37 * Copyright (c) 1995 Ludd, University of Lule}, Sweden.
38 * All rights reserved.
40 * Redistribution and use in source and binary forms, with or without
41 * modification, are permitted provided that the following conditions
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
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
70 #include <sys/param.h>
71 #include <sys/reboot.h>
72 #include <sys/disklabel.h>
74 #include <lib/libsa/stand.h>
75 #include <lib/libkern/libkern.h>
77 #include <hp300/stand/common/samachdep.h>
86 char *kernel_name
= "/netbsd";
94 int opendisk(char *, char *, int, char, int *);
95 void disklabel_edit(struct disklabel
*);
96 void disklabel_show(struct disklabel
*);
97 int disklabel_write(char *, int, struct open_file
*);
98 void get_fstype(struct disklabel
*lp
, int);
101 struct inst_command
{
102 char *ic_cmd
; /* command name */
103 char *ic_desc
; /* command description */
104 void (*ic_func
)(void); /* handling function */
105 } inst_commands
[] = {
106 { "disklabel", "place partition map on disk", dsklabel
},
107 { "miniroot", "place miniroot on disk", miniroot
},
108 { "boot", "boot from miniroot", bootmini
},
109 { "reset", "reset the system", resetsys
},
110 { "help", "display command list", gethelp
},
112 #define NCMDS (sizeof(inst_commands) / sizeof(inst_commands[0]))
120 * We want netopen() to ask for IP address, etc, rather
121 * that using bootparams.
126 printf(">> %s, Revision %s (from NetBSD %s)\n",
127 bootprog_name
, bootprog_rev
, bootprog_kernrev
);
128 printf(">> HP 9000/%s SPU\n", getmachineid());
132 printf("sys_inst> ");
133 memset(line
, 0, sizeof(line
));
135 if (line
[0] == '\n' || line
[0] == '\0')
138 for (i
= 0; i
< NCMDS
; ++i
)
139 if (strcmp(line
, inst_commands
[i
].ic_cmd
) == 0) {
140 (*inst_commands
[i
].ic_func
)();
146 printf("unknown command: %s\n", line
);
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
);
162 * Do all the steps necessary to place a disklabel on a disk.
163 * Note, this assumes 512 byte sectors.
168 struct disklabel
*lp
;
169 struct open_file
*disk_ofp
;
172 char block
[DEV_BSIZE
], diskname
[64];
173 extern struct open_file files
[];
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");
182 /* Error message printed by opendisk() */
183 if (opendisk("Disk to label?", diskname
, sizeof(diskname
),
184 ('a' + RAW_PART
), &dfd
))
187 disk_ofp
= &files
[dfd
];
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
);
196 printf("Successfully read %d bytes from %s\n", xfersize
, diskname
);
198 lp
= (struct disklabel
*)((void *)(&block
[LABELOFFSET
]));
201 memset(line
, 0, sizeof(line
));
202 printf("(z)ap, (e)dit, (s)how, (w)rite, (d)one > ");
204 if (line
[0] == '\n' || line
[0] == '\0')
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
);
231 * Error message will be displayed by disklabel_write()
233 if (disklabel_write(block
, sizeof(block
), disk_ofp
))
236 printf("Successfully wrote label to %s\n", diskname
);
245 printf("unknown command: %s\n", line
);
253 * Close disk. Marks disk `not alive' so that partition
254 * information will be reloaded upon next open.
259 #define GETNUM(out, num) \
260 printf((out), (num)); \
261 memset(line, 0, sizeof(line)); \
266 #define GETNUM2(out, num1, num2) \
267 printf((out), (num1), (num2)); \
268 memset(line, 0, sizeof(line)); \
273 #define GETSTR(out, str) \
274 printf((out), (str)); \
275 memset(line, 0, sizeof(line)); \
280 #define FLAGS(out, flag) \
281 printf((out), lp->d_flags & (flag) ? 'y' : 'n'); \
282 memset(line, 0, sizeof(line)); \
284 if (line[0] == 'y' || line[0] == 'Y') \
285 lp->d_flags |= (flag); \
287 lp->d_flags &= ~(flag);
289 struct fsname_to_type
{
293 { "unused", FS_UNUSED
},
294 { "ffs", FS_BSDFFS
},
301 get_fstype(struct disklabel
*lp
, int partno
)
303 static int blocksize
= 8192; /* XXX */
304 struct partition
*pp
= &lp
->d_partitions
[partno
];
305 struct fsname_to_type
*np
;
307 char line
[80], str
[80];
309 if (pp
->p_size
== 0) {
311 * No need to bother asking for a zero-sized partition.
313 pp
->p_fstype
= FS_UNUSED
;
319 * XXX Should we check what might be in the label already?
323 else if (partno
== RAW_PART
)
329 GETSTR(" fstype? [%s] ", str
);
331 for (np
= n_to_t
; np
->name
!= NULL
; np
++)
332 if (strcmp(str
, np
->name
) == 0)
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
);
343 pp
->p_fstype
= np
->type
;
345 if (pp
->p_fstype
!= FS_BSDFFS
)
349 * Get additional information needed for FFS.
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
);
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
);
366 if ((blocksize
% fragsize
) != 0) {
367 printf("FFS fragment size must be an even divisor of FFS"
368 " block size (%d).\n", blocksize
);
373 * XXX Better sanity checking?
376 pp
->p_frag
= blocksize
/ fragsize
;
377 pp
->p_fsize
= fragsize
;
381 disklabel_edit(struct disklabel
*lp
)
385 printf("Select disk type. Valid types:\n");
386 for (i
= 0; i
< DKMAXTYPES
; i
++)
387 printf("%d %s\n", i
, dktypenames
[i
]);
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
);
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]);
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
);
425 "Enter partition table. Note, sizes and offsets are in sectors.\n\n");
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
);
436 lp
->d_magic
= lp
->d_magic2
= DISKMAGIC
;
438 /* Calculate disklabel checksum. */
440 lp
->d_checksum
= dkcksum(lp
);
444 disklabel_show(struct disklabel
*lp
)
447 struct partition
*pp
;
450 * Check for valid disklabel.
452 if (lp
->d_magic
!= DISKMAGIC
|| lp
->d_magic2
!= DISKMAGIC
) {
453 printf("No disklabel to show.\n");
457 if (lp
->d_npartitions
> MAXPARTITIONS
|| dkcksum(lp
) != 0) {
458 printf("Corrupted disklabel.\n");
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" : "");
469 printf("interleave %d, rpm %d, trackskew %d, cylinderskew %d\n",
470 lp
->d_interleave
, lp
->d_rpm
, lp
->d_trackskew
, lp
->d_cylskew
);
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],
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
);
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
);
495 disklabel_write(char *block
, int len
, struct open_file
*ofp
)
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
);
508 opendisk(char *question
, char *diskname
, int len
, char partition
, int *fdp
)
510 char fulldiskname
[64];
514 printf("%s ", question
);
515 memset(diskname
, 0, len
);
516 memset(fulldiskname
, 0, sizeof(fulldiskname
));
518 if (diskname
[0] == '\n' || diskname
[0] == '\0')
522 * devopen() is picky. Make sure it gets the sort of string it
525 memcpy(fulldiskname
, diskname
,
526 len
< sizeof(fulldiskname
) ? len
: sizeof(fulldiskname
));
527 for (i
= 0; fulldiskname
[i
+ 1] != '\0'; ++i
)
529 if (fulldiskname
[i
] < '0' || fulldiskname
[i
] > '9') {
530 printf("invalid disk name %s\n", diskname
);
533 fulldiskname
[++i
] = partition
; fulldiskname
[++i
] = ':';
536 * We always open for writing.
538 if ((*fdp
= open(fulldiskname
, 1)) < 0) {
539 printf("cannot open %s\n", diskname
);
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.
553 int sfd
, dfd
, i
, nblks
;
554 char diskname
[64], minirootname
[128];
555 char block
[DEV_BSIZE
];
557 int fileno
, ignoreshread
, eof
, len
;
560 struct open_file
*disk_ofp
;
561 extern struct open_file files
[];
563 /* Error message printed by opendisk() */
564 if (opendisk("Disk for miniroot?", diskname
, sizeof(diskname
),
568 disk_ofp
= &files
[dfd
];
571 printf("Source? (N)FS, (t)ape, (d)one > ");
572 memset(line
, 0, sizeof(line
));
580 name_of_nfs_miniroot
:
581 printf("Name of miniroot file? ");
582 memset(line
, 0, sizeof(line
));
583 memset(minirootname
, 0, sizeof(minirootname
));
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
);
595 * Find out how big the miniroot is... we can't
596 * check for size because it may be compressed.
599 if (fstat(sfd
, &st
) < 0) {
600 printf("can't stat %s\n", line
);
603 nblks
= (int)(st
.st_size
/ sizeof(block
));
605 printf("Copying miniroot from %s to %s...", line
,
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
));
618 goto name_of_tape_miniroot
;
619 strcat(minirootname
, line
);
620 strcat(tapename
, line
);
622 printf("File number (first == 1)? ");
623 memset(line
, 0, sizeof(line
));
625 fileno
= a2int(line
);
626 if (fileno
< 1 || fileno
> 8) {
627 printf("Invalid file number: %s\n", line
);
630 for (i
= 0; i
< sizeof(minirootname
); ++i
) {
631 if (minirootname
[i
] == '\0')
634 if (i
== sizeof(minirootname
) ||
635 (sizeof(minirootname
) - i
) < 8) {
636 printf("Invalid device name: %s\n", tapename
);
639 minirootname
[i
++] = 'a' + (fileno
- 1);
640 minirootname
[i
++] = ':';
641 strcat(minirootname
, "XXX"); /* lameness in open() */
644 printf("Copy how many %d byte blocks? ", DEV_BSIZE
);
645 memset(line
, 0, sizeof(line
));
649 printf("Invalid block count: %s\n", line
);
651 } else if (nblks
== 0) {
652 printf("Zero blocks? Ok, aborting.\n");
656 if ((sfd
= open(minirootname
, 0)) < 0) {
657 printf("can't open %s file %c\n", tapename
, fileno
);
661 printf("Copying %s file %d to %s...", tapename
, fileno
,
670 printf("Unknown source: %s\n", line
);
676 * This is fairly slow... if someone wants to speed it
677 * up, they'll get no complaints from me.
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
);
686 * Check for end-of-file.
690 else if (len
< sizeof(block
))
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",
706 printf("Successfully copied miniroot image.\n");
714 * Boot the kernel from the miniroot image into single-user.
719 char diskname
[64], bootname
[64];
723 printf("Disk to boot from? ");
724 memset(diskname
, 0, sizeof(diskname
));
725 memset(bootname
, 0, sizeof(bootname
));
727 if (diskname
[0] == '\n' || diskname
[0] == '\0')
731 * devopen() is picky. Make sure it gets the sort of string it
734 (void)strcat(bootname
, diskname
);
735 for (i
= 0; bootname
[i
+ 1] != '\0'; ++i
)
737 if (bootname
[i
] < '0' || bootname
[i
] > '9') {
738 printf("invalid disk name %s\n", diskname
);
741 bootname
[++i
] = 'b'; bootname
[++i
] = ':';
742 (void)strcat(bootname
, kernel_name
);
744 howto
= RB_SINGLE
; /* _Always_ */
746 printf("booting: %s -s\n", bootname
);
747 exec_hp300(bootname
, (u_long
)lowram
, howto
);
748 printf("boot: %s\n", strerror(errno
));
759 printf("panic: can't reboot, halting\n");
760 __asm("stop #0x2700");
764 * XXX Should have a generic atoi for libkern/libsa.
775 i
= i
* 10 + *cp
++ - '0';