]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sbin/fdisk_pc98/fdisk.c
import ath hal
[FreeBSD/FreeBSD.git] / sbin / fdisk_pc98 / fdisk.c
1 /*
2  * Mach Operating System
3  * Copyright (c) 1992 Carnegie Mellon University
4  * All Rights Reserved.
5  *
6  * Permission to use, copy, modify and distribute this software and its
7  * documentation is hereby granted, provided that both the copyright
8  * notice and this permission notice appear in all copies of the
9  * software, derivative works or modified versions, and any portions
10  * thereof, and that both notices appear in supporting documentation.
11  *
12  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15  *
16  * Carnegie Mellon requests users of this software to return to
17  *
18  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
19  *  School of Computer Science
20  *  Carnegie Mellon University
21  *  Pittsburgh PA 15213-3890
22  *
23  * any improvements or extensions that they make and grant Carnegie Mellon
24  * the rights to redistribute these changes.
25  */
26
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29
30 #include <sys/disk.h>
31 #include <sys/disklabel.h>
32 #include <sys/diskpc98.h>
33 #include <sys/param.h>
34 #include <sys/stat.h>
35 #include <sys/mount.h>
36 #include <ctype.h>
37 #include <fcntl.h>
38 #include <err.h>
39 #include <errno.h>
40 #include <libgeom.h>
41 #include <paths.h>
42 #include <regex.h>
43 #include <stdint.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48
49 int iotest;
50
51 #define LBUF 100
52 static char lbuf[LBUF];
53
54 /*
55  *
56  * Ported to 386bsd by Julian Elischer  Thu Oct 15 20:26:46 PDT 1992
57  *
58  * 14-Dec-89  Robert Baron (rvb) at Carnegie-Mellon University
59  *      Copyright (c) 1989      Robert. V. Baron
60  *      Created.
61  */
62
63 #define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp
64 #define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); }
65
66 #define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs)
67
68 #define MAX_SEC_SIZE 2048       /* maximum section size that is supported */
69 #define MIN_SEC_SIZE 512        /* the sector size to start sensing at */
70 static int secsize = 0;         /* the sensed sector size */
71
72 static char *disk;
73
74 static int cyls, sectors, heads, cylsecs, disksecs;
75
76 struct mboot {
77         unsigned char padding[2]; /* force the longs to be long aligned */
78         unsigned char bootinst[510];
79         unsigned short int      signature;
80         struct  pc98_partition parts[8];
81         unsigned char large_sector_overflow[MAX_SEC_SIZE-MIN_SEC_SIZE];
82 };
83
84 static struct mboot mboot;
85 static int fd;
86
87 #define ACTIVE 0x80
88
89 static uint dos_cyls;
90 static uint dos_heads;
91 static uint dos_sectors;
92 static uint dos_cylsecs;
93
94 #define MAX_ARGS        10
95
96 typedef struct cmd {
97     char                cmd;
98     int                 n_args;
99     struct arg {
100         char    argtype;
101         int     arg_val;
102     }                   args[MAX_ARGS];
103 } CMD;
104
105 static int B_flag  = 0;         /* replace boot code */
106 static int I_flag  = 0;         /* Inizialize disk to defaults */
107 static int a_flag  = 0;         /* set active partition */
108 static int i_flag  = 0;         /* replace partition data */
109 static int u_flag  = 0;         /* update partition data */
110 static int s_flag  = 0;         /* Print a summary and exit */
111 static int t_flag  = 0;         /* test only */
112 static char *f_flag = NULL;     /* Read config info from file */
113 static int v_flag  = 0;         /* Be verbose */
114
115 static struct part_type
116 {
117         unsigned char type;
118         const char *name;
119 } part_types[] = {
120          {0x00, "unused"}
121         ,{0x01, "Primary DOS with 12 bit FAT"}
122         ,{0x11, "MSDOS"}
123         ,{0x20, "MSDOS"}
124         ,{0x21, "MSDOS"}
125         ,{0x22, "MSDOS"}
126         ,{0x23, "MSDOS"}
127         ,{0x02, "XENIX / file system"}  
128         ,{0x03, "XENIX /usr file system"}  
129         ,{0x04, "PC-UX"}   
130         ,{0x05, "Extended DOS"}   
131         ,{0x06, "Primary 'big' DOS (> 32MB)"}   
132         ,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"}  
133         ,{0x08, "AIX file system"}   
134         ,{0x09, "AIX boot partition or Coherent"}  
135         ,{0x0A, "OS/2 Boot Manager or OPUS"}  
136         ,{0x10, "OPUS"} 
137         ,{0x14, "FreeBSD/NetBSD/386BSD"}  
138         ,{0x94, "FreeBSD/NetBSD/386BSD"}
139         ,{0x40, "VENIX 286"}  
140         ,{0x50, "DM"}   
141         ,{0x51, "DM"}   
142         ,{0x52, "CP/M or Microport SysV/AT"}
143         ,{0x56, "GB"}
144         ,{0x61, "Speed"}
145         ,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"}
146         ,{0x64, "Novell Netware 2.xx"}
147         ,{0x65, "Novell Netware 3.xx"}
148         ,{0x75, "PCIX"}
149         ,{0x40, "Minix"} 
150 };
151
152 static void print_s0(int which);
153 static void print_part(int i);
154 static void init_sector0(unsigned long start);
155 static void init_boot(void);
156 static void change_part(int i, int force);
157 static void print_params(void);
158 static void change_active(int which);
159 static void change_code(void);
160 static void get_params_to_use(void);
161 static char *get_rootdisk(void);
162 static void dos(u_int32_t start, u_int32_t size, struct pc98_partition *partp);
163 static int open_disk(int flag);
164 static ssize_t read_disk(off_t sector, void *buf);
165 static int write_disk(off_t sector, void *buf);
166 static int get_params(void);
167 static int read_s0(void);
168 static int write_s0(void);
169 static int ok(const char *str);
170 static int decimal(const char *str, int *num, int deflt);
171 static const char *get_type(int type);
172 static void usage(void);
173 static int string(const char *str, char **ans);
174 static void reset_boot(void);
175
176 int
177 main(int argc, char *argv[])
178 {
179         struct  stat sb;
180         int     c, i;
181         int     partition = -1;
182         struct  pc98_partition *partp;
183
184         while ((c = getopt(argc, argv, "BIa:f:istuv12345678")) != -1)
185                 switch (c) {
186                 case 'B':
187                         B_flag = 1;
188                         break;
189                 case 'I':
190                         I_flag = 1;
191                         break;
192                 case 'a':
193                         a_flag = 1;
194                         break;
195                 case 'f':
196                         f_flag = optarg;
197                         break;
198                 case 'i':
199                         i_flag = 1;
200                         break;
201                 case 's':
202                         s_flag = 1;
203                         break;
204                 case 't':
205                         t_flag = 1;
206                         break;
207                 case 'u':
208                         u_flag = 1;
209                         break;
210                 case 'v':
211                         v_flag = 1;
212                         break;
213                 case '1':
214                 case '2':
215                 case '3':
216                 case '4':
217                 case '5':
218                 case '6':
219                 case '7':
220                 case '8':
221                         partition = c - '0';
222                         break;
223                 default:
224                         usage();
225                 }
226         if (f_flag || i_flag)
227                 u_flag = 1;
228         if (t_flag)
229                 v_flag = 1;
230         argc -= optind;
231         argv += optind;
232
233         if (argc == 0) {
234                 disk = get_rootdisk();
235         } else {
236                 if (stat(argv[0], &sb) == 0) {
237                         /* OK, full pathname given */
238                         disk = argv[0];
239                 } else if (errno == ENOENT && argv[0][0] != '/') {
240                         /* Try prepending "/dev" */
241                         asprintf(&disk, "%s%s", _PATH_DEV, argv[0]);
242                         if (disk == NULL)
243                                 errx(1, "out of memory");
244                 } else {
245                         /* other stat error, let it fail below */
246                         disk = argv[0];
247                 }
248         }
249         if (open_disk(u_flag) < 0)
250                 err(1, "cannot open disk %s", disk);
251
252         if (s_flag) {
253                 if (read_s0())
254                         err(1, "read_s0");
255                 printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads,
256                     dos_sectors);
257                 printf("Part  %11s %11s %4s %4s %-16s\n", "Start", "Size", "MID",
258                     "SID", "Name");
259                 for (i = 0; i < NDOSPART; i++) {
260                         partp = ((struct pc98_partition *) &mboot.parts) + i;
261                         if (partp->dp_sid == 0)
262                                 continue;
263                         printf("%4d: %11u %11u 0x%02x 0x%02x %-16.16s\n", i + 1,
264                             partp->dp_scyl * cylsecs,
265                             (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs,
266                             partp->dp_mid, partp->dp_sid, partp->dp_name);
267                 }
268                 exit(0);
269         }
270
271         printf("******* Working on device %s *******\n",disk);
272
273         if (I_flag) {
274                 read_s0();
275                 reset_boot();
276                 partp = (struct pc98_partition *) (&mboot.parts[0]);
277                 partp->dp_mid = DOSMID_386BSD;
278                 partp->dp_sid = DOSSID_386BSD;
279                 strncpy(partp->dp_name, "FreeBSD", sizeof(partp->dp_name));
280                 /* Start c/h/s. */
281                 partp->dp_scyl = partp->dp_ipl_cyl = 1;
282                 partp->dp_shd = partp->dp_ipl_head = 1;
283                 partp->dp_ssect = partp->dp_ipl_sct = 0;
284
285                 /* End c/h/s. */
286                 partp->dp_ecyl = dos_cyls - 1;
287                 partp->dp_ehd = dos_cylsecs / dos_sectors;
288                 partp->dp_esect = dos_sectors;
289
290                 if (v_flag)
291                         print_s0(-1);
292                 if (!t_flag)
293                         write_s0();
294                 exit(0);
295         }
296
297         if (f_flag) {
298             if (v_flag)
299                 print_s0(-1);
300             if (!t_flag)
301                 write_s0();
302         } else {
303             if(u_flag)
304                 get_params_to_use();
305             else
306                 print_params();
307
308             if (read_s0())
309                 init_sector0(dos_sectors);
310
311             printf("Media sector size is %d\n", secsize);
312             printf("Warning: BIOS sector numbering starts with sector 1\n");
313             printf("Information from DOS bootblock is:\n");
314             if (partition == -1)
315                 for (i = 1; i <= NDOSPART; i++)
316                     change_part(i, v_flag);
317             else
318                 change_part(partition, 1);
319
320             if (u_flag || a_flag)
321                 change_active(partition);
322
323             if (B_flag)
324                 change_code();
325
326             if (u_flag || a_flag || B_flag) {
327                 if (!t_flag) {
328                     printf("\nWe haven't changed the partition table yet.  ");
329                     printf("This is your last chance.\n");
330                 }
331                 print_s0(-1);
332                 if (!t_flag) {
333                     if (ok("Should we write new partition table?"))
334                         write_s0();
335                 } else {
336                     printf("\n-t flag specified -- partition table not written.\n");
337                 }
338             }
339         }
340
341         exit(0);
342 }
343
344 static void
345 usage()
346 {
347         fprintf(stderr, "%s%s",
348                 "usage: fdisk [-BIaistu] [-12345678] [disk]\n",
349                 "       fdisk -f configfile [-itv] [disk]\n");
350         exit(1);
351 }
352
353 static struct pc98_partition mtpart;
354
355 static int
356 part_unused(int i)
357 {
358         struct    pc98_partition *partp;
359
360         partp = ((struct pc98_partition *) &mboot.parts) + i - 1;
361         return (bcmp(partp, &mtpart, sizeof (struct pc98_partition)) == 0);
362 }
363
364 static void
365 print_s0(int which)
366 {
367         int     i;
368
369         print_params();
370         printf("Information from DOS bootblock is:\n");
371         if (which == -1) {
372                 for (i = 1; i <= NDOSPART; i++)
373                         if (v_flag || !part_unused(i)) {
374                                 printf("%d: ", i);
375                                 print_part(i);
376                         }
377         }
378         else
379                 print_part(which);
380 }
381
382 static void
383 print_part(int i)
384 {
385         struct    pc98_partition *partp;
386         u_int64_t part_sz, part_mb;
387
388         if (part_unused(i)) {
389                 printf("<UNUSED>\n");
390                 return;
391         }
392         /*
393          * Be careful not to overflow.
394          */
395         partp = ((struct pc98_partition *) &mboot.parts) + i - 1;
396         part_sz = (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs;
397         part_mb = part_sz * secsize;
398         part_mb /= (1024 * 1024);
399         printf("sysmid %d (%#04x),(%s)\n", partp->dp_mid, partp->dp_mid,
400             get_type(partp->dp_mid));
401         printf("    start %lu, size %lu (%ju Meg), sid %d\n",
402                 (u_long)(partp->dp_scyl * cylsecs), (u_long)part_sz,
403                 (uintmax_t)part_mb, partp->dp_sid);
404         printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n"
405                 ,partp->dp_scyl
406                 ,partp->dp_shd
407                 ,partp->dp_ssect
408                 ,partp->dp_ecyl
409                 ,partp->dp_ehd
410                 ,partp->dp_esect);
411         printf ("\tsystem Name %.16s\n", partp->dp_name);
412 }
413
414
415 static void
416 init_boot(void)
417 {
418
419         mboot.signature = DOSMAGIC;
420 }
421
422
423 static void
424 init_sector0(unsigned long start)
425 {
426         struct pc98_partition *partp =
427                 (struct pc98_partition *)(&mboot.parts[0]);
428
429         init_boot();
430
431         partp->dp_mid = DOSMID_386BSD;
432         partp->dp_sid = DOSSID_386BSD;
433
434         dos(start, disksecs - start, partp);
435 }
436
437 static void
438 change_part(int i, int force)
439 {
440         struct pc98_partition *partp =
441                 ((struct pc98_partition *) &mboot.parts) + i - 1;
442
443         if (!force && part_unused(i))
444                 return;
445
446         printf("The data for partition %d is:\n", i);
447         print_part(i);
448
449         if (u_flag && ok("Do you want to change it?")) {
450                 int tmp;
451
452                 if (i_flag) {
453                         bzero((char *)partp, sizeof (struct pc98_partition));
454                         if (i == 1) {
455                                 init_sector0(1);
456                                 printf("\nThe static data for the slice 1 has been reinitialized to:\n");
457                                 print_part(i);
458                         }
459                 }
460                 do {
461                         int x_start = partp->dp_scyl * cylsecs ;
462                         int x_size  = (partp->dp_ecyl - partp->dp_scyl + 1) * cylsecs;
463                         Decimal("sysmid", partp->dp_mid, tmp);
464                         Decimal("syssid", partp->dp_sid, tmp);
465                         String ("system name", partp->dp_name, 16);
466                         Decimal("start", x_start, tmp);
467                         Decimal("size", x_size, tmp);
468
469                         if (ok("Explicitly specify beg/end address ?"))
470                         {
471                                 int     tsec,tcyl,thd;
472                                 tcyl = partp->dp_scyl;
473                                 thd = partp->dp_shd;
474                                 tsec = partp->dp_ssect;
475                                 Decimal("beginning cylinder", tcyl, tmp);
476                                 Decimal("beginning head", thd, tmp);
477                                 Decimal("beginning sector", tsec, tmp);
478                                 partp->dp_scyl = tcyl;
479                                 partp->dp_ssect = tsec;
480                                 partp->dp_shd = thd;
481                                 partp->dp_ipl_cyl = partp->dp_scyl;
482                                 partp->dp_ipl_sct = partp->dp_ssect;
483                                 partp->dp_ipl_head = partp->dp_shd;
484
485                                 tcyl = partp->dp_ecyl;
486                                 thd = partp->dp_ehd;
487                                 tsec = partp->dp_esect;
488                                 Decimal("ending cylinder", tcyl, tmp);
489                                 Decimal("ending head", thd, tmp);
490                                 Decimal("ending sector", tsec, tmp);
491                                 partp->dp_ecyl = tcyl;
492                                 partp->dp_esect = tsec;
493                                 partp->dp_ehd = thd;
494                         } else
495                                 dos(x_start, x_size, partp);
496
497                         print_part(i);
498                 } while (!ok("Are we happy with this entry?"));
499         }
500 }
501
502 static void
503 print_params()
504 {
505         printf("parameters extracted from in-core disklabel are:\n");
506         printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
507                         ,cyls,heads,sectors,cylsecs);
508         if (dos_cyls > 65535 || dos_heads > 255 || dos_sectors > 255)
509                 printf("Figures below won't work with BIOS for partitions not in cyl 1\n");
510         printf("parameters to be used for BIOS calculations are:\n");
511         printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n"
512                 ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs);
513 }
514
515 static void
516 change_active(int which)
517 {
518         struct pc98_partition *partp = &mboot.parts[0];
519         int active, i, new, tmp;
520
521         active = -1;
522         for (i = 0; i < NDOSPART; i++) {
523                 if ((partp[i].dp_sid & ACTIVE) == 0)
524                         continue;
525                 printf("Partition %d is marked active\n", i + 1);
526                 if (active == -1)
527                         active = i + 1;
528         }
529         if (a_flag && which != -1)
530                 active = which;
531         else if (active == -1)
532                 active = 1;
533
534         if (!ok("Do you want to change the active partition?"))
535                 return;
536 setactive:
537         do {
538                 new = active;
539                 Decimal("active partition", new, tmp);
540                 if (new < 1 || new > 8) {
541                         printf("Active partition number must be in range 1-8."
542                                         "  Try again.\n");
543                         goto setactive;
544                 }
545                 active = new;
546         } while (!ok("Are you happy with this choice"));
547         if (active > 0 && active <= 8)
548                 partp[active-1].dp_sid |= ACTIVE;
549 }
550
551 static void
552 change_code()
553 {
554         if (ok("Do you want to change the boot code?"))
555                 init_boot();
556 }
557
558 void
559 get_params_to_use()
560 {
561         int     tmp;
562         print_params();
563         if (ok("Do you want to change our idea of what BIOS thinks ?"))
564         {
565                 do
566                 {
567                         Decimal("BIOS's idea of #cylinders", dos_cyls, tmp);
568                         Decimal("BIOS's idea of #heads", dos_heads, tmp);
569                         Decimal("BIOS's idea of #sectors", dos_sectors, tmp);
570                         dos_cylsecs = dos_heads * dos_sectors;
571                         print_params();
572                 }
573                 while(!ok("Are you happy with this choice"));
574         }
575 }
576
577
578 /***********************************************\
579 * Change real numbers into strange dos numbers  *
580 \***********************************************/
581 static void
582 dos(u_int32_t start, u_int32_t size, struct pc98_partition *partp)
583 {
584         u_int32_t end;
585
586         if (partp->dp_mid == 0 && partp->dp_sid == 0 &&
587             start == 0 && size == 0) {
588                 memcpy(partp, &mtpart, sizeof(*partp));
589                 return;
590         }
591
592         /* Start c/h/s. */
593         partp->dp_scyl = partp->dp_ipl_cyl = start / dos_cylsecs;
594         partp->dp_shd = partp->dp_ipl_head = start % dos_cylsecs / dos_sectors;
595         partp->dp_ssect = partp->dp_ipl_sct = start % dos_sectors;
596
597         /* End c/h/s. */
598         end = start + size - cylsecs;
599         partp->dp_ecyl = end / dos_cylsecs;
600         partp->dp_ehd = end % dos_cylsecs / dos_sectors;
601         partp->dp_esect = end % dos_sectors;
602 }
603
604 static int
605 open_disk(int flag)
606 {
607         struct stat     st;
608         int rwmode;
609
610         if (stat(disk, &st) == -1) {
611                 if (errno == ENOENT)
612                         return -2;
613                 warnx("can't get file status of %s", disk);
614                 return -1;
615         }
616         if ( !(st.st_mode & S_IFCHR) )
617                 warnx("device %s is not character special", disk);
618         rwmode = I_flag || a_flag || B_flag || flag ? O_RDWR : O_RDONLY;
619         fd = open(disk, rwmode);
620         if (fd == -1 && errno == EPERM && rwmode == O_RDWR)
621                 fd = open(disk, O_RDONLY);
622         if (fd == -1 && errno == ENXIO)
623                 return -2;
624         if (fd == -1) {
625                 warnx("can't open device %s", disk);
626                 return -1;
627         }
628         if (get_params() == -1) {
629                 warnx("can't get disk parameters on %s", disk);
630                 return -1;
631         }
632         return fd;
633 }
634
635 static ssize_t
636 read_disk(off_t sector, void *buf)
637 {
638
639         lseek(fd, (sector * 512), 0);
640         return read(fd, buf,
641                     secsize > MIN_SEC_SIZE ? secsize : MIN_SEC_SIZE * 2);
642 }
643
644 static int
645 write_disk(off_t sector, void *buf)
646 {
647         int error;
648         struct gctl_req *grq;
649         const char *q;
650         char fbuf[BUFSIZ];
651         int i, fdw, sz;
652
653         sz = secsize > MIN_SEC_SIZE ? secsize : MIN_SEC_SIZE * 2;
654         grq = gctl_get_handle();
655         gctl_ro_param(grq, "verb", -1, "write PC98");
656         gctl_ro_param(grq, "class", -1, "PC98");
657         q = strrchr(disk, '/');
658         if (q == NULL)
659                 q = disk;
660         else
661                 q++;
662         gctl_ro_param(grq, "geom", -1, q);
663         gctl_ro_param(grq, "data", sz, buf);
664         q = gctl_issue(grq);
665         if (q == NULL) {
666                 gctl_free(grq);
667                 return(0);
668         }
669         warnx("Geom problem: %s", q);
670         gctl_free(grq);
671
672         warnx("Warning: Partitioning via geom failed, trying raw write");
673         error = pwrite(fd, buf, sz, sector * 512);
674         if (error == sz)
675                 return (0);
676
677         for (i = 0; i < NDOSPART; i++) {
678                 sprintf(fbuf, "%ss%d", disk, i + 1);
679                 fdw = open(fbuf, O_RDWR, 0);
680                 if (fdw < 0)
681                         continue;
682                 error = ioctl(fdw, DIOCSPC98, buf);
683                 close(fdw);
684                 if (error == 0)
685                         return (0);
686         }
687         warnx("Failed to write sector zero");
688         return(EINVAL);
689 }
690
691 static int
692 get_params()
693 {
694         int error;
695         u_int u;
696         off_t o;
697
698         error = ioctl(fd, DIOCGFWSECTORS, &u);
699         if (error == 0)
700                 sectors = dos_sectors = u;
701         else
702                 sectors = dos_sectors = 17;
703
704         error = ioctl(fd, DIOCGFWHEADS, &u);
705         if (error == 0)
706                 heads = dos_heads = u;
707         else
708                 heads = dos_heads = 8;
709
710         dos_cylsecs = cylsecs = heads * sectors;
711         disksecs = cyls * heads * sectors;
712
713         error = ioctl(fd, DIOCGSECTORSIZE, &u);
714         if (error != 0 || u == 0)
715                 u = 512;
716         secsize = u;
717
718         error = ioctl(fd, DIOCGMEDIASIZE, &o);
719         if (error == 0) {
720                 disksecs = o / u;
721                 cyls = dos_cyls = o / (u * dos_heads * dos_sectors);
722         }
723
724         return (disksecs);
725 }
726 \f
727
728 static int
729 read_s0()
730 {
731
732         if (read_disk(0, (char *) mboot.bootinst) == -1) {
733                 warnx("can't read fdisk partition table");
734                 return -1;
735         }
736         if (mboot.signature != DOSMAGIC) {
737                 warnx("invalid fdisk partition table found");
738                 /* So should we initialize things */
739                 return -1;
740         }
741
742         return 0;
743 }
744
745 static int
746 write_s0()
747 {
748
749         if (iotest) {
750                 print_s0(-1);
751                 return 0;
752         }
753
754         /*
755          * write enable label sector before write (if necessary),
756          * disable after writing.
757          * needed if the disklabel protected area also protects
758          * sector 0. (e.g. empty disk)
759          */
760         if (write_disk(0, (char *) mboot.bootinst) == -1) {
761                 warn("can't write fdisk partition table");
762                 return -1;
763         }
764
765         return(0);
766 }
767
768
769 static int
770 ok(const char *str)
771 {
772         printf("%s [n] ", str);
773         fflush(stdout);
774         if (fgets(lbuf, LBUF, stdin) == NULL)
775                 exit(1);
776         lbuf[strlen(lbuf)-1] = 0;
777
778         if (*lbuf &&
779                 (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") ||
780                  !strcmp(lbuf, "y") || !strcmp(lbuf, "Y")))
781                 return 1;
782         else
783                 return 0;
784 }
785
786 static int
787 decimal(const char *str, int *num, int deflt)
788 {
789         int acc = 0, c;
790         char *cp;
791
792         while (1) {
793                 printf("Supply a decimal value for \"%s\" [%d] ", str, deflt);
794                 fflush(stdout);
795                 if (fgets(lbuf, LBUF, stdin) == NULL)
796                         exit(1);
797                 lbuf[strlen(lbuf)-1] = 0;
798
799                 if (!*lbuf)
800                         return 0;
801
802                 cp = lbuf;
803                 while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
804                 if (!c)
805                         return 0;
806                 while ((c = *cp++)) {
807                         if (c <= '9' && c >= '0')
808                                 acc = acc * 10 + c - '0';
809                         else
810                                 break;
811                 }
812                 if (c == ' ' || c == '\t')
813                         while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
814                 if (!c) {
815                         *num = acc;
816                         return 1;
817                 } else
818                         printf("%s is an invalid decimal number.  Try again.\n",
819                                 lbuf);
820         }
821
822 }
823
824 static int
825 string(const char *str, char **ans)
826 {
827         int i, c;
828         char *cp = lbuf;
829
830         while (1) {
831                 printf("Supply a string value for \"%s\" [%s] ", str, *ans);
832                 fgets(lbuf, LBUF, stdin);
833                 lbuf[strlen(lbuf)-1] = 0;
834
835                 if (!*lbuf)
836                         return 0;
837
838                 while ((c = *cp) && (c == ' ' || c == '\t')) cp++;
839                 if (c == '"') {
840                         c = *++cp;
841                         *ans = cp;
842                         while ((c = *cp) && c != '"') cp++;
843                 } else {
844                         *ans = cp;
845                         while ((c = *cp) && c != ' ' && c != '\t') cp++;
846                 }
847
848                 for (i = strlen(*ans); i < 16; i++)
849                         (*ans)[i] = ' ';
850                 (*ans)[16] = 0;
851
852                 return 1;
853         }
854 }
855
856 static const char *
857 get_type(int type)
858 {
859         int     numentries = (sizeof(part_types)/sizeof(struct part_type));
860         int     counter = 0;
861         struct  part_type *ptr = part_types;
862
863
864         while(counter < numentries) {
865                 if(ptr->type == (type & 0x7f))
866                         return(ptr->name);
867                 ptr++;
868                 counter++;
869         }
870         return("unknown");
871 }
872
873 /*
874  * Try figuring out the root device's canonical disk name.
875  * The following choices are considered:
876  *   /dev/ad0s1a     => /dev/ad0
877  *   /dev/da0a       => /dev/da0
878  *   /dev/vinum/root => /dev/vinum/root
879  */
880 static char *
881 get_rootdisk(void)
882 {
883         struct statfs rootfs;
884         regex_t re;
885 #define NMATCHES 2
886         regmatch_t rm[NMATCHES];
887         char *s;
888         int rv;
889
890         if (statfs("/", &rootfs) == -1)
891                 err(1, "statfs(\"/\")");
892
893         if ((rv = regcomp(&re, "^(/dev/[a-z]+[0-9]+)([sp][0-9]+)?[a-h]?$",
894                     REG_EXTENDED)) != 0)
895                 errx(1, "regcomp() failed (%d)", rv);
896         if ((rv = regexec(&re, rootfs.f_mntfromname, NMATCHES, rm, 0)) != 0)
897                 errx(1,
898 "mounted root fs resource doesn't match expectations (regexec returned %d)",
899                     rv);
900         if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL)
901                 errx(1, "out of memory");
902         memcpy(s, rootfs.f_mntfromname + rm[1].rm_so,
903             rm[1].rm_eo - rm[1].rm_so);
904         s[rm[1].rm_eo - rm[1].rm_so] = 0;
905
906         return s;
907 }
908
909 static void
910 reset_boot(void)
911 {
912         int i;
913         struct pc98_partition *partp;
914
915         init_boot();
916         for (i = 1; i <= NDOSPART; i++) {
917                 partp = ((struct pc98_partition *) &mboot.parts) + i - 1;
918                 bzero((char *)partp, sizeof (struct pc98_partition));
919         }
920 }