inst.c revision 1.1 1 /* $NetBSD: inst.c,v 1.1 1997/02/04 03:52:57 thorpej Exp $ */
2
3 /*
4 * Copyright (c) 1995, 1996 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;
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. Make sure it's
493 * an even number of blocks...
494 */
495 if (fstat(sfd, &st) < 0) {
496 printf("can't stat %s\n", line);
497 goto done;
498 }
499 if (st.st_size % DEV_BSIZE) {
500 printf("Miniroot size must be an even multiple of %d\n",
501 DEV_BSIZE);
502 return;
503 }
504 nblks = (int)(st.st_size / sizeof(block));
505
506 printf("Copying %d blocks from %s to %s...", nblks, line,
507 diskname);
508 break;
509
510 case 't':
511 case 'T':
512 name_of_tape_miniroot:
513 printf("Which tape device? ");
514 bzero(line, sizeof(line));
515 bzero(minirootname, sizeof(minirootname));
516 bzero(tapename, sizeof(tapename));
517 gets(line);
518 if (line[0] == '\0')
519 goto name_of_tape_miniroot;
520 strcat(minirootname, line);
521 strcat(tapename, line);
522
523 printf("File number (first == 1)? ");
524 bzero(line, sizeof(line));
525 gets(line);
526 fileno = a2int(line);
527 if (fileno < 1 || fileno > 8) {
528 printf("Invalid file number: %s\n", line);
529 goto getsource;
530 }
531 for (i = 0; i < sizeof(minirootname); ++i) {
532 if (minirootname[i] == '\0')
533 break;
534 }
535 if (i == sizeof(minirootname) ||
536 (sizeof(minirootname) - i) < 8) {
537 printf("Invalid device name: %s\n", tapename);
538 goto getsource;
539 }
540 minirootname[i++] = 'a' + (fileno - 1);
541 minirootname[i++] = ':';
542 strcat(minirootname, "XXX"); /* lameness in open() */
543
544 printf("Copy how many %d byte blocks? ", DEV_BSIZE);
545 bzero(line, sizeof(line));
546 gets(line);
547 nblks = a2int(line);
548 if (nblks < 0) {
549 printf("Invalid block count: %s\n", line);
550 goto getsource;
551 } else if (nblks == 0) {
552 printf("Zero blocks? Ok, aborting.\n");
553 return;
554 }
555
556 if ((sfd = open(minirootname, 0)) < 0) {
557 printf("can't open %s file %c\n", tapename, fileno);
558 return;
559 }
560
561 printf("Copying %s file %c to %s...", tapename, fileno,
562 diskname);
563 break;
564
565 case 'd':
566 case 'D':
567 return;
568
569 default:
570 printf("Unknown source: %s\n", line);
571 goto getsource;
572 }
573
574 /*
575 * Copy loop...
576 * This is fairly slow... if someone wants to speed it
577 * up, they'll get no complaints from me.
578 */
579 for (i = 0; i < nblks; ++i) {
580 if (read(sfd, block, sizeof(block)) != sizeof(block)) {
581 printf("Short read, errno = %d\n", errno);
582 goto done;
583 }
584 if ((*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata,
585 F_WRITE, i, sizeof(block), block, &xfersize) ||
586 xfersize != sizeof(block)) {
587 printf("Bad write at block %d, errno = %d\n",
588 i, errno);
589 goto done;
590 }
591 }
592 printf("done\n");
593
594 printf("Successfully copied miniroot image.\n");
595
596 done:
597 close(sfd);
598 close(dfd);
599 }
600
601 /*
602 * Boot the kernel from the miniroot image into single-user.
603 */
604 void
605 bootmini()
606 {
607 char diskname[64], bootname[64];
608 int i;
609
610 getdiskname:
611 printf("Disk to boot from? ");
612 bzero(diskname, sizeof(diskname));
613 bzero(bootname, sizeof(bootname));
614 gets(diskname);
615 if (diskname[0] == '\n' || diskname[0] == '\0')
616 goto getdiskname;
617
618 /*
619 * devopen() is picky. Make sure it gets the sort of string it
620 * wants.
621 */
622 (void)strcat(bootname, diskname);
623 for (i = 0; bootname[i + 1] != '\0'; ++i)
624 /* Nothing. */ ;
625 if (bootname[i] < '0' || bootname[i] > '9') {
626 printf("invalid disk name %s\n", diskname);
627 goto getdiskname;
628 }
629 bootname[++i] = 'b'; bootname[++i] = ':';
630 (void)strcat(bootname, kernel_name);
631
632 howto = RB_SINGLE; /* _Always_ */
633
634 printf("booting: %s -s\n", bootname);
635 exec(bootname, lowram, howto);
636 printf("boot: %s\n", strerror(errno));
637 }
638
639 /*
640 * Reset the system.
641 */
642 void
643 resetsys()
644 {
645
646 call_req_reboot();
647 printf("panic: can't reboot, halting\n");
648 asm("stop #0x2700");
649 }
650
651 /*
652 * XXX Should have a generic atoi for libkern/libsa.
653 */
654 int
655 a2int(cp)
656 char *cp;
657 {
658 int i = 0;
659
660 if (*cp == '\0')
661 return (-1);
662
663 while (*cp != '\0')
664 i = i * 10 + *cp++ - '0';
665 return (i);
666 }
667