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