inst.c revision 1.5 1 /* $NetBSD: inst.c,v 1.5 1997/12/15 23:17:19 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 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 GETNUM("Sectors/cylinder? [%d] ", lp->d_secpercyl);
425 GETNUM("Cylinders? [%d] ", lp->d_ncylinders);
426
427 printf("
428 Enter partition table. Note, sizes and offsets are in sectors.\n\n");
429
430 lp->d_npartitions = MAXPARTITIONS;
431 for (i = 0; i < lp->d_npartitions; ++i) {
432 GETNUM2("%c partition: offset? [%d] ", ('a' + i),
433 lp->d_partitions[i].p_offset);
434 GETNUM(" size? [%d] ", lp->d_partitions[i].p_size);
435 get_fstype(lp, i);
436 }
437
438 /* Perform magic. */
439 lp->d_magic = lp->d_magic2 = DISKMAGIC;
440
441 /* Calculate disklabel checksum. */
442 lp->d_checksum = 0;
443 lp->d_checksum = dkcksum(lp);
444 }
445
446 void
447 disklabel_show(lp)
448 struct disklabel *lp;
449 {
450 int i, npart;
451 struct partition *pp;
452
453 /*
454 * Check for valid disklabel.
455 */
456 if (lp->d_magic != DISKMAGIC || lp->d_magic2 != DISKMAGIC) {
457 printf("No disklabel to show.\n");
458 return;
459 }
460
461 if (lp->d_npartitions > MAXPARTITIONS || dkcksum(lp) != 0) {
462 printf("Corrupted disklabel.\n");
463 return;
464 }
465
466 printf("\ndisk type %d (%s), %s: %s%s%s\n", lp->d_type,
467 lp->d_type < DKMAXTYPES ? dktypenames[lp->d_type] :
468 dktypenames[0], lp->d_typename,
469 (lp->d_flags & D_REMOVABLE) ? " removable" : "",
470 (lp->d_flags & D_ECC) ? " ecc" : "",
471 (lp->d_flags & D_BADSECT) ? " badsect" : "");
472
473 printf("interleave %d, rpm %d, trackskew %d, cylinderskew %d\n",
474 lp->d_interleave, lp->d_rpm, lp->d_trackskew, lp->d_cylskew);
475
476 printf("headswitch %d, track-to-track %d, drivedata: %d %d %d %d %d\n",
477 lp->d_headswitch, lp->d_trkseek, lp->d_drivedata[0],
478 lp->d_drivedata[1], lp->d_drivedata[2], lp->d_drivedata[3],
479 lp->d_drivedata[4]);
480
481 printf("\nbytes/sector: %d\n", lp->d_secsize);
482 printf("sectors/track: %d\n", lp->d_nsectors);
483 printf("tracks/cylinder: %d\n", lp->d_ntracks);
484 printf("sectors/cylinder: %d\n", lp->d_secpercyl);
485 printf("cylinders: %d\n", lp->d_ncylinders);
486
487 printf("\n%d partitions:\n", lp->d_npartitions);
488 printf(" size offset\n");
489 pp = lp->d_partitions;
490 for (i = 0; i < lp->d_npartitions; i++) {
491 printf("%c: %d, %d\n", 97 + i, lp->d_partitions[i].p_size,
492 lp->d_partitions[i].p_offset);
493 }
494 printf("\n");
495 }
496
497 int
498 disklabel_write(block, len, ofp)
499 char *block;
500 int len;
501 struct open_file *ofp;
502 {
503 int error = 0;
504 size_t xfersize;
505
506 if (error = (*ofp->f_dev->dv_strategy)(ofp->f_devdata, F_WRITE,
507 LABELSECTOR, len, block, &xfersize))
508 printf("cannot write disklabel, errno = %d\n", error);
509
510 return (error);
511 }
512
513 int
514 opendisk(question, diskname, len, partition, fdp)
515 char *question, *diskname;
516 int len;
517 char partition;
518 int *fdp;
519 {
520 char fulldiskname[64], *filename;
521 int i, error = 0;
522
523 getdiskname:
524 printf("%s ", question);
525 bzero(diskname, len);
526 bzero(fulldiskname, sizeof(fulldiskname));
527 gets(diskname);
528 if (diskname[0] == '\n' || diskname[0] == '\0')
529 goto getdiskname;
530
531 /*
532 * devopen() is picky. Make sure it gets the sort of string it
533 * wants.
534 */
535 bcopy(diskname, fulldiskname,
536 len < sizeof(fulldiskname) ? len : sizeof(fulldiskname));
537 for (i = 0; fulldiskname[i + 1] != '\0'; ++i)
538 /* Nothing. */ ;
539 if (fulldiskname[i] < '0' || fulldiskname[i] > '9') {
540 printf("invalid disk name %s\n", diskname);
541 goto getdiskname;
542 }
543 fulldiskname[++i] = partition; fulldiskname[++i] = ':';
544
545 /*
546 * We always open for writing.
547 */
548 if ((*fdp = open(fulldiskname, 1)) < 0) {
549 printf("cannot open %s\n", diskname);
550 return (1);
551 }
552
553 return (0);
554 }
555
556 /*
557 * Copy a miniroot image from an NFS server or tape to the `b' partition
558 * of the specified disk. Note, this assumes 512 byte sectors.
559 */
560 void
561 miniroot()
562 {
563 int sfd, dfd, i, nblks;
564 char diskname[64], minirootname[128];
565 char block[DEV_BSIZE];
566 char tapename[64];
567 int fileno, ignoreshread, eof, len;
568 struct stat st;
569 size_t xfersize;
570 struct open_file *disk_ofp;
571 extern struct open_file files[];
572
573 /* Error message printed by opendisk() */
574 if (opendisk("Disk for miniroot?", diskname, sizeof(diskname),
575 'b', &dfd))
576 return;
577
578 disk_ofp = &files[dfd];
579
580 getsource:
581 printf("Source? (N)FS, (t)ape, (d)one > ");
582 bzero(line, sizeof(line));
583 gets(line);
584 if (line[0] == '\0')
585 goto getsource;
586
587 switch (line[0]) {
588 case 'n':
589 case 'N':
590 name_of_nfs_miniroot:
591 printf("Name of miniroot file? ");
592 bzero(line, sizeof(line));
593 bzero(minirootname, sizeof(minirootname));
594 gets(line);
595 if (line[0] == '\0')
596 goto name_of_nfs_miniroot;
597 (void)strcat(minirootname, "le0a:");
598 (void)strcat(minirootname, line);
599 if ((sfd = open(minirootname, 0)) < 0) {
600 printf("can't open %s\n", line);
601 return;
602 }
603
604 /*
605 * Find out how big the miniroot is... we can't
606 * check for size because it may be compressed.
607 */
608 ignoreshread = 1;
609 if (fstat(sfd, &st) < 0) {
610 printf("can't stat %s\n", line);
611 goto done;
612 }
613 nblks = (int)(st.st_size / sizeof(block));
614
615 printf("Copying miniroot from %s to %s...", line,
616 diskname);
617 break;
618
619 case 't':
620 case 'T':
621 name_of_tape_miniroot:
622 printf("Which tape device? ");
623 bzero(line, sizeof(line));
624 bzero(minirootname, sizeof(minirootname));
625 bzero(tapename, sizeof(tapename));
626 gets(line);
627 if (line[0] == '\0')
628 goto name_of_tape_miniroot;
629 strcat(minirootname, line);
630 strcat(tapename, line);
631
632 printf("File number (first == 1)? ");
633 bzero(line, sizeof(line));
634 gets(line);
635 fileno = a2int(line);
636 if (fileno < 1 || fileno > 8) {
637 printf("Invalid file number: %s\n", line);
638 goto getsource;
639 }
640 for (i = 0; i < sizeof(minirootname); ++i) {
641 if (minirootname[i] == '\0')
642 break;
643 }
644 if (i == sizeof(minirootname) ||
645 (sizeof(minirootname) - i) < 8) {
646 printf("Invalid device name: %s\n", tapename);
647 goto getsource;
648 }
649 minirootname[i++] = 'a' + (fileno - 1);
650 minirootname[i++] = ':';
651 strcat(minirootname, "XXX"); /* lameness in open() */
652
653 ignoreshread = 0;
654 printf("Copy how many %d byte blocks? ", DEV_BSIZE);
655 bzero(line, sizeof(line));
656 gets(line);
657 nblks = a2int(line);
658 if (nblks < 0) {
659 printf("Invalid block count: %s\n", line);
660 goto getsource;
661 } else if (nblks == 0) {
662 printf("Zero blocks? Ok, aborting.\n");
663 return;
664 }
665
666 if ((sfd = open(minirootname, 0)) < 0) {
667 printf("can't open %s file %c\n", tapename, fileno);
668 return;
669 }
670
671 printf("Copying %s file %d to %s...", tapename, fileno,
672 diskname);
673 break;
674
675 case 'd':
676 case 'D':
677 return;
678
679 default:
680 printf("Unknown source: %s\n", line);
681 goto getsource;
682 }
683
684 /*
685 * Copy loop...
686 * This is fairly slow... if someone wants to speed it
687 * up, they'll get no complaints from me.
688 */
689 for (i = 0, eof = 0; i < nblks || ignoreshread == 0; i++) {
690 if ((len = read(sfd, block, sizeof(block))) < 0) {
691 printf("Read error, errno = %d\n", errno);
692 goto out;
693 }
694
695 /*
696 * Check for end-of-file.
697 */
698 if (len == 0)
699 goto done;
700 else if (len < sizeof(block))
701 eof = 1;
702
703 if ((*disk_ofp->f_dev->dv_strategy)(disk_ofp->f_devdata,
704 F_WRITE, i, len, block, &xfersize) || xfersize != len) {
705 printf("Bad write at block %d, errno = %d\n",
706 i, errno);
707 goto out;
708 }
709
710 if (eof)
711 goto done;
712 }
713 done:
714 printf("done\n");
715
716 printf("Successfully copied miniroot image.\n");
717
718 out:
719 close(sfd);
720 close(dfd);
721 }
722
723 /*
724 * Boot the kernel from the miniroot image into single-user.
725 */
726 void
727 bootmini()
728 {
729 char diskname[64], bootname[64];
730 int i;
731
732 getdiskname:
733 printf("Disk to boot from? ");
734 bzero(diskname, sizeof(diskname));
735 bzero(bootname, sizeof(bootname));
736 gets(diskname);
737 if (diskname[0] == '\n' || diskname[0] == '\0')
738 goto getdiskname;
739
740 /*
741 * devopen() is picky. Make sure it gets the sort of string it
742 * wants.
743 */
744 (void)strcat(bootname, diskname);
745 for (i = 0; bootname[i + 1] != '\0'; ++i)
746 /* Nothing. */ ;
747 if (bootname[i] < '0' || bootname[i] > '9') {
748 printf("invalid disk name %s\n", diskname);
749 goto getdiskname;
750 }
751 bootname[++i] = 'b'; bootname[++i] = ':';
752 (void)strcat(bootname, kernel_name);
753
754 howto = RB_SINGLE; /* _Always_ */
755
756 printf("booting: %s -s\n", bootname);
757 exec(bootname, lowram, howto);
758 printf("boot: %s\n", strerror(errno));
759 }
760
761 /*
762 * Reset the system.
763 */
764 void
765 resetsys()
766 {
767
768 call_req_reboot();
769 printf("panic: can't reboot, halting\n");
770 asm("stop #0x2700");
771 }
772
773 /*
774 * XXX Should have a generic atoi for libkern/libsa.
775 */
776 int
777 a2int(cp)
778 char *cp;
779 {
780 int i = 0;
781
782 if (*cp == '\0')
783 return (-1);
784
785 while (*cp != '\0')
786 i = i * 10 + *cp++ - '0';
787 return (i);
788 }
789