inst.c revision 1.2 1 /* $NetBSD: inst.c,v 1.2 1997/02/04 19:34:09 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1995, 1996, 1997 Jason R. Thorpe.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed for the NetBSD Project
18 * by Jason R. Thorpe.
19 * 4. The name of the author may not be used to endorse or promote products
20 * derived from this software without specific prior written permission.
21 *
22 * Portions of this program are inspired by (and have borrowed code from)
23 * the `editlabel' program that accompanies NetBSD/vax, which carries
24 * the following notice:
25 *
26 * Copyright (c) 1995 Ludd, University of Lule}, Sweden.
27 * All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed at Ludd, University of
40 * Lule}, Sweden and its contributors.
41 * 4. The name of the author may not be used to endorse or promote products
42 * derived from this software without specific prior written permission
43 *
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
45 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
46 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
47 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
48 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
49 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
50 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
51 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
52 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
55 */
56
57 #define DKTYPENAMES
58
59 #include <sys/param.h>
60 #include <sys/reboot.h>
61 #include <sys/disklabel.h>
62 #include <a.out.h>
63
64 #include <lib/libsa/stand.h>
65
66 #include <hp300/stand/common/samachdep.h>
67
68 char line[100];
69
70 extern u_int opendev;
71 extern char *lowram;
72 extern int noconsole;
73 extern int netio_ask;
74
75 char *kernel_name = "/netbsd";
76
77 void dsklabel __P((void));
78 void miniroot __P((void));
79 void bootmini __P((void));
80 void resetsys __P((void));
81 void gethelp __P((void));
82 int opendisk __P((char *, char *, int, char, int *));
83 void disklabel_edit __P((struct disklabel *));
84 void disklabel_show __P((struct disklabel *));
85 int disklabel_write __P((char *, int, struct open_file *));
86 int a2int __P((char *));
87
88 struct inst_command {
89 char *ic_cmd; /* command name */
90 char *ic_desc; /* command description */
91 void (*ic_func) __P((void)); /* handling function */
92 } inst_commands[] = {
93 { "disklabel", "place partition map on disk", dsklabel },
94 { "miniroot", "place miniroot on disk", miniroot },
95 { "boot", "boot from miniroot", bootmini },
96 { "reset", "reset the system", resetsys },
97 { "help", "display command list", gethelp },
98 };
99 #define NCMDS (sizeof(inst_commands) / sizeof(inst_commands[0]))
100
101 main()
102 {
103 int i, currname = 0;
104
105 /*
106 * We want netopen() to ask for IP address, etc, rather
107 * that using bootparams.
108 */
109 netio_ask = 1;
110
111 printf("\n");
112 printf(">> %s, Revision %s\n", bootprog_name, bootprog_rev);
113 printf(">> (%s, %s)\n", bootprog_maker, bootprog_date);
114 printf(">> HP 9000/%s CPU\n", getmachineid());
115 gethelp();
116
117 for (;;) {
118 printf("sys_inst> ");
119 bzero(line, sizeof(line));
120 gets(line);
121 if (line[0] == '\n' || line[0] == '\0')
122 continue;
123
124 for (i = 0; i < NCMDS; ++i)
125 if (strcmp(line, inst_commands[i].ic_cmd) == 0) {
126 (*inst_commands[i].ic_func)();
127 break;
128 }
129
130
131 if (i == NCMDS)
132 printf("unknown command: %s\n", line);
133 }
134 }
135
136 void
137 gethelp()
138 {
139 int i;
140
141 printf(">> Available commands:\n");
142 for (i = 0; i < NCMDS; ++i)
143 printf(">> %s - %s\n", inst_commands[i].ic_cmd,
144 inst_commands[i].ic_desc);
145 }
146
147 /*
148 * Do all the steps necessary to place a disklabel on a disk.
149 * Note, this assumes 512 byte sectors.
150 */
151 void
152 dsklabel()
153 {
154 struct disklabel *lp;
155 struct open_file *disk_ofp;
156 int dfd, error;
157 size_t xfersize;
158 char block[DEV_BSIZE], diskname[64];
159 extern struct open_file files[];
160
161 printf("
162 You will be asked several questions about your disk, most of which
163 require prior knowledge of the disk's geometry. There is no easy way
164 for the system to provide this information for you. If you do not have
165 this information, please consult your disk's manual or another
166 informative source.\n\n");
167
168 /* Error message printed by opendisk() */
169 if (opendisk("Disk to label?", diskname, sizeof(diskname),
170 ('a' + RAW_PART), &dfd))
171 return;
172
173 disk_ofp = &files[dfd];
174
175 bzero(block, sizeof(block));
176 if (error = (*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata,
177 F_READ, LABELSECTOR, sizeof(block), block, &xfersize)) {
178 printf("cannot read disk %s, errno = %d\n", diskname, error);
179 return;
180 }
181
182 printf("Sucessfully read %d bytes from %s\n", xfersize, diskname);
183
184 lp = (struct disklabel *)((void *)(&block[LABELOFFSET]));
185
186 disklabel_loop:
187 bzero(line, sizeof(line));
188 printf("(z)ap, (e)dit, (s)how, (w)rite, (d)one > ");
189 gets(line);
190 if (line[0] == '\n' || line[0] == '\0')
191 goto disklabel_loop;
192
193 switch (line[0]) {
194 case 'z':
195 case 'Z': {
196 char zap[DEV_BSIZE];
197 bzero(zap, sizeof(zap));
198 (void)(*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata,
199 F_WRITE, LABELSECTOR, sizeof(zap), zap, &xfersize);
200 }
201 goto out;
202 /* NOTREACHED */
203
204 case 'e':
205 case 'E':
206 disklabel_edit(lp);
207 break;
208
209 case 's':
210 case 'S':
211 disklabel_show(lp);
212 break;
213
214 case 'w':
215 case 'W':
216 /*
217 * Error message will be displayed by disklabel_write()
218 */
219 if (disklabel_write(block, sizeof(block), disk_ofp))
220 goto out;
221 else
222 printf("Sucessfully wrote label to %s\n", diskname);
223 break;
224
225 case 'd':
226 case 'D':
227 goto out;
228 /* NOTREACHED */
229
230 default:
231 printf("unkown command: %s\n", line);
232 }
233
234 goto disklabel_loop;
235 /* NOTREACHED */
236
237 out:
238 /*
239 * Close disk. Marks disk `not alive' so that partition
240 * information will be reloaded upon next open.
241 */
242 (void)close(dfd);
243 }
244
245 #define GETNUM(out, num) \
246 printf((out), (num)); \
247 bzero(line, sizeof(line)); \
248 gets(line); \
249 if (line[0]) \
250 (num) = atoi(line);
251
252 #define GETNUM2(out, num1, num2) \
253 printf((out), (num1), (num2)); \
254 bzero(line, sizeof(line)); \
255 gets(line); \
256 if (line[0]) \
257 (num2) = atoi(line);
258
259 #define GETSTR(out, str) \
260 printf((out), (str)); \
261 bzero(line, sizeof(line)); \
262 gets(line); \
263 if (line[0]) \
264 strcpy((str), line);
265
266 #define FLAGS(out, flag) \
267 printf((out), lp->d_flags & (flag) ? 'y' : 'n'); \
268 bzero(line, sizeof(line)); \
269 gets(line); \
270 if (line[0] == 'y' || line[0] == 'Y') \
271 lp->d_flags |= (flag); \
272 else \
273 lp->d_flags &= ~(flag);
274
275 void
276 disklabel_edit(lp)
277 struct disklabel *lp;
278 {
279 int i;
280
281 printf("Select disk type. Valid types:\n");
282 for (i = 0; i < DKMAXTYPES; i++)
283 printf("%d %s\n", i, dktypenames[i]);
284 printf("\n");
285
286 GETNUM("Disk type (number)? [%d] ", lp->d_type);
287 GETSTR("Disk model name? [%s] ", lp->d_typename);
288 GETSTR("Disk pack name? [%s] ", lp->d_packname);
289 FLAGS("Bad sectoring? [%c] ", D_BADSECT);
290 FLAGS("Ecc? [%c] ", D_ECC);
291 FLAGS("Removable? [%c] ", D_REMOVABLE);
292
293 printf("\n");
294
295 GETNUM("Interleave? [%d] ", lp->d_interleave);
296 GETNUM("Rpm? [%d] ", lp->d_rpm);
297 GETNUM("Trackskew? [%d] ", lp->d_trackskew);
298 GETNUM("Cylinderskew? [%d] ", lp->d_cylskew);
299 GETNUM("Headswitch? [%d] ", lp->d_headswitch);
300 GETNUM("Track-to-track? [%d] ", lp->d_trkseek);
301 GETNUM("Drivedata 0? [%d] ", lp->d_drivedata[0]);
302 GETNUM("Drivedata 1? [%d] ", lp->d_drivedata[1]);
303 GETNUM("Drivedata 2? [%d] ", lp->d_drivedata[2]);
304 GETNUM("Drivedata 3? [%d] ", lp->d_drivedata[3]);
305 GETNUM("Drivedata 4? [%d] ", lp->d_drivedata[4]);
306
307 printf("\n");
308
309 GETNUM("Bytes/sector? [%d] ", lp->d_secsize);
310 GETNUM("Sectors/track? [%d] ", lp->d_nsectors);
311 GETNUM("Tracks/cylinder? [%d] ", lp->d_ntracks);
312 GETNUM("Sectors/cylinder? [%d] ", lp->d_secpercyl);
313 GETNUM("Cylinders? [%d] ", lp->d_ncylinders);
314
315 printf("
316 Enter partition table. Note, sizes and offsets are in sectors.\n\n");
317
318 lp->d_npartitions = MAXPARTITIONS;
319 for (i = 0; i < lp->d_npartitions; ++i) {
320 GETNUM2("%c partition: offset? [%d] ", ('a' + i),
321 lp->d_partitions[i].p_offset);
322 GETNUM(" size? [%d] ", lp->d_partitions[i].p_size);
323 }
324
325 /* Perform magic. */
326 lp->d_magic = lp->d_magic2 = DISKMAGIC;
327
328 /* Calculate disklabel checksum. */
329 lp->d_checksum = 0;
330 lp->d_checksum = dkcksum(lp);
331 }
332
333 void
334 disklabel_show(lp)
335 struct disklabel *lp;
336 {
337 int i, npart;
338 struct partition *pp;
339
340 /*
341 * Check for valid disklabel.
342 */
343 if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC) {
344 printf("No disklabel to show.\n");
345 return;
346 }
347
348 if (lp->d_npartitions > MAXPARTITIONS || dkcksum(lp) != 0) {
349 printf("Corrupted disklabel.\n");
350 return;
351 }
352
353 printf("\ndisk type %d (%s), %s: %s%s%s\n", lp->d_type,
354 lp->d_type < DKMAXTYPES ? dktypenames[lp->d_type] :
355 dktypenames[0], lp->d_typename,
356 (lp->d_flags & D_REMOVABLE) ? " removable" : "",
357 (lp->d_flags & D_ECC) ? " ecc" : "",
358 (lp->d_flags & D_BADSECT) ? " badsect" : "");
359
360 printf("interleave %d, rpm %d, trackskew %d, cylinderskew %d\n",
361 lp->d_interleave, lp->d_rpm, lp->d_trackskew, lp->d_cylskew);
362
363 printf("headswitch %d, track-to-track %d, drivedata: %d %d %d %d %d\n",
364 lp->d_headswitch, lp->d_trkseek, lp->d_drivedata[0],
365 lp->d_drivedata[1], lp->d_drivedata[2], lp->d_drivedata[3],
366 lp->d_drivedata[4]);
367
368 printf("\nbytes/sector: %d\n", lp->d_secsize);
369 printf("sectors/track: %d\n", lp->d_nsectors);
370 printf("tracks/cylinder: %d\n", lp->d_ntracks);
371 printf("sectors/cylinder: %d\n", lp->d_secpercyl);
372 printf("cylinders: %d\n", lp->d_ncylinders);
373
374 printf("\n%d partitions:\n", lp->d_npartitions);
375 printf(" size offset\n");
376 pp = lp->d_partitions;
377 for (i = 0; i < lp->d_npartitions; i++) {
378 printf("%c: %d, %d\n", 97 + i, lp->d_partitions[i].p_size,
379 lp->d_partitions[i].p_offset);
380 }
381 printf("\n");
382 }
383
384 int
385 disklabel_write(block, len, ofp)
386 char *block;
387 int len;
388 struct open_file *ofp;
389 {
390 int error = 0;
391 size_t xfersize;
392
393 if (error = (*ofp->f_dev->dv_strategy)(ofp->f_devdata, F_WRITE,
394 LABELSECTOR, len, block, &xfersize))
395 printf("cannot write disklabel, errno = %d\n", error);
396
397 return (error);
398 }
399
400 int
401 opendisk(question, diskname, len, partition, fdp)
402 char *question, *diskname;
403 int len;
404 char partition;
405 int *fdp;
406 {
407 char fulldiskname[64], *filename;
408 int i, error = 0;
409
410 getdiskname:
411 printf("%s ", question);
412 bzero(diskname, len);
413 bzero(fulldiskname, sizeof(fulldiskname));
414 gets(diskname);
415 if (diskname[0] == '\n' || diskname[0] == '\0')
416 goto getdiskname;
417
418 /*
419 * devopen() is picky. Make sure it gets the sort of string it
420 * wants.
421 */
422 bcopy(diskname, fulldiskname,
423 len < sizeof(fulldiskname) ? len : sizeof(fulldiskname));
424 for (i = 0; fulldiskname[i + 1] != '\0'; ++i)
425 /* Nothing. */ ;
426 if (fulldiskname[i] < '0' || fulldiskname[i] > '9') {
427 printf("invalid disk name %s\n", diskname);
428 goto getdiskname;
429 }
430 fulldiskname[++i] = partition; fulldiskname[++i] = ':';
431
432 /*
433 * We always open for writing.
434 */
435 if ((*fdp = open(fulldiskname, 1)) < 0) {
436 printf("cannot open %s\n", diskname);
437 return (1);
438 }
439
440 return (0);
441 }
442
443 /*
444 * Copy a miniroot image from an NFS server or tape to the `b' partition
445 * of the specified disk. Note, this assumes 512 byte sectors.
446 */
447 void
448 miniroot()
449 {
450 int sfd, dfd, i, nblks;
451 char diskname[64], minirootname[128];
452 char block[DEV_BSIZE];
453 char tapename[64];
454 int fileno, ignoreshread, eof, len;
455 struct stat st;
456 size_t xfersize;
457 struct open_file *disk_ofp;
458 extern struct open_file files[];
459
460 /* Error message printed by opendisk() */
461 if (opendisk("Disk for miniroot?", diskname, sizeof(diskname),
462 'b', &dfd))
463 return;
464
465 disk_ofp = &files[dfd];
466
467 getsource:
468 printf("Source? (N)FS, (t)ape, (d)one > ");
469 bzero(line, sizeof(line));
470 gets(line);
471 if (line[0] == '\0')
472 goto getsource;
473
474 switch (line[0]) {
475 case 'n':
476 case 'N':
477 name_of_nfs_miniroot:
478 printf("Name of miniroot file? ");
479 bzero(line, sizeof(line));
480 bzero(minirootname, sizeof(minirootname));
481 gets(line);
482 if (line[0] == '\0')
483 goto name_of_nfs_miniroot;
484 (void)strcat(minirootname, "le0a:");
485 (void)strcat(minirootname, line);
486 if ((sfd = open(minirootname, 0)) < 0) {
487 printf("can't open %s\n", line);
488 return;
489 }
490
491 /*
492 * Find out how big the miniroot is... we can't
493 * check for size because it may be compressed.
494 */
495 ignoreshread = 1;
496 if (fstat(sfd, &st) < 0) {
497 printf("can't stat %s\n", line);
498 goto done;
499 }
500 nblks = (int)(st.st_size / sizeof(block));
501
502 printf("Copying miniroot from %s to %s...", line,
503 diskname);
504 break;
505
506 case 't':
507 case 'T':
508 name_of_tape_miniroot:
509 printf("Which tape device? ");
510 bzero(line, sizeof(line));
511 bzero(minirootname, sizeof(minirootname));
512 bzero(tapename, sizeof(tapename));
513 gets(line);
514 if (line[0] == '\0')
515 goto name_of_tape_miniroot;
516 strcat(minirootname, line);
517 strcat(tapename, line);
518
519 printf("File number (first == 1)? ");
520 bzero(line, sizeof(line));
521 gets(line);
522 fileno = a2int(line);
523 if (fileno < 1 || fileno > 8) {
524 printf("Invalid file number: %s\n", line);
525 goto getsource;
526 }
527 for (i = 0; i < sizeof(minirootname); ++i) {
528 if (minirootname[i] == '\0')
529 break;
530 }
531 if (i == sizeof(minirootname) ||
532 (sizeof(minirootname) - i) < 8) {
533 printf("Invalid device name: %s\n", tapename);
534 goto getsource;
535 }
536 minirootname[i++] = 'a' + (fileno - 1);
537 minirootname[i++] = ':';
538 strcat(minirootname, "XXX"); /* lameness in open() */
539
540 ignoreshread = 0;
541 printf("Copy how many %d byte blocks? ", DEV_BSIZE);
542 bzero(line, sizeof(line));
543 gets(line);
544 nblks = a2int(line);
545 if (nblks < 0) {
546 printf("Invalid block count: %s\n", line);
547 goto getsource;
548 } else if (nblks == 0) {
549 printf("Zero blocks? Ok, aborting.\n");
550 return;
551 }
552
553 if ((sfd = open(minirootname, 0)) < 0) {
554 printf("can't open %s file %c\n", tapename, fileno);
555 return;
556 }
557
558 printf("Copying %s file %d to %s...", tapename, fileno,
559 diskname);
560 break;
561
562 case 'd':
563 case 'D':
564 return;
565
566 default:
567 printf("Unknown source: %s\n", line);
568 goto getsource;
569 }
570
571 /*
572 * Copy loop...
573 * This is fairly slow... if someone wants to speed it
574 * up, they'll get no complaints from me.
575 */
576 for (i = 0, eof = 0; i < nblks || ignoreshread == 0; i++) {
577 if ((len = read(sfd, block, sizeof(block))) < 0) {
578 printf("Read error, errno = %d\n", errno);
579 goto out;
580 }
581
582 /*
583 * Check for end-of-file.
584 */
585 if (len == 0)
586 goto done;
587 else if (len < sizeof(block))
588 eof = 1;
589
590 if ((*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata,
591 F_WRITE, i, len, block, &xfersize) || xfersize != len) {
592 printf("Bad write at block %d, errno = %d\n",
593 i, errno);
594 goto out;
595 }
596
597 if (eof)
598 goto done;
599 }
600 done:
601 printf("done\n");
602
603 printf("Successfully copied miniroot image.\n");
604
605 out:
606 close(sfd);
607 close(dfd);
608 }
609
610 /*
611 * Boot the kernel from the miniroot image into single-user.
612 */
613 void
614 bootmini()
615 {
616 char diskname[64], bootname[64];
617 int i;
618
619 getdiskname:
620 printf("Disk to boot from? ");
621 bzero(diskname, sizeof(diskname));
622 bzero(bootname, sizeof(bootname));
623 gets(diskname);
624 if (diskname[0] == '\n' || diskname[0] == '\0')
625 goto getdiskname;
626
627 /*
628 * devopen() is picky. Make sure it gets the sort of string it
629 * wants.
630 */
631 (void)strcat(bootname, diskname);
632 for (i = 0; bootname[i + 1] != '\0'; ++i)
633 /* Nothing. */ ;
634 if (bootname[i] < '0' || bootname[i] > '9') {
635 printf("invalid disk name %s\n", diskname);
636 goto getdiskname;
637 }
638 bootname[++i] = 'b'; bootname[++i] = ':';
639 (void)strcat(bootname, kernel_name);
640
641 howto = RB_SINGLE; /* _Always_ */
642
643 printf("booting: %s -s\n", bootname);
644 exec(bootname, lowram, howto);
645 printf("boot: %s\n", strerror(errno));
646 }
647
648 /*
649 * Reset the system.
650 */
651 void
652 resetsys()
653 {
654
655 call_req_reboot();
656 printf("panic: can't reboot, halting\n");
657 asm("stop #0x2700");
658 }
659
660 /*
661 * XXX Should have a generic atoi for libkern/libsa.
662 */
663 int
664 a2int(cp)
665 char *cp;
666 {
667 int i = 0;
668
669 if (*cp == '\0')
670 return (-1);
671
672 while (*cp != '\0')
673 i = i * 10 + *cp++ - '0';
674 return (i);
675 }
676