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