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 27114589Sobrien#include <sys/cdefs.h> 28114589Sobrien__FBSDID("$FreeBSD$"); 2937415Scharnier 30103348Sphk#include <sys/disk.h> 314Srgrimes#include <sys/disklabel.h> 32104272Sphk#include <sys/diskmbr.h> 33113454Sphk#include <sys/endian.h> 3479681Sjoerg#include <sys/param.h> 3537415Scharnier#include <sys/stat.h> 3679681Sjoerg#include <sys/mount.h> 3737415Scharnier#include <ctype.h> 3837415Scharnier#include <fcntl.h> 3937415Scharnier#include <err.h> 4037415Scharnier#include <errno.h> 41148035Sphk#include <libgeom.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 50227081Sedstatic int iotest; 514Srgrimes 52217808Ssobomax#define NO_DISK_SECTORS ((u_int32_t)-1) 53217808Ssobomax#define NO_TRACK_CYLINDERS 1023 54217808Ssobomax#define NO_TRACK_HEADS 255 55217808Ssobomax#define NO_TRACK_SECTORS 63 564Srgrimes#define LBUF 100 574Srgrimesstatic char lbuf[LBUF]; 584Srgrimes 594Srgrimes/* 604Srgrimes * 614Srgrimes * Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992 624Srgrimes * 634Srgrimes * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University 644Srgrimes * Copyright (c) 1989 Robert. V. Baron 654Srgrimes * Created. 664Srgrimes */ 674Srgrimes 68217808Ssobomax#define Decimal(str, ans, tmp, maxval) if (decimal(str, &tmp, ans, maxval)) ans = tmp 694Srgrimes 704Srgrimes#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs) 714Srgrimes 7220061Ssos#define MAX_SEC_SIZE 2048 /* maximum section size that is supported */ 7320061Ssos#define MIN_SEC_SIZE 512 /* the sector size to start sensing at */ 7493394Sphkstatic int secsize = 0; /* the sensed sector size */ 754Srgrimes 7693394Sphkstatic char *disk; 7710514Sjoerg 7893394Sphkstatic int cyls, sectors, heads, cylsecs, disksecs; 794Srgrimes 8093394Sphkstruct mboot { 81145763Snyan unsigned char *bootinst; /* boot code */ 82145763Snyan off_t bootinst_size; 83113454Sphk struct dos_partition parts[NDOSPART]; 844Srgrimes}; 854Srgrimes 8693394Sphkstatic struct mboot mboot; 87148035Sphkstatic int fd; 8893394Sphk 894Srgrimes#define ACTIVE 0x80 904Srgrimes 9193394Sphkstatic uint dos_cyls; 9293394Sphkstatic uint dos_heads; 9393394Sphkstatic uint dos_sectors; 9493394Sphkstatic uint dos_cylsecs; 954Srgrimes 964Srgrimes#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0)) 974Srgrimes#define DOSCYL(c) (c & 0xff) 984Srgrimes 9919459Sjkh#define MAX_ARGS 10 10019459Sjkh 10119459Sjkhstatic int current_line_number; 10219459Sjkh 10319459Sjkhstatic int geom_processed = 0; 10419459Sjkhstatic int part_processed = 0; 10519459Sjkhstatic int active_processed = 0; 10619459Sjkh 10719459Sjkhtypedef struct cmd { 10819459Sjkh char cmd; 10919459Sjkh int n_args; 11019459Sjkh struct arg { 111224150Srstone char argtype; 112224150Srstone unsigned long arg_val; 113224150Srstone char * arg_str; 11419459Sjkh } args[MAX_ARGS]; 11519459Sjkh} CMD; 11619459Sjkh 11748282Srnordierstatic int B_flag = 0; /* replace boot code */ 11857896Simpstatic int I_flag = 0; /* use entire disk for FreeBSD */ 1194Srgrimesstatic int a_flag = 0; /* set active partition */ 12048282Srnordierstatic char *b_flag = NULL; /* path to boot code */ 1214Srgrimesstatic int i_flag = 0; /* replace partition data */ 122181036Sobrienstatic int q_flag = 0; /* Be quiet */ 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 */ 128169143Smaximstatic int print_config_flag = 0; 1294Srgrimes 130187246Sluigi/* 131187246Sluigi * A list of partition types, probably outdated. 132187246Sluigi */ 133187246Sluigistatic const char *const part_types[256] = { 134187246Sluigi [0x00] = "unused", 135187246Sluigi [0x01] = "Primary DOS with 12 bit FAT", 136187246Sluigi [0x02] = "XENIX / file system", 137187246Sluigi [0x03] = "XENIX /usr file system", 138187246Sluigi [0x04] = "Primary DOS with 16 bit FAT (< 32MB)", 139187246Sluigi [0x05] = "Extended DOS", 140187248Sluigi [0x06] = "Primary DOS, 16 bit FAT (>= 32MB)", 141187248Sluigi [0x07] = "NTFS, OS/2 HPFS, QNX-2 (16 bit) or Advanced UNIX", 142187246Sluigi [0x08] = "AIX file system or SplitDrive", 143187246Sluigi [0x09] = "AIX boot partition or Coherent", 144187246Sluigi [0x0A] = "OS/2 Boot Manager, OPUS or Coherent swap", 145187246Sluigi [0x0B] = "DOS or Windows 95 with 32 bit FAT", 146187246Sluigi [0x0C] = "DOS or Windows 95 with 32 bit FAT (LBA)", 147187246Sluigi [0x0E] = "Primary 'big' DOS (>= 32MB, LBA)", 148187246Sluigi [0x0F] = "Extended DOS (LBA)", 149187246Sluigi [0x10] = "OPUS", 150187246Sluigi [0x11] = "OS/2 BM: hidden DOS with 12-bit FAT", 151187246Sluigi [0x12] = "Compaq diagnostics", 152187246Sluigi [0x14] = "OS/2 BM: hidden DOS with 16-bit FAT (< 32MB)", 153187246Sluigi [0x16] = "OS/2 BM: hidden DOS with 16-bit FAT (>= 32MB)", 154187246Sluigi [0x17] = "OS/2 BM: hidden IFS (e.g. HPFS)", 155187246Sluigi [0x18] = "AST Windows swapfile", 156187248Sluigi [0x1b] = "ASUS Recovery partition (NTFS)", 157187246Sluigi [0x24] = "NEC DOS", 158187246Sluigi [0x3C] = "PartitionMagic recovery", 159187246Sluigi [0x39] = "plan9", 160187246Sluigi [0x40] = "VENIX 286", 161187246Sluigi [0x41] = "Linux/MINIX (sharing disk with DRDOS)", 162187246Sluigi [0x42] = "SFS or Linux swap (sharing disk with DRDOS)", 163187246Sluigi [0x43] = "Linux native (sharing disk with DRDOS)", 164187246Sluigi [0x4D] = "QNX 4.2 Primary", 165187246Sluigi [0x4E] = "QNX 4.2 Secondary", 166187246Sluigi [0x4F] = "QNX 4.2 Tertiary", 167187246Sluigi [0x50] = "DM (disk manager)", 168187246Sluigi [0x51] = "DM6 Aux1 (or Novell)", 169187246Sluigi [0x52] = "CP/M or Microport SysV/AT", 170187246Sluigi [0x53] = "DM6 Aux3", 171187246Sluigi [0x54] = "DM6", 172187246Sluigi [0x55] = "EZ-Drive (disk manager)", 173187246Sluigi [0x56] = "Golden Bow (disk manager)", 174187246Sluigi [0x5c] = "Priam Edisk (disk manager)", /* according to S. Widlake */ 175187246Sluigi [0x61] = "SpeedStor", 176187246Sluigi [0x63] = "System V/386 (such as ISC UNIX), GNU HURD or Mach", 177187246Sluigi [0x64] = "Novell Netware/286 2.xx", 178187246Sluigi [0x65] = "Novell Netware/386 3.xx", 179187246Sluigi [0x70] = "DiskSecure Multi-Boot", 180187246Sluigi [0x75] = "PCIX", 181187246Sluigi [0x77] = "QNX4.x", 182187246Sluigi [0x78] = "QNX4.x 2nd part", 183187246Sluigi [0x79] = "QNX4.x 3rd part", 184187246Sluigi [0x80] = "Minix until 1.4a", 185187246Sluigi [0x81] = "Minix since 1.4b, early Linux partition or Mitac disk manager", 186187246Sluigi [0x82] = "Linux swap or Solaris x86", 187187246Sluigi [0x83] = "Linux native", 188187246Sluigi [0x84] = "OS/2 hidden C: drive", 189187246Sluigi [0x85] = "Linux extended", 190187246Sluigi [0x86] = "NTFS volume set??", 191187246Sluigi [0x87] = "NTFS volume set??", 192187246Sluigi [0x93] = "Amoeba file system", 193187246Sluigi [0x94] = "Amoeba bad block table", 194187246Sluigi [0x9F] = "BSD/OS", 195187246Sluigi [0xA0] = "Suspend to Disk", 196187246Sluigi [0xA5] = "FreeBSD/NetBSD/386BSD", 197187246Sluigi [0xA6] = "OpenBSD", 198187246Sluigi [0xA7] = "NeXTSTEP", 199187246Sluigi [0xA9] = "NetBSD", 200187246Sluigi [0xAC] = "IBM JFS", 201187246Sluigi [0xAF] = "HFS+", 202187246Sluigi [0xB7] = "BSDI BSD/386 file system", 203187246Sluigi [0xB8] = "BSDI BSD/386 swap", 204187246Sluigi [0xBE] = "Solaris x86 boot", 205187246Sluigi [0xBF] = "Solaris x86 (new)", 206187246Sluigi [0xC1] = "DRDOS/sec with 12-bit FAT", 207187246Sluigi [0xC4] = "DRDOS/sec with 16-bit FAT (< 32MB)", 208187246Sluigi [0xC6] = "DRDOS/sec with 16-bit FAT (>= 32MB)", 209187246Sluigi [0xC7] = "Syrinx", 210187246Sluigi [0xDB] = "CP/M, Concurrent CP/M, Concurrent DOS or CTOS", 211187248Sluigi [0xDE] = "DELL Utilities - FAT filesystem", 212187246Sluigi [0xE1] = "DOS access or SpeedStor with 12-bit FAT extended partition", 213187246Sluigi [0xE3] = "DOS R/O or SpeedStor", 214187246Sluigi [0xE4] = "SpeedStor with 16-bit FAT extended partition < 1024 cyl.", 215187246Sluigi [0xEB] = "BeOS file system", 216187246Sluigi [0xEE] = "EFI GPT", 217187246Sluigi [0xEF] = "EFI System Partition", 218187246Sluigi [0xF1] = "SpeedStor", 219187246Sluigi [0xF2] = "DOS 3.3+ Secondary", 220187246Sluigi [0xF4] = "SpeedStor large partition", 221234345Smarck [0xFB] = "VMware VMFS", 222187246Sluigi [0xFE] = "SpeedStor >1024 cyl. or LANstep", 223187246Sluigi [0xFF] = "Xenix bad blocks table", 2244Srgrimes}; 2254Srgrimes 226187246Sluigistatic const char * 227187246Sluigiget_type(int t) 228187246Sluigi{ 229187246Sluigi const char *ret; 230187246Sluigi 231187246Sluigi ret = (t >= 0 && t <= 255) ? part_types[t] : NULL; 232187246Sluigi return ret ? ret : "unknown"; 233187246Sluigi} 234187246Sluigi 235187246Sluigi 236227292Saestatic int geom_class_available(const char *); 237187239Sluigistatic void print_s0(void); 238187241Sluigistatic void print_part(const struct dos_partition *); 23916561Salexstatic void init_sector0(unsigned long start); 24019459Sjkhstatic void init_boot(void); 24116561Salexstatic void change_part(int i); 24293394Sphkstatic void print_params(void); 24316561Salexstatic void change_active(int which); 24493394Sphkstatic void change_code(void); 24593394Sphkstatic void get_params_to_use(void); 24679681Sjoergstatic char *get_rootdisk(void); 24781164Siedowsestatic void dos(struct dos_partition *partp); 24893394Sphkstatic int open_disk(int flag); 24916561Salexstatic ssize_t read_disk(off_t sector, void *buf); 250148035Sphkstatic int write_disk(off_t sector, void *buf); 25193394Sphkstatic int get_params(void); 25293394Sphkstatic int read_s0(void); 25393394Sphkstatic int write_s0(void); 25493394Sphkstatic int ok(const char *str); 255217808Ssobomaxstatic int decimal(const char *str, int *num, int deflt, uint32_t maxval); 25619459Sjkhstatic int read_config(char *config_file); 25719459Sjkhstatic void reset_boot(void); 25865054Sjhbstatic int sanitize_partition(struct dos_partition *); 25937415Scharnierstatic void usage(void); 2604Srgrimes 26116561Salexint 26216561Salexmain(int argc, char *argv[]) 2634Srgrimes{ 26448282Srnordier int c, i; 26593394Sphk int partition = -1; 26693394Sphk struct dos_partition *partp; 2674Srgrimes 268181036Sobrien while ((c = getopt(argc, argv, "BIab:f:ipqstuv1234")) != -1) 26948282Srnordier switch (c) { 27048282Srnordier case 'B': 27148282Srnordier B_flag = 1; 2724Srgrimes break; 27357896Simp case 'I': 27457896Simp I_flag = 1; 27557896Simp break; 27648282Srnordier case 'a': 27748282Srnordier a_flag = 1; 27848282Srnordier break; 27948282Srnordier case 'b': 28048282Srnordier b_flag = optarg; 28148282Srnordier break; 28248282Srnordier case 'f': 28348282Srnordier f_flag = optarg; 28448282Srnordier break; 28548282Srnordier case 'i': 28648282Srnordier i_flag = 1; 28748282Srnordier break; 288169143Smaxim case 'p': 289169143Smaxim print_config_flag = 1; 290169143Smaxim break; 291181036Sobrien case 'q': 292181036Sobrien q_flag = 1; 293181036Sobrien break; 29457896Simp case 's': 29557896Simp s_flag = 1; 29657896Simp break; 29748282Srnordier case 't': 29848282Srnordier t_flag = 1; 29948282Srnordier break; 30048282Srnordier case 'u': 30148282Srnordier u_flag = 1; 30248282Srnordier break; 30348282Srnordier case 'v': 30448282Srnordier v_flag = 1; 30548282Srnordier break; 30648282Srnordier case '1': 30748282Srnordier case '2': 30848282Srnordier case '3': 30948282Srnordier case '4': 31048282Srnordier partition = c - '0'; 31148282Srnordier break; 31248282Srnordier default: 31348282Srnordier usage(); 3144Srgrimes } 31548282Srnordier if (f_flag || i_flag) 31648282Srnordier u_flag = 1; 31748282Srnordier if (t_flag) 31848282Srnordier v_flag = 1; 31948282Srnordier argc -= optind; 32048282Srnordier argv += optind; 3214Srgrimes 32279681Sjoerg if (argc == 0) { 32379681Sjoerg disk = get_rootdisk(); 32479681Sjoerg } else { 325182844Slulf disk = g_device_path(argv[0]); 326182844Slulf if (disk == NULL) 327187203Sluigi err(1, "unable to get correct path for %s", argv[0]); 32810514Sjoerg } 32979681Sjoerg if (open_disk(u_flag) < 0) 33079681Sjoerg err(1, "cannot open disk %s", disk); 3314Srgrimes 33263027Sjhb /* (abu)use mboot.bootinst to probe for the sector size */ 33363027Sjhb if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL) 33463027Sjhb err(1, "cannot allocate buffer to determine disk sector size"); 335159757Ssimon if (read_disk(0, mboot.bootinst) == -1) 336159757Ssimon errx(1, "could not detect sector size"); 33763329Sjhb free(mboot.bootinst); 33863329Sjhb mboot.bootinst = NULL; 33963027Sjhb 340169143Smaxim if (print_config_flag) { 341169143Smaxim if (read_s0()) 342169143Smaxim err(1, "read_s0"); 343169143Smaxim 344169143Smaxim printf("# %s\n", disk); 345169143Smaxim printf("g c%d h%d s%d\n", dos_cyls, dos_heads, dos_sectors); 346169143Smaxim 347169143Smaxim for (i = 0; i < NDOSPART; i++) { 348187203Sluigi partp = &mboot.parts[i]; 349169143Smaxim 350169143Smaxim if (partp->dp_start == 0 && partp->dp_size == 0) 351169143Smaxim continue; 352169143Smaxim 353169143Smaxim printf("p %d 0x%02x %lu %lu\n", i + 1, partp->dp_typ, 354169143Smaxim (u_long)partp->dp_start, (u_long)partp->dp_size); 355169143Smaxim 356169143Smaxim /* Fill flags for the partition. */ 357169143Smaxim if (partp->dp_flag & 0x80) 358169143Smaxim printf("a %d\n", i + 1); 359169143Smaxim } 360169143Smaxim exit(0); 361169143Smaxim } 36293394Sphk if (s_flag) { 36357896Simp if (read_s0()) 36457896Simp err(1, "read_s0"); 36557896Simp printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads, 36657896Simp dos_sectors); 36757896Simp printf("Part %11s %11s Type Flags\n", "Start", "Size"); 36857896Simp for (i = 0; i < NDOSPART; i++) { 369187203Sluigi partp = &mboot.parts[i]; 37057896Simp if (partp->dp_start == 0 && partp->dp_size == 0) 37157896Simp continue; 37257896Simp printf("%4d: %11lu %11lu 0x%02x 0x%02x\n", i + 1, 37357896Simp (u_long) partp->dp_start, 37457896Simp (u_long) partp->dp_size, partp->dp_typ, 37557896Simp partp->dp_flag); 37657896Simp } 37757896Simp exit(0); 37857896Simp } 37957896Simp 3804Srgrimes printf("******* Working on device %s *******\n",disk); 38119459Sjkh 38293394Sphk if (I_flag) { 38350215Sphk read_s0(); 38450215Sphk reset_boot(); 385187203Sluigi partp = &mboot.parts[0]; 38650215Sphk partp->dp_typ = DOSPTYP_386BSD; 38750215Sphk partp->dp_flag = ACTIVE; 38850215Sphk partp->dp_start = dos_sectors; 38965054Sjhb partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - 39065054Sjhb dos_sectors; 39181164Siedowse dos(partp); 39250215Sphk if (v_flag) 393187239Sluigi print_s0(); 39495002Strhodes if (!t_flag) 39595002Strhodes write_s0(); 39650215Sphk exit(0); 39750215Sphk } 39893394Sphk if (f_flag) { 39919459Sjkh if (read_s0() || i_flag) 40019459Sjkh reset_boot(); 40119459Sjkh if (!read_config(f_flag)) 40219459Sjkh exit(1); 40319459Sjkh if (v_flag) 404187239Sluigi print_s0(); 40519459Sjkh if (!t_flag) 40619459Sjkh write_s0(); 40793394Sphk } else { 40819459Sjkh if(u_flag) 40919459Sjkh get_params_to_use(); 41019459Sjkh else 4114Srgrimes print_params(); 4124Srgrimes 41319459Sjkh if (read_s0()) 41465054Sjhb init_sector0(dos_sectors); 4154Srgrimes 41620061Ssos printf("Media sector size is %d\n", secsize); 41719459Sjkh printf("Warning: BIOS sector numbering starts with sector 1\n"); 41819459Sjkh printf("Information from DOS bootblock is:\n"); 41919459Sjkh if (partition == -1) 42026421Sbrian for (i = 1; i <= NDOSPART; i++) 42119459Sjkh change_part(i); 42219459Sjkh else 4234Srgrimes change_part(partition); 4244Srgrimes 42519459Sjkh if (u_flag || a_flag) 4264Srgrimes change_active(partition); 4274Srgrimes 42848282Srnordier if (B_flag) 42943054Srnordier change_code(); 43043054Srnordier 43148282Srnordier if (u_flag || a_flag || B_flag) { 43295002Strhodes if (!t_flag) { 43319459Sjkh printf("\nWe haven't changed the partition table yet. "); 43419459Sjkh printf("This is your last chance.\n"); 43519459Sjkh } 436187239Sluigi print_s0(); 43795002Strhodes if (!t_flag) { 43819459Sjkh if (ok("Should we write new partition table?")) 4394Srgrimes write_s0(); 440145763Snyan } else { 44119459Sjkh printf("\n-t flag specified -- partition table not written.\n"); 44219459Sjkh } 44319459Sjkh } 4444Srgrimes } 4454Srgrimes 4464Srgrimes exit(0); 44737415Scharnier} 4484Srgrimes 44937415Scharnierstatic void 45037415Scharnierusage() 45137415Scharnier{ 45248282Srnordier fprintf(stderr, "%s%s", 453181036Sobrien "usage: fdisk [-BIaipqstu] [-b bootcode] [-1234] [disk]\n", 45448282Srnordier " fdisk -f configfile [-itv] [disk]\n"); 45537415Scharnier exit(1); 4564Srgrimes} 4574Srgrimes 45816561Salexstatic void 459187239Sluigiprint_s0(void) 4604Srgrimes{ 46193394Sphk int i; 4624Srgrimes 4634Srgrimes print_params(); 4644Srgrimes printf("Information from DOS bootblock is:\n"); 465187241Sluigi for (i = 1; i <= NDOSPART; i++) { 466187241Sluigi printf("%d: ", i); 467187241Sluigi print_part(&mboot.parts[i - 1]); 468187241Sluigi } 4694Srgrimes} 4704Srgrimes 47193394Sphkstatic struct dos_partition mtpart; 4724Srgrimes 47316561Salexstatic void 474187241Sluigiprint_part(const struct dos_partition *partp) 4754Srgrimes{ 47626389Sgibbs u_int64_t part_mb; 4774Srgrimes 4784Srgrimes if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) { 4794Srgrimes printf("<UNUSED>\n"); 4804Srgrimes return; 4814Srgrimes } 48226389Sgibbs /* 48326389Sgibbs * Be careful not to overflow. 48426389Sgibbs */ 48526389Sgibbs part_mb = partp->dp_size; 48626389Sgibbs part_mb *= secsize; 48726389Sgibbs part_mb /= (1024 * 1024); 48890866Sjoe printf("sysid %d (%#04x),(%s)\n", partp->dp_typ, partp->dp_typ, 48990866Sjoe get_type(partp->dp_typ)); 490100202Sbde printf(" start %lu, size %lu (%ju Meg), flag %x%s\n", 49137244Sbde (u_long)partp->dp_start, 492226908Sjmg (u_long)partp->dp_size, 493100202Sbde (uintmax_t)part_mb, 49434952Sobrien partp->dp_flag, 49534952Sobrien partp->dp_flag == ACTIVE ? " (active)" : ""); 49669371Sobrien printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n" 4974Srgrimes ,DPCYL(partp->dp_scyl, partp->dp_ssect) 49869371Sobrien ,partp->dp_shd 4994Srgrimes ,DPSECT(partp->dp_ssect) 5004Srgrimes ,DPCYL(partp->dp_ecyl, partp->dp_esect) 50169371Sobrien ,partp->dp_ehd 50269371Sobrien ,DPSECT(partp->dp_esect)); 5034Srgrimes} 5044Srgrimes 50519459Sjkh 50616561Salexstatic void 50719459Sjkhinit_boot(void) 50819459Sjkh{ 50995860Speter#ifndef __ia64__ 51048282Srnordier const char *fname; 51193394Sphk int fdesc, n; 51263027Sjhb struct stat sb; 51348282Srnordier 51448282Srnordier fname = b_flag ? b_flag : "/boot/mbr"; 51593394Sphk if ((fdesc = open(fname, O_RDONLY)) == -1 || 51693394Sphk fstat(fdesc, &sb) == -1) 51763027Sjhb err(1, "%s", fname); 518226907Sjmg if (sb.st_size == 0) 519226907Sjmg errx(1, "%s is empty, must not be.", fname); 52063027Sjhb if ((mboot.bootinst_size = sb.st_size) % secsize != 0) 52163027Sjhb errx(1, "%s: length must be a multiple of sector size", fname); 52263218Sache if (mboot.bootinst != NULL) 52363218Sache free(mboot.bootinst); 52463027Sjhb if ((mboot.bootinst = malloc(mboot.bootinst_size = sb.st_size)) == NULL) 52563027Sjhb errx(1, "%s: unable to allocate read buffer", fname); 52693394Sphk if ((n = read(fdesc, mboot.bootinst, mboot.bootinst_size)) == -1 || 52793394Sphk close(fdesc)) 52848282Srnordier err(1, "%s", fname); 52963027Sjhb if (n != mboot.bootinst_size) 53063027Sjhb errx(1, "%s: short read", fname); 53195860Speter#else 53295860Speter if (mboot.bootinst != NULL) 53395860Speter free(mboot.bootinst); 53495860Speter mboot.bootinst_size = secsize; 53595860Speter if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) 53695860Speter errx(1, "unable to allocate boot block buffer"); 53795860Speter memset(mboot.bootinst, 0, mboot.bootinst_size); 538113454Sphk le16enc(&mboot.bootinst[DOSMAGICOFFSET], DOSMAGIC); 53995860Speter#endif 54019459Sjkh} 54119459Sjkh 54219459Sjkh 54319459Sjkhstatic void 54416561Salexinit_sector0(unsigned long start) 5454Srgrimes{ 546187203Sluigi struct dos_partition *partp = &mboot.parts[0]; 5474Srgrimes 54819459Sjkh init_boot(); 5494Srgrimes 5504Srgrimes partp->dp_typ = DOSPTYP_386BSD; 5514Srgrimes partp->dp_flag = ACTIVE; 55265054Sjhb start = ((start + dos_sectors - 1) / dos_sectors) * dos_sectors; 55363027Sjhb if(start == 0) 55463027Sjhb start = dos_sectors; 5554Srgrimes partp->dp_start = start; 55665054Sjhb partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - start; 5574Srgrimes 55881164Siedowse dos(partp); 5594Srgrimes} 5604Srgrimes 56116561Salexstatic void 56216561Salexchange_part(int i) 5634Srgrimes{ 564187203Sluigi struct dos_partition *partp = &mboot.parts[i - 1]; 5654Srgrimes 5664Srgrimes printf("The data for partition %d is:\n", i); 567187241Sluigi print_part(partp); 5684Srgrimes 5694Srgrimes if (u_flag && ok("Do you want to change it?")) { 5704Srgrimes int tmp; 5714Srgrimes 5724Srgrimes if (i_flag) { 573187241Sluigi bzero(partp, sizeof (*partp)); 574187241Sluigi if (i == 1) { 575187241Sluigi init_sector0(1); 576187241Sluigi printf("\nThe static data for the slice 1 has been reinitialized to:\n"); 577187241Sluigi print_part(partp); 578187241Sluigi } 5794Srgrimes } 5804Srgrimes 5814Srgrimes do { 582217808Ssobomax Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp, 255); 583217808Ssobomax Decimal("start", partp->dp_start, tmp, NO_DISK_SECTORS); 584217808Ssobomax Decimal("size", partp->dp_size, tmp, NO_DISK_SECTORS); 58581164Siedowse if (!sanitize_partition(partp)) { 58681164Siedowse warnx("ERROR: failed to adjust; setting sysid to 0"); 58781164Siedowse partp->dp_typ = 0; 58881164Siedowse } 5894Srgrimes 59036262Sjraynard if (ok("Explicitly specify beg/end address ?")) 5914Srgrimes { 5924Srgrimes int tsec,tcyl,thd; 5934Srgrimes tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect); 5944Srgrimes thd = partp->dp_shd; 5954Srgrimes tsec = DPSECT(partp->dp_ssect); 596217808Ssobomax Decimal("beginning cylinder", tcyl, tmp, NO_TRACK_CYLINDERS); 597217808Ssobomax Decimal("beginning head", thd, tmp, NO_TRACK_HEADS); 598217808Ssobomax Decimal("beginning sector", tsec, tmp, NO_TRACK_SECTORS); 5994Srgrimes partp->dp_scyl = DOSCYL(tcyl); 6004Srgrimes partp->dp_ssect = DOSSECT(tsec,tcyl); 6014Srgrimes partp->dp_shd = thd; 6024Srgrimes 6034Srgrimes tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect); 6044Srgrimes thd = partp->dp_ehd; 6054Srgrimes tsec = DPSECT(partp->dp_esect); 606217808Ssobomax Decimal("ending cylinder", tcyl, tmp, NO_TRACK_CYLINDERS); 607217808Ssobomax Decimal("ending head", thd, tmp, NO_TRACK_HEADS); 608217808Ssobomax Decimal("ending sector", tsec, tmp, NO_TRACK_SECTORS); 6094Srgrimes partp->dp_ecyl = DOSCYL(tcyl); 6104Srgrimes partp->dp_esect = DOSSECT(tsec,tcyl); 6114Srgrimes partp->dp_ehd = thd; 61281164Siedowse } else 61381164Siedowse dos(partp); 6148871Srgrimes 615187241Sluigi print_part(partp); 6164Srgrimes } while (!ok("Are we happy with this entry?")); 6174Srgrimes } 618145763Snyan} 6194Srgrimes 62016561Salexstatic void 6214Srgrimesprint_params() 6224Srgrimes{ 6234Srgrimes printf("parameters extracted from in-core disklabel are:\n"); 6244Srgrimes printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 6254Srgrimes ,cyls,heads,sectors,cylsecs); 626145763Snyan if (dos_cyls > 1023 || dos_heads > 255 || dos_sectors > 63) 62720061Ssos printf("Figures below won't work with BIOS for partitions not in cyl 1\n"); 6284Srgrimes printf("parameters to be used for BIOS calculations are:\n"); 6294Srgrimes printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 6304Srgrimes ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); 6314Srgrimes} 6324Srgrimes 63316561Salexstatic void 63416561Salexchange_active(int which) 6354Srgrimes{ 63681164Siedowse struct dos_partition *partp = &mboot.parts[0]; 63781164Siedowse int active, i, new, tmp; 6384Srgrimes 63981164Siedowse active = -1; 64081164Siedowse for (i = 0; i < NDOSPART; i++) { 64181164Siedowse if ((partp[i].dp_flag & ACTIVE) == 0) 64281164Siedowse continue; 64381164Siedowse printf("Partition %d is marked active\n", i + 1); 64481164Siedowse if (active == -1) 64581164Siedowse active = i + 1; 64681164Siedowse } 6474Srgrimes if (a_flag && which != -1) 6484Srgrimes active = which; 64981164Siedowse else if (active == -1) 65081164Siedowse active = 1; 65181164Siedowse 6523723Sbde if (!ok("Do you want to change the active partition?")) 6533723Sbde return; 65434952Sobriensetactive: 65534952Sobrien do { 65681164Siedowse new = active; 657217714Ssobomax Decimal("active partition", new, tmp, 0); 65881164Siedowse if (new < 1 || new > 4) { 65934952Sobrien printf("Active partition number must be in range 1-4." 66034952Sobrien " Try again.\n"); 66134952Sobrien goto setactive; 66234952Sobrien } 66381164Siedowse active = new; 66434952Sobrien } while (!ok("Are you happy with this choice")); 6654Srgrimes for (i = 0; i < NDOSPART; i++) 6664Srgrimes partp[i].dp_flag = 0; 66726421Sbrian if (active > 0 && active <= NDOSPART) 66826421Sbrian partp[active-1].dp_flag = ACTIVE; 6694Srgrimes} 6704Srgrimes 67143054Srnordierstatic void 67243054Srnordierchange_code() 67343054Srnordier{ 67443054Srnordier if (ok("Do you want to change the boot code?")) 67543054Srnordier init_boot(); 67643054Srnordier} 67743054Srnordier 67816561Salexvoid 6794Srgrimesget_params_to_use() 6804Srgrimes{ 6814Srgrimes int tmp; 6824Srgrimes print_params(); 6834Srgrimes if (ok("Do you want to change our idea of what BIOS thinks ?")) 6844Srgrimes { 6854Srgrimes do 6864Srgrimes { 687217714Ssobomax Decimal("BIOS's idea of #cylinders", dos_cyls, tmp, 0); 688217714Ssobomax Decimal("BIOS's idea of #heads", dos_heads, tmp, 0); 689217714Ssobomax Decimal("BIOS's idea of #sectors", dos_sectors, tmp, 0); 6904Srgrimes dos_cylsecs = dos_heads * dos_sectors; 6914Srgrimes print_params(); 6924Srgrimes } 6934Srgrimes while(!ok("Are you happy with this choice")); 6944Srgrimes } 6954Srgrimes} 6964Srgrimes 69719459Sjkh 6984Srgrimes/***********************************************\ 6994Srgrimes* Change real numbers into strange dos numbers * 7004Srgrimes\***********************************************/ 70116561Salexstatic void 70293394Sphkdos(struct dos_partition *partp) 7034Srgrimes{ 70481164Siedowse int cy, sec; 70581164Siedowse u_int32_t end; 7064Srgrimes 70788714Siedowse if (partp->dp_typ == 0 && partp->dp_start == 0 && partp->dp_size == 0) { 70888714Siedowse memcpy(partp, &mtpart, sizeof(*partp)); 7093723Sbde return; 7103723Sbde } 7113723Sbde 71281164Siedowse /* Start c/h/s. */ 71381164Siedowse partp->dp_shd = partp->dp_start % dos_cylsecs / dos_sectors; 71481164Siedowse cy = partp->dp_start / dos_cylsecs; 71581164Siedowse sec = partp->dp_start % dos_sectors + 1; 71681164Siedowse partp->dp_scyl = DOSCYL(cy); 71781164Siedowse partp->dp_ssect = DOSSECT(sec, cy); 7184Srgrimes 71981164Siedowse /* End c/h/s. */ 72081164Siedowse end = partp->dp_start + partp->dp_size - 1; 72181164Siedowse partp->dp_ehd = end % dos_cylsecs / dos_sectors; 72281164Siedowse cy = end / dos_cylsecs; 72381164Siedowse sec = end % dos_sectors + 1; 72481164Siedowse partp->dp_ecyl = DOSCYL(cy); 72581164Siedowse partp->dp_esect = DOSSECT(sec, cy); 7264Srgrimes} 7274Srgrimes 72816561Salexstatic int 72993394Sphkopen_disk(int flag) 7304Srgrimes{ 731148035Sphk int rwmode; 7324Srgrimes 733182844Slulf /* Write mode if one of these flags are set. */ 734182844Slulf rwmode = (a_flag || I_flag || B_flag || flag); 735182844Slulf fd = g_open(disk, rwmode); 736182844Slulf /* If the mode fails, try read-only if we didn't. */ 737182844Slulf if (fd == -1 && errno == EPERM && rwmode) 738182844Slulf fd = g_open(disk, 0); 739108395Sphk if (fd == -1 && errno == ENXIO) 740108395Sphk return -2; 741108395Sphk if (fd == -1) { 74237415Scharnier warnx("can't open device %s", disk); 7434Srgrimes return -1; 7444Srgrimes } 74593394Sphk if (get_params() == -1) { 74637415Scharnier warnx("can't get disk parameters on %s", disk); 7474Srgrimes return -1; 7484Srgrimes } 7494Srgrimes return fd; 7504Srgrimes} 7514Srgrimes 75216561Salexstatic ssize_t 75316561Salexread_disk(off_t sector, void *buf) 7544Srgrimes{ 755145763Snyan 756145763Snyan lseek(fd, (sector * 512), 0); 757145763Snyan if (secsize == 0) 758145763Snyan for (secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; 759145763Snyan secsize *= 2) { 76020061Ssos /* try the read */ 76120061Ssos int size = read(fd, buf, secsize); 762145763Snyan if (size == secsize) 76320061Ssos /* it worked so return */ 76420061Ssos return secsize; 765145763Snyan } 76620061Ssos else 767145763Snyan return read(fd, buf, secsize); 76820061Ssos 76920061Ssos /* we failed to read at any of the sizes */ 77020061Ssos return -1; 7714Srgrimes} 7724Srgrimes 773148035Sphkstatic int 774227292Saegeom_class_available(const char *name) 775227292Sae{ 776227292Sae struct gclass *class; 777227292Sae struct gmesh mesh; 778227292Sae int error; 779227292Sae 780227292Sae error = geom_gettree(&mesh); 781227292Sae if (error != 0) 782227292Sae errc(1, error, "Cannot get GEOM tree"); 783227292Sae 784227292Sae LIST_FOREACH(class, &mesh.lg_class, lg_class) { 785227292Sae if (strcmp(class->lg_name, name) == 0) { 786227292Sae geom_deletetree(&mesh); 787227292Sae return (1); 788227292Sae } 789227292Sae } 790227292Sae 791227292Sae geom_deletetree(&mesh); 792227292Sae 793227292Sae return (0); 794227292Sae} 795227292Sae 796227292Saestatic int 79716561Salexwrite_disk(off_t sector, void *buf) 7984Srgrimes{ 799148035Sphk struct gctl_req *grq; 800182844Slulf const char *errmsg; 801227292Sae char *pname; 802227292Sae int error; 803108395Sphk 804227292Sae /* Check that GEOM_MBR is available */ 805227292Sae if (geom_class_available("MBR") != 0) { 806227292Sae grq = gctl_get_handle(); 807227292Sae gctl_ro_param(grq, "verb", -1, "write MBR"); 808227292Sae gctl_ro_param(grq, "class", -1, "MBR"); 809227292Sae pname = g_providername(fd); 810227292Sae if (pname == NULL) { 811227292Sae warn("Error getting providername for %s", disk); 812227292Sae return (-1); 813227292Sae } 814227292Sae gctl_ro_param(grq, "geom", -1, pname); 815227292Sae gctl_ro_param(grq, "data", secsize, buf); 816227292Sae errmsg = gctl_issue(grq); 817227292Sae free(pname); 818227292Sae if (errmsg == NULL) { 819227292Sae gctl_free(grq); 820227292Sae return(0); 821227292Sae } 822227292Sae if (!q_flag) 823227292Sae warnx("GEOM_MBR: %s", errmsg); 824150249Srodrigc gctl_free(grq); 825227292Sae } else { 826227295Sae /* 827227295Sae * Try to write MBR directly. This may help when disk 828227292Sae * is not in use. 829227292Sae * XXX: hardcoded sectorsize 830227292Sae */ 831227292Sae error = pwrite(fd, buf, secsize, (sector * 512)); 832227292Sae if (error == secsize) 833227292Sae return (0); 834150249Srodrigc } 835182844Slulf 836227295Sae /* 837227295Sae * GEOM_MBR is not available or failed to write MBR. 838227292Sae * Now check that we have GEOM_PART and recommend to use gpart (8). 839227292Sae */ 840227292Sae if (geom_class_available("PART") != 0) 841227292Sae warnx("Failed to write MBR. Try to use gpart(8)."); 842227292Sae else 843227292Sae warnx("Failed to write sector zero"); 844148035Sphk return(EINVAL); 8454Srgrimes} 8464Srgrimes 84716561Salexstatic int 84816561Salexget_params() 8494Srgrimes{ 850103665Sphk int error; 851103665Sphk u_int u; 852103665Sphk off_t o; 8534Srgrimes 854103665Sphk error = ioctl(fd, DIOCGFWSECTORS, &u); 855103665Sphk if (error == 0) 856103665Sphk sectors = dos_sectors = u; 857112826Sphk else 858112826Sphk sectors = dos_sectors = 63; 859112826Sphk 860103665Sphk error = ioctl(fd, DIOCGFWHEADS, &u); 861103665Sphk if (error == 0) 862103665Sphk heads = dos_heads = u; 863112826Sphk else 864112826Sphk heads = dos_heads = 255; 865103665Sphk 8662810Sbde dos_cylsecs = cylsecs = heads * sectors; 8672810Sbde disksecs = cyls * heads * sectors; 8684Srgrimes 869182844Slulf u = g_sectorsize(fd); 870182844Slulf if (u <= 0) 871182844Slulf return (-1); 8724Srgrimes 873182844Slulf o = g_mediasize(fd); 874182844Slulf if (o < 0) 875182844Slulf return (-1); 876182844Slulf disksecs = o / u; 877182844Slulf cyls = dos_cyls = o / (u * dos_heads * dos_sectors); 878103665Sphk 879103665Sphk return (disksecs); 8804Srgrimes} 8814Srgrimes 88216561Salexstatic int 8834Srgrimesread_s0() 8844Srgrimes{ 885113454Sphk int i; 886113454Sphk 88763218Sache mboot.bootinst_size = secsize; 88863218Sache if (mboot.bootinst != NULL) 88963027Sjhb free(mboot.bootinst); 89063218Sache if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) { 89163218Sache warnx("unable to allocate buffer to read fdisk " 89263218Sache "partition table"); 89363218Sache return -1; 89463027Sjhb } 89563027Sjhb if (read_disk(0, mboot.bootinst) == -1) { 89637415Scharnier warnx("can't read fdisk partition table"); 8974Srgrimes return -1; 8984Srgrimes } 899113454Sphk if (le16dec(&mboot.bootinst[DOSMAGICOFFSET]) != DOSMAGIC) { 90037415Scharnier warnx("invalid fdisk partition table found"); 9014Srgrimes /* So should we initialize things */ 9024Srgrimes return -1; 9034Srgrimes } 904113454Sphk for (i = 0; i < NDOSPART; i++) 905113454Sphk dos_partition_dec( 906113454Sphk &mboot.bootinst[DOSPARTOFF + i * DOSPARTSIZE], 907113454Sphk &mboot.parts[i]); 9084Srgrimes return 0; 9094Srgrimes} 9104Srgrimes 91116561Salexstatic int 9124Srgrimeswrite_s0() 9134Srgrimes{ 914113454Sphk int sector, i; 91563027Sjhb 9164Srgrimes if (iotest) { 917187239Sluigi print_s0(); 9184Srgrimes return 0; 9194Srgrimes } 920113454Sphk for(i = 0; i < NDOSPART; i++) 921113454Sphk dos_partition_enc(&mboot.bootinst[DOSPARTOFF + i * DOSPARTSIZE], 922113454Sphk &mboot.parts[i]); 923113454Sphk le16enc(&mboot.bootinst[DOSMAGICOFFSET], DOSMAGIC); 924226908Sjmg for(sector = 0; sector < mboot.bootinst_size / secsize; sector++) 92563027Sjhb if (write_disk(sector, 92663027Sjhb &mboot.bootinst[sector * secsize]) == -1) { 92763027Sjhb warn("can't write fdisk partition table"); 92863027Sjhb return -1; 92963027Sjhb } 93016561Salex return(0); 9314Srgrimes} 9324Srgrimes 9334Srgrimes 93416561Salexstatic int 93593394Sphkok(const char *str) 9364Srgrimes{ 9374Srgrimes printf("%s [n] ", str); 93881164Siedowse fflush(stdout); 93981164Siedowse if (fgets(lbuf, LBUF, stdin) == NULL) 94081164Siedowse exit(1); 9414Srgrimes lbuf[strlen(lbuf)-1] = 0; 9424Srgrimes 9434Srgrimes if (*lbuf && 9444Srgrimes (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || 9454Srgrimes !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) 9464Srgrimes return 1; 9474Srgrimes else 9484Srgrimes return 0; 9494Srgrimes} 9504Srgrimes 95116561Salexstatic int 952217808Ssobomaxdecimal(const char *str, int *num, int deflt, uint32_t maxval) 9534Srgrimes{ 954227280Sae long long acc; 955217714Ssobomax int c; 95693394Sphk char *cp; 9574Srgrimes 9584Srgrimes while (1) { 959227280Sae acc = 0; 9604Srgrimes printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); 96181164Siedowse fflush(stdout); 96281164Siedowse if (fgets(lbuf, LBUF, stdin) == NULL) 96381164Siedowse exit(1); 9644Srgrimes lbuf[strlen(lbuf)-1] = 0; 9654Srgrimes 9664Srgrimes if (!*lbuf) 9674Srgrimes return 0; 9684Srgrimes 9694Srgrimes cp = lbuf; 9704Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 9714Srgrimes if (!c) 9724Srgrimes return 0; 97316561Salex while ((c = *cp++)) { 974217714Ssobomax if (c <= '9' && c >= '0') { 975225007Sae if (acc <= maxval || maxval == 0) 976217714Ssobomax acc = acc * 10 + c - '0'; 977217714Ssobomax } else 9784Srgrimes break; 9794Srgrimes } 9804Srgrimes if (c == ' ' || c == '\t') 9814Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 9824Srgrimes if (!c) { 983217808Ssobomax if (maxval > 0 && acc > maxval) { 984217808Ssobomax acc = maxval; 985217808Ssobomax printf("%s exceeds maximum value allowed for " 986217808Ssobomax "this field. The value has been reduced " 987217808Ssobomax "to %lld\n", lbuf, acc); 988217714Ssobomax } 9894Srgrimes *num = acc; 9904Srgrimes return 1; 9914Srgrimes } else 99234952Sobrien printf("%s is an invalid decimal number. Try again.\n", 9934Srgrimes lbuf); 9944Srgrimes } 9954Srgrimes} 9964Srgrimes 9974Srgrimes 99819459Sjkhstatic void 99993394Sphkparse_config_line(char *line, CMD *command) 100019459Sjkh{ 100119459Sjkh char *cp, *end; 100219459Sjkh 100319459Sjkh cp = line; 100493394Sphk while (1) { 100519459Sjkh memset(command, 0, sizeof(*command)); 100619459Sjkh 100719459Sjkh while (isspace(*cp)) ++cp; 100819459Sjkh if (*cp == '\0' || *cp == '#') 100919459Sjkh break; 101019459Sjkh command->cmd = *cp++; 101119459Sjkh 101219459Sjkh /* 101319459Sjkh * Parse args 101419459Sjkh */ 101593394Sphk while (1) { 101619459Sjkh while (isspace(*cp)) ++cp; 1017192745Sbrian if (*cp == '\0') 1018192745Sbrian break; /* eol */ 101919459Sjkh if (*cp == '#') 102019459Sjkh break; /* found comment */ 102119459Sjkh if (isalpha(*cp)) 102219459Sjkh command->args[command->n_args].argtype = *cp++; 102319459Sjkh end = NULL; 1024224150Srstone command->args[command->n_args].arg_val = strtoul(cp, &end, 0); 1025192745Sbrian if (cp == end || (!isspace(*end) && *end != '\0')) { 1026192745Sbrian char ch; 1027192745Sbrian end = cp; 1028192745Sbrian while (!isspace(*end) && *end != '\0') ++end; 1029192745Sbrian ch = *end; *end = '\0'; 1030192745Sbrian command->args[command->n_args].arg_str = strdup(cp); 1031192745Sbrian *end = ch; 1032192745Sbrian } else 1033192745Sbrian command->args[command->n_args].arg_str = NULL; 103419459Sjkh cp = end; 103519459Sjkh command->n_args++; 103619459Sjkh } 103719459Sjkh break; 103819459Sjkh } 103919459Sjkh} 104019459Sjkh 104119459Sjkh 104219459Sjkhstatic int 104393394Sphkprocess_geometry(CMD *command) 104419459Sjkh{ 104519459Sjkh int status = 1, i; 104619459Sjkh 104793394Sphk while (1) { 104819459Sjkh geom_processed = 1; 104993394Sphk if (part_processed) { 105037415Scharnier warnx( 105137415Scharnier "ERROR line %d: the geometry specification line must occur before\n\ 105237415Scharnier all partition specifications", 105337415Scharnier current_line_number); 105419459Sjkh status = 0; 105519459Sjkh break; 105619459Sjkh } 105793394Sphk if (command->n_args != 3) { 105837415Scharnier warnx("ERROR line %d: incorrect number of geometry args", 105937415Scharnier current_line_number); 106019459Sjkh status = 0; 106119459Sjkh break; 106219459Sjkh } 106393394Sphk dos_cyls = 0; 106493394Sphk dos_heads = 0; 106593394Sphk dos_sectors = 0; 106693394Sphk for (i = 0; i < 3; ++i) { 106793394Sphk switch (command->args[i].argtype) { 106819459Sjkh case 'c': 106919459Sjkh dos_cyls = command->args[i].arg_val; 107019459Sjkh break; 107119459Sjkh case 'h': 107219459Sjkh dos_heads = command->args[i].arg_val; 107319459Sjkh break; 107419459Sjkh case 's': 107519459Sjkh dos_sectors = command->args[i].arg_val; 107619459Sjkh break; 107719459Sjkh default: 107837415Scharnier warnx( 107937415Scharnier "ERROR line %d: unknown geometry arg type: '%c' (0x%02x)", 108037415Scharnier current_line_number, command->args[i].argtype, 108119459Sjkh command->args[i].argtype); 108219459Sjkh status = 0; 108319459Sjkh break; 108419459Sjkh } 108519459Sjkh } 108619459Sjkh if (status == 0) 108719459Sjkh break; 108819459Sjkh 108919459Sjkh dos_cylsecs = dos_heads * dos_sectors; 109019459Sjkh 109119459Sjkh /* 109219459Sjkh * Do sanity checks on parameter values 109319459Sjkh */ 109493394Sphk if (dos_cyls == 0) { 109537415Scharnier warnx("ERROR line %d: number of cylinders not specified", 109637415Scharnier current_line_number); 109719459Sjkh status = 0; 109819459Sjkh } 109993394Sphk if (dos_cyls > 1024) { 110037415Scharnier warnx( 110137415Scharnier "WARNING line %d: number of cylinders (%d) may be out-of-range\n\ 110219459Sjkh (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\ 110337415Scharnier is dedicated to FreeBSD)", 110437415Scharnier current_line_number, dos_cyls); 110519459Sjkh } 110619459Sjkh 110793394Sphk if (dos_heads == 0) { 110837415Scharnier warnx("ERROR line %d: number of heads not specified", 110937415Scharnier current_line_number); 111019459Sjkh status = 0; 1111194333Slulf } else if (dos_heads > 256) { 1112194333Slulf warnx("ERROR line %d: number of heads must be within (1-256)", 111337415Scharnier current_line_number); 111419459Sjkh status = 0; 111519459Sjkh } 111619459Sjkh 111793394Sphk if (dos_sectors == 0) { 111837415Scharnier warnx("ERROR line %d: number of sectors not specified", 111937415Scharnier current_line_number); 112019459Sjkh status = 0; 112193394Sphk } else if (dos_sectors > 63) { 112237415Scharnier warnx("ERROR line %d: number of sectors must be within (1-63)", 112337415Scharnier current_line_number); 112419459Sjkh status = 0; 112519459Sjkh } 112619459Sjkh 112719459Sjkh break; 112819459Sjkh } 112919459Sjkh return (status); 113019459Sjkh} 113119459Sjkh 1132192745Sbrianstatic u_int32_t 1133192745Sbrianstr2sectors(const char *str) 1134192745Sbrian{ 1135192745Sbrian char *end; 1136192745Sbrian unsigned long val; 113719459Sjkh 1138192745Sbrian val = strtoul(str, &end, 0); 1139192745Sbrian if (str == end || *end == '\0') { 1140192745Sbrian warnx("ERROR line %d: unexpected size: \'%s\'", 1141192745Sbrian current_line_number, str); 1142217808Ssobomax return NO_DISK_SECTORS; 1143192745Sbrian } 1144192745Sbrian 1145226908Sjmg if (*end == 'K') 1146192745Sbrian val *= 1024UL / secsize; 1147192745Sbrian else if (*end == 'M') 1148192745Sbrian val *= 1024UL * 1024UL / secsize; 1149192745Sbrian else if (*end == 'G') 1150192745Sbrian val *= 1024UL * 1024UL * 1024UL / secsize; 1151192745Sbrian else { 1152192745Sbrian warnx("ERROR line %d: unexpected modifier: %c " 1153192745Sbrian "(not K/M/G)", current_line_number, *end); 1154217808Ssobomax return NO_DISK_SECTORS; 1155192745Sbrian } 1156192745Sbrian 1157192745Sbrian return val; 1158192745Sbrian} 1159192745Sbrian 116019459Sjkhstatic int 116193394Sphkprocess_partition(CMD *command) 116219459Sjkh{ 116319459Sjkh int status = 0, partition; 116465054Sjhb u_int32_t prev_head_boundary, prev_cyl_boundary; 116565054Sjhb u_int32_t adj_size, max_end; 116619459Sjkh struct dos_partition *partp; 116719459Sjkh 116893394Sphk while (1) { 116919459Sjkh part_processed = 1; 117093394Sphk if (command->n_args != 4) { 117137415Scharnier warnx("ERROR line %d: incorrect number of partition args", 117237415Scharnier current_line_number); 117319459Sjkh break; 117419459Sjkh } 117519459Sjkh partition = command->args[0].arg_val; 117693394Sphk if (partition < 1 || partition > 4) { 117737415Scharnier warnx("ERROR line %d: invalid partition number %d", 117837415Scharnier current_line_number, partition); 117919459Sjkh break; 118019459Sjkh } 1181187203Sluigi partp = &mboot.parts[partition - 1]; 1182187203Sluigi bzero(partp, sizeof (*partp)); 118319459Sjkh partp->dp_typ = command->args[1].arg_val; 1184192745Sbrian if (command->args[2].arg_str != NULL) { 1185192745Sbrian if (strcmp(command->args[2].arg_str, "*") == 0) { 1186192745Sbrian int i; 1187192745Sbrian partp->dp_start = dos_sectors; 1188192745Sbrian for (i = 1; i < partition; i++) { 1189192745Sbrian struct dos_partition *prev_partp; 1190192745Sbrian prev_partp = ((struct dos_partition *) 1191192745Sbrian &mboot.parts) + i - 1; 1192192745Sbrian if (prev_partp->dp_typ != 0) 1193192745Sbrian partp->dp_start = prev_partp->dp_start + 1194192745Sbrian prev_partp->dp_size; 1195192745Sbrian } 1196192745Sbrian if (partp->dp_start % dos_sectors != 0) { 1197192745Sbrian prev_head_boundary = partp->dp_start / 1198192745Sbrian dos_sectors * dos_sectors; 1199192745Sbrian partp->dp_start = prev_head_boundary + 1200192745Sbrian dos_sectors; 1201192745Sbrian } 1202192745Sbrian } else { 1203192745Sbrian partp->dp_start = str2sectors(command->args[2].arg_str); 1204217808Ssobomax if (partp->dp_start == NO_DISK_SECTORS) 1205192745Sbrian break; 1206192745Sbrian } 1207192745Sbrian } else 1208192745Sbrian partp->dp_start = command->args[2].arg_val; 1209192745Sbrian 1210192745Sbrian if (command->args[3].arg_str != NULL) { 1211192745Sbrian if (strcmp(command->args[3].arg_str, "*") == 0) 1212192745Sbrian partp->dp_size = ((disksecs / dos_cylsecs) * 1213192745Sbrian dos_cylsecs) - partp->dp_start; 1214192745Sbrian else { 1215192745Sbrian partp->dp_size = str2sectors(command->args[3].arg_str); 1216217808Ssobomax if (partp->dp_size == NO_DISK_SECTORS) 1217192745Sbrian break; 1218192745Sbrian } 1219192745Sbrian prev_cyl_boundary = ((partp->dp_start + partp->dp_size) / 1220192745Sbrian dos_cylsecs) * dos_cylsecs; 1221192745Sbrian if (prev_cyl_boundary > partp->dp_start) 1222192745Sbrian partp->dp_size = prev_cyl_boundary - partp->dp_start; 1223192745Sbrian } else 1224192745Sbrian partp->dp_size = command->args[3].arg_val; 1225192745Sbrian 122619459Sjkh max_end = partp->dp_start + partp->dp_size; 122719459Sjkh 1228187203Sluigi if (partp->dp_typ == 0) { 122919459Sjkh /* 123019459Sjkh * Get out, the partition is marked as unused. 123119459Sjkh */ 123219459Sjkh /* 123319459Sjkh * Insure that it's unused. 123419459Sjkh */ 1235187203Sluigi bzero(partp, sizeof(*partp)); 123619459Sjkh status = 1; 123719459Sjkh break; 123819459Sjkh } 123919459Sjkh 124019459Sjkh /* 1241108470Sschweikh * Adjust start upwards, if necessary, to fall on a head boundary. 124219459Sjkh */ 124393394Sphk if (partp->dp_start % dos_sectors != 0) { 124465054Sjhb prev_head_boundary = partp->dp_start / dos_sectors * dos_sectors; 124565054Sjhb if (max_end < dos_sectors || 124693394Sphk prev_head_boundary > max_end - dos_sectors) { 124719459Sjkh /* 124819459Sjkh * Can't go past end of partition 124919459Sjkh */ 125037415Scharnier warnx( 125137415Scharnier "ERROR line %d: unable to adjust start of partition %d to fall on\n\ 125265054Sjhb a head boundary", 125337415Scharnier current_line_number, partition); 125419459Sjkh break; 125519459Sjkh } 125637415Scharnier warnx( 125765054Sjhb "WARNING: adjusting start offset of partition %d\n\ 125865054Sjhb from %u to %u, to fall on a head boundary", 125965054Sjhb partition, (u_int)partp->dp_start, 126065054Sjhb (u_int)(prev_head_boundary + dos_sectors)); 126165054Sjhb partp->dp_start = prev_head_boundary + dos_sectors; 126219459Sjkh } 126319459Sjkh 126419459Sjkh /* 126519459Sjkh * Adjust size downwards, if necessary, to fall on a cylinder 126619459Sjkh * boundary. 126719459Sjkh */ 126865054Sjhb prev_cyl_boundary = 126919459Sjkh ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; 127065054Sjhb if (prev_cyl_boundary > partp->dp_start) 127165054Sjhb adj_size = prev_cyl_boundary - partp->dp_start; 127293394Sphk else { 127365054Sjhb warnx( 127465054Sjhb "ERROR: could not adjust partition to start on a head boundary\n\ 127565054Sjhb and end on a cylinder boundary."); 127665054Sjhb return (0); 127765054Sjhb } 127893394Sphk if (adj_size != partp->dp_size) { 127937415Scharnier warnx( 128065054Sjhb "WARNING: adjusting size of partition %d from %u to %u\n\ 128165054Sjhb to end on a cylinder boundary", 128265054Sjhb partition, (u_int)partp->dp_size, (u_int)adj_size); 128365054Sjhb partp->dp_size = adj_size; 128419459Sjkh } 128593394Sphk if (partp->dp_size == 0) { 128681164Siedowse warnx("ERROR line %d: size of partition %d is zero", 128737415Scharnier current_line_number, partition); 128819459Sjkh break; 128919459Sjkh } 129019459Sjkh 129181164Siedowse dos(partp); 129219459Sjkh status = 1; 129319459Sjkh break; 129419459Sjkh } 129519459Sjkh return (status); 129619459Sjkh} 129719459Sjkh 129819459Sjkh 129919459Sjkhstatic int 130093394Sphkprocess_active(CMD *command) 130119459Sjkh{ 130219459Sjkh int status = 0, partition, i; 130319459Sjkh struct dos_partition *partp; 130419459Sjkh 130593394Sphk while (1) { 130619459Sjkh active_processed = 1; 130793394Sphk if (command->n_args != 1) { 130837415Scharnier warnx("ERROR line %d: incorrect number of active args", 130937415Scharnier current_line_number); 131019459Sjkh status = 0; 131119459Sjkh break; 131219459Sjkh } 131319459Sjkh partition = command->args[0].arg_val; 131493394Sphk if (partition < 1 || partition > 4) { 131537415Scharnier warnx("ERROR line %d: invalid partition number %d", 131637415Scharnier current_line_number, partition); 131719459Sjkh break; 131819459Sjkh } 131919459Sjkh /* 132019459Sjkh * Reset active partition 132119459Sjkh */ 1322187203Sluigi partp = mboot.parts; 132319459Sjkh for (i = 0; i < NDOSPART; i++) 132419459Sjkh partp[i].dp_flag = 0; 132526421Sbrian partp[partition-1].dp_flag = ACTIVE; 132619459Sjkh 132719459Sjkh status = 1; 132819459Sjkh break; 132919459Sjkh } 133019459Sjkh return (status); 133119459Sjkh} 133219459Sjkh 133319459Sjkh 133419459Sjkhstatic int 133593394Sphkprocess_line(char *line) 133619459Sjkh{ 133719459Sjkh CMD command; 133819459Sjkh int status = 1; 133919459Sjkh 134093394Sphk while (1) { 134119459Sjkh parse_config_line(line, &command); 134293394Sphk switch (command.cmd) { 134319459Sjkh case 0: 134419459Sjkh /* 134519459Sjkh * Comment or blank line 134619459Sjkh */ 134719459Sjkh break; 134819459Sjkh case 'g': 134919459Sjkh /* 135019459Sjkh * Set geometry 135119459Sjkh */ 135219459Sjkh status = process_geometry(&command); 135319459Sjkh break; 135419459Sjkh case 'p': 135519459Sjkh status = process_partition(&command); 135619459Sjkh break; 135719459Sjkh case 'a': 135819459Sjkh status = process_active(&command); 135919459Sjkh break; 136019459Sjkh default: 136119459Sjkh status = 0; 136219459Sjkh break; 136319459Sjkh } 136419459Sjkh break; 136519459Sjkh } 136619459Sjkh return (status); 136719459Sjkh} 136819459Sjkh 136919459Sjkh 137019459Sjkhstatic int 137193394Sphkread_config(char *config_file) 137219459Sjkh{ 137319459Sjkh FILE *fp = NULL; 137419459Sjkh int status = 1; 137519459Sjkh char buf[1010]; 137619459Sjkh 137793394Sphk while (1) { 137893394Sphk if (strcmp(config_file, "-") != 0) { 137919459Sjkh /* 138019459Sjkh * We're not reading from stdin 138119459Sjkh */ 138293394Sphk if ((fp = fopen(config_file, "r")) == NULL) { 138319459Sjkh status = 0; 138419459Sjkh break; 138519459Sjkh } 138693394Sphk } else { 138719459Sjkh fp = stdin; 138819459Sjkh } 138919459Sjkh current_line_number = 0; 139093394Sphk while (!feof(fp)) { 139119459Sjkh if (fgets(buf, sizeof(buf), fp) == NULL) 139219459Sjkh break; 139319459Sjkh ++current_line_number; 139419459Sjkh status = process_line(buf); 139519459Sjkh if (status == 0) 139619459Sjkh break; 139719459Sjkh } 139819459Sjkh break; 139919459Sjkh } 140093394Sphk if (fp) { 140119459Sjkh /* 140219459Sjkh * It doesn't matter if we're reading from stdin, as we've reached EOF 140319459Sjkh */ 140419459Sjkh fclose(fp); 140519459Sjkh } 140619459Sjkh return (status); 140719459Sjkh} 140819459Sjkh 140919459Sjkh 141019459Sjkhstatic void 141119459Sjkhreset_boot(void) 141219459Sjkh{ 141319459Sjkh int i; 141419459Sjkh struct dos_partition *partp; 141519459Sjkh 141619459Sjkh init_boot(); 1417187203Sluigi for (i = 0; i < 4; ++i) { 1418187203Sluigi partp = &mboot.parts[i]; 1419187203Sluigi bzero(partp, sizeof(*partp)); 142019459Sjkh } 142119459Sjkh} 142265054Sjhb 142365054Sjhbstatic int 142493394Sphksanitize_partition(struct dos_partition *partp) 142565054Sjhb{ 142665054Sjhb u_int32_t prev_head_boundary, prev_cyl_boundary; 142781164Siedowse u_int32_t max_end, size, start; 142865054Sjhb 142981164Siedowse start = partp->dp_start; 143081164Siedowse size = partp->dp_size; 143181164Siedowse max_end = start + size; 143281164Siedowse /* Only allow a zero size if the partition is being marked unused. */ 143381164Siedowse if (size == 0) { 143481164Siedowse if (start == 0 && partp->dp_typ == 0) 143581164Siedowse return (1); 143681164Siedowse warnx("ERROR: size of partition is zero"); 143781164Siedowse return (0); 143881164Siedowse } 143981164Siedowse /* Return if no adjustment is necessary. */ 144081164Siedowse if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0) 144181164Siedowse return (1); 144265054Sjhb 1443122627Sdes if (start == 0) { 1444122627Sdes warnx("WARNING: partition overlaps with partition table"); 1445122627Sdes if (ok("Correct this automatically?")) 1446122627Sdes start = dos_sectors; 1447122627Sdes } 144881164Siedowse if (start % dos_sectors != 0) 144981164Siedowse warnx("WARNING: partition does not start on a head boundary"); 145081164Siedowse if ((start +size) % dos_sectors != 0) 145181164Siedowse warnx("WARNING: partition does not end on a cylinder boundary"); 145281164Siedowse warnx("WARNING: this may confuse the BIOS or some operating systems"); 145381164Siedowse if (!ok("Correct this automatically?")) 145481164Siedowse return (1); 145581164Siedowse 145665054Sjhb /* 1457108470Sschweikh * Adjust start upwards, if necessary, to fall on a head boundary. 145865054Sjhb */ 145981164Siedowse if (start % dos_sectors != 0) { 146081164Siedowse prev_head_boundary = start / dos_sectors * dos_sectors; 146165054Sjhb if (max_end < dos_sectors || 146281164Siedowse prev_head_boundary >= max_end - dos_sectors) { 146365054Sjhb /* 146465054Sjhb * Can't go past end of partition 146565054Sjhb */ 146665054Sjhb warnx( 146765054Sjhb "ERROR: unable to adjust start of partition to fall on a head boundary"); 146865054Sjhb return (0); 146965054Sjhb } 147081164Siedowse start = prev_head_boundary + dos_sectors; 147165054Sjhb } 147265054Sjhb 147365054Sjhb /* 147465054Sjhb * Adjust size downwards, if necessary, to fall on a cylinder 147565054Sjhb * boundary. 147665054Sjhb */ 147781164Siedowse prev_cyl_boundary = ((start + size) / dos_cylsecs) * dos_cylsecs; 147881164Siedowse if (prev_cyl_boundary > start) 147981164Siedowse size = prev_cyl_boundary - start; 148081164Siedowse else { 148165054Sjhb warnx("ERROR: could not adjust partition to start on a head boundary\n\ 148265054Sjhb and end on a cylinder boundary."); 148365054Sjhb return (0); 148465054Sjhb } 148581164Siedowse 148681164Siedowse /* Finally, commit any changes to partp and return. */ 148781164Siedowse if (start != partp->dp_start) { 148881164Siedowse warnx("WARNING: adjusting start offset of partition to %u", 148981164Siedowse (u_int)start); 149081164Siedowse partp->dp_start = start; 149165054Sjhb } 149281164Siedowse if (size != partp->dp_size) { 149381164Siedowse warnx("WARNING: adjusting size of partition to %u", (u_int)size); 149481164Siedowse partp->dp_size = size; 149565054Sjhb } 149665054Sjhb 149765054Sjhb return (1); 149865054Sjhb} 149979681Sjoerg 150079681Sjoerg/* 150179681Sjoerg * Try figuring out the root device's canonical disk name. 150279681Sjoerg * The following choices are considered: 150379681Sjoerg * /dev/ad0s1a => /dev/ad0 150479681Sjoerg * /dev/da0a => /dev/da0 150579681Sjoerg * /dev/vinum/root => /dev/vinum/root 1506212247Sbrian * A ".eli" part is removed if it exists (see geli(8)). 1507212724Sbrian * A ".journal" ending is removed if it exists (see gjournal(8)). 150879681Sjoerg */ 150979681Sjoergstatic char * 151079681Sjoergget_rootdisk(void) 151179681Sjoerg{ 151279681Sjoerg struct statfs rootfs; 151379681Sjoerg regex_t re; 151479681Sjoerg#define NMATCHES 2 151579681Sjoerg regmatch_t rm[NMATCHES]; 1516212247Sbrian char dev[PATH_MAX], *s; 151779681Sjoerg int rv; 151879681Sjoerg 151979681Sjoerg if (statfs("/", &rootfs) == -1) 152079681Sjoerg err(1, "statfs(\"/\")"); 152179681Sjoerg 1522212724Sbrian if ((rv = regcomp(&re, "^(/dev/[a-z/]+[0-9]*)([sp][0-9]+)?[a-h]?(\\.journal)?$", 152379681Sjoerg REG_EXTENDED)) != 0) 152479681Sjoerg errx(1, "regcomp() failed (%d)", rv); 1525212247Sbrian strlcpy(dev, rootfs.f_mntfromname, sizeof (dev)); 1526212247Sbrian if ((s = strstr(dev, ".eli")) != NULL) 1527212247Sbrian memmove(s, s+4, strlen(s + 4) + 1); 1528212247Sbrian 1529212247Sbrian if ((rv = regexec(&re, dev, NMATCHES, rm, 0)) != 0) 153079681Sjoerg errx(1, 153179681Sjoerg"mounted root fs resource doesn't match expectations (regexec returned %d)", 153279681Sjoerg rv); 153379681Sjoerg if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL) 153479681Sjoerg errx(1, "out of memory"); 153579681Sjoerg memcpy(s, rootfs.f_mntfromname + rm[1].rm_so, 153679681Sjoerg rm[1].rm_eo - rm[1].rm_so); 153779681Sjoerg s[rm[1].rm_eo - rm[1].rm_so] = 0; 153879681Sjoerg 153979681Sjoerg return s; 154079681Sjoerg} 1541