inst.c revision 1.4 1 /* $NetBSD: inst.c,v 1.4 1997/10/04 17:22:49 thorpej 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 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
181 require prior knowledge of the disk's geometry. There is no easy way
182 for the system to provide this information for you. If you do not have
183 this information, please consult your disk's manual or another
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("unkown 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 void
294 disklabel_edit(lp)
295 struct disklabel *lp;
296 {
297 int i;
298
299 printf("Select disk type. Valid types:\n");
300 for (i = 0; i < DKMAXTYPES; i++)
301 printf("%d %s\n", i, dktypenames[i]);
302 printf("\n");
303
304 GETNUM("Disk type (number)? [%d] ", lp->d_type);
305 GETSTR("Disk model name? [%s] ", lp->d_typename);
306 GETSTR("Disk pack name? [%s] ", lp->d_packname);
307 FLAGS("Bad sectoring? [%c] ", D_BADSECT);
308 FLAGS("Ecc? [%c] ", D_ECC);
309 FLAGS("Removable? [%c] ", D_REMOVABLE);
310
311 printf("\n");
312
313 GETNUM("Interleave? [%d] ", lp->d_interleave);
314 GETNUM("Rpm? [%d] ", lp->d_rpm);
315 GETNUM("Trackskew? [%d] ", lp->d_trackskew);
316 GETNUM("Cylinderskew? [%d] ", lp->d_cylskew);
317 GETNUM("Headswitch? [%d] ", lp->d_headswitch);
318 GETNUM("Track-to-track? [%d] ", lp->d_trkseek);
319 GETNUM("Drivedata 0? [%d] ", lp->d_drivedata[0]);
320 GETNUM("Drivedata 1? [%d] ", lp->d_drivedata[1]);
321 GETNUM("Drivedata 2? [%d] ", lp->d_drivedata[2]);
322 GETNUM("Drivedata 3? [%d] ", lp->d_drivedata[3]);
323 GETNUM("Drivedata 4? [%d] ", lp->d_drivedata[4]);
324
325 printf("\n");
326
327 GETNUM("Bytes/sector? [%d] ", lp->d_secsize);
328 GETNUM("Sectors/track? [%d] ", lp->d_nsectors);
329 GETNUM("Tracks/cylinder? [%d] ", lp->d_ntracks);
330 GETNUM("Sectors/cylinder? [%d] ", lp->d_secpercyl);
331 GETNUM("Cylinders? [%d] ", lp->d_ncylinders);
332
333 printf("
334 Enter partition table. Note, sizes and offsets are in sectors.\n\n");
335
336 lp->d_npartitions = MAXPARTITIONS;
337 for (i = 0; i < lp->d_npartitions; ++i) {
338 GETNUM2("%c partition: offset? [%d] ", ('a' + i),
339 lp->d_partitions[i].p_offset);
340 GETNUM(" size? [%d] ", lp->d_partitions[i].p_size);
341 }
342
343 /* Perform magic. */
344 lp->d_magic = lp->d_magic2 = DISKMAGIC;
345
346 /* Calculate disklabel checksum. */
347 lp->d_checksum = 0;
348 lp->d_checksum = dkcksum(lp);
349 }
350
351 void
352 disklabel_show(lp)
353 struct disklabel *lp;
354 {
355 int i, npart;
356 struct partition *pp;
357
358 /*
359 * Check for valid disklabel.
360 */
361 if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC) {
362 printf("No disklabel to show.\n");
363 return;
364 }
365
366 if (lp->d_npartitions > MAXPARTITIONS || dkcksum(lp) != 0) {
367 printf("Corrupted disklabel.\n");
368 return;
369 }
370
371 printf("\ndisk type %d (%s), %s: %s%s%s\n", lp->d_type,
372 lp->d_type < DKMAXTYPES ? dktypenames[lp->d_type] :
373 dktypenames[0], lp->d_typename,
374 (lp->d_flags & D_REMOVABLE) ? " removable" : "",
375 (lp->d_flags & D_ECC) ? " ecc" : "",
376 (lp->d_flags & D_BADSECT) ? " badsect" : "");
377
378 printf("interleave %d, rpm %d, trackskew %d, cylinderskew %d\n",
379 lp->d_interleave, lp->d_rpm, lp->d_trackskew, lp->d_cylskew);
380
381 printf("headswitch %d, track-to-track %d, drivedata: %d %d %d %d %d\n",
382 lp->d_headswitch, lp->d_trkseek, lp->d_drivedata[0],
383 lp->d_drivedata[1], lp->d_drivedata[2], lp->d_drivedata[3],
384 lp->d_drivedata[4]);
385
386 printf("\nbytes/sector: %d\n", lp->d_secsize);
387 printf("sectors/track: %d\n", lp->d_nsectors);
388 printf("tracks/cylinder: %d\n", lp->d_ntracks);
389 printf("sectors/cylinder: %d\n", lp->d_secpercyl);
390 printf("cylinders: %d\n", lp->d_ncylinders);
391
392 printf("\n%d partitions:\n", lp->d_npartitions);
393 printf(" size offset\n");
394 pp = lp->d_partitions;
395 for (i = 0; i < lp->d_npartitions; i++) {
396 printf("%c: %d, %d\n", 97 + i, lp->d_partitions[i].p_size,
397 lp->d_partitions[i].p_offset);
398 }
399 printf("\n");
400 }
401
402 int
403 disklabel_write(block, len, ofp)
404 char *block;
405 int len;
406 struct open_file *ofp;
407 {
408 int error = 0;
409 size_t xfersize;
410
411 if (error = (*ofp->f_dev->dv_strategy)(ofp->f_devdata, F_WRITE,
412 LABELSECTOR, len, block, &xfersize))
413 printf("cannot write disklabel, errno = %d\n", error);
414
415 return (error);
416 }
417
418 int
419 opendisk(question, diskname, len, partition, fdp)
420 char *question, *diskname;
421 int len;
422 char partition;
423 int *fdp;
424 {
425 char fulldiskname[64], *filename;
426 int i, error = 0;
427
428 getdiskname:
429 printf("%s ", question);
430 bzero(diskname, len);
431 bzero(fulldiskname, sizeof(fulldiskname));
432 gets(diskname);
433 if (diskname[0] == '\n' || diskname[0] == '\0')
434 goto getdiskname;
435
436 /*
437 * devopen() is picky. Make sure it gets the sort of string it
438 * wants.
439 */
440 bcopy(diskname, fulldiskname,
441 len < sizeof(fulldiskname) ? len : sizeof(fulldiskname));
442 for (i = 0; fulldiskname[i + 1] != '\0'; ++i)
443 /* Nothing. */ ;
444 if (fulldiskname[i] < '0' || fulldiskname[i] > '9') {
445 printf("invalid disk name %s\n", diskname);
446 goto getdiskname;
447 }
448 fulldiskname[++i] = partition; fulldiskname[++i] = ':';
449
450 /*
451 * We always open for writing.
452 */
453 if ((*fdp = open(fulldiskname, 1)) < 0) {
454 printf("cannot open %s\n", diskname);
455 return (1);
456 }
457
458 return (0);
459 }
460
461 /*
462 * Copy a miniroot image from an NFS server or tape to the `b' partition
463 * of the specified disk. Note, this assumes 512 byte sectors.
464 */
465 void
466 miniroot()
467 {
468 int sfd, dfd, i, nblks;
469 char diskname[64], minirootname[128];
470 char block[DEV_BSIZE];
471 char tapename[64];
472 int fileno, ignoreshread, eof, len;
473 struct stat st;
474 size_t xfersize;
475 struct open_file *disk_ofp;
476 extern struct open_file files[];
477
478 /* Error message printed by opendisk() */
479 if (opendisk("Disk for miniroot?", diskname, sizeof(diskname),
480 'b', &dfd))
481 return;
482
483 disk_ofp = &files[dfd];
484
485 getsource:
486 printf("Source? (N)FS, (t)ape, (d)one > ");
487 bzero(line, sizeof(line));
488 gets(line);
489 if (line[0] == '\0')
490 goto getsource;
491
492 switch (line[0]) {
493 case 'n':
494 case 'N':
495 name_of_nfs_miniroot:
496 printf("Name of miniroot file? ");
497 bzero(line, sizeof(line));
498 bzero(minirootname, sizeof(minirootname));
499 gets(line);
500 if (line[0] == '\0')
501 goto name_of_nfs_miniroot;
502 (void)strcat(minirootname, "le0a:");
503 (void)strcat(minirootname, line);
504 if ((sfd = open(minirootname, 0)) < 0) {
505 printf("can't open %s\n", line);
506 return;
507 }
508
509 /*
510 * Find out how big the miniroot is... we can't
511 * check for size because it may be compressed.
512 */
513 ignoreshread = 1;
514 if (fstat(sfd, &st) < 0) {
515 printf("can't stat %s\n", line);
516 goto done;
517 }
518 nblks = (int)(st.st_size / sizeof(block));
519
520 printf("Copying miniroot from %s to %s...", line,
521 diskname);
522 break;
523
524 case 't':
525 case 'T':
526 name_of_tape_miniroot:
527 printf("Which tape device? ");
528 bzero(line, sizeof(line));
529 bzero(minirootname, sizeof(minirootname));
530 bzero(tapename, sizeof(tapename));
531 gets(line);
532 if (line[0] == '\0')
533 goto name_of_tape_miniroot;
534 strcat(minirootname, line);
535 strcat(tapename, line);
536
537 printf("File number (first == 1)? ");
538 bzero(line, sizeof(line));
539 gets(line);
540 fileno = a2int(line);
541 if (fileno < 1 || fileno > 8) {
542 printf("Invalid file number: %s\n", line);
543 goto getsource;
544 }
545 for (i = 0; i < sizeof(minirootname); ++i) {
546 if (minirootname[i] == '\0')
547 break;
548 }
549 if (i == sizeof(minirootname) ||
550 (sizeof(minirootname) - i) < 8) {
551 printf("Invalid device name: %s\n", tapename);
552 goto getsource;
553 }
554 minirootname[i++] = 'a' + (fileno - 1);
555 minirootname[i++] = ':';
556 strcat(minirootname, "XXX"); /* lameness in open() */
557
558 ignoreshread = 0;
559 printf("Copy how many %d byte blocks? ", DEV_BSIZE);
560 bzero(line, sizeof(line));
561 gets(line);
562 nblks = a2int(line);
563 if (nblks < 0) {
564 printf("Invalid block count: %s\n", line);
565 goto getsource;
566 } else if (nblks == 0) {
567 printf("Zero blocks? Ok, aborting.\n");
568 return;
569 }
570
571 if ((sfd = open(minirootname, 0)) < 0) {
572 printf("can't open %s file %c\n", tapename, fileno);
573 return;
574 }
575
576 printf("Copying %s file %d to %s...", tapename, fileno,
577 diskname);
578 break;
579
580 case 'd':
581 case 'D':
582 return;
583
584 default:
585 printf("Unknown source: %s\n", line);
586 goto getsource;
587 }
588
589 /*
590 * Copy loop...
591 * This is fairly slow... if someone wants to speed it
592 * up, they'll get no complaints from me.
593 */
594 for (i = 0, eof = 0; i < nblks || ignoreshread == 0; i++) {
595 if ((len = read(sfd, block, sizeof(block))) < 0) {
596 printf("Read error, errno = %d\n", errno);
597 goto out;
598 }
599
600 /*
601 * Check for end-of-file.
602 */
603 if (len == 0)
604 goto done;
605 else if (len < sizeof(block))
606 eof = 1;
607
608 if ((*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata,
609 F_WRITE, i, len, block, &xfersize) || xfersize != len) {
610 printf("Bad write at block %d, errno = %d\n",
611 i, errno);
612 goto out;
613 }
614
615 if (eof)
616 goto done;
617 }
618 done:
619 printf("done\n");
620
621 printf("Successfully copied miniroot image.\n");
622
623 out:
624 close(sfd);
625 close(dfd);
626 }
627
628 /*
629 * Boot the kernel from the miniroot image into single-user.
630 */
631 void
632 bootmini()
633 {
634 char diskname[64], bootname[64];
635 int i;
636
637 getdiskname:
638 printf("Disk to boot from? ");
639 bzero(diskname, sizeof(diskname));
640 bzero(bootname, sizeof(bootname));
641 gets(diskname);
642 if (diskname[0] == '\n' || diskname[0] == '\0')
643 goto getdiskname;
644
645 /*
646 * devopen() is picky. Make sure it gets the sort of string it
647 * wants.
648 */
649 (void)strcat(bootname, diskname);
650 for (i = 0; bootname[i + 1] != '\0'; ++i)
651 /* Nothing. */ ;
652 if (bootname[i] < '0' || bootname[i] > '9') {
653 printf("invalid disk name %s\n", diskname);
654 goto getdiskname;
655 }
656 bootname[++i] = 'b'; bootname[++i] = ':';
657 (void)strcat(bootname, kernel_name);
658
659 howto = RB_SINGLE; /* _Always_ */
660
661 printf("booting: %s -s\n", bootname);
662 exec(bootname, lowram, howto);
663 printf("boot: %s\n", strerror(errno));
664 }
665
666 /*
667 * Reset the system.
668 */
669 void
670 resetsys()
671 {
672
673 call_req_reboot();
674 printf("panic: can't reboot, halting\n");
675 asm("stop #0x2700");
676 }
677
678 /*
679 * XXX Should have a generic atoi for libkern/libsa.
680 */
681 int
682 a2int(cp)
683 char *cp;
684 {
685 int i = 0;
686
687 if (*cp == '\0')
688 return (-1);
689
690 while (*cp != '\0')
691 i = i * 10 + *cp++ - '0';
692 return (i);
693 }
694