fdisk.c revision 90866
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 90866 2002-02-18 19:32:38Z joe $"; 3037415Scharnier#endif /* not lint */ 3137415Scharnier 324Srgrimes#include <sys/disklabel.h> 3379681Sjoerg#include <sys/param.h> 3437415Scharnier#include <sys/stat.h> 3579681Sjoerg#include <sys/mount.h> 3637415Scharnier#include <ctype.h> 3737415Scharnier#include <fcntl.h> 3837415Scharnier#include <err.h> 3937415Scharnier#include <errno.h> 4079681Sjoerg#include <paths.h> 4179681Sjoerg#include <regex.h> 424Srgrimes#include <stdio.h> 4337415Scharnier#include <stdlib.h> 4416561Salex#include <string.h> 4516561Salex#include <unistd.h> 464Srgrimes 474Srgrimesint iotest; 484Srgrimes 494Srgrimes#define LBUF 100 504Srgrimesstatic char lbuf[LBUF]; 514Srgrimes 5263027Sjhb#define MBRSIGOFF 510 5363027Sjhb 544Srgrimes/* 554Srgrimes * 564Srgrimes * Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992 574Srgrimes * 584Srgrimes * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University 594Srgrimes * Copyright (c) 1989 Robert. V. Baron 604Srgrimes * Created. 614Srgrimes */ 624Srgrimes 634Srgrimes#define Decimal(str, ans, tmp) if (decimal(str, &tmp, ans)) ans = tmp 644Srgrimes#define Hex(str, ans, tmp) if (hex(str, &tmp, ans)) ans = tmp 654Srgrimes#define String(str, ans, len) {char *z = ans; char **dflt = &z; if (string(str, dflt)) strncpy(ans, *dflt, len); } 664Srgrimes 674Srgrimes#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs) 684Srgrimes 6920061Ssos#define MAX_SEC_SIZE 2048 /* maximum section size that is supported */ 7020061Ssos#define MIN_SEC_SIZE 512 /* the sector size to start sensing at */ 7120061Ssosint secsize = 0; /* the sensed sector size */ 724Srgrimes 7379681Sjoergchar *disk; 7410514Sjoerg 754Srgrimesstruct disklabel disklabel; /* disk parameters */ 764Srgrimes 774Srgrimesint cyls, sectors, heads, cylsecs, disksecs; 784Srgrimes 794Srgrimesstruct mboot 804Srgrimes{ 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}; 8663027Sjhbstruct mboot mboot = {{0}, NULL, 0}; 874Srgrimes 884Srgrimes#define ACTIVE 0x80 894Srgrimes#define BOOT_MAGIC 0xAA55 904Srgrimes 914Srgrimesint dos_cyls; 924Srgrimesint dos_heads; 934Srgrimesint dos_sectors; 944Srgrimesint dos_cylsecs; 954Srgrimes 964Srgrimes#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0)) 974Srgrimes#define DOSCYL(c) (c & 0xff) 984Srgrimesstatic int partition = -1; 994Srgrimes 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 10919459Sjkh 11019459Sjkhtypedef struct cmd { 11119459Sjkh char cmd; 11219459Sjkh int n_args; 11319459Sjkh struct arg { 11419459Sjkh char argtype; 11519459Sjkh int arg_val; 11619459Sjkh } args[MAX_ARGS]; 11719459Sjkh} CMD; 11819459Sjkh 11919459Sjkh 12048282Srnordierstatic int B_flag = 0; /* replace boot code */ 12157896Simpstatic int I_flag = 0; /* use entire disk for FreeBSD */ 1224Srgrimesstatic int a_flag = 0; /* set active partition */ 12348282Srnordierstatic char *b_flag = NULL; /* path to boot code */ 1244Srgrimesstatic int i_flag = 0; /* replace partition data */ 1254Srgrimesstatic int u_flag = 0; /* update partition data */ 12657896Simpstatic int s_flag = 0; /* Print a summary and exit */ 12719459Sjkhstatic int t_flag = 0; /* test only, if f_flag is given */ 12819459Sjkhstatic char *f_flag = NULL; /* Read config info from file */ 12919459Sjkhstatic int v_flag = 0; /* Be verbose */ 1304Srgrimes 1314Srgrimesstruct part_type 1324Srgrimes{ 1334Srgrimes unsigned char type; 1344Srgrimes char *name; 1354Srgrimes}part_types[] = 1364Srgrimes{ 1378871Srgrimes {0x00, "unused"} 1388871Srgrimes ,{0x01, "Primary DOS with 12 bit FAT"} 1398871Srgrimes ,{0x02, "XENIX / filesystem"} 1408871Srgrimes ,{0x03, "XENIX /usr filesystem"} 14190866Sjoe ,{0x04, "Primary DOS with 16 bit FAT (< 32MB)"} 1428871Srgrimes ,{0x05, "Extended DOS"} 14390866Sjoe ,{0x06, "Primary 'big' DOS (>= 32MB)"} 14461461Sghelmer ,{0x07, "OS/2 HPFS, NTFS, QNX-2 (16 bit) or Advanced UNIX"} 14590866Sjoe ,{0x08, "AIX filesystem or SplitDrive"} 1468871Srgrimes ,{0x09, "AIX boot partition or Coherent"} 14790866Sjoe ,{0x0A, "OS/2 Boot Manager, OPUS or Coherent swap"} 14834582Sache ,{0x0B, "DOS or Windows 95 with 32 bit FAT"} 14990866Sjoe ,{0x0C, "DOS or Windows 95 with 32 bit FAT (LBA)"} 15090866Sjoe ,{0x0E, "Primary 'big' DOS (>= 32MB, LBA)"} 15190866Sjoe ,{0x0F, "Extended DOS (LBA)"} 1528871Srgrimes ,{0x10, "OPUS"} 15390866Sjoe ,{0x11, "OS/2 BM: hidden DOS with 12-bit FAT"} 15490866Sjoe ,{0x12, "Compaq diagnostics"} 15590866Sjoe ,{0x14, "OS/2 BM: hidden DOS with 16-bit FAT (< 32MB)"} 15690866Sjoe ,{0x16, "OS/2 BM: hidden DOS with 16-bit FAT (>= 32MB)"} 15790866Sjoe ,{0x17, "OS/2 BM: hidden IFS (e.g. HPFS)"} 15890866Sjoe ,{0x18, "AST Windows swapfile"} 15990866Sjoe ,{0x24, "NEC DOS"} 16090866Sjoe ,{0x3C, "PartitionMagic recovery"} 16161568Sbrian ,{0x39, "plan9"} 1628871Srgrimes ,{0x40, "VENIX 286"} 16390866Sjoe ,{0x41, "Linux/MINIX (sharing disk with DRDOS)"} 16490866Sjoe ,{0x42, "SFS or Linux swap (sharing disk with DRDOS)"} 16590866Sjoe ,{0x43, "Linux native (sharing disk with DRDOS)"} 16661461Sghelmer ,{0x4D, "QNX 4.2 Primary"} 16761461Sghelmer ,{0x4E, "QNX 4.2 Secondary"} 16861461Sghelmer ,{0x4F, "QNX 4.2 Tertiary"} 16990866Sjoe ,{0x50, "DM (disk manager)"} 17090866Sjoe ,{0x51, "DM6 Aux1 (or Novell)"} 1718871Srgrimes ,{0x52, "CP/M or Microport SysV/AT"} 17290866Sjoe ,{0x53, "DM6 Aux3"} 17390866Sjoe ,{0x54, "DM6"} 17490866Sjoe ,{0x55, "EZ-Drive (disk manager)"} 17590866Sjoe ,{0x56, "Golden Bow (disk manager)"} 17690866Sjoe ,{0x5c, "Priam Edisk (disk manager)"} /* according to S. Widlake */ 17790866Sjoe ,{0x61, "SpeedStor"} 17890866Sjoe ,{0x63, "System V/386 (such as ISC UNIX), GNU HURD or Mach"} 17990866Sjoe ,{0x64, "Novell Netware/286 2.xx"} 18090866Sjoe ,{0x65, "Novell Netware/386 3.xx"} 18190866Sjoe ,{0x70, "DiskSecure Multi-Boot"} 1828871Srgrimes ,{0x75, "PCIX"} 18390866Sjoe ,{0x77, "QNX4.x"} 18490866Sjoe ,{0x78, "QNX4.x 2nd part"} 18590866Sjoe ,{0x79, "QNX4.x 3rd part"} 18690866Sjoe ,{0x80, "Minix until 1.4a"} 18790866Sjoe ,{0x81, "Minix since 1.4b, early Linux partition or Mitac (disk manager)"} 18839377Sobrien ,{0x82, "Linux swap or Solaris x86"} 18990866Sjoe ,{0x83, "Linux native"} 19090866Sjoe ,{0x84, "OS/2 hidden C: drive"} 19190866Sjoe ,{0x85, "Linux extended"} 19290866Sjoe ,{0x86, "NTFS volume set??"} 19390866Sjoe ,{0x87, "NTFS volume set??"} 1948871Srgrimes ,{0x93, "Amoeba filesystem"} 1958871Srgrimes ,{0x94, "Amoeba bad block table"} 19640946Sjkoshy ,{0x9F, "BSD/OS"} 19764316Sjoe ,{0xA0, "Suspend to Disk"} 1988871Srgrimes ,{0xA5, "FreeBSD/NetBSD/386BSD"} 19925378Simp ,{0xA6, "OpenBSD"} 20090866Sjoe ,{0xA7, "NeXTSTEP"} 20140947Salex ,{0xA9, "NetBSD"} 2028871Srgrimes ,{0xB7, "BSDI BSD/386 filesystem"} 2038871Srgrimes ,{0xB8, "BSDI BSD/386 swap"} 20490866Sjoe ,{0xC1, "DRDOS/sec with 12-bit FAT"} 20590866Sjoe ,{0xC4, "DRDOS/sec with 16-bit FAT (< 32MB)"} 20690866Sjoe ,{0xC6, "DRDOS/sec with 16-bit FAT (>= 32MB)"} 20790866Sjoe ,{0xC7, "Syrinx"} 20890866Sjoe ,{0xDB, "CP/M, Concurrent CP/M, Concurrent DOS or CTOS"} 20990866Sjoe ,{0xE1, "DOS access or SpeedStor with 12-bit FAT extended partition"} 21090866Sjoe ,{0xE3, "DOS R/O or SpeedStor"} 21190866Sjoe ,{0xE4, "SpeedStor with 16-bit FAT extended partition < 1024 cyl."} 21290866Sjoe ,{0xEB, "BeOS filesystem"} 21384964Speter ,{0xEE, "EFI GPT"} 21485027Sbde ,{0xEF, "EFI System Partition"} 21590866Sjoe ,{0xF1, "SpeedStor"} 2168871Srgrimes ,{0xF2, "DOS 3.3+ Secondary"} 21790866Sjoe ,{0xF4, "SpeedStor large partition"} 21890866Sjoe ,{0xFE, "SpeedStor >1024 cyl. or LANstep"} 21990866Sjoe ,{0xFF, "Xenix bad blocks table"} 2204Srgrimes}; 2214Srgrimes 22216561Salexstatic void print_s0(int which); 22316561Salexstatic void print_part(int i); 22416561Salexstatic void init_sector0(unsigned long start); 22519459Sjkhstatic void init_boot(void); 22616561Salexstatic void change_part(int i); 22716561Salexstatic void print_params(); 22816561Salexstatic void change_active(int which); 22943054Srnordierstatic void change_code(); 23016561Salexstatic void get_params_to_use(); 23179681Sjoergstatic char *get_rootdisk(void); 23281164Siedowsestatic void dos(struct dos_partition *partp); 23316561Salexstatic int open_disk(int u_flag); 23416561Salexstatic ssize_t read_disk(off_t sector, void *buf); 23516561Salexstatic ssize_t write_disk(off_t sector, void *buf); 23616561Salexstatic int get_params(); 23716561Salexstatic int read_s0(); 23816561Salexstatic int write_s0(); 23916561Salexstatic int ok(char *str); 24016561Salexstatic int decimal(char *str, int *num, int deflt); 24116561Salexstatic char *get_type(int type); 24219459Sjkhstatic int read_config(char *config_file); 24319459Sjkhstatic void reset_boot(void); 24465054Sjhbstatic int sanitize_partition(struct dos_partition *); 24537415Scharnierstatic void usage(void); 24616561Salex#if 0 24716561Salexstatic int hex(char *str, int *num, int deflt); 24816561Salexstatic int string(char *str, char **ans); 24916561Salex#endif 2504Srgrimes 25116561Salex 25216561Salexint 25316561Salexmain(int argc, char *argv[]) 2544Srgrimes{ 25579681Sjoerg struct stat sb; 25648282Srnordier int c, i; 2574Srgrimes 25857896Simp while ((c = getopt(argc, argv, "BIab:f:istuv1234")) != -1) 25948282Srnordier switch (c) { 26048282Srnordier case 'B': 26148282Srnordier B_flag = 1; 2624Srgrimes break; 26357896Simp case 'I': 26457896Simp I_flag = 1; 26557896Simp break; 26648282Srnordier case 'a': 26748282Srnordier a_flag = 1; 26848282Srnordier break; 26948282Srnordier case 'b': 27048282Srnordier b_flag = optarg; 27148282Srnordier break; 27248282Srnordier case 'f': 27348282Srnordier f_flag = optarg; 27448282Srnordier break; 27548282Srnordier case 'i': 27648282Srnordier i_flag = 1; 27748282Srnordier break; 27857896Simp case 's': 27957896Simp s_flag = 1; 28057896Simp break; 28148282Srnordier case 't': 28248282Srnordier t_flag = 1; 28348282Srnordier break; 28448282Srnordier case 'u': 28548282Srnordier u_flag = 1; 28648282Srnordier break; 28748282Srnordier case 'v': 28848282Srnordier v_flag = 1; 28948282Srnordier break; 29048282Srnordier case '1': 29148282Srnordier case '2': 29248282Srnordier case '3': 29348282Srnordier case '4': 29448282Srnordier partition = c - '0'; 29548282Srnordier break; 29648282Srnordier default: 29748282Srnordier usage(); 2984Srgrimes } 29948282Srnordier if (f_flag || i_flag) 30048282Srnordier u_flag = 1; 30148282Srnordier if (t_flag) 30248282Srnordier v_flag = 1; 30348282Srnordier argc -= optind; 30448282Srnordier argv += optind; 3054Srgrimes 30679681Sjoerg if (argc == 0) { 30779681Sjoerg disk = get_rootdisk(); 30879681Sjoerg } else { 30979681Sjoerg if (stat(argv[0], &sb) == 0) { 31079681Sjoerg /* OK, full pathname given */ 31110514Sjoerg disk = argv[0]; 31279681Sjoerg } else if (errno == ENOENT) { 31379681Sjoerg /* Try prepending "/dev" */ 31479681Sjoerg if ((disk = malloc(strlen(argv[0]) + strlen(_PATH_DEV) + 31579681Sjoerg 1)) == NULL) 31679681Sjoerg errx(1, "out of memory"); 31779681Sjoerg strcpy(disk, _PATH_DEV); 31879681Sjoerg strcat(disk, argv[0]); 31979681Sjoerg } else { 32079681Sjoerg /* other stat error, let it fail below */ 32179681Sjoerg disk = argv[0]; 32210514Sjoerg } 32310514Sjoerg } 32479681Sjoerg if (open_disk(u_flag) < 0) 32579681Sjoerg err(1, "cannot open disk %s", disk); 3264Srgrimes 32763027Sjhb /* (abu)use mboot.bootinst to probe for the sector size */ 32863027Sjhb if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL) 32963027Sjhb err(1, "cannot allocate buffer to determine disk sector size"); 33063027Sjhb read_disk(0, mboot.bootinst); 33163329Sjhb free(mboot.bootinst); 33263329Sjhb mboot.bootinst = NULL; 33363027Sjhb 33457896Simp if (s_flag) 33557896Simp { 33657896Simp int i; 33757896Simp struct dos_partition *partp; 33810514Sjoerg 33957896Simp if (read_s0()) 34057896Simp err(1, "read_s0"); 34157896Simp printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads, 34257896Simp dos_sectors); 34357896Simp printf("Part %11s %11s Type Flags\n", "Start", "Size"); 34457896Simp for (i = 0; i < NDOSPART; i++) { 34557896Simp partp = ((struct dos_partition *) &mboot.parts) + i; 34657896Simp if (partp->dp_start == 0 && partp->dp_size == 0) 34757896Simp continue; 34857896Simp printf("%4d: %11lu %11lu 0x%02x 0x%02x\n", i + 1, 34957896Simp (u_long) partp->dp_start, 35057896Simp (u_long) partp->dp_size, partp->dp_typ, 35157896Simp partp->dp_flag); 35257896Simp } 35357896Simp exit(0); 35457896Simp } 35557896Simp 3564Srgrimes printf("******* Working on device %s *******\n",disk); 35719459Sjkh 35857896Simp if (I_flag) 35950215Sphk { 36050215Sphk struct dos_partition *partp; 36150215Sphk 36250215Sphk read_s0(); 36350215Sphk reset_boot(); 36450215Sphk partp = (struct dos_partition *) (&mboot.parts[0]); 36550215Sphk partp->dp_typ = DOSPTYP_386BSD; 36650215Sphk partp->dp_flag = ACTIVE; 36750215Sphk partp->dp_start = dos_sectors; 36865054Sjhb partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - 36965054Sjhb dos_sectors; 37050215Sphk 37181164Siedowse dos(partp); 37250215Sphk if (v_flag) 37350215Sphk print_s0(-1); 37450215Sphk write_s0(); 37550215Sphk exit(0); 37650215Sphk } 37719459Sjkh if (f_flag) 3784Srgrimes { 37919459Sjkh if (read_s0() || i_flag) 38019459Sjkh { 38119459Sjkh reset_boot(); 38219459Sjkh } 38319459Sjkh 38419459Sjkh if (!read_config(f_flag)) 38519459Sjkh { 38619459Sjkh exit(1); 38719459Sjkh } 38819459Sjkh if (v_flag) 38919459Sjkh { 39019459Sjkh print_s0(-1); 39119459Sjkh } 39219459Sjkh if (!t_flag) 39319459Sjkh { 39419459Sjkh write_s0(); 39519459Sjkh } 3964Srgrimes } 3974Srgrimes else 3984Srgrimes { 39919459Sjkh if(u_flag) 40019459Sjkh { 40119459Sjkh get_params_to_use(); 40219459Sjkh } 40319459Sjkh else 40419459Sjkh { 4054Srgrimes print_params(); 40619459Sjkh } 4074Srgrimes 40819459Sjkh if (read_s0()) 40965054Sjhb init_sector0(dos_sectors); 4104Srgrimes 41120061Ssos printf("Media sector size is %d\n", secsize); 41219459Sjkh printf("Warning: BIOS sector numbering starts with sector 1\n"); 41319459Sjkh printf("Information from DOS bootblock is:\n"); 41419459Sjkh if (partition == -1) 41526421Sbrian for (i = 1; i <= NDOSPART; i++) 41619459Sjkh change_part(i); 41719459Sjkh else 4184Srgrimes change_part(partition); 4194Srgrimes 42019459Sjkh if (u_flag || a_flag) 4214Srgrimes change_active(partition); 4224Srgrimes 42348282Srnordier if (B_flag) 42443054Srnordier change_code(); 42543054Srnordier 42648282Srnordier if (u_flag || a_flag || B_flag) { 42719459Sjkh if (!t_flag) 42819459Sjkh { 42919459Sjkh printf("\nWe haven't changed the partition table yet. "); 43019459Sjkh printf("This is your last chance.\n"); 43119459Sjkh } 4324Srgrimes print_s0(-1); 43319459Sjkh if (!t_flag) 43419459Sjkh { 43519459Sjkh if (ok("Should we write new partition table?")) 4364Srgrimes write_s0(); 43719459Sjkh } 43819459Sjkh else 43919459Sjkh { 44019459Sjkh printf("\n-t flag specified -- partition table not written.\n"); 44119459Sjkh } 44219459Sjkh } 4434Srgrimes } 4444Srgrimes 4454Srgrimes exit(0); 44637415Scharnier} 4474Srgrimes 44837415Scharnierstatic void 44937415Scharnierusage() 45037415Scharnier{ 45148282Srnordier fprintf(stderr, "%s%s", 45262178Sjhb "usage: fdisk [-BIaistu] [-b bootcode] [-1234] [disk]\n", 45348282Srnordier " fdisk -f configfile [-itv] [disk]\n"); 45437415Scharnier exit(1); 4554Srgrimes} 4564Srgrimes 45716561Salexstatic void 45816561Salexprint_s0(int which) 4594Srgrimes{ 4604Srgrimesint i; 4614Srgrimes 4624Srgrimes print_params(); 4634Srgrimes printf("Information from DOS bootblock is:\n"); 4644Srgrimes if (which == -1) 46526421Sbrian for (i = 1; i <= NDOSPART; i++) 4664Srgrimes printf("%d: ", i), print_part(i); 4674Srgrimes else 4684Srgrimes print_part(which); 4694Srgrimes} 4704Srgrimes 4714Srgrimesstatic struct dos_partition mtpart = { 0 }; 4724Srgrimes 47316561Salexstatic void 47416561Salexprint_part(int i) 4754Srgrimes{ 47626389Sgibbs struct dos_partition *partp; 47726389Sgibbs u_int64_t part_mb; 4784Srgrimes 47926421Sbrian partp = ((struct dos_partition *) &mboot.parts) + i - 1; 4804Srgrimes 4814Srgrimes if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) { 4824Srgrimes printf("<UNUSED>\n"); 4834Srgrimes return; 4844Srgrimes } 48526389Sgibbs /* 48626389Sgibbs * Be careful not to overflow. 48726389Sgibbs */ 48826389Sgibbs part_mb = partp->dp_size; 48926389Sgibbs part_mb *= secsize; 49026389Sgibbs part_mb /= (1024 * 1024); 49190866Sjoe printf("sysid %d (%#04x),(%s)\n", partp->dp_typ, partp->dp_typ, 49290866Sjoe get_type(partp->dp_typ)); 49337244Sbde printf(" start %lu, size %lu (%qd Meg), flag %x%s\n", 49437244Sbde (u_long)partp->dp_start, 49537244Sbde (u_long)partp->dp_size, 49626389Sgibbs part_mb, 49734952Sobrien partp->dp_flag, 49834952Sobrien partp->dp_flag == ACTIVE ? " (active)" : ""); 49969371Sobrien printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n" 5004Srgrimes ,DPCYL(partp->dp_scyl, partp->dp_ssect) 50169371Sobrien ,partp->dp_shd 5024Srgrimes ,DPSECT(partp->dp_ssect) 5034Srgrimes ,DPCYL(partp->dp_ecyl, partp->dp_esect) 50469371Sobrien ,partp->dp_ehd 50569371Sobrien ,DPSECT(partp->dp_esect)); 5064Srgrimes} 5074Srgrimes 50819459Sjkh 50916561Salexstatic void 51019459Sjkhinit_boot(void) 51119459Sjkh{ 51248282Srnordier const char *fname; 51363027Sjhb int fd, n; 51463027Sjhb struct stat sb; 51548282Srnordier 51648282Srnordier fname = b_flag ? b_flag : "/boot/mbr"; 51748282Srnordier if ((fd = open(fname, O_RDONLY)) == -1 || 51863027Sjhb fstat(fd, &sb) == -1) 51963027Sjhb err(1, "%s", 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); 52663027Sjhb if ((n = read(fd, mboot.bootinst, mboot.bootinst_size)) == -1 || 52748282Srnordier close(fd)) 52848282Srnordier err(1, "%s", fname); 52963027Sjhb if (n != mboot.bootinst_size) 53063027Sjhb errx(1, "%s: short read", fname); 53119459Sjkh} 53219459Sjkh 53319459Sjkh 53419459Sjkhstatic void 53516561Salexinit_sector0(unsigned long start) 5364Srgrimes{ 5374Srgrimesstruct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]); 5384Srgrimes 53919459Sjkh init_boot(); 5404Srgrimes 5414Srgrimes partp->dp_typ = DOSPTYP_386BSD; 5424Srgrimes partp->dp_flag = ACTIVE; 54365054Sjhb start = ((start + dos_sectors - 1) / dos_sectors) * dos_sectors; 54463027Sjhb if(start == 0) 54563027Sjhb start = dos_sectors; 5464Srgrimes partp->dp_start = start; 54765054Sjhb partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - start; 5484Srgrimes 54981164Siedowse dos(partp); 5504Srgrimes} 5514Srgrimes 55216561Salexstatic void 55316561Salexchange_part(int i) 5544Srgrimes{ 55526421Sbrianstruct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1; 5564Srgrimes 5574Srgrimes printf("The data for partition %d is:\n", i); 5584Srgrimes print_part(i); 5594Srgrimes 5604Srgrimes if (u_flag && ok("Do you want to change it?")) { 5614Srgrimes int tmp; 5624Srgrimes 5634Srgrimes if (i_flag) { 5644Srgrimes bzero((char *)partp, sizeof (struct dos_partition)); 56526421Sbrian if (i == 4) { 5664Srgrimes init_sector0(1); 56726421Sbrian printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n"); 5684Srgrimes print_part(i); 5694Srgrimes } 5704Srgrimes } 5714Srgrimes 5724Srgrimes do { 57334952Sobrien Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp); 5744Srgrimes Decimal("start", partp->dp_start, tmp); 5754Srgrimes Decimal("size", partp->dp_size, tmp); 57681164Siedowse if (!sanitize_partition(partp)) { 57781164Siedowse warnx("ERROR: failed to adjust; setting sysid to 0"); 57881164Siedowse partp->dp_typ = 0; 57981164Siedowse } 5804Srgrimes 58136262Sjraynard if (ok("Explicitly specify beg/end address ?")) 5824Srgrimes { 5834Srgrimes int tsec,tcyl,thd; 5844Srgrimes tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect); 5854Srgrimes thd = partp->dp_shd; 5864Srgrimes tsec = DPSECT(partp->dp_ssect); 5874Srgrimes Decimal("beginning cylinder", tcyl, tmp); 58869371Sobrien Decimal("beginning head", thd, tmp); 58968871Sobrien Decimal("beginning sector", tsec, tmp); 5904Srgrimes partp->dp_scyl = DOSCYL(tcyl); 5914Srgrimes partp->dp_ssect = DOSSECT(tsec,tcyl); 5924Srgrimes partp->dp_shd = thd; 5934Srgrimes 5944Srgrimes tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect); 5954Srgrimes thd = partp->dp_ehd; 5964Srgrimes tsec = DPSECT(partp->dp_esect); 5974Srgrimes Decimal("ending cylinder", tcyl, tmp); 59869371Sobrien Decimal("ending head", thd, tmp); 59968871Sobrien Decimal("ending sector", tsec, tmp); 6004Srgrimes partp->dp_ecyl = DOSCYL(tcyl); 6014Srgrimes partp->dp_esect = DOSSECT(tsec,tcyl); 6024Srgrimes partp->dp_ehd = thd; 60381164Siedowse } else 60481164Siedowse dos(partp); 6058871Srgrimes 6064Srgrimes print_part(i); 6074Srgrimes } while (!ok("Are we happy with this entry?")); 6084Srgrimes } 6094Srgrimes} 6104Srgrimes 61116561Salexstatic void 6124Srgrimesprint_params() 6134Srgrimes{ 6144Srgrimes printf("parameters extracted from in-core disklabel are:\n"); 6154Srgrimes printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 6164Srgrimes ,cyls,heads,sectors,cylsecs); 6174Srgrimes if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255)) 61820061Ssos printf("Figures below won't work with BIOS for partitions not in cyl 1\n"); 6194Srgrimes printf("parameters to be used for BIOS calculations are:\n"); 6204Srgrimes printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 6214Srgrimes ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); 6224Srgrimes} 6234Srgrimes 62416561Salexstatic void 62516561Salexchange_active(int which) 6264Srgrimes{ 62781164Siedowse struct dos_partition *partp = &mboot.parts[0]; 62881164Siedowse int active, i, new, tmp; 6294Srgrimes 63081164Siedowse active = -1; 63181164Siedowse for (i = 0; i < NDOSPART; i++) { 63281164Siedowse if ((partp[i].dp_flag & ACTIVE) == 0) 63381164Siedowse continue; 63481164Siedowse printf("Partition %d is marked active\n", i + 1); 63581164Siedowse if (active == -1) 63681164Siedowse active = i + 1; 63781164Siedowse } 6384Srgrimes if (a_flag && which != -1) 6394Srgrimes active = which; 64081164Siedowse else if (active == -1) 64181164Siedowse active = 1; 64281164Siedowse 6433723Sbde if (!ok("Do you want to change the active partition?")) 6443723Sbde return; 64534952Sobriensetactive: 64634952Sobrien do { 64781164Siedowse new = active; 64881164Siedowse Decimal("active partition", new, tmp); 64981164Siedowse if (new < 1 || new > 4) { 65034952Sobrien printf("Active partition number must be in range 1-4." 65134952Sobrien " Try again.\n"); 65234952Sobrien goto setactive; 65334952Sobrien } 65481164Siedowse active = new; 65534952Sobrien } while (!ok("Are you happy with this choice")); 6564Srgrimes for (i = 0; i < NDOSPART; i++) 6574Srgrimes partp[i].dp_flag = 0; 65826421Sbrian if (active > 0 && active <= NDOSPART) 65926421Sbrian partp[active-1].dp_flag = ACTIVE; 6604Srgrimes} 6614Srgrimes 66243054Srnordierstatic void 66343054Srnordierchange_code() 66443054Srnordier{ 66543054Srnordier if (ok("Do you want to change the boot code?")) 66643054Srnordier init_boot(); 66743054Srnordier} 66843054Srnordier 66916561Salexvoid 6704Srgrimesget_params_to_use() 6714Srgrimes{ 6724Srgrimes int tmp; 6734Srgrimes print_params(); 6744Srgrimes if (ok("Do you want to change our idea of what BIOS thinks ?")) 6754Srgrimes { 6764Srgrimes do 6774Srgrimes { 6784Srgrimes Decimal("BIOS's idea of #cylinders", dos_cyls, tmp); 6794Srgrimes Decimal("BIOS's idea of #heads", dos_heads, tmp); 6804Srgrimes Decimal("BIOS's idea of #sectors", dos_sectors, tmp); 6814Srgrimes dos_cylsecs = dos_heads * dos_sectors; 6824Srgrimes print_params(); 6834Srgrimes } 6844Srgrimes while(!ok("Are you happy with this choice")); 6854Srgrimes } 6864Srgrimes} 6874Srgrimes 68819459Sjkh 6894Srgrimes/***********************************************\ 6904Srgrimes* Change real numbers into strange dos numbers * 6914Srgrimes\***********************************************/ 69216561Salexstatic void 69381164Siedowsedos(partp) 69481164Siedowse struct dos_partition *partp; 6954Srgrimes{ 69681164Siedowse int cy, sec; 69781164Siedowse u_int32_t end; 6984Srgrimes 69988714Siedowse if (partp->dp_typ == 0 && partp->dp_start == 0 && partp->dp_size == 0) { 70088714Siedowse memcpy(partp, &mtpart, sizeof(*partp)); 7013723Sbde return; 7023723Sbde } 7033723Sbde 70481164Siedowse /* Start c/h/s. */ 70581164Siedowse partp->dp_shd = partp->dp_start % dos_cylsecs / dos_sectors; 70681164Siedowse cy = partp->dp_start / dos_cylsecs; 70781164Siedowse sec = partp->dp_start % dos_sectors + 1; 70881164Siedowse partp->dp_scyl = DOSCYL(cy); 70981164Siedowse partp->dp_ssect = DOSSECT(sec, cy); 7104Srgrimes 71181164Siedowse /* End c/h/s. */ 71281164Siedowse end = partp->dp_start + partp->dp_size - 1; 71381164Siedowse partp->dp_ehd = end % dos_cylsecs / dos_sectors; 71481164Siedowse cy = end / dos_cylsecs; 71581164Siedowse sec = end % dos_sectors + 1; 71681164Siedowse partp->dp_ecyl = DOSCYL(cy); 71781164Siedowse partp->dp_esect = DOSSECT(sec, cy); 7184Srgrimes} 7194Srgrimes 7204Srgrimesint fd; 7214Srgrimes 7224Srgrimes /* Getting device status */ 7234Srgrimes 72416561Salexstatic int 72516561Salexopen_disk(int u_flag) 7264Srgrimes{ 72779306Sjoerg struct stat st; 7284Srgrimes 7298871Srgrimes if (stat(disk, &st) == -1) { 73079306Sjoerg if (errno == ENOENT) 73179306Sjoerg return -2; 73237415Scharnier warnx("can't get file status of %s", disk); 7334Srgrimes return -1; 7342810Sbde } 7352810Sbde if ( !(st.st_mode & S_IFCHR) ) 73637415Scharnier warnx("device %s is not character special", disk); 73743054Srnordier if ((fd = open(disk, 73857896Simp a_flag || I_flag || B_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) { 73910514Sjoerg if(errno == ENXIO) 74010514Sjoerg return -2; 74137415Scharnier warnx("can't open device %s", disk); 7424Srgrimes return -1; 7434Srgrimes } 7444Srgrimes if (get_params(0) == -1) { 74537415Scharnier warnx("can't get disk parameters on %s", disk); 7464Srgrimes return -1; 7474Srgrimes } 7484Srgrimes return fd; 7494Srgrimes} 7504Srgrimes 75116561Salexstatic ssize_t 75216561Salexread_disk(off_t sector, void *buf) 7534Srgrimes{ 7544Srgrimes lseek(fd,(sector * 512), 0); 75520061Ssos if( secsize == 0 ) 75620061Ssos for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 ) 75720061Ssos { 75820061Ssos /* try the read */ 75920061Ssos int size = read(fd, buf, secsize); 76020061Ssos if( size == secsize ) 76120061Ssos /* it worked so return */ 76220061Ssos return secsize; 76320061Ssos } 76420061Ssos else 76520061Ssos return read( fd, buf, secsize ); 76620061Ssos 76720061Ssos /* we failed to read at any of the sizes */ 76820061Ssos return -1; 7694Srgrimes} 7704Srgrimes 77116561Salexstatic ssize_t 77216561Salexwrite_disk(off_t sector, void *buf) 7734Srgrimes{ 7744Srgrimes lseek(fd,(sector * 512), 0); 77520061Ssos /* write out in the size that the read_disk found worked */ 77620061Ssos return write(fd, buf, secsize); 7774Srgrimes} 7784Srgrimes 77916561Salexstatic int 78016561Salexget_params() 7814Srgrimes{ 7824Srgrimes 7834Srgrimes if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 78437415Scharnier warnx("can't get disk parameters on %s; supplying dummy ones", disk); 7852810Sbde dos_cyls = cyls = 1; 7862810Sbde dos_heads = heads = 1; 7872810Sbde dos_sectors = sectors = 1; 7882810Sbde dos_cylsecs = cylsecs = heads * sectors; 7892810Sbde disksecs = cyls * heads * sectors; 7902810Sbde return disksecs; 7914Srgrimes } 7924Srgrimes 7934Srgrimes dos_cyls = cyls = disklabel.d_ncylinders; 7944Srgrimes dos_heads = heads = disklabel.d_ntracks; 7954Srgrimes dos_sectors = sectors = disklabel.d_nsectors; 7964Srgrimes dos_cylsecs = cylsecs = heads * sectors; 7974Srgrimes disksecs = cyls * heads * sectors; 7984Srgrimes 7994Srgrimes return (disksecs); 8004Srgrimes} 8014Srgrimes 8024Srgrimes 80316561Salexstatic int 8044Srgrimesread_s0() 8054Srgrimes{ 80663218Sache mboot.bootinst_size = secsize; 80763218Sache if (mboot.bootinst != NULL) 80863027Sjhb free(mboot.bootinst); 80963218Sache if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) { 81063218Sache warnx("unable to allocate buffer to read fdisk " 81163218Sache "partition table"); 81263218Sache return -1; 81363027Sjhb } 81463027Sjhb if (read_disk(0, mboot.bootinst) == -1) { 81537415Scharnier warnx("can't read fdisk partition table"); 8164Srgrimes return -1; 8174Srgrimes } 81863729Sjhb if (*(uint16_t *)&mboot.bootinst[MBRSIGOFF] != BOOT_MAGIC) { 81937415Scharnier warnx("invalid fdisk partition table found"); 8204Srgrimes /* So should we initialize things */ 8214Srgrimes return -1; 8224Srgrimes } 82363027Sjhb memcpy(mboot.parts, &mboot.bootinst[DOSPARTOFF], sizeof(mboot.parts)); 8244Srgrimes return 0; 8254Srgrimes} 8264Srgrimes 82716561Salexstatic int 8284Srgrimeswrite_s0() 8294Srgrimes{ 83051636Sbillf#ifdef NOT_NOW 8314Srgrimes int flag; 83251636Sbillf#endif 83363027Sjhb int sector; 83463027Sjhb 8354Srgrimes if (iotest) { 8364Srgrimes print_s0(-1); 8374Srgrimes return 0; 8384Srgrimes } 83963027Sjhb memcpy(&mboot.bootinst[DOSPARTOFF], mboot.parts, sizeof(mboot.parts)); 8404Srgrimes /* 8414Srgrimes * write enable label sector before write (if necessary), 8424Srgrimes * disable after writing. 8434Srgrimes * needed if the disklabel protected area also protects 8444Srgrimes * sector 0. (e.g. empty disk) 8454Srgrimes */ 84650215Sphk#ifdef NOT_NOW 8474Srgrimes flag = 1; 8484Srgrimes if (ioctl(fd, DIOCWLABEL, &flag) < 0) 84937415Scharnier warn("ioctl DIOCWLABEL"); 85011143Sjulian#endif 85163027Sjhb for(sector = 0; sector < mboot.bootinst_size / secsize; sector++) 85263027Sjhb if (write_disk(sector, 85363027Sjhb &mboot.bootinst[sector * secsize]) == -1) { 85463027Sjhb warn("can't write fdisk partition table"); 85563027Sjhb return -1; 85650215Sphk#ifdef NOT_NOW 85763027Sjhb flag = 0; 85863027Sjhb (void) ioctl(fd, DIOCWLABEL, &flag); 85963027Sjhb#endif 86063027Sjhb } 86163027Sjhb#ifdef NOT_NOW 8624Srgrimes flag = 0; 8634Srgrimes (void) ioctl(fd, DIOCWLABEL, &flag); 86411143Sjulian#endif 86516561Salex return(0); 8664Srgrimes} 8674Srgrimes 8684Srgrimes 86916561Salexstatic int 8704Srgrimesok(str) 8714Srgrimeschar *str; 8724Srgrimes{ 8734Srgrimes printf("%s [n] ", str); 87481164Siedowse fflush(stdout); 87581164Siedowse if (fgets(lbuf, LBUF, stdin) == NULL) 87681164Siedowse exit(1); 8774Srgrimes lbuf[strlen(lbuf)-1] = 0; 8784Srgrimes 8794Srgrimes if (*lbuf && 8804Srgrimes (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || 8814Srgrimes !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) 8824Srgrimes return 1; 8834Srgrimes else 8844Srgrimes return 0; 8854Srgrimes} 8864Srgrimes 88716561Salexstatic int 88816561Salexdecimal(char *str, int *num, int deflt) 8894Srgrimes{ 8904Srgrimesint acc = 0, c; 8914Srgrimeschar *cp; 8924Srgrimes 8934Srgrimes while (1) { 8944Srgrimes printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); 89581164Siedowse fflush(stdout); 89681164Siedowse if (fgets(lbuf, LBUF, stdin) == NULL) 89781164Siedowse exit(1); 8984Srgrimes lbuf[strlen(lbuf)-1] = 0; 8994Srgrimes 9004Srgrimes if (!*lbuf) 9014Srgrimes return 0; 9024Srgrimes 9034Srgrimes cp = lbuf; 9044Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 9054Srgrimes if (!c) 9064Srgrimes return 0; 90716561Salex while ((c = *cp++)) { 9084Srgrimes if (c <= '9' && c >= '0') 9094Srgrimes acc = acc * 10 + c - '0'; 9104Srgrimes else 9114Srgrimes break; 9124Srgrimes } 9134Srgrimes if (c == ' ' || c == '\t') 9144Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 9154Srgrimes if (!c) { 9164Srgrimes *num = acc; 9174Srgrimes return 1; 9184Srgrimes } else 91934952Sobrien printf("%s is an invalid decimal number. Try again.\n", 9204Srgrimes lbuf); 9214Srgrimes } 9224Srgrimes 9234Srgrimes} 9244Srgrimes 92516561Salex#if 0 92616561Salexstatic int 92716561Salexhex(char *str, int *num, int deflt) 9284Srgrimes{ 9294Srgrimesint acc = 0, c; 9304Srgrimeschar *cp; 9314Srgrimes 9324Srgrimes while (1) { 9334Srgrimes printf("Supply a hex value for \"%s\" [%x] ", str, deflt); 9344Srgrimes fgets(lbuf, LBUF, stdin); 9354Srgrimes lbuf[strlen(lbuf)-1] = 0; 9364Srgrimes 9374Srgrimes if (!*lbuf) 9384Srgrimes return 0; 9394Srgrimes 9404Srgrimes cp = lbuf; 9414Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 9424Srgrimes if (!c) 9434Srgrimes return 0; 94416561Salex while ((c = *cp++)) { 9454Srgrimes if (c <= '9' && c >= '0') 9464Srgrimes acc = (acc << 4) + c - '0'; 9474Srgrimes else if (c <= 'f' && c >= 'a') 9484Srgrimes acc = (acc << 4) + c - 'a' + 10; 9494Srgrimes else if (c <= 'F' && c >= 'A') 9504Srgrimes acc = (acc << 4) + c - 'A' + 10; 9514Srgrimes else 9524Srgrimes break; 9534Srgrimes } 9544Srgrimes if (c == ' ' || c == '\t') 9554Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 9564Srgrimes if (!c) { 9574Srgrimes *num = acc; 9584Srgrimes return 1; 9594Srgrimes } else 96034952Sobrien printf("%s is an invalid hex number. Try again.\n", 9614Srgrimes lbuf); 9624Srgrimes } 9634Srgrimes 9644Srgrimes} 9654Srgrimes 96616561Salexstatic int 96716561Salexstring(char *str, char **ans) 9684Srgrimes{ 9694Srgrimesint c; 9704Srgrimeschar *cp = lbuf; 9714Srgrimes 9724Srgrimes while (1) { 9734Srgrimes printf("Supply a string value for \"%s\" [%s] ", str, *ans); 9744Srgrimes fgets(lbuf, LBUF, stdin); 9754Srgrimes lbuf[strlen(lbuf)-1] = 0; 9764Srgrimes 9774Srgrimes if (!*lbuf) 9784Srgrimes return 0; 9794Srgrimes 9804Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 9814Srgrimes if (c == '"') { 9824Srgrimes c = *++cp; 9834Srgrimes *ans = cp; 9844Srgrimes while ((c = *cp) && c != '"') cp++; 9854Srgrimes } else { 9864Srgrimes *ans = cp; 9874Srgrimes while ((c = *cp) && c != ' ' && c != '\t') cp++; 9884Srgrimes } 9894Srgrimes 9904Srgrimes if (c) 9914Srgrimes *cp = 0; 9924Srgrimes return 1; 9934Srgrimes } 9944Srgrimes} 99516561Salex#endif 9964Srgrimes 99716561Salexstatic char * 99816561Salexget_type(int type) 9994Srgrimes{ 10004Srgrimes int numentries = (sizeof(part_types)/sizeof(struct part_type)); 10014Srgrimes int counter = 0; 10024Srgrimes struct part_type *ptr = part_types; 10034Srgrimes 10048871Srgrimes 10054Srgrimes while(counter < numentries) 10064Srgrimes { 10074Srgrimes if(ptr->type == type) 10084Srgrimes { 10094Srgrimes return(ptr->name); 10104Srgrimes } 10114Srgrimes ptr++; 10124Srgrimes counter++; 10134Srgrimes } 10144Srgrimes return("unknown"); 10154Srgrimes} 101619459Sjkh 101719459Sjkh 101819459Sjkhstatic void 101919459Sjkhparse_config_line(line, command) 102019459Sjkh char *line; 102119459Sjkh CMD *command; 102219459Sjkh{ 102319459Sjkh char *cp, *end; 102419459Sjkh 102519459Sjkh cp = line; 102619459Sjkh while (1) /* dirty trick used to insure one exit point for this 102719459Sjkh function */ 102819459Sjkh { 102919459Sjkh memset(command, 0, sizeof(*command)); 103019459Sjkh 103119459Sjkh while (isspace(*cp)) ++cp; 103219459Sjkh if (*cp == '\0' || *cp == '#') 103319459Sjkh { 103419459Sjkh break; 103519459Sjkh } 103619459Sjkh command->cmd = *cp++; 103719459Sjkh 103819459Sjkh /* 103919459Sjkh * Parse args 104019459Sjkh */ 104119459Sjkh while (1) 104219459Sjkh { 104319459Sjkh while (isspace(*cp)) ++cp; 104419459Sjkh if (*cp == '#') 104519459Sjkh { 104619459Sjkh break; /* found comment */ 104719459Sjkh } 104819459Sjkh if (isalpha(*cp)) 104919459Sjkh { 105019459Sjkh command->args[command->n_args].argtype = *cp++; 105119459Sjkh } 105219459Sjkh if (!isdigit(*cp)) 105319459Sjkh { 105419459Sjkh break; /* assume end of line */ 105519459Sjkh } 105619459Sjkh end = NULL; 105719459Sjkh command->args[command->n_args].arg_val = strtol(cp, &end, 0); 105819459Sjkh if (cp == end) 105919459Sjkh { 106019459Sjkh break; /* couldn't parse number */ 106119459Sjkh } 106219459Sjkh cp = end; 106319459Sjkh command->n_args++; 106419459Sjkh } 106519459Sjkh break; 106619459Sjkh } 106719459Sjkh} 106819459Sjkh 106919459Sjkh 107019459Sjkhstatic int 107119459Sjkhprocess_geometry(command) 107219459Sjkh CMD *command; 107319459Sjkh{ 107419459Sjkh int status = 1, i; 107519459Sjkh 107619459Sjkh while (1) 107719459Sjkh { 107819459Sjkh geom_processed = 1; 107919459Sjkh if (part_processed) 108019459Sjkh { 108137415Scharnier warnx( 108237415Scharnier "ERROR line %d: the geometry specification line must occur before\n\ 108337415Scharnier all partition specifications", 108437415Scharnier current_line_number); 108519459Sjkh status = 0; 108619459Sjkh break; 108719459Sjkh } 108819459Sjkh if (command->n_args != 3) 108919459Sjkh { 109037415Scharnier warnx("ERROR line %d: incorrect number of geometry args", 109137415Scharnier current_line_number); 109219459Sjkh status = 0; 109319459Sjkh break; 109419459Sjkh } 109519459Sjkh dos_cyls = -1; 109619459Sjkh dos_heads = -1; 109719459Sjkh dos_sectors = -1; 109819459Sjkh for (i = 0; i < 3; ++i) 109919459Sjkh { 110019459Sjkh switch (command->args[i].argtype) 110119459Sjkh { 110219459Sjkh case 'c': 110319459Sjkh dos_cyls = command->args[i].arg_val; 110419459Sjkh break; 110519459Sjkh case 'h': 110619459Sjkh dos_heads = command->args[i].arg_val; 110719459Sjkh break; 110819459Sjkh case 's': 110919459Sjkh dos_sectors = command->args[i].arg_val; 111019459Sjkh break; 111119459Sjkh default: 111237415Scharnier warnx( 111337415Scharnier "ERROR line %d: unknown geometry arg type: '%c' (0x%02x)", 111437415Scharnier current_line_number, command->args[i].argtype, 111519459Sjkh command->args[i].argtype); 111619459Sjkh status = 0; 111719459Sjkh break; 111819459Sjkh } 111919459Sjkh } 112019459Sjkh if (status == 0) 112119459Sjkh { 112219459Sjkh break; 112319459Sjkh } 112419459Sjkh 112519459Sjkh dos_cylsecs = dos_heads * dos_sectors; 112619459Sjkh 112719459Sjkh /* 112819459Sjkh * Do sanity checks on parameter values 112919459Sjkh */ 113019459Sjkh if (dos_cyls < 0) 113119459Sjkh { 113237415Scharnier warnx("ERROR line %d: number of cylinders not specified", 113337415Scharnier current_line_number); 113419459Sjkh status = 0; 113519459Sjkh } 113619459Sjkh if (dos_cyls == 0 || dos_cyls > 1024) 113719459Sjkh { 113837415Scharnier warnx( 113937415Scharnier "WARNING line %d: number of cylinders (%d) may be out-of-range\n\ 114019459Sjkh (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\ 114137415Scharnier is dedicated to FreeBSD)", 114237415Scharnier current_line_number, dos_cyls); 114319459Sjkh } 114419459Sjkh 114519459Sjkh if (dos_heads < 0) 114619459Sjkh { 114737415Scharnier warnx("ERROR line %d: number of heads not specified", 114837415Scharnier current_line_number); 114919459Sjkh status = 0; 115019459Sjkh } 115119459Sjkh else if (dos_heads < 1 || dos_heads > 256) 115219459Sjkh { 115337415Scharnier warnx("ERROR line %d: number of heads must be within (1-256)", 115437415Scharnier current_line_number); 115519459Sjkh status = 0; 115619459Sjkh } 115719459Sjkh 115819459Sjkh if (dos_sectors < 0) 115919459Sjkh { 116037415Scharnier warnx("ERROR line %d: number of sectors not specified", 116137415Scharnier current_line_number); 116219459Sjkh status = 0; 116319459Sjkh } 116419459Sjkh else if (dos_sectors < 1 || dos_sectors > 63) 116519459Sjkh { 116637415Scharnier warnx("ERROR line %d: number of sectors must be within (1-63)", 116737415Scharnier current_line_number); 116819459Sjkh status = 0; 116919459Sjkh } 117019459Sjkh 117119459Sjkh break; 117219459Sjkh } 117319459Sjkh return (status); 117419459Sjkh} 117519459Sjkh 117619459Sjkh 117719459Sjkhstatic int 117819459Sjkhprocess_partition(command) 117919459Sjkh CMD *command; 118019459Sjkh{ 118119459Sjkh int status = 0, partition; 118265054Sjhb u_int32_t prev_head_boundary, prev_cyl_boundary; 118365054Sjhb u_int32_t adj_size, max_end; 118419459Sjkh struct dos_partition *partp; 118519459Sjkh 118619459Sjkh while (1) 118719459Sjkh { 118819459Sjkh part_processed = 1; 118919459Sjkh if (command->n_args != 4) 119019459Sjkh { 119137415Scharnier warnx("ERROR line %d: incorrect number of partition args", 119237415Scharnier current_line_number); 119319459Sjkh break; 119419459Sjkh } 119519459Sjkh partition = command->args[0].arg_val; 119626421Sbrian if (partition < 1 || partition > 4) 119719459Sjkh { 119837415Scharnier warnx("ERROR line %d: invalid partition number %d", 119937415Scharnier current_line_number, partition); 120019459Sjkh break; 120119459Sjkh } 120226421Sbrian partp = ((struct dos_partition *) &mboot.parts) + partition - 1; 120319459Sjkh bzero((char *)partp, sizeof (struct dos_partition)); 120419459Sjkh partp->dp_typ = command->args[1].arg_val; 120519459Sjkh partp->dp_start = command->args[2].arg_val; 120619459Sjkh partp->dp_size = command->args[3].arg_val; 120719459Sjkh max_end = partp->dp_start + partp->dp_size; 120819459Sjkh 120919459Sjkh if (partp->dp_typ == 0) 121019459Sjkh { 121119459Sjkh /* 121219459Sjkh * Get out, the partition is marked as unused. 121319459Sjkh */ 121419459Sjkh /* 121519459Sjkh * Insure that it's unused. 121619459Sjkh */ 121719459Sjkh bzero((char *)partp, sizeof (struct dos_partition)); 121819459Sjkh status = 1; 121919459Sjkh break; 122019459Sjkh } 122119459Sjkh 122219459Sjkh /* 122319459Sjkh * Adjust start upwards, if necessary, to fall on an head boundary. 122419459Sjkh */ 122519459Sjkh if (partp->dp_start % dos_sectors != 0) 122619459Sjkh { 122765054Sjhb prev_head_boundary = partp->dp_start / dos_sectors * dos_sectors; 122865054Sjhb if (max_end < dos_sectors || 122965054Sjhb prev_head_boundary > max_end - dos_sectors) 123019459Sjkh { 123119459Sjkh /* 123219459Sjkh * Can't go past end of partition 123319459Sjkh */ 123437415Scharnier warnx( 123537415Scharnier "ERROR line %d: unable to adjust start of partition %d to fall on\n\ 123665054Sjhb a head boundary", 123737415Scharnier current_line_number, partition); 123819459Sjkh break; 123919459Sjkh } 124037415Scharnier warnx( 124165054Sjhb "WARNING: adjusting start offset of partition %d\n\ 124265054Sjhb from %u to %u, to fall on a head boundary", 124365054Sjhb partition, (u_int)partp->dp_start, 124465054Sjhb (u_int)(prev_head_boundary + dos_sectors)); 124565054Sjhb partp->dp_start = prev_head_boundary + dos_sectors; 124619459Sjkh } 124719459Sjkh 124819459Sjkh /* 124919459Sjkh * Adjust size downwards, if necessary, to fall on a cylinder 125019459Sjkh * boundary. 125119459Sjkh */ 125265054Sjhb prev_cyl_boundary = 125319459Sjkh ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; 125465054Sjhb if (prev_cyl_boundary > partp->dp_start) 125565054Sjhb adj_size = prev_cyl_boundary - partp->dp_start; 125665054Sjhb else 125765054Sjhb { 125865054Sjhb warnx( 125965054Sjhb "ERROR: could not adjust partition to start on a head boundary\n\ 126065054Sjhb and end on a cylinder boundary."); 126165054Sjhb return (0); 126265054Sjhb } 126319459Sjkh if (adj_size != partp->dp_size) 126419459Sjkh { 126537415Scharnier warnx( 126665054Sjhb "WARNING: adjusting size of partition %d from %u to %u\n\ 126765054Sjhb to end on a cylinder boundary", 126865054Sjhb partition, (u_int)partp->dp_size, (u_int)adj_size); 126965054Sjhb partp->dp_size = adj_size; 127019459Sjkh } 127165054Sjhb if (partp->dp_size == 0) 127219459Sjkh { 127381164Siedowse warnx("ERROR line %d: size of partition %d is zero", 127437415Scharnier current_line_number, partition); 127519459Sjkh break; 127619459Sjkh } 127719459Sjkh 127881164Siedowse dos(partp); 127919459Sjkh status = 1; 128019459Sjkh break; 128119459Sjkh } 128219459Sjkh return (status); 128319459Sjkh} 128419459Sjkh 128519459Sjkh 128619459Sjkhstatic int 128719459Sjkhprocess_active(command) 128819459Sjkh CMD *command; 128919459Sjkh{ 129019459Sjkh int status = 0, partition, i; 129119459Sjkh struct dos_partition *partp; 129219459Sjkh 129319459Sjkh while (1) 129419459Sjkh { 129519459Sjkh active_processed = 1; 129619459Sjkh if (command->n_args != 1) 129719459Sjkh { 129837415Scharnier warnx("ERROR line %d: incorrect number of active args", 129937415Scharnier current_line_number); 130019459Sjkh status = 0; 130119459Sjkh break; 130219459Sjkh } 130319459Sjkh partition = command->args[0].arg_val; 130426421Sbrian if (partition < 1 || partition > 4) 130519459Sjkh { 130637415Scharnier warnx("ERROR line %d: invalid partition number %d", 130737415Scharnier current_line_number, partition); 130819459Sjkh break; 130919459Sjkh } 131019459Sjkh /* 131119459Sjkh * Reset active partition 131219459Sjkh */ 131319459Sjkh partp = ((struct dos_partition *) &mboot.parts); 131419459Sjkh for (i = 0; i < NDOSPART; i++) 131519459Sjkh partp[i].dp_flag = 0; 131626421Sbrian partp[partition-1].dp_flag = ACTIVE; 131719459Sjkh 131819459Sjkh status = 1; 131919459Sjkh break; 132019459Sjkh } 132119459Sjkh return (status); 132219459Sjkh} 132319459Sjkh 132419459Sjkh 132519459Sjkhstatic int 132619459Sjkhprocess_line(line) 132719459Sjkh char *line; 132819459Sjkh{ 132919459Sjkh CMD command; 133019459Sjkh int status = 1; 133119459Sjkh 133219459Sjkh while (1) 133319459Sjkh { 133419459Sjkh parse_config_line(line, &command); 133519459Sjkh switch (command.cmd) 133619459Sjkh { 133719459Sjkh case 0: 133819459Sjkh /* 133919459Sjkh * Comment or blank line 134019459Sjkh */ 134119459Sjkh break; 134219459Sjkh case 'g': 134319459Sjkh /* 134419459Sjkh * Set geometry 134519459Sjkh */ 134619459Sjkh status = process_geometry(&command); 134719459Sjkh break; 134819459Sjkh case 'p': 134919459Sjkh status = process_partition(&command); 135019459Sjkh break; 135119459Sjkh case 'a': 135219459Sjkh status = process_active(&command); 135319459Sjkh break; 135419459Sjkh default: 135519459Sjkh status = 0; 135619459Sjkh break; 135719459Sjkh } 135819459Sjkh break; 135919459Sjkh } 136019459Sjkh return (status); 136119459Sjkh} 136219459Sjkh 136319459Sjkh 136419459Sjkhstatic int 136519459Sjkhread_config(config_file) 136619459Sjkh char *config_file; 136719459Sjkh{ 136819459Sjkh FILE *fp = NULL; 136919459Sjkh int status = 1; 137019459Sjkh char buf[1010]; 137119459Sjkh 137219459Sjkh while (1) /* dirty trick used to insure one exit point for this 137319459Sjkh function */ 137419459Sjkh { 137519459Sjkh if (strcmp(config_file, "-") != 0) 137619459Sjkh { 137719459Sjkh /* 137819459Sjkh * We're not reading from stdin 137919459Sjkh */ 138019459Sjkh if ((fp = fopen(config_file, "r")) == NULL) 138119459Sjkh { 138219459Sjkh status = 0; 138319459Sjkh break; 138419459Sjkh } 138519459Sjkh } 138619459Sjkh else 138719459Sjkh { 138819459Sjkh fp = stdin; 138919459Sjkh } 139019459Sjkh current_line_number = 0; 139119459Sjkh while (!feof(fp)) 139219459Sjkh { 139319459Sjkh if (fgets(buf, sizeof(buf), fp) == NULL) 139419459Sjkh { 139519459Sjkh break; 139619459Sjkh } 139719459Sjkh ++current_line_number; 139819459Sjkh status = process_line(buf); 139919459Sjkh if (status == 0) 140019459Sjkh { 140119459Sjkh break; 140219459Sjkh } 140319459Sjkh } 140419459Sjkh break; 140519459Sjkh } 140619459Sjkh if (fp) 140719459Sjkh { 140819459Sjkh /* 140919459Sjkh * It doesn't matter if we're reading from stdin, as we've reached EOF 141019459Sjkh */ 141119459Sjkh fclose(fp); 141219459Sjkh } 141319459Sjkh return (status); 141419459Sjkh} 141519459Sjkh 141619459Sjkh 141719459Sjkhstatic void 141819459Sjkhreset_boot(void) 141919459Sjkh{ 142019459Sjkh int i; 142119459Sjkh struct dos_partition *partp; 142219459Sjkh 142319459Sjkh init_boot(); 142419459Sjkh for (i = 0; i < 4; ++i) 142519459Sjkh { 142619459Sjkh partp = ((struct dos_partition *) &mboot.parts) + i; 142719459Sjkh bzero((char *)partp, sizeof (struct dos_partition)); 142819459Sjkh } 142919459Sjkh} 143065054Sjhb 143165054Sjhbstatic int 143265054Sjhbsanitize_partition(partp) 143365054Sjhb struct dos_partition *partp; 143465054Sjhb{ 143565054Sjhb u_int32_t prev_head_boundary, prev_cyl_boundary; 143681164Siedowse u_int32_t max_end, size, start; 143765054Sjhb 143881164Siedowse start = partp->dp_start; 143981164Siedowse size = partp->dp_size; 144081164Siedowse max_end = start + size; 144181164Siedowse /* Only allow a zero size if the partition is being marked unused. */ 144281164Siedowse if (size == 0) { 144381164Siedowse if (start == 0 && partp->dp_typ == 0) 144481164Siedowse return (1); 144581164Siedowse warnx("ERROR: size of partition is zero"); 144681164Siedowse return (0); 144781164Siedowse } 144881164Siedowse /* Return if no adjustment is necessary. */ 144981164Siedowse if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0) 145081164Siedowse return (1); 145165054Sjhb 145281164Siedowse if (start % dos_sectors != 0) 145381164Siedowse warnx("WARNING: partition does not start on a head boundary"); 145481164Siedowse if ((start +size) % dos_sectors != 0) 145581164Siedowse warnx("WARNING: partition does not end on a cylinder boundary"); 145681164Siedowse warnx("WARNING: this may confuse the BIOS or some operating systems"); 145781164Siedowse if (!ok("Correct this automatically?")) 145881164Siedowse return (1); 145981164Siedowse 146065054Sjhb /* 146165054Sjhb * Adjust start upwards, if necessary, to fall on an head boundary. 146265054Sjhb */ 146381164Siedowse if (start % dos_sectors != 0) { 146481164Siedowse prev_head_boundary = start / dos_sectors * dos_sectors; 146565054Sjhb if (max_end < dos_sectors || 146681164Siedowse prev_head_boundary >= max_end - dos_sectors) { 146765054Sjhb /* 146865054Sjhb * Can't go past end of partition 146965054Sjhb */ 147065054Sjhb warnx( 147165054Sjhb "ERROR: unable to adjust start of partition to fall on a head boundary"); 147265054Sjhb return (0); 147365054Sjhb } 147481164Siedowse start = prev_head_boundary + dos_sectors; 147565054Sjhb } 147665054Sjhb 147765054Sjhb /* 147865054Sjhb * Adjust size downwards, if necessary, to fall on a cylinder 147965054Sjhb * boundary. 148065054Sjhb */ 148181164Siedowse prev_cyl_boundary = ((start + size) / dos_cylsecs) * dos_cylsecs; 148281164Siedowse if (prev_cyl_boundary > start) 148381164Siedowse size = prev_cyl_boundary - start; 148481164Siedowse else { 148565054Sjhb warnx("ERROR: could not adjust partition to start on a head boundary\n\ 148665054Sjhb and end on a cylinder boundary."); 148765054Sjhb return (0); 148865054Sjhb } 148981164Siedowse 149081164Siedowse /* Finally, commit any changes to partp and return. */ 149181164Siedowse if (start != partp->dp_start) { 149281164Siedowse warnx("WARNING: adjusting start offset of partition to %u", 149381164Siedowse (u_int)start); 149481164Siedowse partp->dp_start = start; 149565054Sjhb } 149681164Siedowse if (size != partp->dp_size) { 149781164Siedowse warnx("WARNING: adjusting size of partition to %u", (u_int)size); 149881164Siedowse partp->dp_size = size; 149965054Sjhb } 150065054Sjhb 150165054Sjhb return (1); 150265054Sjhb} 150379681Sjoerg 150479681Sjoerg/* 150579681Sjoerg * Try figuring out the root device's canonical disk name. 150679681Sjoerg * The following choices are considered: 150779681Sjoerg * /dev/ad0s1a => /dev/ad0 150879681Sjoerg * /dev/da0a => /dev/da0 150979681Sjoerg * /dev/vinum/root => /dev/vinum/root 151079681Sjoerg */ 151179681Sjoergstatic char * 151279681Sjoergget_rootdisk(void) 151379681Sjoerg{ 151479681Sjoerg struct statfs rootfs; 151579681Sjoerg regex_t re; 151679681Sjoerg#define NMATCHES 2 151779681Sjoerg regmatch_t rm[NMATCHES]; 151879681Sjoerg char *s; 151979681Sjoerg int rv; 152079681Sjoerg 152179681Sjoerg if (statfs("/", &rootfs) == -1) 152279681Sjoerg err(1, "statfs(\"/\")"); 152379681Sjoerg 152479681Sjoerg if ((rv = regcomp(&re, "^(/dev/.*)(\\d+(s\\d+)?[a-h])?$", 152579681Sjoerg REG_EXTENDED)) != 0) 152679681Sjoerg errx(1, "regcomp() failed (%d)", rv); 152779681Sjoerg if ((rv = regexec(&re, rootfs.f_mntfromname, NMATCHES, rm, 0)) != 0) 152879681Sjoerg errx(1, 152979681Sjoerg"mounted root fs resource doesn't match expectations (regexec returned %d)", 153079681Sjoerg rv); 153179681Sjoerg if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL) 153279681Sjoerg errx(1, "out of memory"); 153379681Sjoerg memcpy(s, rootfs.f_mntfromname + rm[1].rm_so, 153479681Sjoerg rm[1].rm_eo - rm[1].rm_so); 153579681Sjoerg s[rm[1].rm_eo - rm[1].rm_so] = 0; 153679681Sjoerg 153779681Sjoerg return s; 153879681Sjoerg} 1539