fdisk.c revision 26421
10SN/A/* 22362SN/A * Mach Operating System 30SN/A * Copyright (c) 1992 Carnegie Mellon University 40SN/A * All Rights Reserved. 50SN/A * 60SN/A * Permission to use, copy, modify and distribute this software and its 72362SN/A * documentation is hereby granted, provided that both the copyright 80SN/A * notice and this permission notice appear in all copies of the 92362SN/A * software, derivative works or modified versions, and any portions 100SN/A * thereof, and that both notices appear in supporting documentation. 110SN/A * 120SN/A * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 130SN/A * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 140SN/A * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 150SN/A * 160SN/A * Carnegie Mellon requests users of this software to return to 170SN/A * 180SN/A * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 190SN/A * School of Computer Science 200SN/A * Carnegie Mellon University 212362SN/A * Pittsburgh PA 15213-3890 222362SN/A * 232362SN/A * any improvements or extensions that they make and grant Carnegie Mellon 240SN/A * the rights to redistribute these changes. 250SN/A */ 260SN/A 270SN/A#include <sys/types.h> 280SN/A#include <sys/disklabel.h> 290SN/A#include <stdio.h> 300SN/A#include <string.h> 310SN/A#include <errno.h> 320SN/A#include <sys/stat.h> 330SN/A#include <sys/ioctl.h> 340SN/A#include <fcntl.h> 350SN/A#include <unistd.h> 360SN/A 370SN/Aint iotest; 380SN/A 390SN/A#define LBUF 100 400SN/Astatic char lbuf[LBUF]; 410SN/A 420SN/A/* 430SN/A * 440SN/A * Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992 450SN/A * 460SN/A * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University 470SN/A * Copyright (c) 1989 Robert. V. Baron 480SN/A * Created. 490SN/A */ 500SN/A 510SN/A#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp 520SN/A#define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp 530SN/A#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); } 540SN/A 550SN/A#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs) 560SN/A 570SN/A#define MAX_SEC_SIZE 2048 /* maximum section size that is supported */ 580SN/A#define MIN_SEC_SIZE 512 /* the sector size to start sensing at */ 590SN/Aint secsize = 0; /* the sensed sector size */ 600SN/A 610SN/Aconst char *disk; 620SN/Aconst char *disks[] = 630SN/A{ 640SN/A "/dev/rwd0", "/dev/rsd0", "/dev/rod0", 0 650SN/A}; 660SN/A 670SN/Achar *name; 680SN/A 690SN/Astruct disklabel disklabel; /* disk parameters */ 700SN/A 710SN/Aint cyls, sectors, heads, cylsecs, disksecs; 720SN/A 730SN/Astruct mboot 740SN/A{ 750SN/A unsigned char padding[2]; /* force the longs to be long alligned */ 760SN/A unsigned char bootinst[DOSPARTOFF]; 770SN/A struct dos_partition parts[4]; 780SN/A unsigned short int signature; 790SN/A /* room to read in MBRs that are bigger then DEV_BSIZE */ 800SN/A unsigned char large_sector_overflow[MAX_SEC_SIZE-MIN_SEC_SIZE]; 810SN/A}; 820SN/Astruct mboot mboot; 830SN/A 840SN/A#define ACTIVE 0x80 850SN/A#define BOOT_MAGIC 0xAA55 860SN/A 870SN/Aint dos_cyls; 880SN/Aint dos_heads; 890SN/Aint dos_sectors; 900SN/Aint dos_cylsecs; 910SN/A 920SN/A#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0)) 930SN/A#define DOSCYL(c) (c & 0xff) 940SN/Astatic int partition = -1; 950SN/A 960SN/A 970SN/A#define MAX_ARGS 10 980SN/A 990SN/Astatic int current_line_number; 1000SN/A 1010SN/Astatic int geom_processed = 0; 1020SN/Astatic int part_processed = 0; 1030SN/Astatic int active_processed = 0; 1040SN/A 1050SN/A 1060SN/Atypedef struct cmd { 1070SN/A char cmd; 1080SN/A int n_args; 1090SN/A struct arg { 1100SN/A char argtype; 1110SN/A int arg_val; 1120SN/A } args[MAX_ARGS]; 1130SN/A} CMD; 1140SN/A 1150SN/A 1160SN/Astatic int a_flag = 0; /* set active partition */ 1170SN/Astatic int i_flag = 0; /* replace partition data */ 1180SN/Astatic int u_flag = 0; /* update partition data */ 1190SN/Astatic int t_flag = 0; /* test only, if f_flag is given */ 1200SN/Astatic char *f_flag = NULL; /* Read config info from file */ 1210SN/Astatic int v_flag = 0; /* Be verbose */ 1220SN/A 1230SN/Astatic unsigned char bootcode[] = { 1240SN/A0x33, 0xc0, 0xfa, 0x8e, 0xd0, 0xbc, 0x00, 0x7c, 0x8e, 0xc0, 0x8e, 0xd8, 0xfb, 0x8b, 0xf4, 0xbf, 1250SN/A0x00, 0x06, 0xb9, 0x00, 0x02, 0xfc, 0xf3, 0xa4, 0xea, 0x1d, 0x06, 0x00, 0x00, 0xb0, 0x04, 0xbe, 1260SN/A0xbe, 0x07, 0x80, 0x3c, 0x80, 0x74, 0x0c, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x75, 0xf4, 0xbe, 0xbd, 1270SN/A0x06, 0xeb, 0x43, 0x8b, 0xfe, 0x8b, 0x14, 0x8b, 0x4c, 0x02, 0x83, 0xc6, 0x10, 0xfe, 0xc8, 0x74, 1280SN/A0x0a, 0x80, 0x3c, 0x80, 0x75, 0xf4, 0xbe, 0xbd, 0x06, 0xeb, 0x2b, 0xbd, 0x05, 0x00, 0xbb, 0x00, 1290SN/A0x7c, 0xb8, 0x01, 0x02, 0xcd, 0x13, 0x73, 0x0c, 0x33, 0xc0, 0xcd, 0x13, 0x4d, 0x75, 0xef, 0xbe, 1300SN/A0x9e, 0x06, 0xeb, 0x12, 0x81, 0x3e, 0xfe, 0x7d, 0x55, 0xaa, 0x75, 0x07, 0x8b, 0xf7, 0xea, 0x00, 1310SN/A0x7c, 0x00, 0x00, 0xbe, 0x85, 0x06, 0x2e, 0xac, 0x0a, 0xc0, 0x74, 0x06, 0xb4, 0x0e, 0xcd, 0x10, 1320SN/A0xeb, 0xf4, 0xfb, 0xeb, 0xfe, 1330SN/A'M', 'i', 's', 's', 'i', 'n', 'g', ' ', 1340SN/A 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0, 1350SN/A'E', 'r', 'r', 'o', 'r', ' ', 'l', 'o', 'a', 'd', 'i', 'n', 'g', ' ', 1360SN/A 'o', 'p', 'e', 'r', 'a', 't', 'i', 'n', 'g', ' ', 's', 'y', 's', 't', 'e', 'm', 0, 1370SN/A'I', 'n', 'v', 'a', 'l', 'i', 'd', ' ', 1380SN/A 'p', 'a', 'r', 't', 'i', 't', 'i', 'o', 'n', ' ', 't', 'a', 'b', 'l', 'e', 0, 1390SN/A'A', 'u', 't', 'h', 'o', 'r', ' ', '-', ' ', 1400SN/A 'S', 'i', 'e', 'g', 'm', 'a', 'r', ' ', 'S', 'c', 'h', 'm', 'i', 'd', 't', 0,0,0, 1410SN/A 1420SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1430SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1440SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1450SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1460SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1470SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1480SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1490SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1500SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1510SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1520SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1530SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1540SN/A 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 1550SN/A}; 1560SN/A 1570SN/Astruct part_type 1580SN/A{ 1590SN/A unsigned char type; 1600SN/A char *name; 1610SN/A}part_types[] = 1620SN/A{ 1630SN/A {0x00, "unused"} 1640SN/A ,{0x01, "Primary DOS with 12 bit FAT"} 1650SN/A ,{0x02, "XENIX / filesystem"} 1660SN/A ,{0x03, "XENIX /usr filesystem"} 1670SN/A ,{0x04, "Primary DOS with 16 bit FAT"} 1680SN/A ,{0x05, "Extended DOS"} 1690SN/A ,{0x06, "Primary 'big' DOS (> 32MB)"} 1700SN/A ,{0x07, "OS/2 HPFS, QNX or Advanced UNIX"} 1710SN/A ,{0x08, "AIX filesystem"} 1720SN/A ,{0x09, "AIX boot partition or Coherent"} 1730SN/A ,{0x0A, "OS/2 Boot Manager or OPUS"} 1740SN/A ,{0x10, "OPUS"} 1750SN/A ,{0x40, "VENIX 286"} 1760SN/A ,{0x50, "DM"} 1770SN/A ,{0x51, "DM"} 1780SN/A ,{0x52, "CP/M or Microport SysV/AT"} 1790SN/A ,{0x56, "GB"} 1800SN/A ,{0x61, "Speed"} 1810SN/A ,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"} 1820SN/A ,{0x64, "Novell Netware 2.xx"} 1830SN/A ,{0x65, "Novell Netware 3.xx"} 1840SN/A ,{0x75, "PCIX"} 1850SN/A ,{0x80, "Minix 1.1 ... 1.4a"} 1860SN/A ,{0x81, "Minix 1.4b ... 1.5.10"} 1870SN/A ,{0x82, "Linux swap"} 1880SN/A ,{0x83, "Linux filesystem"} 1890SN/A ,{0x93, "Amoeba filesystem"} 1900SN/A ,{0x94, "Amoeba bad block table"} 1910SN/A ,{0xA5, "FreeBSD/NetBSD/386BSD"} 1920SN/A ,{0xA6, "OpenBSD"} 1930SN/A ,{0xA7, "NEXTSTEP"} 1940SN/A ,{0xB7, "BSDI BSD/386 filesystem"} 1950SN/A ,{0xB8, "BSDI BSD/386 swap"} 1960SN/A ,{0xDB, "Concurrent CPM or C.DOS or CTOS"} 1970SN/A ,{0xE1, "Speed"} 1980SN/A ,{0xE3, "Speed"} 1990SN/A ,{0xE4, "Speed"} 2000SN/A ,{0xF1, "Speed"} 2010SN/A ,{0xF2, "DOS 3.3+ Secondary"} 2020SN/A ,{0xF4, "Speed"} 2030SN/A ,{0xFF, "BBT (Bad Blocks Table)"} 2040SN/A}; 2050SN/A 2060SN/Astatic void print_s0(int which); 2070SN/Astatic void print_part(int i); 2080SN/Astatic void init_sector0(unsigned long start); 2090SN/Astatic void init_boot(void); 2100SN/Astatic void change_part(int i); 2110SN/Astatic void print_params(); 2120SN/Astatic void change_active(int which); 2130SN/Astatic void get_params_to_use(); 2140SN/Astatic void dos(int sec, int size, unsigned char *c, unsigned char *s, 2150SN/A unsigned char *h); 2160SN/Astatic int open_disk(int u_flag); 2170SN/Astatic ssize_t read_disk(off_t sector, void *buf); 2180SN/Astatic ssize_t write_disk(off_t sector, void *buf); 2190SN/Astatic int get_params(); 2200SN/Astatic int read_s0(); 2210SN/Astatic int write_s0(); 2220SN/Astatic int ok(char *str); 2230SN/Astatic int decimal(char *str, int *num, int deflt); 2240SN/Astatic char *get_type(int type); 2250SN/Astatic int read_config(char *config_file); 2260SN/Astatic void reset_boot(void); 2270SN/A#if 0 2280SN/Astatic int hex(char *str, int *num, int deflt); 2290SN/Astatic int string(char *str, char **ans); 2300SN/A#endif 2310SN/A 2320SN/A 2330SN/Aint 2340SN/Amain(int argc, char *argv[]) 2350SN/A{ 2360SN/A int i; 2370SN/A 2380SN/A name = *argv; 2390SN/A {register char *cp = name; 2400SN/A while (*cp) if (*cp++ == '/') name = cp; 2410SN/A } 2420SN/A 2430SN/A for ( argv++ ; --argc ; argv++ ) { register char *token = *argv; 2440SN/A if (*token++ != '-' || !*token) 2450SN/A break; 2460SN/A else { register int flag; 2470SN/A for ( ; (flag = *token++) ; ) { 2480SN/A switch (flag) { 2490SN/A case '1': 2500SN/A partition = 1; 2510SN/A break; 2520SN/A case '2': 2530SN/A partition = 2; 2540SN/A break; 2550SN/A case '3': 2560SN/A partition = 3; 2570SN/A break; 2580SN/A case '4': 2590SN/A partition = 4; 2600SN/A break; 2610SN/A case 'a': 2620SN/A a_flag = 1; 2630SN/A break; 2640SN/A case 'f': 2650SN/A if (*token) 2660SN/A { 2670SN/A f_flag = token; 2680SN/A token = ""; 2690SN/A } 2700SN/A else 2710SN/A { 2720SN/A if (argc == 1) 2730SN/A { 2740SN/A goto usage; 2750SN/A } 2760SN/A --argc; 2770SN/A f_flag = *++argv; 2780SN/A } 2790SN/A /* 2800SN/A * u_flag is needed, because we're 2810SN/A * writing to the disk. 2820SN/A */ 2830SN/A u_flag = 1; 2840SN/A break; 2850SN/A case 'i': 2860SN/A i_flag = 1; 2870SN/A case 'u': 2880SN/A u_flag = 1; 2890SN/A break; 2900SN/A case 't': 2910SN/A t_flag = 1; 2920SN/A case 'v': 2930SN/A v_flag = 1; 2940SN/A break; 2950SN/A default: 2960SN/A goto usage; 2970SN/A } 2980SN/A } 2990SN/A } 3000SN/A } 3010SN/A 3020SN/A if (argc > 0) 3030SN/A { 3040SN/A static char realname[12]; 3050SN/A 3060SN/A if(strncmp(argv[0], "/dev", 4) == 0) 3070SN/A disk = argv[0]; 3080SN/A else 3090SN/A { 3100SN/A snprintf(realname, 12, "/dev/r%s", argv[0]); 3110SN/A disk = realname; 3120SN/A } 3130SN/A 3140SN/A if (open_disk(u_flag) < 0) 3150SN/A { 3160SN/A fprintf(stderr, "Cannot open disk %s (%s)\n", 3170SN/A disk, sys_errlist[errno]); 3180SN/A exit(1); 3190SN/A } 3200SN/A } 3210SN/A else 3220SN/A { 3230SN/A int i, rv = 0; 3240SN/A 3250SN/A for(i = 0; disks[i]; i++) 3260SN/A { 3270SN/A disk = disks[i]; 3280SN/A rv = open_disk(u_flag); 3290SN/A if(rv != -2) break; 3300SN/A } 3310SN/A if(rv < 0) 3320SN/A { 3330SN/A fprintf(stderr, "Cannot open any disk (%s)\n", 3340SN/A sys_errlist[errno]); 3350SN/A exit(1); 3360SN/A } 3370SN/A } 3380SN/A 3390SN/A printf("******* Working on device %s *******\n",disk); 3400SN/A 3410SN/A if (f_flag) 3420SN/A { 3430SN/A if (read_s0() || i_flag) 3440SN/A { 3450SN/A reset_boot(); 3460SN/A } 3470SN/A 3480SN/A if (!read_config(f_flag)) 3490SN/A { 3500SN/A exit(1); 3510SN/A } 3520SN/A if (v_flag) 3530SN/A { 3540SN/A print_s0(-1); 3550SN/A } 3560SN/A if (!t_flag) 3570SN/A { 3580SN/A write_s0(); 3590SN/A } 3600SN/A } 3610SN/A else 3620SN/A { 3630SN/A if(u_flag) 3640SN/A { 3650SN/A get_params_to_use(); 3660SN/A } 3670SN/A else 3680SN/A { 3690SN/A print_params(); 3700SN/A } 3710SN/A 3720SN/A if (read_s0()) 3730SN/A init_sector0(1); 3740SN/A 3750SN/A printf("Media sector size is %d\n", secsize); 3760SN/A printf("Warning: BIOS sector numbering starts with sector 1\n"); 3770SN/A printf("Information from DOS bootblock is:\n"); 3780SN/A if (partition == -1) 3790SN/A for (i = 1; i <= NDOSPART; i++) 3800SN/A change_part(i); 3810SN/A else 3820SN/A change_part(partition); 3830SN/A 3840SN/A if (u_flag || a_flag) 3850SN/A change_active(partition); 3860SN/A 3870SN/A if (u_flag || a_flag) { 3880SN/A if (!t_flag) 3890SN/A { 3900SN/A printf("\nWe haven't changed the partition table yet. "); 3910SN/A printf("This is your last chance.\n"); 3920SN/A } 3930SN/A print_s0(-1); 3940SN/A if (!t_flag) 3950SN/A { 3960SN/A if (ok("Should we write new partition table?")) 3970SN/A write_s0(); 3980SN/A } 3990SN/A else 4000SN/A { 4010SN/A printf("\n-t flag specified -- partition table not written.\n"); 4020SN/A } 4030SN/A } 4040SN/A } 4050SN/A 4060SN/A exit(0); 4070SN/A 4080SN/Ausage: 4090SN/A printf("fdisk {-a|-i|-u} [-f <config file> [-t] [-v]] [-{1,2,3,4}] [disk]\n"); 4100SN/A return(1); 4110SN/A} 4120SN/A 4130SN/Astatic void 4140SN/Aprint_s0(int which) 4150SN/A{ 4160SN/Aint i; 4170SN/A 4180SN/A print_params(); 4190SN/A printf("Information from DOS bootblock is:\n"); 4200SN/A if (which == -1) 4210SN/A for (i = 1; i <= NDOSPART; i++) 4220SN/A printf("%d: ", i), print_part(i); 4230SN/A else 4240SN/A print_part(which); 4250SN/A} 4260SN/A 4270SN/Astatic struct dos_partition mtpart = { 0 }; 4280SN/A 4290SN/Astatic void 4300SN/Aprint_part(int i) 4310SN/A{ 4320SN/A struct dos_partition *partp; 4330SN/A u_int64_t part_mb; 4340SN/A 4350SN/A partp = ((struct dos_partition *) &mboot.parts) + i - 1; 4360SN/A 4370SN/A if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) { 4380SN/A printf("<UNUSED>\n"); 4390SN/A return; 4400SN/A } 4410SN/A /* 4420SN/A * Be careful not to overflow. 4430SN/A */ 4440SN/A part_mb = partp->dp_size; 4450SN/A part_mb *= secsize; 4460SN/A part_mb /= (1024 * 1024); 4470SN/A printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ)); 4480SN/A printf(" start %ld, size %ld (%qd Meg), flag %x\n", 4490SN/A partp->dp_start, 4500SN/A partp->dp_size, 4510SN/A part_mb, 4520SN/A partp->dp_flag); 4530SN/A printf("\tbeg: cyl %d/ sector %d/ head %d;\n\tend: cyl %d/ sector %d/ head %d\n" 4540SN/A ,DPCYL(partp->dp_scyl, partp->dp_ssect) 4550SN/A ,DPSECT(partp->dp_ssect) 4560SN/A ,partp->dp_shd 4570SN/A ,DPCYL(partp->dp_ecyl, partp->dp_esect) 4580SN/A ,DPSECT(partp->dp_esect) 4590SN/A ,partp->dp_ehd); 4600SN/A} 4610SN/A 4620SN/A 4630SN/Astatic void 4640SN/Ainit_boot(void) 4650SN/A{ 4660SN/A memcpy(mboot.bootinst, bootcode, sizeof(bootcode)); 4670SN/A mboot.signature = BOOT_MAGIC; 4680SN/A} 4690SN/A 4700SN/A 4710SN/Astatic void 4720SN/Ainit_sector0(unsigned long start) 4730SN/A{ 4740SN/Astruct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]); 4750SN/Aunsigned long size = disksecs - start; 4760SN/A 4770SN/A init_boot(); 4780SN/A 4790SN/A partp->dp_typ = DOSPTYP_386BSD; 4800SN/A partp->dp_flag = ACTIVE; 4810SN/A partp->dp_start = start; 4820SN/A partp->dp_size = size; 4830SN/A 4840SN/A dos(partp->dp_start, partp->dp_size, 4850SN/A &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 4860SN/A dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, 4870SN/A &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 4880SN/A} 4890SN/A 4900SN/Astatic void 4910SN/Achange_part(int i) 4920SN/A{ 4930SN/Astruct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1; 4940SN/A 4950SN/A printf("The data for partition %d is:\n", i); 4960SN/A print_part(i); 4970SN/A 4980SN/A if (u_flag && ok("Do you want to change it?")) { 4990SN/A int tmp; 5000SN/A 5010SN/A if (i_flag) { 5020SN/A bzero((char *)partp, sizeof (struct dos_partition)); 5030SN/A if (i == 4) { 5040SN/A init_sector0(1); 5050SN/A printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n"); 5060SN/A print_part(i); 5070SN/A } 5080SN/A } 5090SN/A 5100SN/A do { 5110SN/A Decimal("sysid", partp->dp_typ, tmp); 5120SN/A Decimal("start", partp->dp_start, tmp); 5130SN/A Decimal("size", partp->dp_size, tmp); 5140SN/A 5150SN/A if (ok("Explicitly specifiy beg/end address ?")) 5160SN/A { 5170SN/A int tsec,tcyl,thd; 5180SN/A tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect); 5190SN/A thd = partp->dp_shd; 5200SN/A tsec = DPSECT(partp->dp_ssect); 5210SN/A Decimal("beginning cylinder", tcyl, tmp); 5220SN/A Decimal("beginning head", thd, tmp); 5230SN/A Decimal("beginning sector", tsec, tmp); 5240SN/A partp->dp_scyl = DOSCYL(tcyl); 5250SN/A partp->dp_ssect = DOSSECT(tsec,tcyl); 5260SN/A partp->dp_shd = thd; 5270SN/A 5280SN/A tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect); 5290SN/A thd = partp->dp_ehd; 5300SN/A tsec = DPSECT(partp->dp_esect); 5310SN/A Decimal("ending cylinder", tcyl, tmp); 5320SN/A Decimal("ending head", thd, tmp); 5330SN/A Decimal("ending sector", tsec, tmp); 5340SN/A partp->dp_ecyl = DOSCYL(tcyl); 5350SN/A partp->dp_esect = DOSSECT(tsec,tcyl); 5360SN/A partp->dp_ehd = thd; 5370SN/A } else { 5380SN/A dos(partp->dp_start, partp->dp_size, 5390SN/A &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 5400SN/A dos(partp->dp_start + partp->dp_size - 1, partp->dp_size, 5410SN/A &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 5420SN/A } 5430SN/A 5440SN/A print_part(i); 5450SN/A } while (!ok("Are we happy with this entry?")); 5460SN/A } 5470SN/A} 5480SN/A 5490SN/Astatic void 5500SN/Aprint_params() 5510SN/A{ 5520SN/A printf("parameters extracted from in-core disklabel are:\n"); 5530SN/A printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 5540SN/A ,cyls,heads,sectors,cylsecs); 5550SN/A if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255)) 5560SN/A printf("Figures below won't work with BIOS for partitions not in cyl 1\n"); 5570SN/A printf("parameters to be used for BIOS calculations are:\n"); 5580SN/A printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 5590SN/A ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); 5600SN/A} 5610SN/A 5620SN/Astatic void 5630SN/Achange_active(int which) 5640SN/A{ 5650SN/Aint i; 5660SN/Aint active = 4, tmp; 5670SN/Astruct dos_partition *partp = ((struct dos_partition *) &mboot.parts); 5680SN/A 5690SN/A if (a_flag && which != -1) 5700SN/A active = which; 5710SN/A if (!ok("Do you want to change the active partition?")) 5720SN/A return; 5730SN/A do 5740SN/A Decimal("active partition", active, tmp); 5750SN/A while (!ok("Are you happy with this choice")); 5760SN/A for (i = 0; i < NDOSPART; i++) 5770SN/A partp[i].dp_flag = 0; 5780SN/A if (active > 0 && active <= NDOSPART) 5790SN/A partp[active-1].dp_flag = ACTIVE; 5800SN/A} 5810SN/A 5820SN/Avoid 5830SN/Aget_params_to_use() 5840SN/A{ 5850SN/A int tmp; 5860SN/A print_params(); 5870SN/A if (ok("Do you want to change our idea of what BIOS thinks ?")) 5880SN/A { 5890SN/A do 5900SN/A { 5910SN/A Decimal("BIOS's idea of #cylinders", dos_cyls, tmp); 5920SN/A Decimal("BIOS's idea of #heads", dos_heads, tmp); 5930SN/A Decimal("BIOS's idea of #sectors", dos_sectors, tmp); 5940SN/A dos_cylsecs = dos_heads * dos_sectors; 5950SN/A print_params(); 5960SN/A } 5970SN/A while(!ok("Are you happy with this choice")); 5980SN/A } 5990SN/A} 6000SN/A 6010SN/A 6020SN/A/***********************************************\ 6030SN/A* Change real numbers into strange dos numbers * 6040SN/A\***********************************************/ 6050SN/Astatic void 6060SN/Ados(sec, size, c, s, h) 6070SN/Aint sec, size; 6080SN/Aunsigned char *c, *s, *h; 6090SN/A{ 6100SN/Aint cy; 6110SN/Aint hd; 6120SN/A 6130SN/A if (sec == 0 && size == 0) { 6140SN/A *s = *c = *h = 0; 6150SN/A return; 6160SN/A } 6170SN/A 6180SN/A cy = sec / ( dos_cylsecs ); 6190SN/A sec = sec - cy * ( dos_cylsecs ); 6200SN/A 6210SN/A hd = sec / dos_sectors; 6220SN/A sec = (sec - hd * dos_sectors) + 1; 6230SN/A 6240SN/A *h = hd; 6250SN/A *c = cy & 0xff; 6260SN/A *s = (sec & 0x3f) | ( (cy & 0x300) >> 2); 6270SN/A} 6280SN/A 6290SN/Aint fd; 6300SN/A 6310SN/A /* Getting device status */ 6320SN/A 6330SN/Astatic int 6340SN/Aopen_disk(int u_flag) 6350SN/A{ 6360SN/Astruct stat st; 6370SN/A 6380SN/A if (stat(disk, &st) == -1) { 6390SN/A fprintf(stderr, "%s: Can't get file status of %s\n", 6400SN/A name, disk); 6410SN/A return -1; 6420SN/A } 6430SN/A if ( !(st.st_mode & S_IFCHR) ) 6440SN/A fprintf(stderr,"%s: Device %s is not character special\n", 6450SN/A name, disk); 6460SN/A if ((fd = open(disk, a_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) { 6470SN/A if(errno == ENXIO) 6480SN/A return -2; 6490SN/A fprintf(stderr,"%s: Can't open device %s\n", name, disk); 6500SN/A return -1; 6510SN/A } 6520SN/A if (get_params(0) == -1) { 6530SN/A fprintf(stderr, "%s: Can't get disk parameters on %s\n", 6540SN/A name, disk); 6550SN/A return -1; 6560SN/A } 6570SN/A return fd; 6580SN/A} 6590SN/A 6600SN/Astatic ssize_t 6610SN/Aread_disk(off_t sector, void *buf) 6620SN/A{ 6630SN/A lseek(fd,(sector * 512), 0); 6640SN/A if( secsize == 0 ) 6650SN/A for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 ) 6660SN/A { 6670SN/A /* try the read */ 6680SN/A int size = read(fd, buf, secsize); 6690SN/A if( size == secsize ) 6700SN/A /* it worked so return */ 6710SN/A return secsize; 6720SN/A } 6730SN/A else 6740SN/A return read( fd, buf, secsize ); 6750SN/A 6760SN/A /* we failed to read at any of the sizes */ 6770SN/A return -1; 6780SN/A} 6790SN/A 6800SN/Astatic ssize_t 6810SN/Awrite_disk(off_t sector, void *buf) 6820SN/A{ 6830SN/A lseek(fd,(sector * 512), 0); 6840SN/A /* write out in the size that the read_disk found worked */ 6850SN/A return write(fd, buf, secsize); 6860SN/A} 6870SN/A 6880SN/Astatic int 6890SN/Aget_params() 6900SN/A{ 6910SN/A 6920SN/A if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 6930SN/A fprintf(stderr, 6940SN/A "%s: Can't get disk parameters on %s; supplying dummy ones\n", 6950SN/A name, disk); 6960SN/A dos_cyls = cyls = 1; 6970SN/A dos_heads = heads = 1; 6980SN/A dos_sectors = sectors = 1; 6990SN/A dos_cylsecs = cylsecs = heads * sectors; 7000SN/A disksecs = cyls * heads * sectors; 7010SN/A return disksecs; 7020SN/A } 7030SN/A 7040SN/A dos_cyls = cyls = disklabel.d_ncylinders; 7050SN/A dos_heads = heads = disklabel.d_ntracks; 7060SN/A dos_sectors = sectors = disklabel.d_nsectors; 7070SN/A dos_cylsecs = cylsecs = heads * sectors; 7080SN/A disksecs = cyls * heads * sectors; 7090SN/A 7100SN/A return (disksecs); 711} 712 713 714static int 715read_s0() 716{ 717 if (read_disk(0, (char *) mboot.bootinst) == -1) { 718 fprintf(stderr, "%s: Can't read fdisk partition table\n", name); 719 return -1; 720 } 721 if (mboot.signature != BOOT_MAGIC) { 722 fprintf(stderr, "%s: Invalid fdisk partition table found\n", 723 name); 724 /* So should we initialize things */ 725 return -1; 726 } 727 return 0; 728} 729 730static int 731write_s0() 732{ 733 int flag; 734 if (iotest) { 735 print_s0(-1); 736 return 0; 737 } 738 /* 739 * write enable label sector before write (if necessary), 740 * disable after writing. 741 * needed if the disklabel protected area also protects 742 * sector 0. (e.g. empty disk) 743 */ 744 flag = 1; 745#ifdef NOT_NOW 746 if (ioctl(fd, DIOCWLABEL, &flag) < 0) 747 perror("ioctl DIOCWLABEL"); 748#endif 749 if (write_disk(0, (char *) mboot.bootinst) == -1) { 750 fprintf(stderr, "%s: Can't write fdisk partition table\n", 751 name); 752 return -1; 753 flag = 0; 754#ifdef NOT_NOW 755 (void) ioctl(fd, DIOCWLABEL, &flag); 756#endif 757 } 758 return(0); 759} 760 761 762static int 763ok(str) 764char *str; 765{ 766 printf("%s [n] ", str); 767 fgets(lbuf, LBUF, stdin); 768 lbuf[strlen(lbuf)-1] = 0; 769 770 if (*lbuf && 771 (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || 772 !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) 773 return 1; 774 else 775 return 0; 776} 777 778static int 779decimal(char *str, int *num, int deflt) 780{ 781int acc = 0, c; 782char *cp; 783 784 while (1) { 785 printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); 786 fgets(lbuf, LBUF, stdin); 787 lbuf[strlen(lbuf)-1] = 0; 788 789 if (!*lbuf) 790 return 0; 791 792 cp = lbuf; 793 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 794 if (!c) 795 return 0; 796 while ((c = *cp++)) { 797 if (c <= '9' && c >= '0') 798 acc = acc * 10 + c - '0'; 799 else 800 break; 801 } 802 if (c == ' ' || c == '\t') 803 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 804 if (!c) { 805 *num = acc; 806 return 1; 807 } else 808 printf("%s is an invalid decimal number. Try again\n", 809 lbuf); 810 } 811 812} 813 814#if 0 815static int 816hex(char *str, int *num, int deflt) 817{ 818int acc = 0, c; 819char *cp; 820 821 while (1) { 822 printf("Supply a hex value for \"%s\" [%x] ", str, deflt); 823 fgets(lbuf, LBUF, stdin); 824 lbuf[strlen(lbuf)-1] = 0; 825 826 if (!*lbuf) 827 return 0; 828 829 cp = lbuf; 830 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 831 if (!c) 832 return 0; 833 while ((c = *cp++)) { 834 if (c <= '9' && c >= '0') 835 acc = (acc << 4) + c - '0'; 836 else if (c <= 'f' && c >= 'a') 837 acc = (acc << 4) + c - 'a' + 10; 838 else if (c <= 'F' && c >= 'A') 839 acc = (acc << 4) + c - 'A' + 10; 840 else 841 break; 842 } 843 if (c == ' ' || c == '\t') 844 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 845 if (!c) { 846 *num = acc; 847 return 1; 848 } else 849 printf("%s is an invalid hex number. Try again\n", 850 lbuf); 851 } 852 853} 854 855static int 856string(char *str, char **ans) 857{ 858int c; 859char *cp = lbuf; 860 861 while (1) { 862 printf("Supply a string value for \"%s\" [%s] ", str, *ans); 863 fgets(lbuf, LBUF, stdin); 864 lbuf[strlen(lbuf)-1] = 0; 865 866 if (!*lbuf) 867 return 0; 868 869 while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 870 if (c == '"') { 871 c = *++cp; 872 *ans = cp; 873 while ((c = *cp) && c != '"') cp++; 874 } else { 875 *ans = cp; 876 while ((c = *cp) && c != ' ' && c != '\t') cp++; 877 } 878 879 if (c) 880 *cp = 0; 881 return 1; 882 } 883} 884#endif 885 886static char * 887get_type(int type) 888{ 889 int numentries = (sizeof(part_types)/sizeof(struct part_type)); 890 int counter = 0; 891 struct part_type *ptr = part_types; 892 893 894 while(counter < numentries) 895 { 896 if(ptr->type == type) 897 { 898 return(ptr->name); 899 } 900 ptr++; 901 counter++; 902 } 903 return("unknown"); 904} 905 906 907static void 908parse_config_line(line, command) 909 char *line; 910 CMD *command; 911{ 912 char *cp, *end; 913 914 cp = line; 915 while (1) /* dirty trick used to insure one exit point for this 916 function */ 917 { 918 memset(command, 0, sizeof(*command)); 919 920 while (isspace(*cp)) ++cp; 921 if (*cp == '\0' || *cp == '#') 922 { 923 break; 924 } 925 command->cmd = *cp++; 926 927 /* 928 * Parse args 929 */ 930 while (1) 931 { 932 while (isspace(*cp)) ++cp; 933 if (*cp == '#') 934 { 935 break; /* found comment */ 936 } 937 if (isalpha(*cp)) 938 { 939 command->args[command->n_args].argtype = *cp++; 940 } 941 if (!isdigit(*cp)) 942 { 943 break; /* assume end of line */ 944 } 945 end = NULL; 946 command->args[command->n_args].arg_val = strtol(cp, &end, 0); 947 if (cp == end) 948 { 949 break; /* couldn't parse number */ 950 } 951 cp = end; 952 command->n_args++; 953 } 954 break; 955 } 956} 957 958 959static int 960process_geometry(command) 961 CMD *command; 962{ 963 int status = 1, i; 964 965 while (1) 966 { 967 geom_processed = 1; 968 if (part_processed) 969 { 970 fprintf(stderr, 971 "%s: ERROR line %d: the geometry specification line must occur before\n\ 972 all partition specifications.\n", 973 name, current_line_number); 974 status = 0; 975 break; 976 } 977 if (command->n_args != 3) 978 { 979 fprintf(stderr, 980 "%s: ERROR line %d: incorrect number of geometry args\n", 981 name, current_line_number); 982 status = 0; 983 break; 984 } 985 dos_cyls = -1; 986 dos_heads = -1; 987 dos_sectors = -1; 988 for (i = 0; i < 3; ++i) 989 { 990 switch (command->args[i].argtype) 991 { 992 case 'c': 993 dos_cyls = command->args[i].arg_val; 994 break; 995 case 'h': 996 dos_heads = command->args[i].arg_val; 997 break; 998 case 's': 999 dos_sectors = command->args[i].arg_val; 1000 break; 1001 default: 1002 fprintf(stderr, 1003 "%s: ERROR line %d: unknown geometry arg type: '%c' (0x%02x)\n", 1004 name, current_line_number, command->args[i].argtype, 1005 command->args[i].argtype); 1006 status = 0; 1007 break; 1008 } 1009 } 1010 if (status == 0) 1011 { 1012 break; 1013 } 1014 1015 dos_cylsecs = dos_heads * dos_sectors; 1016 1017 /* 1018 * Do sanity checks on parameter values 1019 */ 1020 if (dos_cyls < 0) 1021 { 1022 fprintf(stderr, 1023 "%s: ERROR line %d: number of cylinders not specified\n", 1024 name, current_line_number); 1025 status = 0; 1026 } 1027 if (dos_cyls == 0 || dos_cyls > 1024) 1028 { 1029 fprintf(stderr, 1030 "%s: WARNING line %d: number of cylinders (%d) may be out-of-range\n\ 1031 (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\ 1032 is dedicated to FreeBSD).\n", 1033 name, current_line_number, dos_cyls); 1034 } 1035 1036 if (dos_heads < 0) 1037 { 1038 fprintf(stderr, 1039 "%s: ERROR line %d: number of heads not specified\n", 1040 name, current_line_number); 1041 status = 0; 1042 } 1043 else if (dos_heads < 1 || dos_heads > 256) 1044 { 1045 fprintf(stderr, 1046 "%s: ERROR line %d: number of heads must be within (1-256)\n", 1047 name, current_line_number); 1048 status = 0; 1049 } 1050 1051 if (dos_sectors < 0) 1052 { 1053 fprintf(stderr, "%s: ERROR line %d: number of sectors not specified\n", 1054 name, current_line_number); 1055 status = 0; 1056 } 1057 else if (dos_sectors < 1 || dos_sectors > 63) 1058 { 1059 fprintf(stderr, 1060 "%s: ERROR line %d: number of sectors must be within (1-63)\n", 1061 name, current_line_number); 1062 status = 0; 1063 } 1064 1065 break; 1066 } 1067 return (status); 1068} 1069 1070 1071static int 1072process_partition(command) 1073 CMD *command; 1074{ 1075 int status = 0, partition; 1076 unsigned long chunks, adj_size, max_end; 1077 struct dos_partition *partp; 1078 1079 while (1) 1080 { 1081 part_processed = 1; 1082 if (command->n_args != 4) 1083 { 1084 fprintf(stderr, 1085 "%s: ERROR line %d: incorrect number of partition args\n", 1086 name, current_line_number); 1087 break; 1088 } 1089 partition = command->args[0].arg_val; 1090 if (partition < 1 || partition > 4) 1091 { 1092 fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n", 1093 name, current_line_number, partition); 1094 break; 1095 } 1096 partp = ((struct dos_partition *) &mboot.parts) + partition - 1; 1097 bzero((char *)partp, sizeof (struct dos_partition)); 1098 partp->dp_typ = command->args[1].arg_val; 1099 partp->dp_start = command->args[2].arg_val; 1100 partp->dp_size = command->args[3].arg_val; 1101 max_end = partp->dp_start + partp->dp_size; 1102 1103 if (partp->dp_typ == 0) 1104 { 1105 /* 1106 * Get out, the partition is marked as unused. 1107 */ 1108 /* 1109 * Insure that it's unused. 1110 */ 1111 bzero((char *)partp, sizeof (struct dos_partition)); 1112 status = 1; 1113 break; 1114 } 1115 1116 /* 1117 * Adjust start upwards, if necessary, to fall on an head boundary. 1118 */ 1119 if (partp->dp_start % dos_sectors != 0) 1120 { 1121 adj_size = 1122 (partp->dp_start / dos_sectors + 1) * dos_sectors; 1123 if (adj_size > max_end) 1124 { 1125 /* 1126 * Can't go past end of partition 1127 */ 1128 fprintf(stderr, 1129 "%s: ERROR line %d: unable to adjust start of partition %d to fall on\n\ 1130 a cylinder boundary.\n", 1131 name, current_line_number, partition); 1132 break; 1133 } 1134 fprintf(stderr, 1135 "%s: WARNING: adjusting start offset of partition '%d' from %d\n\ 1136 to %d, to round to an head boundary.\n", 1137 name, partition, partp->dp_start, adj_size); 1138 partp->dp_start = adj_size; 1139 } 1140 1141 /* 1142 * Adjust size downwards, if necessary, to fall on a cylinder 1143 * boundary. 1144 */ 1145 chunks = 1146 ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; 1147 adj_size = chunks - partp->dp_start; 1148 if (adj_size != partp->dp_size) 1149 { 1150 fprintf(stderr, 1151 "%s: WARNING: adjusting size of partition '%d' from %d to %d,\n\ 1152 to round to a cylinder boundary.\n", 1153 name, partition, partp->dp_size, adj_size); 1154 if (chunks > 0) 1155 { 1156 partp->dp_size = adj_size; 1157 } 1158 else 1159 { 1160 partp->dp_size = 0; 1161 } 1162 } 1163 if (partp->dp_size < 1) 1164 { 1165 fprintf(stderr, 1166 "%s: ERROR line %d: size for partition '%d' is zero.\n", 1167 name, current_line_number, partition); 1168 break; 1169 } 1170 1171 dos(partp->dp_start, partp->dp_size, 1172 &partp->dp_scyl, &partp->dp_ssect, &partp->dp_shd); 1173 dos(partp->dp_start+partp->dp_size - 1, partp->dp_size, 1174 &partp->dp_ecyl, &partp->dp_esect, &partp->dp_ehd); 1175 status = 1; 1176 break; 1177 } 1178 return (status); 1179} 1180 1181 1182static int 1183process_active(command) 1184 CMD *command; 1185{ 1186 int status = 0, partition, i; 1187 struct dos_partition *partp; 1188 1189 while (1) 1190 { 1191 active_processed = 1; 1192 if (command->n_args != 1) 1193 { 1194 fprintf(stderr, 1195 "%s: ERROR line %d: incorrect number of active args\n", 1196 name, current_line_number); 1197 status = 0; 1198 break; 1199 } 1200 partition = command->args[0].arg_val; 1201 if (partition < 1 || partition > 4) 1202 { 1203 fprintf(stderr, "%s: ERROR line %d: invalid partition number %d\n", 1204 name, current_line_number, partition); 1205 break; 1206 } 1207 /* 1208 * Reset active partition 1209 */ 1210 partp = ((struct dos_partition *) &mboot.parts); 1211 for (i = 0; i < NDOSPART; i++) 1212 partp[i].dp_flag = 0; 1213 partp[partition-1].dp_flag = ACTIVE; 1214 1215 status = 1; 1216 break; 1217 } 1218 return (status); 1219} 1220 1221 1222static int 1223process_line(line) 1224 char *line; 1225{ 1226 CMD command; 1227 int status = 1; 1228 1229 while (1) 1230 { 1231 parse_config_line(line, &command); 1232 switch (command.cmd) 1233 { 1234 case 0: 1235 /* 1236 * Comment or blank line 1237 */ 1238 break; 1239 case 'g': 1240 /* 1241 * Set geometry 1242 */ 1243 status = process_geometry(&command); 1244 break; 1245 case 'p': 1246 status = process_partition(&command); 1247 break; 1248 case 'a': 1249 status = process_active(&command); 1250 break; 1251 default: 1252 status = 0; 1253 break; 1254 } 1255 break; 1256 } 1257 return (status); 1258} 1259 1260 1261static int 1262read_config(config_file) 1263 char *config_file; 1264{ 1265 FILE *fp = NULL; 1266 int status = 1; 1267 char buf[1010]; 1268 1269 while (1) /* dirty trick used to insure one exit point for this 1270 function */ 1271 { 1272 if (strcmp(config_file, "-") != 0) 1273 { 1274 /* 1275 * We're not reading from stdin 1276 */ 1277 if ((fp = fopen(config_file, "r")) == NULL) 1278 { 1279 status = 0; 1280 break; 1281 } 1282 } 1283 else 1284 { 1285 fp = stdin; 1286 } 1287 current_line_number = 0; 1288 while (!feof(fp)) 1289 { 1290 if (fgets(buf, sizeof(buf), fp) == NULL) 1291 { 1292 break; 1293 } 1294 ++current_line_number; 1295 status = process_line(buf); 1296 if (status == 0) 1297 { 1298 break; 1299 } 1300 } 1301 break; 1302 } 1303 if (fp) 1304 { 1305 /* 1306 * It doesn't matter if we're reading from stdin, as we've reached EOF 1307 */ 1308 fclose(fp); 1309 } 1310 return (status); 1311} 1312 1313 1314static void 1315reset_boot(void) 1316{ 1317 int i; 1318 struct dos_partition *partp; 1319 1320 init_boot(); 1321 for (i = 0; i < 4; ++i) 1322 { 1323 partp = ((struct dos_partition *) &mboot.parts) + i; 1324 bzero((char *)partp, sizeof (struct dos_partition)); 1325 } 1326} 1327