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