fdisk.c revision 104272
18871Srgrimes/* 24Srgrimes * Mach Operating System 34Srgrimes * Copyright (c) 1992 Carnegie Mellon University 44Srgrimes * All Rights Reserved. 58871Srgrimes * 64Srgrimes * Permission to use, copy, modify and distribute this software and its 74Srgrimes * documentation is hereby granted, provided that both the copyright 84Srgrimes * notice and this permission notice appear in all copies of the 94Srgrimes * software, derivative works or modified versions, and any portions 104Srgrimes * thereof, and that both notices appear in supporting documentation. 118871Srgrimes * 124Srgrimes * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 134Srgrimes * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 144Srgrimes * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 158871Srgrimes * 164Srgrimes * Carnegie Mellon requests users of this software to return to 178871Srgrimes * 184Srgrimes * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 194Srgrimes * School of Computer Science 204Srgrimes * Carnegie Mellon University 214Srgrimes * Pittsburgh PA 15213-3890 228871Srgrimes * 234Srgrimes * any improvements or extensions that they make and grant Carnegie Mellon 244Srgrimes * the rights to redistribute these changes. 254Srgrimes */ 264Srgrimes 2737415Scharnier#ifndef lint 2837415Scharnierstatic const char rcsid[] = 2950476Speter "$FreeBSD: head/sbin/fdisk/fdisk.c 104272 2002-10-01 07:24:55Z phk $"; 3037415Scharnier#endif /* not lint */ 3137415Scharnier 32103348Sphk#include <sys/disk.h> 334Srgrimes#include <sys/disklabel.h> 34104272Sphk#include <sys/diskmbr.h> 3579681Sjoerg#include <sys/param.h> 3637415Scharnier#include <sys/stat.h> 3779681Sjoerg#include <sys/mount.h> 3837415Scharnier#include <ctype.h> 3937415Scharnier#include <fcntl.h> 4037415Scharnier#include <err.h> 4137415Scharnier#include <errno.h> 4279681Sjoerg#include <paths.h> 4379681Sjoerg#include <regex.h> 44100202Sbde#include <stdint.h> 454Srgrimes#include <stdio.h> 4637415Scharnier#include <stdlib.h> 4716561Salex#include <string.h> 4816561Salex#include <unistd.h> 494Srgrimes 504Srgrimesint iotest; 514Srgrimes 524Srgrimes#define LBUF 100 534Srgrimesstatic char lbuf[LBUF]; 544Srgrimes 5563027Sjhb#define MBRSIGOFF 510 5663027Sjhb 574Srgrimes/* 584Srgrimes * 594Srgrimes * Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992 604Srgrimes * 614Srgrimes * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University 624Srgrimes * Copyright (c) 1989 Robert. V. Baron 634Srgrimes * Created. 644Srgrimes */ 654Srgrimes 664Srgrimes#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp 674Srgrimes 684Srgrimes#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs) 694Srgrimes 7020061Ssos#define MAX_SEC_SIZE 2048 /* maximum section size that is supported */ 7120061Ssos#define MIN_SEC_SIZE 512 /* the sector size to start sensing at */ 7293394Sphkstatic int secsize = 0; /* the sensed sector size */ 734Srgrimes 7493394Sphkstatic char *disk; 7510514Sjoerg 7693394Sphkstatic struct disklabel disklabel; /* disk parameters */ 774Srgrimes 7893394Sphkstatic int cyls, sectors, heads, cylsecs, disksecs; 794Srgrimes 8093394Sphkstruct mboot { 8137415Scharnier unsigned char padding[2]; /* force the longs to be long aligned */ 8263027Sjhb unsigned char *bootinst; /* boot code */ 8363027Sjhb off_t bootinst_size; 844Srgrimes struct dos_partition parts[4]; 854Srgrimes}; 864Srgrimes 8793394Sphkstatic struct mboot mboot; 8893394Sphkstatic int fd; 8993394Sphk 904Srgrimes#define ACTIVE 0x80 914Srgrimes#define BOOT_MAGIC 0xAA55 924Srgrimes 9393394Sphkstatic uint dos_cyls; 9493394Sphkstatic uint dos_heads; 9593394Sphkstatic uint dos_sectors; 9693394Sphkstatic uint dos_cylsecs; 974Srgrimes 984Srgrimes#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0)) 994Srgrimes#define DOSCYL(c) (c & 0xff) 1004Srgrimes 10119459Sjkh#define MAX_ARGS 10 10219459Sjkh 10319459Sjkhstatic int current_line_number; 10419459Sjkh 10519459Sjkhstatic int geom_processed = 0; 10619459Sjkhstatic int part_processed = 0; 10719459Sjkhstatic int active_processed = 0; 10819459Sjkh 10919459Sjkhtypedef struct cmd { 11019459Sjkh char cmd; 11119459Sjkh int n_args; 11219459Sjkh struct arg { 11319459Sjkh char argtype; 11419459Sjkh int arg_val; 11519459Sjkh } args[MAX_ARGS]; 11619459Sjkh} CMD; 11719459Sjkh 11848282Srnordierstatic int B_flag = 0; /* replace boot code */ 11957896Simpstatic int I_flag = 0; /* use entire disk for FreeBSD */ 1204Srgrimesstatic int a_flag = 0; /* set active partition */ 12148282Srnordierstatic char *b_flag = NULL; /* path to boot code */ 1224Srgrimesstatic int i_flag = 0; /* replace partition data */ 1234Srgrimesstatic int u_flag = 0; /* update partition data */ 12457896Simpstatic int s_flag = 0; /* Print a summary and exit */ 12595002Strhodesstatic int t_flag = 0; /* test only */ 12619459Sjkhstatic char *f_flag = NULL; /* Read config info from file */ 12719459Sjkhstatic int v_flag = 0; /* Be verbose */ 1284Srgrimes 12993394Sphkstatic struct part_type 1304Srgrimes{ 1314Srgrimes unsigned char type; 13293394Sphk const char *name; 13393394Sphk} part_types[] = { 1348871Srgrimes {0x00, "unused"} 1358871Srgrimes ,{0x01, "Primary DOS with 12 bit FAT"} 136102231Strhodes ,{0x02, "XENIX / file system"} 137102231Strhodes ,{0x03, "XENIX /usr file system"} 13890866Sjoe ,{0x04, "Primary DOS with 16 bit FAT (< 32MB)"} 1398871Srgrimes ,{0x05, "Extended DOS"} 14090866Sjoe ,{0x06, "Primary 'big' DOS (>= 32MB)"} 14161461Sghelmer ,{0x07, "OS/2 HPFS, NTFS, QNX-2 (16 bit) or Advanced UNIX"} 142102231Strhodes ,{0x08, "AIX file system or SplitDrive"} 1438871Srgrimes ,{0x09, "AIX boot partition or Coherent"} 14490866Sjoe ,{0x0A, "OS/2 Boot Manager, OPUS or Coherent swap"} 14534582Sache ,{0x0B, "DOS or Windows 95 with 32 bit FAT"} 14690866Sjoe ,{0x0C, "DOS or Windows 95 with 32 bit FAT (LBA)"} 14790866Sjoe ,{0x0E, "Primary 'big' DOS (>= 32MB, LBA)"} 14890866Sjoe ,{0x0F, "Extended DOS (LBA)"} 1498871Srgrimes ,{0x10, "OPUS"} 15090866Sjoe ,{0x11, "OS/2 BM: hidden DOS with 12-bit FAT"} 15190866Sjoe ,{0x12, "Compaq diagnostics"} 15290866Sjoe ,{0x14, "OS/2 BM: hidden DOS with 16-bit FAT (< 32MB)"} 15390866Sjoe ,{0x16, "OS/2 BM: hidden DOS with 16-bit FAT (>= 32MB)"} 15490866Sjoe ,{0x17, "OS/2 BM: hidden IFS (e.g. HPFS)"} 15590866Sjoe ,{0x18, "AST Windows swapfile"} 15690866Sjoe ,{0x24, "NEC DOS"} 15790866Sjoe ,{0x3C, "PartitionMagic recovery"} 15861568Sbrian ,{0x39, "plan9"} 1598871Srgrimes ,{0x40, "VENIX 286"} 16090866Sjoe ,{0x41, "Linux/MINIX (sharing disk with DRDOS)"} 16190866Sjoe ,{0x42, "SFS or Linux swap (sharing disk with DRDOS)"} 16290866Sjoe ,{0x43, "Linux native (sharing disk with DRDOS)"} 16361461Sghelmer ,{0x4D, "QNX 4.2 Primary"} 16461461Sghelmer ,{0x4E, "QNX 4.2 Secondary"} 16561461Sghelmer ,{0x4F, "QNX 4.2 Tertiary"} 16690866Sjoe ,{0x50, "DM (disk manager)"} 16790866Sjoe ,{0x51, "DM6 Aux1 (or Novell)"} 1688871Srgrimes ,{0x52, "CP/M or Microport SysV/AT"} 16990866Sjoe ,{0x53, "DM6 Aux3"} 17090866Sjoe ,{0x54, "DM6"} 17190866Sjoe ,{0x55, "EZ-Drive (disk manager)"} 17290866Sjoe ,{0x56, "Golden Bow (disk manager)"} 17390866Sjoe ,{0x5c, "Priam Edisk (disk manager)"} /* according to S. Widlake */ 17490866Sjoe ,{0x61, "SpeedStor"} 17590866Sjoe ,{0x63, "System V/386 (such as ISC UNIX), GNU HURD or Mach"} 17690866Sjoe ,{0x64, "Novell Netware/286 2.xx"} 17790866Sjoe ,{0x65, "Novell Netware/386 3.xx"} 17890866Sjoe ,{0x70, "DiskSecure Multi-Boot"} 1798871Srgrimes ,{0x75, "PCIX"} 18090866Sjoe ,{0x77, "QNX4.x"} 18190866Sjoe ,{0x78, "QNX4.x 2nd part"} 18290866Sjoe ,{0x79, "QNX4.x 3rd part"} 18390866Sjoe ,{0x80, "Minix until 1.4a"} 18493394Sphk ,{0x81, "Minix since 1.4b, early Linux partition or Mitac disk manager"} 18539377Sobrien ,{0x82, "Linux swap or Solaris x86"} 18690866Sjoe ,{0x83, "Linux native"} 18790866Sjoe ,{0x84, "OS/2 hidden C: drive"} 18890866Sjoe ,{0x85, "Linux extended"} 18990866Sjoe ,{0x86, "NTFS volume set??"} 19090866Sjoe ,{0x87, "NTFS volume set??"} 191102231Strhodes ,{0x93, "Amoeba file system"} 1928871Srgrimes ,{0x94, "Amoeba bad block table"} 19340946Sjkoshy ,{0x9F, "BSD/OS"} 19464316Sjoe ,{0xA0, "Suspend to Disk"} 1958871Srgrimes ,{0xA5, "FreeBSD/NetBSD/386BSD"} 19625378Simp ,{0xA6, "OpenBSD"} 19790866Sjoe ,{0xA7, "NeXTSTEP"} 19840947Salex ,{0xA9, "NetBSD"} 19995602Sgrog ,{0xAC, "IBM JFS"} 200102231Strhodes ,{0xB7, "BSDI BSD/386 file system"} 2018871Srgrimes ,{0xB8, "BSDI BSD/386 swap"} 20290866Sjoe ,{0xC1, "DRDOS/sec with 12-bit FAT"} 20390866Sjoe ,{0xC4, "DRDOS/sec with 16-bit FAT (< 32MB)"} 20490866Sjoe ,{0xC6, "DRDOS/sec with 16-bit FAT (>= 32MB)"} 20590866Sjoe ,{0xC7, "Syrinx"} 20690866Sjoe ,{0xDB, "CP/M, Concurrent CP/M, Concurrent DOS or CTOS"} 20790866Sjoe ,{0xE1, "DOS access or SpeedStor with 12-bit FAT extended partition"} 20890866Sjoe ,{0xE3, "DOS R/O or SpeedStor"} 20990866Sjoe ,{0xE4, "SpeedStor with 16-bit FAT extended partition < 1024 cyl."} 210102231Strhodes ,{0xEB, "BeOS file system"} 21184964Speter ,{0xEE, "EFI GPT"} 21285027Sbde ,{0xEF, "EFI System Partition"} 21390866Sjoe ,{0xF1, "SpeedStor"} 2148871Srgrimes ,{0xF2, "DOS 3.3+ Secondary"} 21590866Sjoe ,{0xF4, "SpeedStor large partition"} 21690866Sjoe ,{0xFE, "SpeedStor >1024 cyl. or LANstep"} 21790866Sjoe ,{0xFF, "Xenix bad blocks table"} 2184Srgrimes}; 2194Srgrimes 22016561Salexstatic void print_s0(int which); 22116561Salexstatic void print_part(int i); 22216561Salexstatic void init_sector0(unsigned long start); 22319459Sjkhstatic void init_boot(void); 22416561Salexstatic void change_part(int i); 22593394Sphkstatic void print_params(void); 22616561Salexstatic void change_active(int which); 22793394Sphkstatic void change_code(void); 22893394Sphkstatic void get_params_to_use(void); 22979681Sjoergstatic char *get_rootdisk(void); 23081164Siedowsestatic void dos(struct dos_partition *partp); 23193394Sphkstatic int open_disk(int flag); 23216561Salexstatic ssize_t read_disk(off_t sector, void *buf); 23316561Salexstatic ssize_t write_disk(off_t sector, void *buf); 23493394Sphkstatic int get_params(void); 23593394Sphkstatic int read_s0(void); 23693394Sphkstatic int write_s0(void); 23793394Sphkstatic int ok(const char *str); 23893394Sphkstatic int decimal(const char *str, int *num, int deflt); 23993394Sphkstatic const char *get_type(int type); 24019459Sjkhstatic int read_config(char *config_file); 24119459Sjkhstatic void reset_boot(void); 24265054Sjhbstatic int sanitize_partition(struct dos_partition *); 24337415Scharnierstatic void usage(void); 2444Srgrimes 24516561Salexint 24616561Salexmain(int argc, char *argv[]) 2474Srgrimes{ 24879681Sjoerg struct stat sb; 24948282Srnordier int c, i; 25093394Sphk int partition = -1; 25193394Sphk struct dos_partition *partp; 2524Srgrimes 25357896Simp while ((c = getopt(argc, argv, "BIab:f:istuv1234")) != -1) 25448282Srnordier switch (c) { 25548282Srnordier case 'B': 25648282Srnordier B_flag = 1; 2574Srgrimes break; 25857896Simp case 'I': 25957896Simp I_flag = 1; 26057896Simp break; 26148282Srnordier case 'a': 26248282Srnordier a_flag = 1; 26348282Srnordier break; 26448282Srnordier case 'b': 26548282Srnordier b_flag = optarg; 26648282Srnordier break; 26748282Srnordier case 'f': 26848282Srnordier f_flag = optarg; 26948282Srnordier break; 27048282Srnordier case 'i': 27148282Srnordier i_flag = 1; 27248282Srnordier break; 27357896Simp case 's': 27457896Simp s_flag = 1; 27557896Simp break; 27648282Srnordier case 't': 27748282Srnordier t_flag = 1; 27848282Srnordier break; 27948282Srnordier case 'u': 28048282Srnordier u_flag = 1; 28148282Srnordier break; 28248282Srnordier case 'v': 28348282Srnordier v_flag = 1; 28448282Srnordier break; 28548282Srnordier case '1': 28648282Srnordier case '2': 28748282Srnordier case '3': 28848282Srnordier case '4': 28948282Srnordier partition = c - '0'; 29048282Srnordier break; 29148282Srnordier default: 29248282Srnordier usage(); 2934Srgrimes } 29448282Srnordier if (f_flag || i_flag) 29548282Srnordier u_flag = 1; 29648282Srnordier if (t_flag) 29748282Srnordier v_flag = 1; 29848282Srnordier argc -= optind; 29948282Srnordier argv += optind; 3004Srgrimes 30179681Sjoerg if (argc == 0) { 30279681Sjoerg disk = get_rootdisk(); 30379681Sjoerg } else { 30479681Sjoerg if (stat(argv[0], &sb) == 0) { 30579681Sjoerg /* OK, full pathname given */ 30610514Sjoerg disk = argv[0]; 30779681Sjoerg } else if (errno == ENOENT) { 30879681Sjoerg /* Try prepending "/dev" */ 30993394Sphk asprintf(&disk, "%s%s", _PATH_DEV, argv[0]); 31093394Sphk if (disk == NULL) 31179681Sjoerg errx(1, "out of memory"); 31279681Sjoerg } else { 31379681Sjoerg /* other stat error, let it fail below */ 31479681Sjoerg disk = argv[0]; 31510514Sjoerg } 31610514Sjoerg } 31779681Sjoerg if (open_disk(u_flag) < 0) 31879681Sjoerg err(1, "cannot open disk %s", disk); 3194Srgrimes 32063027Sjhb /* (abu)use mboot.bootinst to probe for the sector size */ 32163027Sjhb if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL) 32263027Sjhb err(1, "cannot allocate buffer to determine disk sector size"); 32363027Sjhb read_disk(0, mboot.bootinst); 32463329Sjhb free(mboot.bootinst); 32563329Sjhb mboot.bootinst = NULL; 32663027Sjhb 32793394Sphk if (s_flag) { 32857896Simp if (read_s0()) 32957896Simp err(1, "read_s0"); 33057896Simp printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads, 33157896Simp dos_sectors); 33257896Simp printf("Part %11s %11s Type Flags\n", "Start", "Size"); 33357896Simp for (i = 0; i < NDOSPART; i++) { 33457896Simp partp = ((struct dos_partition *) &mboot.parts) + i; 33557896Simp if (partp->dp_start == 0 && partp->dp_size == 0) 33657896Simp continue; 33757896Simp printf("%4d: %11lu %11lu 0x%02x 0x%02x\n", i + 1, 33857896Simp (u_long) partp->dp_start, 33957896Simp (u_long) partp->dp_size, partp->dp_typ, 34057896Simp partp->dp_flag); 34157896Simp } 34257896Simp exit(0); 34357896Simp } 34457896Simp 3454Srgrimes printf("******* Working on device %s *******\n",disk); 34619459Sjkh 34793394Sphk if (I_flag) { 34850215Sphk read_s0(); 34950215Sphk reset_boot(); 35050215Sphk partp = (struct dos_partition *) (&mboot.parts[0]); 35150215Sphk partp->dp_typ = DOSPTYP_386BSD; 35250215Sphk partp->dp_flag = ACTIVE; 35350215Sphk partp->dp_start = dos_sectors; 35465054Sjhb partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - 35565054Sjhb dos_sectors; 35681164Siedowse dos(partp); 35750215Sphk if (v_flag) 35850215Sphk print_s0(-1); 35995002Strhodes if (!t_flag) 36095002Strhodes write_s0(); 36150215Sphk exit(0); 36250215Sphk } 36393394Sphk if (f_flag) { 36419459Sjkh if (read_s0() || i_flag) 36519459Sjkh reset_boot(); 36619459Sjkh if (!read_config(f_flag)) 36719459Sjkh exit(1); 36819459Sjkh if (v_flag) 36919459Sjkh print_s0(-1); 37019459Sjkh if (!t_flag) 37119459Sjkh write_s0(); 37293394Sphk } else { 37319459Sjkh if(u_flag) 37419459Sjkh get_params_to_use(); 37519459Sjkh else 3764Srgrimes print_params(); 3774Srgrimes 37819459Sjkh if (read_s0()) 37965054Sjhb init_sector0(dos_sectors); 3804Srgrimes 38120061Ssos printf("Media sector size is %d\n", secsize); 38219459Sjkh printf("Warning: BIOS sector numbering starts with sector 1\n"); 38319459Sjkh printf("Information from DOS bootblock is:\n"); 38419459Sjkh if (partition == -1) 38526421Sbrian for (i = 1; i <= NDOSPART; i++) 38619459Sjkh change_part(i); 38719459Sjkh else 3884Srgrimes change_part(partition); 3894Srgrimes 39019459Sjkh if (u_flag || a_flag) 3914Srgrimes change_active(partition); 3924Srgrimes 39348282Srnordier if (B_flag) 39443054Srnordier change_code(); 39543054Srnordier 39648282Srnordier if (u_flag || a_flag || B_flag) { 39795002Strhodes if (!t_flag) { 39819459Sjkh printf("\nWe haven't changed the partition table yet. "); 39919459Sjkh printf("This is your last chance.\n"); 40019459Sjkh } 4014Srgrimes print_s0(-1); 40295002Strhodes if (!t_flag) { 40319459Sjkh if (ok("Should we write new partition table?")) 4044Srgrimes write_s0(); 40593394Sphk } else { 40619459Sjkh printf("\n-t flag specified -- partition table not written.\n"); 40719459Sjkh } 40819459Sjkh } 4094Srgrimes } 4104Srgrimes 4114Srgrimes exit(0); 41237415Scharnier} 4134Srgrimes 41437415Scharnierstatic void 41537415Scharnierusage() 41637415Scharnier{ 41748282Srnordier fprintf(stderr, "%s%s", 41862178Sjhb "usage: fdisk [-BIaistu] [-b bootcode] [-1234] [disk]\n", 41948282Srnordier " fdisk -f configfile [-itv] [disk]\n"); 42037415Scharnier exit(1); 4214Srgrimes} 4224Srgrimes 42316561Salexstatic void 42416561Salexprint_s0(int which) 4254Srgrimes{ 42693394Sphk int i; 4274Srgrimes 4284Srgrimes print_params(); 4294Srgrimes printf("Information from DOS bootblock is:\n"); 4304Srgrimes if (which == -1) 43126421Sbrian for (i = 1; i <= NDOSPART; i++) 4324Srgrimes printf("%d: ", i), print_part(i); 4334Srgrimes else 4344Srgrimes print_part(which); 4354Srgrimes} 4364Srgrimes 43793394Sphkstatic struct dos_partition mtpart; 4384Srgrimes 43916561Salexstatic void 44016561Salexprint_part(int i) 4414Srgrimes{ 44226389Sgibbs struct dos_partition *partp; 44326389Sgibbs u_int64_t part_mb; 4444Srgrimes 44526421Sbrian partp = ((struct dos_partition *) &mboot.parts) + i - 1; 4464Srgrimes 4474Srgrimes if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) { 4484Srgrimes printf("<UNUSED>\n"); 4494Srgrimes return; 4504Srgrimes } 45126389Sgibbs /* 45226389Sgibbs * Be careful not to overflow. 45326389Sgibbs */ 45426389Sgibbs part_mb = partp->dp_size; 45526389Sgibbs part_mb *= secsize; 45626389Sgibbs part_mb /= (1024 * 1024); 45790866Sjoe printf("sysid %d (%#04x),(%s)\n", partp->dp_typ, partp->dp_typ, 45890866Sjoe get_type(partp->dp_typ)); 459100202Sbde printf(" start %lu, size %lu (%ju Meg), flag %x%s\n", 46037244Sbde (u_long)partp->dp_start, 46137244Sbde (u_long)partp->dp_size, 462100202Sbde (uintmax_t)part_mb, 46334952Sobrien partp->dp_flag, 46434952Sobrien partp->dp_flag == ACTIVE ? " (active)" : ""); 46569371Sobrien printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n" 4664Srgrimes ,DPCYL(partp->dp_scyl, partp->dp_ssect) 46769371Sobrien ,partp->dp_shd 4684Srgrimes ,DPSECT(partp->dp_ssect) 4694Srgrimes ,DPCYL(partp->dp_ecyl, partp->dp_esect) 47069371Sobrien ,partp->dp_ehd 47169371Sobrien ,DPSECT(partp->dp_esect)); 4724Srgrimes} 4734Srgrimes 47419459Sjkh 47516561Salexstatic void 47619459Sjkhinit_boot(void) 47719459Sjkh{ 47895860Speter#ifndef __ia64__ 47948282Srnordier const char *fname; 48093394Sphk int fdesc, n; 48163027Sjhb struct stat sb; 48248282Srnordier 48348282Srnordier fname = b_flag ? b_flag : "/boot/mbr"; 48493394Sphk if ((fdesc = open(fname, O_RDONLY)) == -1 || 48593394Sphk fstat(fdesc, &sb) == -1) 48663027Sjhb err(1, "%s", fname); 48763027Sjhb if ((mboot.bootinst_size = sb.st_size) % secsize != 0) 48863027Sjhb errx(1, "%s: length must be a multiple of sector size", fname); 48963218Sache if (mboot.bootinst != NULL) 49063218Sache free(mboot.bootinst); 49163027Sjhb if ((mboot.bootinst = malloc(mboot.bootinst_size = sb.st_size)) == NULL) 49263027Sjhb errx(1, "%s: unable to allocate read buffer", fname); 49393394Sphk if ((n = read(fdesc, mboot.bootinst, mboot.bootinst_size)) == -1 || 49493394Sphk close(fdesc)) 49548282Srnordier err(1, "%s", fname); 49663027Sjhb if (n != mboot.bootinst_size) 49763027Sjhb errx(1, "%s: short read", fname); 49895860Speter#else 49995860Speter if (mboot.bootinst != NULL) 50095860Speter free(mboot.bootinst); 50195860Speter mboot.bootinst_size = secsize; 50295860Speter if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) 50395860Speter errx(1, "unable to allocate boot block buffer"); 50495860Speter memset(mboot.bootinst, 0, mboot.bootinst_size); 505100202Sbde *(uint16_t *)(void *)&mboot.bootinst[MBRSIGOFF] = BOOT_MAGIC; 50695860Speter#endif 50719459Sjkh} 50819459Sjkh 50919459Sjkh 51019459Sjkhstatic void 51116561Salexinit_sector0(unsigned long start) 5124Srgrimes{ 51393394Sphk struct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]); 5144Srgrimes 51519459Sjkh init_boot(); 5164Srgrimes 5174Srgrimes partp->dp_typ = DOSPTYP_386BSD; 5184Srgrimes partp->dp_flag = ACTIVE; 51965054Sjhb start = ((start + dos_sectors - 1) / dos_sectors) * dos_sectors; 52063027Sjhb if(start == 0) 52163027Sjhb start = dos_sectors; 5224Srgrimes partp->dp_start = start; 52365054Sjhb partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - start; 5244Srgrimes 52581164Siedowse dos(partp); 5264Srgrimes} 5274Srgrimes 52816561Salexstatic void 52916561Salexchange_part(int i) 5304Srgrimes{ 53193394Sphk struct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1; 5324Srgrimes 5334Srgrimes printf("The data for partition %d is:\n", i); 5344Srgrimes print_part(i); 5354Srgrimes 5364Srgrimes if (u_flag && ok("Do you want to change it?")) { 5374Srgrimes int tmp; 5384Srgrimes 5394Srgrimes if (i_flag) { 5404Srgrimes bzero((char *)partp, sizeof (struct dos_partition)); 54126421Sbrian if (i == 4) { 5424Srgrimes init_sector0(1); 54326421Sbrian printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n"); 5444Srgrimes print_part(i); 5454Srgrimes } 5464Srgrimes } 5474Srgrimes 5484Srgrimes do { 54934952Sobrien Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp); 5504Srgrimes Decimal("start", partp->dp_start, tmp); 5514Srgrimes Decimal("size", partp->dp_size, tmp); 55281164Siedowse if (!sanitize_partition(partp)) { 55381164Siedowse warnx("ERROR: failed to adjust; setting sysid to 0"); 55481164Siedowse partp->dp_typ = 0; 55581164Siedowse } 5564Srgrimes 55736262Sjraynard if (ok("Explicitly specify beg/end address ?")) 5584Srgrimes { 5594Srgrimes int tsec,tcyl,thd; 5604Srgrimes tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect); 5614Srgrimes thd = partp->dp_shd; 5624Srgrimes tsec = DPSECT(partp->dp_ssect); 5634Srgrimes Decimal("beginning cylinder", tcyl, tmp); 56469371Sobrien Decimal("beginning head", thd, tmp); 56568871Sobrien Decimal("beginning sector", tsec, tmp); 5664Srgrimes partp->dp_scyl = DOSCYL(tcyl); 5674Srgrimes partp->dp_ssect = DOSSECT(tsec,tcyl); 5684Srgrimes partp->dp_shd = thd; 5694Srgrimes 5704Srgrimes tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect); 5714Srgrimes thd = partp->dp_ehd; 5724Srgrimes tsec = DPSECT(partp->dp_esect); 5734Srgrimes Decimal("ending cylinder", tcyl, tmp); 57469371Sobrien Decimal("ending head", thd, tmp); 57568871Sobrien Decimal("ending sector", tsec, tmp); 5764Srgrimes partp->dp_ecyl = DOSCYL(tcyl); 5774Srgrimes partp->dp_esect = DOSSECT(tsec,tcyl); 5784Srgrimes partp->dp_ehd = thd; 57981164Siedowse } else 58081164Siedowse dos(partp); 5818871Srgrimes 5824Srgrimes print_part(i); 5834Srgrimes } while (!ok("Are we happy with this entry?")); 5844Srgrimes } 58593394Sphk } 5864Srgrimes 58716561Salexstatic void 5884Srgrimesprint_params() 5894Srgrimes{ 5904Srgrimes printf("parameters extracted from in-core disklabel are:\n"); 5914Srgrimes printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 5924Srgrimes ,cyls,heads,sectors,cylsecs); 5934Srgrimes if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255)) 59420061Ssos printf("Figures below won't work with BIOS for partitions not in cyl 1\n"); 5954Srgrimes printf("parameters to be used for BIOS calculations are:\n"); 5964Srgrimes printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 5974Srgrimes ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); 5984Srgrimes} 5994Srgrimes 60016561Salexstatic void 60116561Salexchange_active(int which) 6024Srgrimes{ 60381164Siedowse struct dos_partition *partp = &mboot.parts[0]; 60481164Siedowse int active, i, new, tmp; 6054Srgrimes 60681164Siedowse active = -1; 60781164Siedowse for (i = 0; i < NDOSPART; i++) { 60881164Siedowse if ((partp[i].dp_flag & ACTIVE) == 0) 60981164Siedowse continue; 61081164Siedowse printf("Partition %d is marked active\n", i + 1); 61181164Siedowse if (active == -1) 61281164Siedowse active = i + 1; 61381164Siedowse } 6144Srgrimes if (a_flag && which != -1) 6154Srgrimes active = which; 61681164Siedowse else if (active == -1) 61781164Siedowse active = 1; 61881164Siedowse 6193723Sbde if (!ok("Do you want to change the active partition?")) 6203723Sbde return; 62134952Sobriensetactive: 62234952Sobrien do { 62381164Siedowse new = active; 62481164Siedowse Decimal("active partition", new, tmp); 62581164Siedowse if (new < 1 || new > 4) { 62634952Sobrien printf("Active partition number must be in range 1-4." 62734952Sobrien " Try again.\n"); 62834952Sobrien goto setactive; 62934952Sobrien } 63081164Siedowse active = new; 63134952Sobrien } while (!ok("Are you happy with this choice")); 6324Srgrimes for (i = 0; i < NDOSPART; i++) 6334Srgrimes partp[i].dp_flag = 0; 63426421Sbrian if (active > 0 && active <= NDOSPART) 63526421Sbrian partp[active-1].dp_flag = ACTIVE; 6364Srgrimes} 6374Srgrimes 63843054Srnordierstatic void 63943054Srnordierchange_code() 64043054Srnordier{ 64143054Srnordier if (ok("Do you want to change the boot code?")) 64243054Srnordier init_boot(); 64343054Srnordier} 64443054Srnordier 64516561Salexvoid 6464Srgrimesget_params_to_use() 6474Srgrimes{ 6484Srgrimes int tmp; 6494Srgrimes print_params(); 6504Srgrimes if (ok("Do you want to change our idea of what BIOS thinks ?")) 6514Srgrimes { 6524Srgrimes do 6534Srgrimes { 6544Srgrimes Decimal("BIOS's idea of #cylinders", dos_cyls, tmp); 6554Srgrimes Decimal("BIOS's idea of #heads", dos_heads, tmp); 6564Srgrimes Decimal("BIOS's idea of #sectors", dos_sectors, tmp); 6574Srgrimes dos_cylsecs = dos_heads * dos_sectors; 6584Srgrimes print_params(); 6594Srgrimes } 6604Srgrimes while(!ok("Are you happy with this choice")); 6614Srgrimes } 6624Srgrimes} 6634Srgrimes 66419459Sjkh 6654Srgrimes/***********************************************\ 6664Srgrimes* Change real numbers into strange dos numbers * 6674Srgrimes\***********************************************/ 66816561Salexstatic void 66993394Sphkdos(struct dos_partition *partp) 6704Srgrimes{ 67181164Siedowse int cy, sec; 67281164Siedowse u_int32_t end; 6734Srgrimes 67488714Siedowse if (partp->dp_typ == 0 && partp->dp_start == 0 && partp->dp_size == 0) { 67588714Siedowse memcpy(partp, &mtpart, sizeof(*partp)); 6763723Sbde return; 6773723Sbde } 6783723Sbde 67981164Siedowse /* Start c/h/s. */ 68081164Siedowse partp->dp_shd = partp->dp_start % dos_cylsecs / dos_sectors; 68181164Siedowse cy = partp->dp_start / dos_cylsecs; 68281164Siedowse sec = partp->dp_start % dos_sectors + 1; 68381164Siedowse partp->dp_scyl = DOSCYL(cy); 68481164Siedowse partp->dp_ssect = DOSSECT(sec, cy); 6854Srgrimes 68681164Siedowse /* End c/h/s. */ 68781164Siedowse end = partp->dp_start + partp->dp_size - 1; 68881164Siedowse partp->dp_ehd = end % dos_cylsecs / dos_sectors; 68981164Siedowse cy = end / dos_cylsecs; 69081164Siedowse sec = end % dos_sectors + 1; 69181164Siedowse partp->dp_ecyl = DOSCYL(cy); 69281164Siedowse partp->dp_esect = DOSSECT(sec, cy); 6934Srgrimes} 6944Srgrimes 69516561Salexstatic int 69693394Sphkopen_disk(int flag) 6974Srgrimes{ 69879306Sjoerg struct stat st; 6994Srgrimes 7008871Srgrimes if (stat(disk, &st) == -1) { 70179306Sjoerg if (errno == ENOENT) 70279306Sjoerg return -2; 70337415Scharnier warnx("can't get file status of %s", disk); 7044Srgrimes return -1; 7052810Sbde } 7062810Sbde if ( !(st.st_mode & S_IFCHR) ) 70737415Scharnier warnx("device %s is not character special", disk); 70843054Srnordier if ((fd = open(disk, 70993394Sphk a_flag || I_flag || B_flag || flag ? O_RDWR : O_RDONLY)) == -1) { 71010514Sjoerg if(errno == ENXIO) 71110514Sjoerg return -2; 71237415Scharnier warnx("can't open device %s", disk); 7134Srgrimes return -1; 7144Srgrimes } 71593394Sphk if (get_params() == -1) { 71637415Scharnier warnx("can't get disk parameters on %s", disk); 7174Srgrimes return -1; 7184Srgrimes } 7194Srgrimes return fd; 7204Srgrimes} 7214Srgrimes 72216561Salexstatic ssize_t 72316561Salexread_disk(off_t sector, void *buf) 7244Srgrimes{ 7254Srgrimes lseek(fd,(sector * 512), 0); 72620061Ssos if( secsize == 0 ) 72720061Ssos for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 ) 72820061Ssos { 72920061Ssos /* try the read */ 73020061Ssos int size = read(fd, buf, secsize); 73120061Ssos if( size == secsize ) 73220061Ssos /* it worked so return */ 73320061Ssos return secsize; 73420061Ssos } 73520061Ssos else 73620061Ssos return read( fd, buf, secsize ); 73720061Ssos 73820061Ssos /* we failed to read at any of the sizes */ 73920061Ssos return -1; 7404Srgrimes} 7414Srgrimes 74216561Salexstatic ssize_t 74316561Salexwrite_disk(off_t sector, void *buf) 7444Srgrimes{ 7454Srgrimes lseek(fd,(sector * 512), 0); 74620061Ssos /* write out in the size that the read_disk found worked */ 74720061Ssos return write(fd, buf, secsize); 7484Srgrimes} 7494Srgrimes 75016561Salexstatic int 75116561Salexget_params() 7524Srgrimes{ 753103665Sphk int error; 754103665Sphk u_int u; 755103665Sphk off_t o; 7564Srgrimes 757103665Sphk if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 758103665Sphk warnx("can't get disk parameters on %s; supplying dummy ones", disk); 759103665Sphk dos_cyls = cyls = 1; 760103665Sphk dos_heads = heads = 1; 761103665Sphk dos_sectors = sectors = 1; 762103665Sphk dos_cylsecs = cylsecs = heads * sectors; 763103665Sphk disksecs = cyls * heads * sectors; 764103665Sphk } else { 765103665Sphk dos_cyls = cyls = disklabel.d_ncylinders; 766103665Sphk dos_heads = heads = disklabel.d_ntracks; 767103665Sphk dos_sectors = sectors = disklabel.d_nsectors; 768103665Sphk } 769103665Sphk error = ioctl(fd, DIOCGFWSECTORS, &u); 770103665Sphk if (error == 0) 771103665Sphk sectors = dos_sectors = u; 772103665Sphk error = ioctl(fd, DIOCGFWHEADS, &u); 773103665Sphk if (error == 0) 774103665Sphk heads = dos_heads = u; 775103665Sphk 7762810Sbde dos_cylsecs = cylsecs = heads * sectors; 7772810Sbde disksecs = cyls * heads * sectors; 7784Srgrimes 779103665Sphk error = ioctl(fd, DIOCGSECTORSIZE, &u); 780103665Sphk if (error != 0) 781103665Sphk u = 512; 7824Srgrimes 783103665Sphk error = ioctl(fd, DIOCGMEDIASIZE, &o); 784103665Sphk if (error == 0) { 785103665Sphk disksecs = o / u; 786103665Sphk cyls = dos_cyls = o / (u * dos_heads * dos_sectors); 787103665Sphk } 788103665Sphk 789103665Sphk 790103665Sphk return (disksecs); 7914Srgrimes} 7924Srgrimes 7934Srgrimes 79416561Salexstatic int 7954Srgrimesread_s0() 7964Srgrimes{ 79763218Sache mboot.bootinst_size = secsize; 79863218Sache if (mboot.bootinst != NULL) 79963027Sjhb free(mboot.bootinst); 80063218Sache if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) { 80163218Sache warnx("unable to allocate buffer to read fdisk " 80263218Sache "partition table"); 80363218Sache return -1; 80463027Sjhb } 80563027Sjhb if (read_disk(0, mboot.bootinst) == -1) { 80637415Scharnier warnx("can't read fdisk partition table"); 8074Srgrimes return -1; 8084Srgrimes } 809100202Sbde if (*(uint16_t *)(void *)&mboot.bootinst[MBRSIGOFF] != BOOT_MAGIC) { 81037415Scharnier warnx("invalid fdisk partition table found"); 8114Srgrimes /* So should we initialize things */ 8124Srgrimes return -1; 8134Srgrimes } 81463027Sjhb memcpy(mboot.parts, &mboot.bootinst[DOSPARTOFF], sizeof(mboot.parts)); 8154Srgrimes return 0; 8164Srgrimes} 8174Srgrimes 81816561Salexstatic int 8194Srgrimeswrite_s0() 8204Srgrimes{ 82163027Sjhb int sector; 82263027Sjhb 8234Srgrimes if (iotest) { 8244Srgrimes print_s0(-1); 8254Srgrimes return 0; 8264Srgrimes } 82763027Sjhb memcpy(&mboot.bootinst[DOSPARTOFF], mboot.parts, sizeof(mboot.parts)); 8284Srgrimes /* 8294Srgrimes * write enable label sector before write (if necessary), 8304Srgrimes * disable after writing. 8314Srgrimes * needed if the disklabel protected area also protects 8324Srgrimes * sector 0. (e.g. empty disk) 8334Srgrimes */ 83463027Sjhb for(sector = 0; sector < mboot.bootinst_size / secsize; sector++) 83563027Sjhb if (write_disk(sector, 83663027Sjhb &mboot.bootinst[sector * secsize]) == -1) { 83763027Sjhb warn("can't write fdisk partition table"); 83863027Sjhb return -1; 83963027Sjhb } 84016561Salex return(0); 8414Srgrimes} 8424Srgrimes 8434Srgrimes 84416561Salexstatic int 84593394Sphkok(const char *str) 8464Srgrimes{ 8474Srgrimes printf("%s [n] ", str); 84881164Siedowse fflush(stdout); 84981164Siedowse if (fgets(lbuf, LBUF, stdin) == NULL) 85081164Siedowse exit(1); 8514Srgrimes lbuf[strlen(lbuf)-1] = 0; 8524Srgrimes 8534Srgrimes if (*lbuf && 8544Srgrimes (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || 8554Srgrimes !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) 8564Srgrimes return 1; 8574Srgrimes else 8584Srgrimes return 0; 8594Srgrimes} 8604Srgrimes 86116561Salexstatic int 86293394Sphkdecimal(const char *str, int *num, int deflt) 8634Srgrimes{ 86493394Sphk int acc = 0, c; 86593394Sphk char *cp; 8664Srgrimes 8674Srgrimes while (1) { 8684Srgrimes printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); 86981164Siedowse fflush(stdout); 87081164Siedowse if (fgets(lbuf, LBUF, stdin) == NULL) 87181164Siedowse exit(1); 8724Srgrimes lbuf[strlen(lbuf)-1] = 0; 8734Srgrimes 8744Srgrimes if (!*lbuf) 8754Srgrimes return 0; 8764Srgrimes 8774Srgrimes cp = lbuf; 8784Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 8794Srgrimes if (!c) 8804Srgrimes return 0; 88116561Salex while ((c = *cp++)) { 8824Srgrimes if (c <= '9' && c >= '0') 8834Srgrimes acc = acc * 10 + c - '0'; 8844Srgrimes else 8854Srgrimes break; 8864Srgrimes } 8874Srgrimes if (c == ' ' || c == '\t') 8884Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 8894Srgrimes if (!c) { 8904Srgrimes *num = acc; 8914Srgrimes return 1; 8924Srgrimes } else 89334952Sobrien printf("%s is an invalid decimal number. Try again.\n", 8944Srgrimes lbuf); 8954Srgrimes } 8964Srgrimes 8974Srgrimes} 8984Srgrimes 89993394Sphkstatic const char * 90016561Salexget_type(int type) 9014Srgrimes{ 9024Srgrimes int numentries = (sizeof(part_types)/sizeof(struct part_type)); 9034Srgrimes int counter = 0; 9044Srgrimes struct part_type *ptr = part_types; 9054Srgrimes 9068871Srgrimes 90793394Sphk while(counter < numentries) { 9084Srgrimes if(ptr->type == type) 9094Srgrimes return(ptr->name); 9104Srgrimes ptr++; 9114Srgrimes counter++; 9124Srgrimes } 9134Srgrimes return("unknown"); 9144Srgrimes} 91519459Sjkh 91619459Sjkh 91719459Sjkhstatic void 91893394Sphkparse_config_line(char *line, CMD *command) 91919459Sjkh{ 92019459Sjkh char *cp, *end; 92119459Sjkh 92219459Sjkh cp = line; 92393394Sphk while (1) { 92419459Sjkh memset(command, 0, sizeof(*command)); 92519459Sjkh 92619459Sjkh while (isspace(*cp)) ++cp; 92719459Sjkh if (*cp == '\0' || *cp == '#') 92819459Sjkh break; 92919459Sjkh command->cmd = *cp++; 93019459Sjkh 93119459Sjkh /* 93219459Sjkh * Parse args 93319459Sjkh */ 93493394Sphk while (1) { 93519459Sjkh while (isspace(*cp)) ++cp; 93619459Sjkh if (*cp == '#') 93719459Sjkh break; /* found comment */ 93819459Sjkh if (isalpha(*cp)) 93919459Sjkh command->args[command->n_args].argtype = *cp++; 94019459Sjkh if (!isdigit(*cp)) 94119459Sjkh break; /* assume end of line */ 94219459Sjkh end = NULL; 94319459Sjkh command->args[command->n_args].arg_val = strtol(cp, &end, 0); 94419459Sjkh if (cp == end) 94519459Sjkh break; /* couldn't parse number */ 94619459Sjkh cp = end; 94719459Sjkh command->n_args++; 94819459Sjkh } 94919459Sjkh break; 95019459Sjkh } 95119459Sjkh} 95219459Sjkh 95319459Sjkh 95419459Sjkhstatic int 95593394Sphkprocess_geometry(CMD *command) 95619459Sjkh{ 95719459Sjkh int status = 1, i; 95819459Sjkh 95993394Sphk while (1) { 96019459Sjkh geom_processed = 1; 96193394Sphk if (part_processed) { 96237415Scharnier warnx( 96337415Scharnier "ERROR line %d: the geometry specification line must occur before\n\ 96437415Scharnier all partition specifications", 96537415Scharnier current_line_number); 96619459Sjkh status = 0; 96719459Sjkh break; 96819459Sjkh } 96993394Sphk if (command->n_args != 3) { 97037415Scharnier warnx("ERROR line %d: incorrect number of geometry args", 97137415Scharnier current_line_number); 97219459Sjkh status = 0; 97319459Sjkh break; 97419459Sjkh } 97593394Sphk dos_cyls = 0; 97693394Sphk dos_heads = 0; 97793394Sphk dos_sectors = 0; 97893394Sphk for (i = 0; i < 3; ++i) { 97993394Sphk switch (command->args[i].argtype) { 98019459Sjkh case 'c': 98119459Sjkh dos_cyls = command->args[i].arg_val; 98219459Sjkh break; 98319459Sjkh case 'h': 98419459Sjkh dos_heads = command->args[i].arg_val; 98519459Sjkh break; 98619459Sjkh case 's': 98719459Sjkh dos_sectors = command->args[i].arg_val; 98819459Sjkh break; 98919459Sjkh default: 99037415Scharnier warnx( 99137415Scharnier "ERROR line %d: unknown geometry arg type: '%c' (0x%02x)", 99237415Scharnier current_line_number, command->args[i].argtype, 99319459Sjkh command->args[i].argtype); 99419459Sjkh status = 0; 99519459Sjkh break; 99619459Sjkh } 99719459Sjkh } 99819459Sjkh if (status == 0) 99919459Sjkh break; 100019459Sjkh 100119459Sjkh dos_cylsecs = dos_heads * dos_sectors; 100219459Sjkh 100319459Sjkh /* 100419459Sjkh * Do sanity checks on parameter values 100519459Sjkh */ 100693394Sphk if (dos_cyls == 0) { 100737415Scharnier warnx("ERROR line %d: number of cylinders not specified", 100837415Scharnier current_line_number); 100919459Sjkh status = 0; 101019459Sjkh } 101193394Sphk if (dos_cyls > 1024) { 101237415Scharnier warnx( 101337415Scharnier "WARNING line %d: number of cylinders (%d) may be out-of-range\n\ 101419459Sjkh (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\ 101537415Scharnier is dedicated to FreeBSD)", 101637415Scharnier current_line_number, dos_cyls); 101719459Sjkh } 101819459Sjkh 101993394Sphk if (dos_heads == 0) { 102037415Scharnier warnx("ERROR line %d: number of heads not specified", 102137415Scharnier current_line_number); 102219459Sjkh status = 0; 102393394Sphk } else if (dos_heads > 256) { 102437415Scharnier warnx("ERROR line %d: number of heads must be within (1-256)", 102537415Scharnier current_line_number); 102619459Sjkh status = 0; 102719459Sjkh } 102819459Sjkh 102993394Sphk if (dos_sectors == 0) { 103037415Scharnier warnx("ERROR line %d: number of sectors not specified", 103137415Scharnier current_line_number); 103219459Sjkh status = 0; 103393394Sphk } else if (dos_sectors > 63) { 103437415Scharnier warnx("ERROR line %d: number of sectors must be within (1-63)", 103537415Scharnier current_line_number); 103619459Sjkh status = 0; 103719459Sjkh } 103819459Sjkh 103919459Sjkh break; 104019459Sjkh } 104119459Sjkh return (status); 104219459Sjkh} 104319459Sjkh 104419459Sjkh 104519459Sjkhstatic int 104693394Sphkprocess_partition(CMD *command) 104719459Sjkh{ 104819459Sjkh int status = 0, partition; 104965054Sjhb u_int32_t prev_head_boundary, prev_cyl_boundary; 105065054Sjhb u_int32_t adj_size, max_end; 105119459Sjkh struct dos_partition *partp; 105219459Sjkh 105393394Sphk while (1) { 105419459Sjkh part_processed = 1; 105593394Sphk if (command->n_args != 4) { 105637415Scharnier warnx("ERROR line %d: incorrect number of partition args", 105737415Scharnier current_line_number); 105819459Sjkh break; 105919459Sjkh } 106019459Sjkh partition = command->args[0].arg_val; 106193394Sphk if (partition < 1 || partition > 4) { 106237415Scharnier warnx("ERROR line %d: invalid partition number %d", 106337415Scharnier current_line_number, partition); 106419459Sjkh break; 106519459Sjkh } 106626421Sbrian partp = ((struct dos_partition *) &mboot.parts) + partition - 1; 106719459Sjkh bzero((char *)partp, sizeof (struct dos_partition)); 106819459Sjkh partp->dp_typ = command->args[1].arg_val; 106919459Sjkh partp->dp_start = command->args[2].arg_val; 107019459Sjkh partp->dp_size = command->args[3].arg_val; 107119459Sjkh max_end = partp->dp_start + partp->dp_size; 107219459Sjkh 107393394Sphk if (partp->dp_typ == 0) { 107419459Sjkh /* 107519459Sjkh * Get out, the partition is marked as unused. 107619459Sjkh */ 107719459Sjkh /* 107819459Sjkh * Insure that it's unused. 107919459Sjkh */ 108019459Sjkh bzero((char *)partp, sizeof (struct dos_partition)); 108119459Sjkh status = 1; 108219459Sjkh break; 108319459Sjkh } 108419459Sjkh 108519459Sjkh /* 108619459Sjkh * Adjust start upwards, if necessary, to fall on an head boundary. 108719459Sjkh */ 108893394Sphk if (partp->dp_start % dos_sectors != 0) { 108965054Sjhb prev_head_boundary = partp->dp_start / dos_sectors * dos_sectors; 109065054Sjhb if (max_end < dos_sectors || 109193394Sphk prev_head_boundary > max_end - dos_sectors) { 109219459Sjkh /* 109319459Sjkh * Can't go past end of partition 109419459Sjkh */ 109537415Scharnier warnx( 109637415Scharnier "ERROR line %d: unable to adjust start of partition %d to fall on\n\ 109765054Sjhb a head boundary", 109837415Scharnier current_line_number, partition); 109919459Sjkh break; 110019459Sjkh } 110137415Scharnier warnx( 110265054Sjhb "WARNING: adjusting start offset of partition %d\n\ 110365054Sjhb from %u to %u, to fall on a head boundary", 110465054Sjhb partition, (u_int)partp->dp_start, 110565054Sjhb (u_int)(prev_head_boundary + dos_sectors)); 110665054Sjhb partp->dp_start = prev_head_boundary + dos_sectors; 110719459Sjkh } 110819459Sjkh 110919459Sjkh /* 111019459Sjkh * Adjust size downwards, if necessary, to fall on a cylinder 111119459Sjkh * boundary. 111219459Sjkh */ 111365054Sjhb prev_cyl_boundary = 111419459Sjkh ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; 111565054Sjhb if (prev_cyl_boundary > partp->dp_start) 111665054Sjhb adj_size = prev_cyl_boundary - partp->dp_start; 111793394Sphk else { 111865054Sjhb warnx( 111965054Sjhb "ERROR: could not adjust partition to start on a head boundary\n\ 112065054Sjhb and end on a cylinder boundary."); 112165054Sjhb return (0); 112265054Sjhb } 112393394Sphk if (adj_size != partp->dp_size) { 112437415Scharnier warnx( 112565054Sjhb "WARNING: adjusting size of partition %d from %u to %u\n\ 112665054Sjhb to end on a cylinder boundary", 112765054Sjhb partition, (u_int)partp->dp_size, (u_int)adj_size); 112865054Sjhb partp->dp_size = adj_size; 112919459Sjkh } 113093394Sphk if (partp->dp_size == 0) { 113181164Siedowse warnx("ERROR line %d: size of partition %d is zero", 113237415Scharnier current_line_number, partition); 113319459Sjkh break; 113419459Sjkh } 113519459Sjkh 113681164Siedowse dos(partp); 113719459Sjkh status = 1; 113819459Sjkh break; 113919459Sjkh } 114019459Sjkh return (status); 114119459Sjkh} 114219459Sjkh 114319459Sjkh 114419459Sjkhstatic int 114593394Sphkprocess_active(CMD *command) 114619459Sjkh{ 114719459Sjkh int status = 0, partition, i; 114819459Sjkh struct dos_partition *partp; 114919459Sjkh 115093394Sphk while (1) { 115119459Sjkh active_processed = 1; 115293394Sphk if (command->n_args != 1) { 115337415Scharnier warnx("ERROR line %d: incorrect number of active args", 115437415Scharnier current_line_number); 115519459Sjkh status = 0; 115619459Sjkh break; 115719459Sjkh } 115819459Sjkh partition = command->args[0].arg_val; 115993394Sphk if (partition < 1 || partition > 4) { 116037415Scharnier warnx("ERROR line %d: invalid partition number %d", 116137415Scharnier current_line_number, partition); 116219459Sjkh break; 116319459Sjkh } 116419459Sjkh /* 116519459Sjkh * Reset active partition 116619459Sjkh */ 116719459Sjkh partp = ((struct dos_partition *) &mboot.parts); 116819459Sjkh for (i = 0; i < NDOSPART; i++) 116919459Sjkh partp[i].dp_flag = 0; 117026421Sbrian partp[partition-1].dp_flag = ACTIVE; 117119459Sjkh 117219459Sjkh status = 1; 117319459Sjkh break; 117419459Sjkh } 117519459Sjkh return (status); 117619459Sjkh} 117719459Sjkh 117819459Sjkh 117919459Sjkhstatic int 118093394Sphkprocess_line(char *line) 118119459Sjkh{ 118219459Sjkh CMD command; 118319459Sjkh int status = 1; 118419459Sjkh 118593394Sphk while (1) { 118619459Sjkh parse_config_line(line, &command); 118793394Sphk switch (command.cmd) { 118819459Sjkh case 0: 118919459Sjkh /* 119019459Sjkh * Comment or blank line 119119459Sjkh */ 119219459Sjkh break; 119319459Sjkh case 'g': 119419459Sjkh /* 119519459Sjkh * Set geometry 119619459Sjkh */ 119719459Sjkh status = process_geometry(&command); 119819459Sjkh break; 119919459Sjkh case 'p': 120019459Sjkh status = process_partition(&command); 120119459Sjkh break; 120219459Sjkh case 'a': 120319459Sjkh status = process_active(&command); 120419459Sjkh break; 120519459Sjkh default: 120619459Sjkh status = 0; 120719459Sjkh break; 120819459Sjkh } 120919459Sjkh break; 121019459Sjkh } 121119459Sjkh return (status); 121219459Sjkh} 121319459Sjkh 121419459Sjkh 121519459Sjkhstatic int 121693394Sphkread_config(char *config_file) 121719459Sjkh{ 121819459Sjkh FILE *fp = NULL; 121919459Sjkh int status = 1; 122019459Sjkh char buf[1010]; 122119459Sjkh 122293394Sphk while (1) { 122393394Sphk if (strcmp(config_file, "-") != 0) { 122419459Sjkh /* 122519459Sjkh * We're not reading from stdin 122619459Sjkh */ 122793394Sphk if ((fp = fopen(config_file, "r")) == NULL) { 122819459Sjkh status = 0; 122919459Sjkh break; 123019459Sjkh } 123193394Sphk } else { 123219459Sjkh fp = stdin; 123319459Sjkh } 123419459Sjkh current_line_number = 0; 123593394Sphk while (!feof(fp)) { 123619459Sjkh if (fgets(buf, sizeof(buf), fp) == NULL) 123719459Sjkh break; 123819459Sjkh ++current_line_number; 123919459Sjkh status = process_line(buf); 124019459Sjkh if (status == 0) 124119459Sjkh break; 124219459Sjkh } 124319459Sjkh break; 124419459Sjkh } 124593394Sphk if (fp) { 124619459Sjkh /* 124719459Sjkh * It doesn't matter if we're reading from stdin, as we've reached EOF 124819459Sjkh */ 124919459Sjkh fclose(fp); 125019459Sjkh } 125119459Sjkh return (status); 125219459Sjkh} 125319459Sjkh 125419459Sjkh 125519459Sjkhstatic void 125619459Sjkhreset_boot(void) 125719459Sjkh{ 125819459Sjkh int i; 125919459Sjkh struct dos_partition *partp; 126019459Sjkh 126119459Sjkh init_boot(); 126293394Sphk for (i = 0; i < 4; ++i) { 126319459Sjkh partp = ((struct dos_partition *) &mboot.parts) + i; 126419459Sjkh bzero((char *)partp, sizeof (struct dos_partition)); 126519459Sjkh } 126619459Sjkh} 126765054Sjhb 126865054Sjhbstatic int 126993394Sphksanitize_partition(struct dos_partition *partp) 127065054Sjhb{ 127165054Sjhb u_int32_t prev_head_boundary, prev_cyl_boundary; 127281164Siedowse u_int32_t max_end, size, start; 127365054Sjhb 127481164Siedowse start = partp->dp_start; 127581164Siedowse size = partp->dp_size; 127681164Siedowse max_end = start + size; 127781164Siedowse /* Only allow a zero size if the partition is being marked unused. */ 127881164Siedowse if (size == 0) { 127981164Siedowse if (start == 0 && partp->dp_typ == 0) 128081164Siedowse return (1); 128181164Siedowse warnx("ERROR: size of partition is zero"); 128281164Siedowse return (0); 128381164Siedowse } 128481164Siedowse /* Return if no adjustment is necessary. */ 128581164Siedowse if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0) 128681164Siedowse return (1); 128765054Sjhb 128881164Siedowse if (start % dos_sectors != 0) 128981164Siedowse warnx("WARNING: partition does not start on a head boundary"); 129081164Siedowse if ((start +size) % dos_sectors != 0) 129181164Siedowse warnx("WARNING: partition does not end on a cylinder boundary"); 129281164Siedowse warnx("WARNING: this may confuse the BIOS or some operating systems"); 129381164Siedowse if (!ok("Correct this automatically?")) 129481164Siedowse return (1); 129581164Siedowse 129665054Sjhb /* 129765054Sjhb * Adjust start upwards, if necessary, to fall on an head boundary. 129865054Sjhb */ 129981164Siedowse if (start % dos_sectors != 0) { 130081164Siedowse prev_head_boundary = start / dos_sectors * dos_sectors; 130165054Sjhb if (max_end < dos_sectors || 130281164Siedowse prev_head_boundary >= max_end - dos_sectors) { 130365054Sjhb /* 130465054Sjhb * Can't go past end of partition 130565054Sjhb */ 130665054Sjhb warnx( 130765054Sjhb "ERROR: unable to adjust start of partition to fall on a head boundary"); 130865054Sjhb return (0); 130965054Sjhb } 131081164Siedowse start = prev_head_boundary + dos_sectors; 131165054Sjhb } 131265054Sjhb 131365054Sjhb /* 131465054Sjhb * Adjust size downwards, if necessary, to fall on a cylinder 131565054Sjhb * boundary. 131665054Sjhb */ 131781164Siedowse prev_cyl_boundary = ((start + size) / dos_cylsecs) * dos_cylsecs; 131881164Siedowse if (prev_cyl_boundary > start) 131981164Siedowse size = prev_cyl_boundary - start; 132081164Siedowse else { 132165054Sjhb warnx("ERROR: could not adjust partition to start on a head boundary\n\ 132265054Sjhb and end on a cylinder boundary."); 132365054Sjhb return (0); 132465054Sjhb } 132581164Siedowse 132681164Siedowse /* Finally, commit any changes to partp and return. */ 132781164Siedowse if (start != partp->dp_start) { 132881164Siedowse warnx("WARNING: adjusting start offset of partition to %u", 132981164Siedowse (u_int)start); 133081164Siedowse partp->dp_start = start; 133165054Sjhb } 133281164Siedowse if (size != partp->dp_size) { 133381164Siedowse warnx("WARNING: adjusting size of partition to %u", (u_int)size); 133481164Siedowse partp->dp_size = size; 133565054Sjhb } 133665054Sjhb 133765054Sjhb return (1); 133865054Sjhb} 133979681Sjoerg 134079681Sjoerg/* 134179681Sjoerg * Try figuring out the root device's canonical disk name. 134279681Sjoerg * The following choices are considered: 134379681Sjoerg * /dev/ad0s1a => /dev/ad0 134479681Sjoerg * /dev/da0a => /dev/da0 134579681Sjoerg * /dev/vinum/root => /dev/vinum/root 134679681Sjoerg */ 134779681Sjoergstatic char * 134879681Sjoergget_rootdisk(void) 134979681Sjoerg{ 135079681Sjoerg struct statfs rootfs; 135179681Sjoerg regex_t re; 135279681Sjoerg#define NMATCHES 2 135379681Sjoerg regmatch_t rm[NMATCHES]; 135479681Sjoerg char *s; 135579681Sjoerg int rv; 135679681Sjoerg 135779681Sjoerg if (statfs("/", &rootfs) == -1) 135879681Sjoerg err(1, "statfs(\"/\")"); 135979681Sjoerg 136079681Sjoerg if ((rv = regcomp(&re, "^(/dev/.*)(\\d+(s\\d+)?[a-h])?$", 136179681Sjoerg REG_EXTENDED)) != 0) 136279681Sjoerg errx(1, "regcomp() failed (%d)", rv); 136379681Sjoerg if ((rv = regexec(&re, rootfs.f_mntfromname, NMATCHES, rm, 0)) != 0) 136479681Sjoerg errx(1, 136579681Sjoerg"mounted root fs resource doesn't match expectations (regexec returned %d)", 136679681Sjoerg rv); 136779681Sjoerg if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL) 136879681Sjoerg errx(1, "out of memory"); 136979681Sjoerg memcpy(s, rootfs.f_mntfromname + rm[1].rm_so, 137079681Sjoerg rm[1].rm_eo - rm[1].rm_so); 137179681Sjoerg s[rm[1].rm_eo - rm[1].rm_so] = 0; 137279681Sjoerg 137379681Sjoerg return s; 137479681Sjoerg} 1375