fdisk.c revision 81164
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 81164 2001-08-05 16:24:13Z iedowse $"; 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"} 14134582Sache ,{0x04, "Primary DOS with 16 bit FAT (<= 32MB)"} 1428871Srgrimes ,{0x05, "Extended DOS"} 1438871Srgrimes ,{0x06, "Primary 'big' DOS (> 32MB)"} 14461461Sghelmer ,{0x07, "OS/2 HPFS, NTFS, QNX-2 (16 bit) or Advanced UNIX"} 1458871Srgrimes ,{0x08, "AIX filesystem"} 1468871Srgrimes ,{0x09, "AIX boot partition or Coherent"} 1478871Srgrimes ,{0x0A, "OS/2 Boot Manager or OPUS"} 14834582Sache ,{0x0B, "DOS or Windows 95 with 32 bit FAT"} 14934582Sache ,{0x0C, "DOS or Windows 95 with 32 bit FAT, LBA"} 15034582Sache ,{0x0E, "Primary 'big' DOS (> 32MB, LBA)"} 15134582Sache ,{0x0F, "Extended DOS, LBA"} 1528871Srgrimes ,{0x10, "OPUS"} 15361568Sbrian ,{0x39, "plan9"} 1548871Srgrimes ,{0x40, "VENIX 286"} 15561461Sghelmer ,{0x4D, "QNX 4.2 Primary"} 15661461Sghelmer ,{0x4E, "QNX 4.2 Secondary"} 15761461Sghelmer ,{0x4F, "QNX 4.2 Tertiary"} 1588871Srgrimes ,{0x50, "DM"} 1598871Srgrimes ,{0x51, "DM"} 1608871Srgrimes ,{0x52, "CP/M or Microport SysV/AT"} 1618871Srgrimes ,{0x56, "GB"} 1628871Srgrimes ,{0x61, "Speed"} 1638871Srgrimes ,{0x63, "ISC UNIX, other System V/386, GNU HURD or Mach"} 1648871Srgrimes ,{0x64, "Novell Netware 2.xx"} 1658871Srgrimes ,{0x65, "Novell Netware 3.xx"} 1668871Srgrimes ,{0x75, "PCIX"} 1678871Srgrimes ,{0x80, "Minix 1.1 ... 1.4a"} 1688871Srgrimes ,{0x81, "Minix 1.4b ... 1.5.10"} 16939377Sobrien ,{0x82, "Linux swap or Solaris x86"} 1708871Srgrimes ,{0x83, "Linux filesystem"} 1718871Srgrimes ,{0x93, "Amoeba filesystem"} 1728871Srgrimes ,{0x94, "Amoeba bad block table"} 17340946Sjkoshy ,{0x9F, "BSD/OS"} 17464316Sjoe ,{0xA0, "Suspend to Disk"} 1758871Srgrimes ,{0xA5, "FreeBSD/NetBSD/386BSD"} 17625378Simp ,{0xA6, "OpenBSD"} 1777902Sgpalmer ,{0xA7, "NEXTSTEP"} 17840947Salex ,{0xA9, "NetBSD"} 1798871Srgrimes ,{0xB7, "BSDI BSD/386 filesystem"} 1808871Srgrimes ,{0xB8, "BSDI BSD/386 swap"} 1818871Srgrimes ,{0xDB, "Concurrent CPM or C.DOS or CTOS"} 1828871Srgrimes ,{0xE1, "Speed"} 1838871Srgrimes ,{0xE3, "Speed"} 1848871Srgrimes ,{0xE4, "Speed"} 1858871Srgrimes ,{0xF1, "Speed"} 1868871Srgrimes ,{0xF2, "DOS 3.3+ Secondary"} 1878871Srgrimes ,{0xF4, "Speed"} 1888871Srgrimes ,{0xFF, "BBT (Bad Blocks Table)"} 1894Srgrimes}; 1904Srgrimes 19116561Salexstatic void print_s0(int which); 19216561Salexstatic void print_part(int i); 19316561Salexstatic void init_sector0(unsigned long start); 19419459Sjkhstatic void init_boot(void); 19516561Salexstatic void change_part(int i); 19616561Salexstatic void print_params(); 19716561Salexstatic void change_active(int which); 19843054Srnordierstatic void change_code(); 19916561Salexstatic void get_params_to_use(); 20079681Sjoergstatic char *get_rootdisk(void); 20181164Siedowsestatic void dos(struct dos_partition *partp); 20216561Salexstatic int open_disk(int u_flag); 20316561Salexstatic ssize_t read_disk(off_t sector, void *buf); 20416561Salexstatic ssize_t write_disk(off_t sector, void *buf); 20516561Salexstatic int get_params(); 20616561Salexstatic int read_s0(); 20716561Salexstatic int write_s0(); 20816561Salexstatic int ok(char *str); 20916561Salexstatic int decimal(char *str, int *num, int deflt); 21016561Salexstatic char *get_type(int type); 21119459Sjkhstatic int read_config(char *config_file); 21219459Sjkhstatic void reset_boot(void); 21365054Sjhbstatic int sanitize_partition(struct dos_partition *); 21437415Scharnierstatic void usage(void); 21516561Salex#if 0 21616561Salexstatic int hex(char *str, int *num, int deflt); 21716561Salexstatic int string(char *str, char **ans); 21816561Salex#endif 2194Srgrimes 22016561Salex 22116561Salexint 22216561Salexmain(int argc, char *argv[]) 2234Srgrimes{ 22479681Sjoerg struct stat sb; 22548282Srnordier int c, i; 2264Srgrimes 22757896Simp while ((c = getopt(argc, argv, "BIab:f:istuv1234")) != -1) 22848282Srnordier switch (c) { 22948282Srnordier case 'B': 23048282Srnordier B_flag = 1; 2314Srgrimes break; 23257896Simp case 'I': 23357896Simp I_flag = 1; 23457896Simp break; 23548282Srnordier case 'a': 23648282Srnordier a_flag = 1; 23748282Srnordier break; 23848282Srnordier case 'b': 23948282Srnordier b_flag = optarg; 24048282Srnordier break; 24148282Srnordier case 'f': 24248282Srnordier f_flag = optarg; 24348282Srnordier break; 24448282Srnordier case 'i': 24548282Srnordier i_flag = 1; 24648282Srnordier break; 24757896Simp case 's': 24857896Simp s_flag = 1; 24957896Simp break; 25048282Srnordier case 't': 25148282Srnordier t_flag = 1; 25248282Srnordier break; 25348282Srnordier case 'u': 25448282Srnordier u_flag = 1; 25548282Srnordier break; 25648282Srnordier case 'v': 25748282Srnordier v_flag = 1; 25848282Srnordier break; 25948282Srnordier case '1': 26048282Srnordier case '2': 26148282Srnordier case '3': 26248282Srnordier case '4': 26348282Srnordier partition = c - '0'; 26448282Srnordier break; 26548282Srnordier default: 26648282Srnordier usage(); 2674Srgrimes } 26848282Srnordier if (f_flag || i_flag) 26948282Srnordier u_flag = 1; 27048282Srnordier if (t_flag) 27148282Srnordier v_flag = 1; 27248282Srnordier argc -= optind; 27348282Srnordier argv += optind; 2744Srgrimes 27579681Sjoerg if (argc == 0) { 27679681Sjoerg disk = get_rootdisk(); 27779681Sjoerg } else { 27879681Sjoerg if (stat(argv[0], &sb) == 0) { 27979681Sjoerg /* OK, full pathname given */ 28010514Sjoerg disk = argv[0]; 28179681Sjoerg } else if (errno == ENOENT) { 28279681Sjoerg /* Try prepending "/dev" */ 28379681Sjoerg if ((disk = malloc(strlen(argv[0]) + strlen(_PATH_DEV) + 28479681Sjoerg 1)) == NULL) 28579681Sjoerg errx(1, "out of memory"); 28679681Sjoerg strcpy(disk, _PATH_DEV); 28779681Sjoerg strcat(disk, argv[0]); 28879681Sjoerg } else { 28979681Sjoerg /* other stat error, let it fail below */ 29079681Sjoerg disk = argv[0]; 29110514Sjoerg } 29210514Sjoerg } 29379681Sjoerg if (open_disk(u_flag) < 0) 29479681Sjoerg err(1, "cannot open disk %s", disk); 2954Srgrimes 29663027Sjhb /* (abu)use mboot.bootinst to probe for the sector size */ 29763027Sjhb if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL) 29863027Sjhb err(1, "cannot allocate buffer to determine disk sector size"); 29963027Sjhb read_disk(0, mboot.bootinst); 30063329Sjhb free(mboot.bootinst); 30163329Sjhb mboot.bootinst = NULL; 30263027Sjhb 30357896Simp if (s_flag) 30457896Simp { 30557896Simp int i; 30657896Simp struct dos_partition *partp; 30710514Sjoerg 30857896Simp if (read_s0()) 30957896Simp err(1, "read_s0"); 31057896Simp printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads, 31157896Simp dos_sectors); 31257896Simp printf("Part %11s %11s Type Flags\n", "Start", "Size"); 31357896Simp for (i = 0; i < NDOSPART; i++) { 31457896Simp partp = ((struct dos_partition *) &mboot.parts) + i; 31557896Simp if (partp->dp_start == 0 && partp->dp_size == 0) 31657896Simp continue; 31757896Simp printf("%4d: %11lu %11lu 0x%02x 0x%02x\n", i + 1, 31857896Simp (u_long) partp->dp_start, 31957896Simp (u_long) partp->dp_size, partp->dp_typ, 32057896Simp partp->dp_flag); 32157896Simp } 32257896Simp exit(0); 32357896Simp } 32457896Simp 3254Srgrimes printf("******* Working on device %s *******\n",disk); 32619459Sjkh 32757896Simp if (I_flag) 32850215Sphk { 32950215Sphk struct dos_partition *partp; 33050215Sphk 33150215Sphk read_s0(); 33250215Sphk reset_boot(); 33350215Sphk partp = (struct dos_partition *) (&mboot.parts[0]); 33450215Sphk partp->dp_typ = DOSPTYP_386BSD; 33550215Sphk partp->dp_flag = ACTIVE; 33650215Sphk partp->dp_start = dos_sectors; 33765054Sjhb partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - 33865054Sjhb dos_sectors; 33950215Sphk 34081164Siedowse dos(partp); 34150215Sphk if (v_flag) 34250215Sphk print_s0(-1); 34350215Sphk write_s0(); 34450215Sphk exit(0); 34550215Sphk } 34619459Sjkh if (f_flag) 3474Srgrimes { 34819459Sjkh if (read_s0() || i_flag) 34919459Sjkh { 35019459Sjkh reset_boot(); 35119459Sjkh } 35219459Sjkh 35319459Sjkh if (!read_config(f_flag)) 35419459Sjkh { 35519459Sjkh exit(1); 35619459Sjkh } 35719459Sjkh if (v_flag) 35819459Sjkh { 35919459Sjkh print_s0(-1); 36019459Sjkh } 36119459Sjkh if (!t_flag) 36219459Sjkh { 36319459Sjkh write_s0(); 36419459Sjkh } 3654Srgrimes } 3664Srgrimes else 3674Srgrimes { 36819459Sjkh if(u_flag) 36919459Sjkh { 37019459Sjkh get_params_to_use(); 37119459Sjkh } 37219459Sjkh else 37319459Sjkh { 3744Srgrimes print_params(); 37519459Sjkh } 3764Srgrimes 37719459Sjkh if (read_s0()) 37865054Sjhb init_sector0(dos_sectors); 3794Srgrimes 38020061Ssos printf("Media sector size is %d\n", secsize); 38119459Sjkh printf("Warning: BIOS sector numbering starts with sector 1\n"); 38219459Sjkh printf("Information from DOS bootblock is:\n"); 38319459Sjkh if (partition == -1) 38426421Sbrian for (i = 1; i <= NDOSPART; i++) 38519459Sjkh change_part(i); 38619459Sjkh else 3874Srgrimes change_part(partition); 3884Srgrimes 38919459Sjkh if (u_flag || a_flag) 3904Srgrimes change_active(partition); 3914Srgrimes 39248282Srnordier if (B_flag) 39343054Srnordier change_code(); 39443054Srnordier 39548282Srnordier if (u_flag || a_flag || B_flag) { 39619459Sjkh if (!t_flag) 39719459Sjkh { 39819459Sjkh printf("\nWe haven't changed the partition table yet. "); 39919459Sjkh printf("This is your last chance.\n"); 40019459Sjkh } 4014Srgrimes print_s0(-1); 40219459Sjkh if (!t_flag) 40319459Sjkh { 40419459Sjkh if (ok("Should we write new partition table?")) 4054Srgrimes write_s0(); 40619459Sjkh } 40719459Sjkh else 40819459Sjkh { 40919459Sjkh printf("\n-t flag specified -- partition table not written.\n"); 41019459Sjkh } 41119459Sjkh } 4124Srgrimes } 4134Srgrimes 4144Srgrimes exit(0); 41537415Scharnier} 4164Srgrimes 41737415Scharnierstatic void 41837415Scharnierusage() 41937415Scharnier{ 42048282Srnordier fprintf(stderr, "%s%s", 42162178Sjhb "usage: fdisk [-BIaistu] [-b bootcode] [-1234] [disk]\n", 42248282Srnordier " fdisk -f configfile [-itv] [disk]\n"); 42337415Scharnier exit(1); 4244Srgrimes} 4254Srgrimes 42616561Salexstatic void 42716561Salexprint_s0(int which) 4284Srgrimes{ 4294Srgrimesint i; 4304Srgrimes 4314Srgrimes print_params(); 4324Srgrimes printf("Information from DOS bootblock is:\n"); 4334Srgrimes if (which == -1) 43426421Sbrian for (i = 1; i <= NDOSPART; i++) 4354Srgrimes printf("%d: ", i), print_part(i); 4364Srgrimes else 4374Srgrimes print_part(which); 4384Srgrimes} 4394Srgrimes 4404Srgrimesstatic struct dos_partition mtpart = { 0 }; 4414Srgrimes 44216561Salexstatic void 44316561Salexprint_part(int i) 4444Srgrimes{ 44526389Sgibbs struct dos_partition *partp; 44626389Sgibbs u_int64_t part_mb; 4474Srgrimes 44826421Sbrian partp = ((struct dos_partition *) &mboot.parts) + i - 1; 4494Srgrimes 4504Srgrimes if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) { 4514Srgrimes printf("<UNUSED>\n"); 4524Srgrimes return; 4534Srgrimes } 45426389Sgibbs /* 45526389Sgibbs * Be careful not to overflow. 45626389Sgibbs */ 45726389Sgibbs part_mb = partp->dp_size; 45826389Sgibbs part_mb *= secsize; 45926389Sgibbs part_mb /= (1024 * 1024); 4604Srgrimes printf("sysid %d,(%s)\n", partp->dp_typ, get_type(partp->dp_typ)); 46137244Sbde printf(" start %lu, size %lu (%qd Meg), flag %x%s\n", 46237244Sbde (u_long)partp->dp_start, 46337244Sbde (u_long)partp->dp_size, 46426389Sgibbs part_mb, 46534952Sobrien partp->dp_flag, 46634952Sobrien partp->dp_flag == ACTIVE ? " (active)" : ""); 46769371Sobrien printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n" 4684Srgrimes ,DPCYL(partp->dp_scyl, partp->dp_ssect) 46969371Sobrien ,partp->dp_shd 4704Srgrimes ,DPSECT(partp->dp_ssect) 4714Srgrimes ,DPCYL(partp->dp_ecyl, partp->dp_esect) 47269371Sobrien ,partp->dp_ehd 47369371Sobrien ,DPSECT(partp->dp_esect)); 4744Srgrimes} 4754Srgrimes 47619459Sjkh 47716561Salexstatic void 47819459Sjkhinit_boot(void) 47919459Sjkh{ 48048282Srnordier const char *fname; 48163027Sjhb int fd, n; 48263027Sjhb struct stat sb; 48348282Srnordier 48448282Srnordier fname = b_flag ? b_flag : "/boot/mbr"; 48548282Srnordier if ((fd = open(fname, O_RDONLY)) == -1 || 48663027Sjhb fstat(fd, &sb) == -1) 48763027Sjhb err(1, "%s", fname); 48863027Sjhb if ((mboot.bootinst_size = sb.st_size) % secsize != 0) 48963027Sjhb errx(1, "%s: length must be a multiple of sector size", fname); 49063218Sache if (mboot.bootinst != NULL) 49163218Sache free(mboot.bootinst); 49263027Sjhb if ((mboot.bootinst = malloc(mboot.bootinst_size = sb.st_size)) == NULL) 49363027Sjhb errx(1, "%s: unable to allocate read buffer", fname); 49463027Sjhb if ((n = read(fd, mboot.bootinst, mboot.bootinst_size)) == -1 || 49548282Srnordier close(fd)) 49648282Srnordier err(1, "%s", fname); 49763027Sjhb if (n != mboot.bootinst_size) 49863027Sjhb errx(1, "%s: short read", fname); 49919459Sjkh} 50019459Sjkh 50119459Sjkh 50219459Sjkhstatic void 50316561Salexinit_sector0(unsigned long start) 5044Srgrimes{ 5054Srgrimesstruct dos_partition *partp = (struct dos_partition *) (&mboot.parts[3]); 5064Srgrimes 50719459Sjkh init_boot(); 5084Srgrimes 5094Srgrimes partp->dp_typ = DOSPTYP_386BSD; 5104Srgrimes partp->dp_flag = ACTIVE; 51165054Sjhb start = ((start + dos_sectors - 1) / dos_sectors) * dos_sectors; 51263027Sjhb if(start == 0) 51363027Sjhb start = dos_sectors; 5144Srgrimes partp->dp_start = start; 51565054Sjhb partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - start; 5164Srgrimes 51781164Siedowse dos(partp); 5184Srgrimes} 5194Srgrimes 52016561Salexstatic void 52116561Salexchange_part(int i) 5224Srgrimes{ 52326421Sbrianstruct dos_partition *partp = ((struct dos_partition *) &mboot.parts) + i - 1; 5244Srgrimes 5254Srgrimes printf("The data for partition %d is:\n", i); 5264Srgrimes print_part(i); 5274Srgrimes 5284Srgrimes if (u_flag && ok("Do you want to change it?")) { 5294Srgrimes int tmp; 5304Srgrimes 5314Srgrimes if (i_flag) { 5324Srgrimes bzero((char *)partp, sizeof (struct dos_partition)); 53326421Sbrian if (i == 4) { 5344Srgrimes init_sector0(1); 53526421Sbrian printf("\nThe static data for the DOS partition 4 has been reinitialized to:\n"); 5364Srgrimes print_part(i); 5374Srgrimes } 5384Srgrimes } 5394Srgrimes 5404Srgrimes do { 54134952Sobrien Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp); 5424Srgrimes Decimal("start", partp->dp_start, tmp); 5434Srgrimes Decimal("size", partp->dp_size, tmp); 54481164Siedowse if (!sanitize_partition(partp)) { 54581164Siedowse warnx("ERROR: failed to adjust; setting sysid to 0"); 54681164Siedowse partp->dp_typ = 0; 54781164Siedowse } 5484Srgrimes 54936262Sjraynard if (ok("Explicitly specify beg/end address ?")) 5504Srgrimes { 5514Srgrimes int tsec,tcyl,thd; 5524Srgrimes tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect); 5534Srgrimes thd = partp->dp_shd; 5544Srgrimes tsec = DPSECT(partp->dp_ssect); 5554Srgrimes Decimal("beginning cylinder", tcyl, tmp); 55669371Sobrien Decimal("beginning head", thd, tmp); 55768871Sobrien Decimal("beginning sector", tsec, tmp); 5584Srgrimes partp->dp_scyl = DOSCYL(tcyl); 5594Srgrimes partp->dp_ssect = DOSSECT(tsec,tcyl); 5604Srgrimes partp->dp_shd = thd; 5614Srgrimes 5624Srgrimes tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect); 5634Srgrimes thd = partp->dp_ehd; 5644Srgrimes tsec = DPSECT(partp->dp_esect); 5654Srgrimes Decimal("ending cylinder", tcyl, tmp); 56669371Sobrien Decimal("ending head", thd, tmp); 56768871Sobrien Decimal("ending sector", tsec, tmp); 5684Srgrimes partp->dp_ecyl = DOSCYL(tcyl); 5694Srgrimes partp->dp_esect = DOSSECT(tsec,tcyl); 5704Srgrimes partp->dp_ehd = thd; 57181164Siedowse } else 57281164Siedowse dos(partp); 5738871Srgrimes 5744Srgrimes print_part(i); 5754Srgrimes } while (!ok("Are we happy with this entry?")); 5764Srgrimes } 5774Srgrimes} 5784Srgrimes 57916561Salexstatic void 5804Srgrimesprint_params() 5814Srgrimes{ 5824Srgrimes printf("parameters extracted from in-core disklabel are:\n"); 5834Srgrimes printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 5844Srgrimes ,cyls,heads,sectors,cylsecs); 5854Srgrimes if((dos_sectors > 63) || (dos_cyls > 1023) || (dos_heads > 255)) 58620061Ssos printf("Figures below won't work with BIOS for partitions not in cyl 1\n"); 5874Srgrimes printf("parameters to be used for BIOS calculations are:\n"); 5884Srgrimes printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 5894Srgrimes ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); 5904Srgrimes} 5914Srgrimes 59216561Salexstatic void 59316561Salexchange_active(int which) 5944Srgrimes{ 59581164Siedowse struct dos_partition *partp = &mboot.parts[0]; 59681164Siedowse int active, i, new, tmp; 5974Srgrimes 59881164Siedowse active = -1; 59981164Siedowse for (i = 0; i < NDOSPART; i++) { 60081164Siedowse if ((partp[i].dp_flag & ACTIVE) == 0) 60181164Siedowse continue; 60281164Siedowse printf("Partition %d is marked active\n", i + 1); 60381164Siedowse if (active == -1) 60481164Siedowse active = i + 1; 60581164Siedowse } 6064Srgrimes if (a_flag && which != -1) 6074Srgrimes active = which; 60881164Siedowse else if (active == -1) 60981164Siedowse active = 1; 61081164Siedowse 6113723Sbde if (!ok("Do you want to change the active partition?")) 6123723Sbde return; 61334952Sobriensetactive: 61434952Sobrien do { 61581164Siedowse new = active; 61681164Siedowse Decimal("active partition", new, tmp); 61781164Siedowse if (new < 1 || new > 4) { 61834952Sobrien printf("Active partition number must be in range 1-4." 61934952Sobrien " Try again.\n"); 62034952Sobrien goto setactive; 62134952Sobrien } 62281164Siedowse active = new; 62334952Sobrien } while (!ok("Are you happy with this choice")); 6244Srgrimes for (i = 0; i < NDOSPART; i++) 6254Srgrimes partp[i].dp_flag = 0; 62626421Sbrian if (active > 0 && active <= NDOSPART) 62726421Sbrian partp[active-1].dp_flag = ACTIVE; 6284Srgrimes} 6294Srgrimes 63043054Srnordierstatic void 63143054Srnordierchange_code() 63243054Srnordier{ 63343054Srnordier if (ok("Do you want to change the boot code?")) 63443054Srnordier init_boot(); 63543054Srnordier} 63643054Srnordier 63716561Salexvoid 6384Srgrimesget_params_to_use() 6394Srgrimes{ 6404Srgrimes int tmp; 6414Srgrimes print_params(); 6424Srgrimes if (ok("Do you want to change our idea of what BIOS thinks ?")) 6434Srgrimes { 6444Srgrimes do 6454Srgrimes { 6464Srgrimes Decimal("BIOS's idea of #cylinders", dos_cyls, tmp); 6474Srgrimes Decimal("BIOS's idea of #heads", dos_heads, tmp); 6484Srgrimes Decimal("BIOS's idea of #sectors", dos_sectors, tmp); 6494Srgrimes dos_cylsecs = dos_heads * dos_sectors; 6504Srgrimes print_params(); 6514Srgrimes } 6524Srgrimes while(!ok("Are you happy with this choice")); 6534Srgrimes } 6544Srgrimes} 6554Srgrimes 65619459Sjkh 6574Srgrimes/***********************************************\ 6584Srgrimes* Change real numbers into strange dos numbers * 6594Srgrimes\***********************************************/ 66016561Salexstatic void 66181164Siedowsedos(partp) 66281164Siedowse struct dos_partition *partp; 6634Srgrimes{ 66481164Siedowse int cy, sec; 66581164Siedowse u_int32_t end; 6664Srgrimes 66781164Siedowse if (partp->dp_typ == 0 && partp->dp_start == 0 && 66881164Siedowse partp->dp_size == 0) { 66981164Siedowse bcopy(partp, &mtpart, sizeof(*partp)); 6703723Sbde return; 6713723Sbde } 6723723Sbde 67381164Siedowse /* Start c/h/s. */ 67481164Siedowse partp->dp_shd = partp->dp_start % dos_cylsecs / dos_sectors; 67581164Siedowse cy = partp->dp_start / dos_cylsecs; 67681164Siedowse sec = partp->dp_start % dos_sectors + 1; 67781164Siedowse partp->dp_scyl = DOSCYL(cy); 67881164Siedowse partp->dp_ssect = DOSSECT(sec, cy); 6794Srgrimes 68081164Siedowse /* End c/h/s. */ 68181164Siedowse end = partp->dp_start + partp->dp_size - 1; 68281164Siedowse partp->dp_ehd = end % dos_cylsecs / dos_sectors; 68381164Siedowse cy = end / dos_cylsecs; 68481164Siedowse sec = end % dos_sectors + 1; 68581164Siedowse partp->dp_ecyl = DOSCYL(cy); 68681164Siedowse partp->dp_esect = DOSSECT(sec, cy); 6874Srgrimes} 6884Srgrimes 6894Srgrimesint fd; 6904Srgrimes 6914Srgrimes /* Getting device status */ 6924Srgrimes 69316561Salexstatic int 69416561Salexopen_disk(int u_flag) 6954Srgrimes{ 69679306Sjoerg struct stat st; 6974Srgrimes 6988871Srgrimes if (stat(disk, &st) == -1) { 69979306Sjoerg if (errno == ENOENT) 70079306Sjoerg return -2; 70137415Scharnier warnx("can't get file status of %s", disk); 7024Srgrimes return -1; 7032810Sbde } 7042810Sbde if ( !(st.st_mode & S_IFCHR) ) 70537415Scharnier warnx("device %s is not character special", disk); 70643054Srnordier if ((fd = open(disk, 70757896Simp a_flag || I_flag || B_flag || u_flag ? O_RDWR : O_RDONLY)) == -1) { 70810514Sjoerg if(errno == ENXIO) 70910514Sjoerg return -2; 71037415Scharnier warnx("can't open device %s", disk); 7114Srgrimes return -1; 7124Srgrimes } 7134Srgrimes if (get_params(0) == -1) { 71437415Scharnier warnx("can't get disk parameters on %s", disk); 7154Srgrimes return -1; 7164Srgrimes } 7174Srgrimes return fd; 7184Srgrimes} 7194Srgrimes 72016561Salexstatic ssize_t 72116561Salexread_disk(off_t sector, void *buf) 7224Srgrimes{ 7234Srgrimes lseek(fd,(sector * 512), 0); 72420061Ssos if( secsize == 0 ) 72520061Ssos for( secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; secsize *= 2 ) 72620061Ssos { 72720061Ssos /* try the read */ 72820061Ssos int size = read(fd, buf, secsize); 72920061Ssos if( size == secsize ) 73020061Ssos /* it worked so return */ 73120061Ssos return secsize; 73220061Ssos } 73320061Ssos else 73420061Ssos return read( fd, buf, secsize ); 73520061Ssos 73620061Ssos /* we failed to read at any of the sizes */ 73720061Ssos return -1; 7384Srgrimes} 7394Srgrimes 74016561Salexstatic ssize_t 74116561Salexwrite_disk(off_t sector, void *buf) 7424Srgrimes{ 7434Srgrimes lseek(fd,(sector * 512), 0); 74420061Ssos /* write out in the size that the read_disk found worked */ 74520061Ssos return write(fd, buf, secsize); 7464Srgrimes} 7474Srgrimes 74816561Salexstatic int 74916561Salexget_params() 7504Srgrimes{ 7514Srgrimes 7524Srgrimes if (ioctl(fd, DIOCGDINFO, &disklabel) == -1) { 75337415Scharnier warnx("can't get disk parameters on %s; supplying dummy ones", disk); 7542810Sbde dos_cyls = cyls = 1; 7552810Sbde dos_heads = heads = 1; 7562810Sbde dos_sectors = sectors = 1; 7572810Sbde dos_cylsecs = cylsecs = heads * sectors; 7582810Sbde disksecs = cyls * heads * sectors; 7592810Sbde return disksecs; 7604Srgrimes } 7614Srgrimes 7624Srgrimes dos_cyls = cyls = disklabel.d_ncylinders; 7634Srgrimes dos_heads = heads = disklabel.d_ntracks; 7644Srgrimes dos_sectors = sectors = disklabel.d_nsectors; 7654Srgrimes dos_cylsecs = cylsecs = heads * sectors; 7664Srgrimes disksecs = cyls * heads * sectors; 7674Srgrimes 7684Srgrimes return (disksecs); 7694Srgrimes} 7704Srgrimes 7714Srgrimes 77216561Salexstatic int 7734Srgrimesread_s0() 7744Srgrimes{ 77563218Sache mboot.bootinst_size = secsize; 77663218Sache if (mboot.bootinst != NULL) 77763027Sjhb free(mboot.bootinst); 77863218Sache if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) { 77963218Sache warnx("unable to allocate buffer to read fdisk " 78063218Sache "partition table"); 78163218Sache return -1; 78263027Sjhb } 78363027Sjhb if (read_disk(0, mboot.bootinst) == -1) { 78437415Scharnier warnx("can't read fdisk partition table"); 7854Srgrimes return -1; 7864Srgrimes } 78763729Sjhb if (*(uint16_t *)&mboot.bootinst[MBRSIGOFF] != BOOT_MAGIC) { 78837415Scharnier warnx("invalid fdisk partition table found"); 7894Srgrimes /* So should we initialize things */ 7904Srgrimes return -1; 7914Srgrimes } 79263027Sjhb memcpy(mboot.parts, &mboot.bootinst[DOSPARTOFF], sizeof(mboot.parts)); 7934Srgrimes return 0; 7944Srgrimes} 7954Srgrimes 79616561Salexstatic int 7974Srgrimeswrite_s0() 7984Srgrimes{ 79951636Sbillf#ifdef NOT_NOW 8004Srgrimes int flag; 80151636Sbillf#endif 80263027Sjhb int sector; 80363027Sjhb 8044Srgrimes if (iotest) { 8054Srgrimes print_s0(-1); 8064Srgrimes return 0; 8074Srgrimes } 80863027Sjhb memcpy(&mboot.bootinst[DOSPARTOFF], mboot.parts, sizeof(mboot.parts)); 8094Srgrimes /* 8104Srgrimes * write enable label sector before write (if necessary), 8114Srgrimes * disable after writing. 8124Srgrimes * needed if the disklabel protected area also protects 8134Srgrimes * sector 0. (e.g. empty disk) 8144Srgrimes */ 81550215Sphk#ifdef NOT_NOW 8164Srgrimes flag = 1; 8174Srgrimes if (ioctl(fd, DIOCWLABEL, &flag) < 0) 81837415Scharnier warn("ioctl DIOCWLABEL"); 81911143Sjulian#endif 82063027Sjhb for(sector = 0; sector < mboot.bootinst_size / secsize; sector++) 82163027Sjhb if (write_disk(sector, 82263027Sjhb &mboot.bootinst[sector * secsize]) == -1) { 82363027Sjhb warn("can't write fdisk partition table"); 82463027Sjhb return -1; 82550215Sphk#ifdef NOT_NOW 82663027Sjhb flag = 0; 82763027Sjhb (void) ioctl(fd, DIOCWLABEL, &flag); 82863027Sjhb#endif 82963027Sjhb } 83063027Sjhb#ifdef NOT_NOW 8314Srgrimes flag = 0; 8324Srgrimes (void) ioctl(fd, DIOCWLABEL, &flag); 83311143Sjulian#endif 83416561Salex return(0); 8354Srgrimes} 8364Srgrimes 8374Srgrimes 83816561Salexstatic int 8394Srgrimesok(str) 8404Srgrimeschar *str; 8414Srgrimes{ 8424Srgrimes printf("%s [n] ", str); 84381164Siedowse fflush(stdout); 84481164Siedowse if (fgets(lbuf, LBUF, stdin) == NULL) 84581164Siedowse exit(1); 8464Srgrimes lbuf[strlen(lbuf)-1] = 0; 8474Srgrimes 8484Srgrimes if (*lbuf && 8494Srgrimes (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || 8504Srgrimes !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) 8514Srgrimes return 1; 8524Srgrimes else 8534Srgrimes return 0; 8544Srgrimes} 8554Srgrimes 85616561Salexstatic int 85716561Salexdecimal(char *str, int *num, int deflt) 8584Srgrimes{ 8594Srgrimesint acc = 0, c; 8604Srgrimeschar *cp; 8614Srgrimes 8624Srgrimes while (1) { 8634Srgrimes printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); 86481164Siedowse fflush(stdout); 86581164Siedowse if (fgets(lbuf, LBUF, stdin) == NULL) 86681164Siedowse exit(1); 8674Srgrimes lbuf[strlen(lbuf)-1] = 0; 8684Srgrimes 8694Srgrimes if (!*lbuf) 8704Srgrimes return 0; 8714Srgrimes 8724Srgrimes cp = lbuf; 8734Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 8744Srgrimes if (!c) 8754Srgrimes return 0; 87616561Salex while ((c = *cp++)) { 8774Srgrimes if (c <= '9' && c >= '0') 8784Srgrimes acc = acc * 10 + c - '0'; 8794Srgrimes else 8804Srgrimes break; 8814Srgrimes } 8824Srgrimes if (c == ' ' || c == '\t') 8834Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 8844Srgrimes if (!c) { 8854Srgrimes *num = acc; 8864Srgrimes return 1; 8874Srgrimes } else 88834952Sobrien printf("%s is an invalid decimal number. Try again.\n", 8894Srgrimes lbuf); 8904Srgrimes } 8914Srgrimes 8924Srgrimes} 8934Srgrimes 89416561Salex#if 0 89516561Salexstatic int 89616561Salexhex(char *str, int *num, int deflt) 8974Srgrimes{ 8984Srgrimesint acc = 0, c; 8994Srgrimeschar *cp; 9004Srgrimes 9014Srgrimes while (1) { 9024Srgrimes printf("Supply a hex value for \"%s\" [%x] ", str, deflt); 9034Srgrimes fgets(lbuf, LBUF, stdin); 9044Srgrimes lbuf[strlen(lbuf)-1] = 0; 9054Srgrimes 9064Srgrimes if (!*lbuf) 9074Srgrimes return 0; 9084Srgrimes 9094Srgrimes cp = lbuf; 9104Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 9114Srgrimes if (!c) 9124Srgrimes return 0; 91316561Salex while ((c = *cp++)) { 9144Srgrimes if (c <= '9' && c >= '0') 9154Srgrimes acc = (acc << 4) + c - '0'; 9164Srgrimes else if (c <= 'f' && c >= 'a') 9174Srgrimes acc = (acc << 4) + c - 'a' + 10; 9184Srgrimes else if (c <= 'F' && c >= 'A') 9194Srgrimes acc = (acc << 4) + c - 'A' + 10; 9204Srgrimes else 9214Srgrimes break; 9224Srgrimes } 9234Srgrimes if (c == ' ' || c == '\t') 9244Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 9254Srgrimes if (!c) { 9264Srgrimes *num = acc; 9274Srgrimes return 1; 9284Srgrimes } else 92934952Sobrien printf("%s is an invalid hex number. Try again.\n", 9304Srgrimes lbuf); 9314Srgrimes } 9324Srgrimes 9334Srgrimes} 9344Srgrimes 93516561Salexstatic int 93616561Salexstring(char *str, char **ans) 9374Srgrimes{ 9384Srgrimesint c; 9394Srgrimeschar *cp = lbuf; 9404Srgrimes 9414Srgrimes while (1) { 9424Srgrimes printf("Supply a string value for \"%s\" [%s] ", str, *ans); 9434Srgrimes fgets(lbuf, LBUF, stdin); 9444Srgrimes lbuf[strlen(lbuf)-1] = 0; 9454Srgrimes 9464Srgrimes if (!*lbuf) 9474Srgrimes return 0; 9484Srgrimes 9494Srgrimes while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 9504Srgrimes if (c == '"') { 9514Srgrimes c = *++cp; 9524Srgrimes *ans = cp; 9534Srgrimes while ((c = *cp) && c != '"') cp++; 9544Srgrimes } else { 9554Srgrimes *ans = cp; 9564Srgrimes while ((c = *cp) && c != ' ' && c != '\t') cp++; 9574Srgrimes } 9584Srgrimes 9594Srgrimes if (c) 9604Srgrimes *cp = 0; 9614Srgrimes return 1; 9624Srgrimes } 9634Srgrimes} 96416561Salex#endif 9654Srgrimes 96616561Salexstatic char * 96716561Salexget_type(int type) 9684Srgrimes{ 9694Srgrimes int numentries = (sizeof(part_types)/sizeof(struct part_type)); 9704Srgrimes int counter = 0; 9714Srgrimes struct part_type *ptr = part_types; 9724Srgrimes 9738871Srgrimes 9744Srgrimes while(counter < numentries) 9754Srgrimes { 9764Srgrimes if(ptr->type == type) 9774Srgrimes { 9784Srgrimes return(ptr->name); 9794Srgrimes } 9804Srgrimes ptr++; 9814Srgrimes counter++; 9824Srgrimes } 9834Srgrimes return("unknown"); 9844Srgrimes} 98519459Sjkh 98619459Sjkh 98719459Sjkhstatic void 98819459Sjkhparse_config_line(line, command) 98919459Sjkh char *line; 99019459Sjkh CMD *command; 99119459Sjkh{ 99219459Sjkh char *cp, *end; 99319459Sjkh 99419459Sjkh cp = line; 99519459Sjkh while (1) /* dirty trick used to insure one exit point for this 99619459Sjkh function */ 99719459Sjkh { 99819459Sjkh memset(command, 0, sizeof(*command)); 99919459Sjkh 100019459Sjkh while (isspace(*cp)) ++cp; 100119459Sjkh if (*cp == '\0' || *cp == '#') 100219459Sjkh { 100319459Sjkh break; 100419459Sjkh } 100519459Sjkh command->cmd = *cp++; 100619459Sjkh 100719459Sjkh /* 100819459Sjkh * Parse args 100919459Sjkh */ 101019459Sjkh while (1) 101119459Sjkh { 101219459Sjkh while (isspace(*cp)) ++cp; 101319459Sjkh if (*cp == '#') 101419459Sjkh { 101519459Sjkh break; /* found comment */ 101619459Sjkh } 101719459Sjkh if (isalpha(*cp)) 101819459Sjkh { 101919459Sjkh command->args[command->n_args].argtype = *cp++; 102019459Sjkh } 102119459Sjkh if (!isdigit(*cp)) 102219459Sjkh { 102319459Sjkh break; /* assume end of line */ 102419459Sjkh } 102519459Sjkh end = NULL; 102619459Sjkh command->args[command->n_args].arg_val = strtol(cp, &end, 0); 102719459Sjkh if (cp == end) 102819459Sjkh { 102919459Sjkh break; /* couldn't parse number */ 103019459Sjkh } 103119459Sjkh cp = end; 103219459Sjkh command->n_args++; 103319459Sjkh } 103419459Sjkh break; 103519459Sjkh } 103619459Sjkh} 103719459Sjkh 103819459Sjkh 103919459Sjkhstatic int 104019459Sjkhprocess_geometry(command) 104119459Sjkh CMD *command; 104219459Sjkh{ 104319459Sjkh int status = 1, i; 104419459Sjkh 104519459Sjkh while (1) 104619459Sjkh { 104719459Sjkh geom_processed = 1; 104819459Sjkh if (part_processed) 104919459Sjkh { 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 } 105719459Sjkh if (command->n_args != 3) 105819459Sjkh { 105937415Scharnier warnx("ERROR line %d: incorrect number of geometry args", 106037415Scharnier current_line_number); 106119459Sjkh status = 0; 106219459Sjkh break; 106319459Sjkh } 106419459Sjkh dos_cyls = -1; 106519459Sjkh dos_heads = -1; 106619459Sjkh dos_sectors = -1; 106719459Sjkh for (i = 0; i < 3; ++i) 106819459Sjkh { 106919459Sjkh switch (command->args[i].argtype) 107019459Sjkh { 107119459Sjkh case 'c': 107219459Sjkh dos_cyls = command->args[i].arg_val; 107319459Sjkh break; 107419459Sjkh case 'h': 107519459Sjkh dos_heads = command->args[i].arg_val; 107619459Sjkh break; 107719459Sjkh case 's': 107819459Sjkh dos_sectors = command->args[i].arg_val; 107919459Sjkh break; 108019459Sjkh default: 108137415Scharnier warnx( 108237415Scharnier "ERROR line %d: unknown geometry arg type: '%c' (0x%02x)", 108337415Scharnier current_line_number, command->args[i].argtype, 108419459Sjkh command->args[i].argtype); 108519459Sjkh status = 0; 108619459Sjkh break; 108719459Sjkh } 108819459Sjkh } 108919459Sjkh if (status == 0) 109019459Sjkh { 109119459Sjkh break; 109219459Sjkh } 109319459Sjkh 109419459Sjkh dos_cylsecs = dos_heads * dos_sectors; 109519459Sjkh 109619459Sjkh /* 109719459Sjkh * Do sanity checks on parameter values 109819459Sjkh */ 109919459Sjkh if (dos_cyls < 0) 110019459Sjkh { 110137415Scharnier warnx("ERROR line %d: number of cylinders not specified", 110237415Scharnier current_line_number); 110319459Sjkh status = 0; 110419459Sjkh } 110519459Sjkh if (dos_cyls == 0 || dos_cyls > 1024) 110619459Sjkh { 110737415Scharnier warnx( 110837415Scharnier "WARNING line %d: number of cylinders (%d) may be out-of-range\n\ 110919459Sjkh (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\ 111037415Scharnier is dedicated to FreeBSD)", 111137415Scharnier current_line_number, dos_cyls); 111219459Sjkh } 111319459Sjkh 111419459Sjkh if (dos_heads < 0) 111519459Sjkh { 111637415Scharnier warnx("ERROR line %d: number of heads not specified", 111737415Scharnier current_line_number); 111819459Sjkh status = 0; 111919459Sjkh } 112019459Sjkh else if (dos_heads < 1 || dos_heads > 256) 112119459Sjkh { 112237415Scharnier warnx("ERROR line %d: number of heads must be within (1-256)", 112337415Scharnier current_line_number); 112419459Sjkh status = 0; 112519459Sjkh } 112619459Sjkh 112719459Sjkh if (dos_sectors < 0) 112819459Sjkh { 112937415Scharnier warnx("ERROR line %d: number of sectors not specified", 113037415Scharnier current_line_number); 113119459Sjkh status = 0; 113219459Sjkh } 113319459Sjkh else if (dos_sectors < 1 || dos_sectors > 63) 113419459Sjkh { 113537415Scharnier warnx("ERROR line %d: number of sectors must be within (1-63)", 113637415Scharnier current_line_number); 113719459Sjkh status = 0; 113819459Sjkh } 113919459Sjkh 114019459Sjkh break; 114119459Sjkh } 114219459Sjkh return (status); 114319459Sjkh} 114419459Sjkh 114519459Sjkh 114619459Sjkhstatic int 114719459Sjkhprocess_partition(command) 114819459Sjkh CMD *command; 114919459Sjkh{ 115019459Sjkh int status = 0, partition; 115165054Sjhb u_int32_t prev_head_boundary, prev_cyl_boundary; 115265054Sjhb u_int32_t adj_size, max_end; 115319459Sjkh struct dos_partition *partp; 115419459Sjkh 115519459Sjkh while (1) 115619459Sjkh { 115719459Sjkh part_processed = 1; 115819459Sjkh if (command->n_args != 4) 115919459Sjkh { 116037415Scharnier warnx("ERROR line %d: incorrect number of partition args", 116137415Scharnier current_line_number); 116219459Sjkh break; 116319459Sjkh } 116419459Sjkh partition = command->args[0].arg_val; 116526421Sbrian if (partition < 1 || partition > 4) 116619459Sjkh { 116737415Scharnier warnx("ERROR line %d: invalid partition number %d", 116837415Scharnier current_line_number, partition); 116919459Sjkh break; 117019459Sjkh } 117126421Sbrian partp = ((struct dos_partition *) &mboot.parts) + partition - 1; 117219459Sjkh bzero((char *)partp, sizeof (struct dos_partition)); 117319459Sjkh partp->dp_typ = command->args[1].arg_val; 117419459Sjkh partp->dp_start = command->args[2].arg_val; 117519459Sjkh partp->dp_size = command->args[3].arg_val; 117619459Sjkh max_end = partp->dp_start + partp->dp_size; 117719459Sjkh 117819459Sjkh if (partp->dp_typ == 0) 117919459Sjkh { 118019459Sjkh /* 118119459Sjkh * Get out, the partition is marked as unused. 118219459Sjkh */ 118319459Sjkh /* 118419459Sjkh * Insure that it's unused. 118519459Sjkh */ 118619459Sjkh bzero((char *)partp, sizeof (struct dos_partition)); 118719459Sjkh status = 1; 118819459Sjkh break; 118919459Sjkh } 119019459Sjkh 119119459Sjkh /* 119219459Sjkh * Adjust start upwards, if necessary, to fall on an head boundary. 119319459Sjkh */ 119419459Sjkh if (partp->dp_start % dos_sectors != 0) 119519459Sjkh { 119665054Sjhb prev_head_boundary = partp->dp_start / dos_sectors * dos_sectors; 119765054Sjhb if (max_end < dos_sectors || 119865054Sjhb prev_head_boundary > max_end - dos_sectors) 119919459Sjkh { 120019459Sjkh /* 120119459Sjkh * Can't go past end of partition 120219459Sjkh */ 120337415Scharnier warnx( 120437415Scharnier "ERROR line %d: unable to adjust start of partition %d to fall on\n\ 120565054Sjhb a head boundary", 120637415Scharnier current_line_number, partition); 120719459Sjkh break; 120819459Sjkh } 120937415Scharnier warnx( 121065054Sjhb "WARNING: adjusting start offset of partition %d\n\ 121165054Sjhb from %u to %u, to fall on a head boundary", 121265054Sjhb partition, (u_int)partp->dp_start, 121365054Sjhb (u_int)(prev_head_boundary + dos_sectors)); 121465054Sjhb partp->dp_start = prev_head_boundary + dos_sectors; 121519459Sjkh } 121619459Sjkh 121719459Sjkh /* 121819459Sjkh * Adjust size downwards, if necessary, to fall on a cylinder 121919459Sjkh * boundary. 122019459Sjkh */ 122165054Sjhb prev_cyl_boundary = 122219459Sjkh ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; 122365054Sjhb if (prev_cyl_boundary > partp->dp_start) 122465054Sjhb adj_size = prev_cyl_boundary - partp->dp_start; 122565054Sjhb else 122665054Sjhb { 122765054Sjhb warnx( 122865054Sjhb "ERROR: could not adjust partition to start on a head boundary\n\ 122965054Sjhb and end on a cylinder boundary."); 123065054Sjhb return (0); 123165054Sjhb } 123219459Sjkh if (adj_size != partp->dp_size) 123319459Sjkh { 123437415Scharnier warnx( 123565054Sjhb "WARNING: adjusting size of partition %d from %u to %u\n\ 123665054Sjhb to end on a cylinder boundary", 123765054Sjhb partition, (u_int)partp->dp_size, (u_int)adj_size); 123865054Sjhb partp->dp_size = adj_size; 123919459Sjkh } 124065054Sjhb if (partp->dp_size == 0) 124119459Sjkh { 124281164Siedowse warnx("ERROR line %d: size of partition %d is zero", 124337415Scharnier current_line_number, partition); 124419459Sjkh break; 124519459Sjkh } 124619459Sjkh 124781164Siedowse dos(partp); 124819459Sjkh status = 1; 124919459Sjkh break; 125019459Sjkh } 125119459Sjkh return (status); 125219459Sjkh} 125319459Sjkh 125419459Sjkh 125519459Sjkhstatic int 125619459Sjkhprocess_active(command) 125719459Sjkh CMD *command; 125819459Sjkh{ 125919459Sjkh int status = 0, partition, i; 126019459Sjkh struct dos_partition *partp; 126119459Sjkh 126219459Sjkh while (1) 126319459Sjkh { 126419459Sjkh active_processed = 1; 126519459Sjkh if (command->n_args != 1) 126619459Sjkh { 126737415Scharnier warnx("ERROR line %d: incorrect number of active args", 126837415Scharnier current_line_number); 126919459Sjkh status = 0; 127019459Sjkh break; 127119459Sjkh } 127219459Sjkh partition = command->args[0].arg_val; 127326421Sbrian if (partition < 1 || partition > 4) 127419459Sjkh { 127537415Scharnier warnx("ERROR line %d: invalid partition number %d", 127637415Scharnier current_line_number, partition); 127719459Sjkh break; 127819459Sjkh } 127919459Sjkh /* 128019459Sjkh * Reset active partition 128119459Sjkh */ 128219459Sjkh partp = ((struct dos_partition *) &mboot.parts); 128319459Sjkh for (i = 0; i < NDOSPART; i++) 128419459Sjkh partp[i].dp_flag = 0; 128526421Sbrian partp[partition-1].dp_flag = ACTIVE; 128619459Sjkh 128719459Sjkh status = 1; 128819459Sjkh break; 128919459Sjkh } 129019459Sjkh return (status); 129119459Sjkh} 129219459Sjkh 129319459Sjkh 129419459Sjkhstatic int 129519459Sjkhprocess_line(line) 129619459Sjkh char *line; 129719459Sjkh{ 129819459Sjkh CMD command; 129919459Sjkh int status = 1; 130019459Sjkh 130119459Sjkh while (1) 130219459Sjkh { 130319459Sjkh parse_config_line(line, &command); 130419459Sjkh switch (command.cmd) 130519459Sjkh { 130619459Sjkh case 0: 130719459Sjkh /* 130819459Sjkh * Comment or blank line 130919459Sjkh */ 131019459Sjkh break; 131119459Sjkh case 'g': 131219459Sjkh /* 131319459Sjkh * Set geometry 131419459Sjkh */ 131519459Sjkh status = process_geometry(&command); 131619459Sjkh break; 131719459Sjkh case 'p': 131819459Sjkh status = process_partition(&command); 131919459Sjkh break; 132019459Sjkh case 'a': 132119459Sjkh status = process_active(&command); 132219459Sjkh break; 132319459Sjkh default: 132419459Sjkh status = 0; 132519459Sjkh break; 132619459Sjkh } 132719459Sjkh break; 132819459Sjkh } 132919459Sjkh return (status); 133019459Sjkh} 133119459Sjkh 133219459Sjkh 133319459Sjkhstatic int 133419459Sjkhread_config(config_file) 133519459Sjkh char *config_file; 133619459Sjkh{ 133719459Sjkh FILE *fp = NULL; 133819459Sjkh int status = 1; 133919459Sjkh char buf[1010]; 134019459Sjkh 134119459Sjkh while (1) /* dirty trick used to insure one exit point for this 134219459Sjkh function */ 134319459Sjkh { 134419459Sjkh if (strcmp(config_file, "-") != 0) 134519459Sjkh { 134619459Sjkh /* 134719459Sjkh * We're not reading from stdin 134819459Sjkh */ 134919459Sjkh if ((fp = fopen(config_file, "r")) == NULL) 135019459Sjkh { 135119459Sjkh status = 0; 135219459Sjkh break; 135319459Sjkh } 135419459Sjkh } 135519459Sjkh else 135619459Sjkh { 135719459Sjkh fp = stdin; 135819459Sjkh } 135919459Sjkh current_line_number = 0; 136019459Sjkh while (!feof(fp)) 136119459Sjkh { 136219459Sjkh if (fgets(buf, sizeof(buf), fp) == NULL) 136319459Sjkh { 136419459Sjkh break; 136519459Sjkh } 136619459Sjkh ++current_line_number; 136719459Sjkh status = process_line(buf); 136819459Sjkh if (status == 0) 136919459Sjkh { 137019459Sjkh break; 137119459Sjkh } 137219459Sjkh } 137319459Sjkh break; 137419459Sjkh } 137519459Sjkh if (fp) 137619459Sjkh { 137719459Sjkh /* 137819459Sjkh * It doesn't matter if we're reading from stdin, as we've reached EOF 137919459Sjkh */ 138019459Sjkh fclose(fp); 138119459Sjkh } 138219459Sjkh return (status); 138319459Sjkh} 138419459Sjkh 138519459Sjkh 138619459Sjkhstatic void 138719459Sjkhreset_boot(void) 138819459Sjkh{ 138919459Sjkh int i; 139019459Sjkh struct dos_partition *partp; 139119459Sjkh 139219459Sjkh init_boot(); 139319459Sjkh for (i = 0; i < 4; ++i) 139419459Sjkh { 139519459Sjkh partp = ((struct dos_partition *) &mboot.parts) + i; 139619459Sjkh bzero((char *)partp, sizeof (struct dos_partition)); 139719459Sjkh } 139819459Sjkh} 139965054Sjhb 140065054Sjhbstatic int 140165054Sjhbsanitize_partition(partp) 140265054Sjhb struct dos_partition *partp; 140365054Sjhb{ 140465054Sjhb u_int32_t prev_head_boundary, prev_cyl_boundary; 140581164Siedowse u_int32_t max_end, size, start; 140665054Sjhb 140781164Siedowse start = partp->dp_start; 140881164Siedowse size = partp->dp_size; 140981164Siedowse max_end = start + size; 141081164Siedowse /* Only allow a zero size if the partition is being marked unused. */ 141181164Siedowse if (size == 0) { 141281164Siedowse if (start == 0 && partp->dp_typ == 0) 141381164Siedowse return (1); 141481164Siedowse warnx("ERROR: size of partition is zero"); 141581164Siedowse return (0); 141681164Siedowse } 141781164Siedowse /* Return if no adjustment is necessary. */ 141881164Siedowse if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0) 141981164Siedowse return (1); 142065054Sjhb 142181164Siedowse if (start % dos_sectors != 0) 142281164Siedowse warnx("WARNING: partition does not start on a head boundary"); 142381164Siedowse if ((start +size) % dos_sectors != 0) 142481164Siedowse warnx("WARNING: partition does not end on a cylinder boundary"); 142581164Siedowse warnx("WARNING: this may confuse the BIOS or some operating systems"); 142681164Siedowse if (!ok("Correct this automatically?")) 142781164Siedowse return (1); 142881164Siedowse 142965054Sjhb /* 143065054Sjhb * Adjust start upwards, if necessary, to fall on an head boundary. 143165054Sjhb */ 143281164Siedowse if (start % dos_sectors != 0) { 143381164Siedowse prev_head_boundary = start / dos_sectors * dos_sectors; 143465054Sjhb if (max_end < dos_sectors || 143581164Siedowse prev_head_boundary >= max_end - dos_sectors) { 143665054Sjhb /* 143765054Sjhb * Can't go past end of partition 143865054Sjhb */ 143965054Sjhb warnx( 144065054Sjhb "ERROR: unable to adjust start of partition to fall on a head boundary"); 144165054Sjhb return (0); 144265054Sjhb } 144381164Siedowse start = prev_head_boundary + dos_sectors; 144465054Sjhb } 144565054Sjhb 144665054Sjhb /* 144765054Sjhb * Adjust size downwards, if necessary, to fall on a cylinder 144865054Sjhb * boundary. 144965054Sjhb */ 145081164Siedowse prev_cyl_boundary = ((start + size) / dos_cylsecs) * dos_cylsecs; 145181164Siedowse if (prev_cyl_boundary > start) 145281164Siedowse size = prev_cyl_boundary - start; 145381164Siedowse else { 145465054Sjhb warnx("ERROR: could not adjust partition to start on a head boundary\n\ 145565054Sjhb and end on a cylinder boundary."); 145665054Sjhb return (0); 145765054Sjhb } 145881164Siedowse 145981164Siedowse /* Finally, commit any changes to partp and return. */ 146081164Siedowse if (start != partp->dp_start) { 146181164Siedowse warnx("WARNING: adjusting start offset of partition to %u", 146281164Siedowse (u_int)start); 146381164Siedowse partp->dp_start = start; 146465054Sjhb } 146581164Siedowse if (size != partp->dp_size) { 146681164Siedowse warnx("WARNING: adjusting size of partition to %u", (u_int)size); 146781164Siedowse partp->dp_size = size; 146865054Sjhb } 146965054Sjhb 147065054Sjhb return (1); 147165054Sjhb} 147279681Sjoerg 147379681Sjoerg/* 147479681Sjoerg * Try figuring out the root device's canonical disk name. 147579681Sjoerg * The following choices are considered: 147679681Sjoerg * /dev/ad0s1a => /dev/ad0 147779681Sjoerg * /dev/da0a => /dev/da0 147879681Sjoerg * /dev/vinum/root => /dev/vinum/root 147979681Sjoerg */ 148079681Sjoergstatic char * 148179681Sjoergget_rootdisk(void) 148279681Sjoerg{ 148379681Sjoerg struct statfs rootfs; 148479681Sjoerg regex_t re; 148579681Sjoerg#define NMATCHES 2 148679681Sjoerg regmatch_t rm[NMATCHES]; 148779681Sjoerg char *s; 148879681Sjoerg int rv; 148979681Sjoerg 149079681Sjoerg if (statfs("/", &rootfs) == -1) 149179681Sjoerg err(1, "statfs(\"/\")"); 149279681Sjoerg 149379681Sjoerg if ((rv = regcomp(&re, "^(/dev/.*)(\\d+(s\\d+)?[a-h])?$", 149479681Sjoerg REG_EXTENDED)) != 0) 149579681Sjoerg errx(1, "regcomp() failed (%d)", rv); 149679681Sjoerg if ((rv = regexec(&re, rootfs.f_mntfromname, NMATCHES, rm, 0)) != 0) 149779681Sjoerg errx(1, 149879681Sjoerg"mounted root fs resource doesn't match expectations (regexec returned %d)", 149979681Sjoerg rv); 150079681Sjoerg if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL) 150179681Sjoerg errx(1, "out of memory"); 150279681Sjoerg memcpy(s, rootfs.f_mntfromname + rm[1].rm_so, 150379681Sjoerg rm[1].rm_eo - rm[1].rm_so); 150479681Sjoerg s[rm[1].rm_eo - rm[1].rm_so] = 0; 150579681Sjoerg 150679681Sjoerg return s; 150779681Sjoerg} 1508