1254721Semaste/* 2254721Semaste * Mach Operating System 3254721Semaste * Copyright (c) 1992 Carnegie Mellon University 4254721Semaste * All Rights Reserved. 5254721Semaste * 6254721Semaste * Permission to use, copy, modify and distribute this software and its 7254721Semaste * documentation is hereby granted, provided that both the copyright 8254721Semaste * notice and this permission notice appear in all copies of the 9254721Semaste * software, derivative works or modified versions, and any portions 10254721Semaste * thereof, and that both notices appear in supporting documentation. 11254721Semaste * 12254721Semaste * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 13254721Semaste * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14254721Semaste * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 15254721Semaste * 16254721Semaste * Carnegie Mellon requests users of this software to return to 17254721Semaste * 18254721Semaste * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 19254721Semaste * School of Computer Science 20254721Semaste * Carnegie Mellon University 21254721Semaste * Pittsburgh PA 15213-3890 22254721Semaste * 23254721Semaste * any improvements or extensions that they make and grant Carnegie Mellon 24254721Semaste * the rights to redistribute these changes. 25269024Semaste */ 26254721Semaste 27254721Semaste#include <sys/cdefs.h> 28254721Semaste__FBSDID("$FreeBSD$"); 29254721Semaste 30254721Semaste#include <sys/disk.h> 31254721Semaste#include <sys/disklabel.h> 32254721Semaste#include <sys/diskmbr.h> 33254721Semaste#include <sys/endian.h> 34254721Semaste#include <sys/param.h> 35254721Semaste#include <sys/stat.h> 36254721Semaste#include <sys/mount.h> 37254721Semaste#include <ctype.h> 38254721Semaste#include <fcntl.h> 39254721Semaste#include <err.h> 40254721Semaste#include <errno.h> 41254721Semaste#include <libgeom.h> 42254721Semaste#include <paths.h> 43254721Semaste#include <regex.h> 44254721Semaste#include <stdint.h> 45254721Semaste#include <stdio.h> 46254721Semaste#include <stdlib.h> 47254721Semaste#include <string.h> 48269024Semaste#include <unistd.h> 49254721Semaste 50254721Semastestatic int iotest; 51269024Semaste 52254721Semaste#define NO_DISK_SECTORS ((u_int32_t)-1) 53254721Semaste#define NO_TRACK_CYLINDERS 1023 54254721Semaste#define NO_TRACK_HEADS 255 55254721Semaste#define NO_TRACK_SECTORS 63 56254721Semaste#define LBUF 100 57254721Semastestatic char lbuf[LBUF]; 58254721Semaste 59254721Semaste/* 60254721Semaste * 61254721Semaste * Ported to 386bsd by Julian Elischer Thu Oct 15 20:26:46 PDT 1992 62254721Semaste * 63254721Semaste * 14-Dec-89 Robert Baron (rvb) at Carnegie-Mellon University 64254721Semaste * Copyright (c) 1989 Robert. V. Baron 65254721Semaste * Created. 66254721Semaste */ 67254721Semaste 68254721Semaste#define Decimal(str, ans, tmp, maxval) if (decimal(str, &tmp, ans, maxval)) ans = tmp 69254721Semaste 70254721Semaste#define RoundCyl(x) ((((x) + cylsecs - 1) / cylsecs) * cylsecs) 71254721Semaste 72254721Semaste#define MAX_SEC_SIZE 2048 /* maximum section size that is supported */ 73254721Semaste#define MIN_SEC_SIZE 512 /* the sector size to start sensing at */ 74254721Semastestatic int secsize = 0; /* the sensed sector size */ 75254721Semaste 76254721Semastestatic char *disk; 77254721Semaste 78254721Semastestatic int cyls, sectors, heads, cylsecs, disksecs; 79254721Semaste 80254721Semastestruct mboot { 81254721Semaste unsigned char *bootinst; /* boot code */ 82254721Semaste off_t bootinst_size; 83254721Semaste struct dos_partition parts[NDOSPART]; 84254721Semaste}; 85254721Semaste 86254721Semastestatic struct mboot mboot; 87254721Semastestatic int fd; 88254721Semaste 89254721Semaste#define ACTIVE 0x80 90254721Semaste 91254721Semastestatic uint dos_cyls; 92254721Semastestatic uint dos_heads; 93254721Semastestatic uint dos_sectors; 94254721Semastestatic uint dos_cylsecs; 95254721Semaste 96254721Semaste#define DOSSECT(s,c) ((s & 0x3f) | ((c >> 2) & 0xc0)) 97254721Semaste#define DOSCYL(c) (c & 0xff) 98254721Semaste 99254721Semaste#define MAX_ARGS 10 100254721Semaste 101254721Semastestatic int current_line_number; 102254721Semaste 103254721Semastestatic int geom_processed = 0; 104269024Semastestatic int part_processed = 0; 105254721Semastestatic int active_processed = 0; 106254721Semaste 107254721Semastetypedef struct cmd { 108254721Semaste char cmd; 109254721Semaste int n_args; 110269024Semaste struct arg { 111254721Semaste char argtype; 112254721Semaste unsigned long arg_val; 113254721Semaste char * arg_str; 114254721Semaste } args[MAX_ARGS]; 115254721Semaste} CMD; 116254721Semaste 117254721Semastestatic int B_flag = 0; /* replace boot code */ 118254721Semastestatic int I_flag = 0; /* use entire disk for FreeBSD */ 119254721Semastestatic int a_flag = 0; /* set active partition */ 120254721Semastestatic char *b_flag = NULL; /* path to boot code */ 121254721Semastestatic int i_flag = 0; /* replace partition data */ 122254721Semastestatic int q_flag = 0; /* Be quiet */ 123254721Semastestatic int u_flag = 0; /* update partition data */ 124254721Semastestatic int s_flag = 0; /* Print a summary and exit */ 125254721Semastestatic int t_flag = 0; /* test only */ 126254721Semastestatic char *f_flag = NULL; /* Read config info from file */ 127254721Semastestatic int v_flag = 0; /* Be verbose */ 128254721Semastestatic int print_config_flag = 0; 129254721Semaste 130254721Semaste/* 131254721Semaste * A list of partition types, probably outdated. 132254721Semaste */ 133254721Semastestatic const char *const part_types[256] = { 134254721Semaste [0x00] = "unused", 135254721Semaste [0x01] = "Primary DOS with 12 bit FAT", 136254721Semaste [0x02] = "XENIX / file system", 137254721Semaste [0x03] = "XENIX /usr file system", 138254721Semaste [0x04] = "Primary DOS with 16 bit FAT (< 32MB)", 139254721Semaste [0x05] = "Extended DOS", 140254721Semaste [0x06] = "Primary DOS, 16 bit FAT (>= 32MB)", 141254721Semaste [0x07] = "NTFS, OS/2 HPFS, QNX-2 (16 bit) or Advanced UNIX", 142254721Semaste [0x08] = "AIX file system or SplitDrive", 143254721Semaste [0x09] = "AIX boot partition or Coherent", 144254721Semaste [0x0A] = "OS/2 Boot Manager, OPUS or Coherent swap", 145254721Semaste [0x0B] = "DOS or Windows 95 with 32 bit FAT", 146254721Semaste [0x0C] = "DOS or Windows 95 with 32 bit FAT (LBA)", 147254721Semaste [0x0E] = "Primary 'big' DOS (>= 32MB, LBA)", 148254721Semaste [0x0F] = "Extended DOS (LBA)", 149254721Semaste [0x10] = "OPUS", 150254721Semaste [0x11] = "OS/2 BM: hidden DOS with 12-bit FAT", 151254721Semaste [0x12] = "Compaq diagnostics", 152254721Semaste [0x14] = "OS/2 BM: hidden DOS with 16-bit FAT (< 32MB)", 153254721Semaste [0x16] = "OS/2 BM: hidden DOS with 16-bit FAT (>= 32MB)", 154254721Semaste [0x17] = "OS/2 BM: hidden IFS (e.g. HPFS)", 155254721Semaste [0x18] = "AST Windows swapfile", 156254721Semaste [0x1b] = "ASUS Recovery partition (NTFS)", 157254721Semaste [0x24] = "NEC DOS", 158254721Semaste [0x3C] = "PartitionMagic recovery", 159254721Semaste [0x39] = "plan9", 160254721Semaste [0x40] = "VENIX 286", 161254721Semaste [0x41] = "Linux/MINIX (sharing disk with DRDOS)", 162254721Semaste [0x42] = "SFS or Linux swap (sharing disk with DRDOS)", 163254721Semaste [0x43] = "Linux native (sharing disk with DRDOS)", 164254721Semaste [0x4D] = "QNX 4.2 Primary", 165254721Semaste [0x4E] = "QNX 4.2 Secondary", 166254721Semaste [0x4F] = "QNX 4.2 Tertiary", 167254721Semaste [0x50] = "DM (disk manager)", 168254721Semaste [0x51] = "DM6 Aux1 (or Novell)", 169254721Semaste [0x52] = "CP/M or Microport SysV/AT", 170254721Semaste [0x53] = "DM6 Aux3", 171254721Semaste [0x54] = "DM6", 172254721Semaste [0x55] = "EZ-Drive (disk manager)", 173254721Semaste [0x56] = "Golden Bow (disk manager)", 174254721Semaste [0x5c] = "Priam Edisk (disk manager)", /* according to S. Widlake */ 175254721Semaste [0x61] = "SpeedStor", 176254721Semaste [0x63] = "System V/386 (such as ISC UNIX), GNU HURD or Mach", 177254721Semaste [0x64] = "Novell Netware/286 2.xx", 178254721Semaste [0x65] = "Novell Netware/386 3.xx", 179254721Semaste [0x70] = "DiskSecure Multi-Boot", 180254721Semaste [0x75] = "PCIX", 181254721Semaste [0x77] = "QNX4.x", 182254721Semaste [0x78] = "QNX4.x 2nd part", 183254721Semaste [0x79] = "QNX4.x 3rd part", 184254721Semaste [0x80] = "Minix until 1.4a", 185254721Semaste [0x81] = "Minix since 1.4b, early Linux partition or Mitac disk manager", 186254721Semaste [0x82] = "Linux swap or Solaris x86", 187254721Semaste [0x83] = "Linux native", 188254721Semaste [0x84] = "OS/2 hidden C: drive", 189254721Semaste [0x85] = "Linux extended", 190254721Semaste [0x86] = "NTFS volume set??", 191254721Semaste [0x87] = "NTFS volume set??", 192254721Semaste [0x93] = "Amoeba file system", 193254721Semaste [0x94] = "Amoeba bad block table", 194254721Semaste [0x9F] = "BSD/OS", 195254721Semaste [0xA0] = "Suspend to Disk", 196254721Semaste [0xA5] = "FreeBSD/NetBSD/386BSD", 197254721Semaste [0xA6] = "OpenBSD", 198254721Semaste [0xA7] = "NeXTSTEP", 199254721Semaste [0xA9] = "NetBSD", 200254721Semaste [0xAC] = "IBM JFS", 201254721Semaste [0xAF] = "HFS+", 202254721Semaste [0xB7] = "BSDI BSD/386 file system", 203254721Semaste [0xB8] = "BSDI BSD/386 swap", 204254721Semaste [0xBE] = "Solaris x86 boot", 205254721Semaste [0xBF] = "Solaris x86 (new)", 206254721Semaste [0xC1] = "DRDOS/sec with 12-bit FAT", 207254721Semaste [0xC4] = "DRDOS/sec with 16-bit FAT (< 32MB)", 208254721Semaste [0xC6] = "DRDOS/sec with 16-bit FAT (>= 32MB)", 209254721Semaste [0xC7] = "Syrinx", 210254721Semaste [0xDB] = "CP/M, Concurrent CP/M, Concurrent DOS or CTOS", 211254721Semaste [0xDE] = "DELL Utilities - FAT filesystem", 212254721Semaste [0xE1] = "DOS access or SpeedStor with 12-bit FAT extended partition", 213254721Semaste [0xE3] = "DOS R/O or SpeedStor", 214254721Semaste [0xE4] = "SpeedStor with 16-bit FAT extended partition < 1024 cyl.", 215254721Semaste [0xEB] = "BeOS file system", 216254721Semaste [0xEE] = "EFI GPT", 217254721Semaste [0xEF] = "EFI System Partition", 218254721Semaste [0xF1] = "SpeedStor", 219254721Semaste [0xF2] = "DOS 3.3+ Secondary", 220254721Semaste [0xF4] = "SpeedStor large partition", 221254721Semaste [0xFB] = "VMware VMFS", 222254721Semaste [0xFE] = "SpeedStor >1024 cyl. or LANstep", 223254721Semaste [0xFF] = "Xenix bad blocks table", 224254721Semaste}; 225254721Semaste 226254721Semastestatic const char * 227254721Semasteget_type(int t) 228254721Semaste{ 229254721Semaste const char *ret; 230254721Semaste 231254721Semaste ret = (t >= 0 && t <= 255) ? part_types[t] : NULL; 232254721Semaste return ret ? ret : "unknown"; 233254721Semaste} 234254721Semaste 235263363Semaste 236263363Semastestatic int geom_class_available(const char *); 237263363Semastestatic void print_s0(void); 238263363Semastestatic void print_part(const struct dos_partition *); 239263363Semastestatic void init_sector0(unsigned long start); 240263363Semastestatic void init_boot(void); 241263363Semastestatic void change_part(int i); 242254721Semastestatic void print_params(void); 243254721Semastestatic void change_active(int which); 244254721Semastestatic void change_code(void); 245254721Semastestatic void get_params_to_use(void); 246254721Semastestatic char *get_rootdisk(void); 247254721Semastestatic void dos(struct dos_partition *partp); 248254721Semastestatic int open_disk(int flag); 249254721Semastestatic ssize_t read_disk(off_t sector, void *buf); 250254721Semastestatic int write_disk(off_t sector, void *buf); 251254721Semastestatic int get_params(void); 252254721Semastestatic int read_s0(void); 253254721Semastestatic int write_s0(void); 254254721Semastestatic int ok(const char *str); 255254721Semastestatic int decimal(const char *str, int *num, int deflt, uint32_t maxval); 256254721Semastestatic int read_config(char *config_file); 257254721Semastestatic void reset_boot(void); 258254721Semastestatic int sanitize_partition(struct dos_partition *); 259254721Semastestatic void usage(void); 260254721Semaste 261254721Semasteint 262254721Semastemain(int argc, char *argv[]) 263254721Semaste{ 264254721Semaste int c, i; 265254721Semaste int partition = -1; 266254721Semaste struct dos_partition *partp; 267254721Semaste 268254721Semaste while ((c = getopt(argc, argv, "BIab:f:ipqstuv1234")) != -1) 269254721Semaste switch (c) { 270254721Semaste case 'B': 271254721Semaste B_flag = 1; 272254721Semaste break; 273254721Semaste case 'I': 274254721Semaste I_flag = 1; 275254721Semaste break; 276254721Semaste case 'a': 277254721Semaste a_flag = 1; 278254721Semaste break; 279254721Semaste case 'b': 280254721Semaste b_flag = optarg; 281254721Semaste break; 282254721Semaste case 'f': 283254721Semaste f_flag = optarg; 284254721Semaste break; 285254721Semaste case 'i': 286254721Semaste i_flag = 1; 287254721Semaste break; 288254721Semaste case 'p': 289254721Semaste print_config_flag = 1; 290254721Semaste break; 291254721Semaste case 'q': 292254721Semaste q_flag = 1; 293254721Semaste break; 294254721Semaste case 's': 295254721Semaste s_flag = 1; 296254721Semaste break; 297254721Semaste case 't': 298254721Semaste t_flag = 1; 299254721Semaste break; 300254721Semaste case 'u': 301254721Semaste u_flag = 1; 302254721Semaste break; 303254721Semaste case 'v': 304254721Semaste v_flag = 1; 305254721Semaste break; 306254721Semaste case '1': 307254721Semaste case '2': 308254721Semaste case '3': 309254721Semaste case '4': 310254721Semaste partition = c - '0'; 311254721Semaste break; 312254721Semaste default: 313254721Semaste usage(); 314254721Semaste } 315254721Semaste if (f_flag || i_flag) 316254721Semaste u_flag = 1; 317254721Semaste if (t_flag) 318254721Semaste v_flag = 1; 319254721Semaste argc -= optind; 320254721Semaste argv += optind; 321254721Semaste 322254721Semaste if (argc == 0) { 323254721Semaste disk = get_rootdisk(); 324254721Semaste } else { 325254721Semaste disk = g_device_path(argv[0]); 326254721Semaste if (disk == NULL) 327254721Semaste err(1, "unable to get correct path for %s", argv[0]); 328254721Semaste } 329254721Semaste if (open_disk(u_flag) < 0) 330263363Semaste err(1, "cannot open disk %s", disk); 331254721Semaste 332254721Semaste /* (abu)use mboot.bootinst to probe for the sector size */ 333254721Semaste if ((mboot.bootinst = malloc(MAX_SEC_SIZE)) == NULL) 334254721Semaste err(1, "cannot allocate buffer to determine disk sector size"); 335254721Semaste if (read_disk(0, mboot.bootinst) == -1) 336254721Semaste errx(1, "could not detect sector size"); 337254721Semaste free(mboot.bootinst); 338254721Semaste mboot.bootinst = NULL; 339254721Semaste 340254721Semaste if (print_config_flag) { 341254721Semaste if (read_s0()) 342254721Semaste err(1, "read_s0"); 343254721Semaste 344254721Semaste printf("# %s\n", disk); 345254721Semaste printf("g c%d h%d s%d\n", dos_cyls, dos_heads, dos_sectors); 346254721Semaste 347254721Semaste for (i = 0; i < NDOSPART; i++) { 348254721Semaste partp = &mboot.parts[i]; 349254721Semaste 350254721Semaste if (partp->dp_start == 0 && partp->dp_size == 0) 351254721Semaste continue; 352254721Semaste 353254721Semaste printf("p %d 0x%02x %lu %lu\n", i + 1, partp->dp_typ, 354254721Semaste (u_long)partp->dp_start, (u_long)partp->dp_size); 355254721Semaste 356254721Semaste /* Fill flags for the partition. */ 357254721Semaste if (partp->dp_flag & 0x80) 358254721Semaste printf("a %d\n", i + 1); 359254721Semaste } 360254721Semaste exit(0); 361254721Semaste } 362254721Semaste if (s_flag) { 363254721Semaste if (read_s0()) 364254721Semaste err(1, "read_s0"); 365254721Semaste printf("%s: %d cyl %d hd %d sec\n", disk, dos_cyls, dos_heads, 366254721Semaste dos_sectors); 367254721Semaste printf("Part %11s %11s Type Flags\n", "Start", "Size"); 368254721Semaste for (i = 0; i < NDOSPART; i++) { 369254721Semaste partp = &mboot.parts[i]; 370254721Semaste if (partp->dp_start == 0 && partp->dp_size == 0) 371254721Semaste continue; 372254721Semaste printf("%4d: %11lu %11lu 0x%02x 0x%02x\n", i + 1, 373254721Semaste (u_long) partp->dp_start, 374254721Semaste (u_long) partp->dp_size, partp->dp_typ, 375254721Semaste partp->dp_flag); 376254721Semaste } 377254721Semaste exit(0); 378254721Semaste } 379254721Semaste 380254721Semaste printf("******* Working on device %s *******\n",disk); 381254721Semaste 382254721Semaste if (I_flag) { 383269024Semaste read_s0(); 384254721Semaste reset_boot(); 385254721Semaste partp = &mboot.parts[0]; 386254721Semaste partp->dp_typ = DOSPTYP_386BSD; 387254721Semaste partp->dp_flag = ACTIVE; 388254721Semaste partp->dp_start = dos_sectors; 389254721Semaste partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - 390254721Semaste dos_sectors; 391254721Semaste dos(partp); 392254721Semaste if (v_flag) 393254721Semaste print_s0(); 394254721Semaste if (!t_flag) 395254721Semaste write_s0(); 396254721Semaste exit(0); 397254721Semaste } 398254721Semaste if (f_flag) { 399254721Semaste if (read_s0() || i_flag) 400254721Semaste reset_boot(); 401254721Semaste if (!read_config(f_flag)) 402254721Semaste exit(1); 403254721Semaste if (v_flag) 404254721Semaste print_s0(); 405254721Semaste if (!t_flag) 406254721Semaste write_s0(); 407254721Semaste } else { 408254721Semaste if(u_flag) 409254721Semaste get_params_to_use(); 410254721Semaste else 411254721Semaste print_params(); 412254721Semaste 413254721Semaste if (read_s0()) 414254721Semaste init_sector0(dos_sectors); 415254721Semaste 416254721Semaste printf("Media sector size is %d\n", secsize); 417254721Semaste printf("Warning: BIOS sector numbering starts with sector 1\n"); 418254721Semaste printf("Information from DOS bootblock is:\n"); 419254721Semaste if (partition == -1) 420254721Semaste for (i = 1; i <= NDOSPART; i++) 421254721Semaste change_part(i); 422254721Semaste else 423254721Semaste change_part(partition); 424254721Semaste 425254721Semaste if (u_flag || a_flag) 426254721Semaste change_active(partition); 427254721Semaste 428254721Semaste if (B_flag) 429254721Semaste change_code(); 430254721Semaste 431254721Semaste if (u_flag || a_flag || B_flag) { 432254721Semaste if (!t_flag) { 433254721Semaste printf("\nWe haven't changed the partition table yet. "); 434254721Semaste printf("This is your last chance.\n"); 435254721Semaste } 436254721Semaste print_s0(); 437254721Semaste if (!t_flag) { 438254721Semaste if (ok("Should we write new partition table?")) 439254721Semaste write_s0(); 440254721Semaste } else { 441254721Semaste printf("\n-t flag specified -- partition table not written.\n"); 442254721Semaste } 443254721Semaste } 444254721Semaste } 445254721Semaste 446254721Semaste exit(0); 447254721Semaste} 448254721Semaste 449254721Semastestatic void 450254721Semasteusage() 451254721Semaste{ 452254721Semaste fprintf(stderr, "%s%s", 453254721Semaste "usage: fdisk [-BIaipqstu] [-b bootcode] [-1234] [disk]\n", 454254721Semaste " fdisk -f configfile [-itv] [disk]\n"); 455254721Semaste exit(1); 456254721Semaste} 457254721Semaste 458254721Semastestatic void 459254721Semasteprint_s0(void) 460254721Semaste{ 461254721Semaste int i; 462254721Semaste 463254721Semaste print_params(); 464254721Semaste printf("Information from DOS bootblock is:\n"); 465254721Semaste for (i = 1; i <= NDOSPART; i++) { 466254721Semaste printf("%d: ", i); 467254721Semaste print_part(&mboot.parts[i - 1]); 468254721Semaste } 469254721Semaste} 470254721Semaste 471254721Semastestatic struct dos_partition mtpart; 472254721Semaste 473254721Semastestatic void 474254721Semasteprint_part(const struct dos_partition *partp) 475254721Semaste{ 476254721Semaste u_int64_t part_mb; 477254721Semaste 478254721Semaste if (!bcmp(partp, &mtpart, sizeof (struct dos_partition))) { 479254721Semaste printf("<UNUSED>\n"); 480254721Semaste return; 481254721Semaste } 482254721Semaste /* 483254721Semaste * Be careful not to overflow. 484254721Semaste */ 485254721Semaste part_mb = partp->dp_size; 486254721Semaste part_mb *= secsize; 487254721Semaste part_mb /= (1024 * 1024); 488254721Semaste printf("sysid %d (%#04x),(%s)\n", partp->dp_typ, partp->dp_typ, 489254721Semaste get_type(partp->dp_typ)); 490254721Semaste printf(" start %lu, size %lu (%ju Meg), flag %x%s\n", 491254721Semaste (u_long)partp->dp_start, 492254721Semaste (u_long)partp->dp_size, 493254721Semaste (uintmax_t)part_mb, 494254721Semaste partp->dp_flag, 495254721Semaste partp->dp_flag == ACTIVE ? " (active)" : ""); 496254721Semaste printf("\tbeg: cyl %d/ head %d/ sector %d;\n\tend: cyl %d/ head %d/ sector %d\n" 497254721Semaste ,DPCYL(partp->dp_scyl, partp->dp_ssect) 498254721Semaste ,partp->dp_shd 499254721Semaste ,DPSECT(partp->dp_ssect) 500254721Semaste ,DPCYL(partp->dp_ecyl, partp->dp_esect) 501254721Semaste ,partp->dp_ehd 502254721Semaste ,DPSECT(partp->dp_esect)); 503254721Semaste} 504254721Semaste 505254721Semaste 506254721Semastestatic void 507254721Semasteinit_boot(void) 508254721Semaste{ 509254721Semaste#ifndef __ia64__ 510254721Semaste const char *fname; 511254721Semaste int fdesc, n; 512254721Semaste struct stat sb; 513254721Semaste 514254721Semaste fname = b_flag ? b_flag : "/boot/mbr"; 515254721Semaste if ((fdesc = open(fname, O_RDONLY)) == -1 || 516254721Semaste fstat(fdesc, &sb) == -1) 517254721Semaste err(1, "%s", fname); 518254721Semaste if (sb.st_size == 0) 519254721Semaste errx(1, "%s is empty, must not be.", fname); 520254721Semaste if ((mboot.bootinst_size = sb.st_size) % secsize != 0) 521254721Semaste errx(1, "%s: length must be a multiple of sector size", fname); 522254721Semaste if (mboot.bootinst != NULL) 523254721Semaste free(mboot.bootinst); 524254721Semaste if ((mboot.bootinst = malloc(mboot.bootinst_size = sb.st_size)) == NULL) 525254721Semaste errx(1, "%s: unable to allocate read buffer", fname); 526254721Semaste if ((n = read(fdesc, mboot.bootinst, mboot.bootinst_size)) == -1 || 527254721Semaste close(fdesc)) 528254721Semaste err(1, "%s", fname); 529254721Semaste if (n != mboot.bootinst_size) 530254721Semaste errx(1, "%s: short read", fname); 531254721Semaste#else 532254721Semaste if (mboot.bootinst != NULL) 533254721Semaste free(mboot.bootinst); 534254721Semaste mboot.bootinst_size = secsize; 535254721Semaste if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) 536254721Semaste errx(1, "unable to allocate boot block buffer"); 537254721Semaste memset(mboot.bootinst, 0, mboot.bootinst_size); 538254721Semaste le16enc(&mboot.bootinst[DOSMAGICOFFSET], DOSMAGIC); 539254721Semaste#endif 540254721Semaste} 541254721Semaste 542254721Semaste 543254721Semastestatic void 544254721Semasteinit_sector0(unsigned long start) 545254721Semaste{ 546254721Semaste struct dos_partition *partp = &mboot.parts[0]; 547254721Semaste 548254721Semaste init_boot(); 549254721Semaste 550254721Semaste partp->dp_typ = DOSPTYP_386BSD; 551254721Semaste partp->dp_flag = ACTIVE; 552254721Semaste start = ((start + dos_sectors - 1) / dos_sectors) * dos_sectors; 553254721Semaste if(start == 0) 554254721Semaste start = dos_sectors; 555254721Semaste partp->dp_start = start; 556254721Semaste partp->dp_size = (disksecs / dos_cylsecs) * dos_cylsecs - start; 557254721Semaste 558254721Semaste dos(partp); 559254721Semaste} 560254721Semaste 561254721Semastestatic void 562254721Semastechange_part(int i) 563254721Semaste{ 564254721Semaste struct dos_partition *partp = &mboot.parts[i - 1]; 565254721Semaste 566254721Semaste printf("The data for partition %d is:\n", i); 567254721Semaste print_part(partp); 568254721Semaste 569254721Semaste if (u_flag && ok("Do you want to change it?")) { 570254721Semaste int tmp; 571254721Semaste 572254721Semaste if (i_flag) { 573254721Semaste bzero(partp, sizeof (*partp)); 574254721Semaste if (i == 1) { 575254721Semaste init_sector0(1); 576254721Semaste printf("\nThe static data for the slice 1 has been reinitialized to:\n"); 577254721Semaste print_part(partp); 578254721Semaste } 579254721Semaste } 580254721Semaste 581254721Semaste do { 582254721Semaste Decimal("sysid (165=FreeBSD)", partp->dp_typ, tmp, 255); 583254721Semaste Decimal("start", partp->dp_start, tmp, NO_DISK_SECTORS); 584254721Semaste Decimal("size", partp->dp_size, tmp, NO_DISK_SECTORS); 585254721Semaste if (!sanitize_partition(partp)) { 586254721Semaste warnx("ERROR: failed to adjust; setting sysid to 0"); 587254721Semaste partp->dp_typ = 0; 588254721Semaste } 589254721Semaste 590254721Semaste if (ok("Explicitly specify beg/end address ?")) 591254721Semaste { 592254721Semaste int tsec,tcyl,thd; 593254721Semaste tcyl = DPCYL(partp->dp_scyl,partp->dp_ssect); 594254721Semaste thd = partp->dp_shd; 595254721Semaste tsec = DPSECT(partp->dp_ssect); 596254721Semaste Decimal("beginning cylinder", tcyl, tmp, NO_TRACK_CYLINDERS); 597254721Semaste Decimal("beginning head", thd, tmp, NO_TRACK_HEADS); 598254721Semaste Decimal("beginning sector", tsec, tmp, NO_TRACK_SECTORS); 599254721Semaste partp->dp_scyl = DOSCYL(tcyl); 600263363Semaste partp->dp_ssect = DOSSECT(tsec,tcyl); 601254721Semaste partp->dp_shd = thd; 602254721Semaste 603254721Semaste tcyl = DPCYL(partp->dp_ecyl,partp->dp_esect); 604254721Semaste thd = partp->dp_ehd; 605254721Semaste tsec = DPSECT(partp->dp_esect); 606254721Semaste Decimal("ending cylinder", tcyl, tmp, NO_TRACK_CYLINDERS); 607254721Semaste Decimal("ending head", thd, tmp, NO_TRACK_HEADS); 608254721Semaste Decimal("ending sector", tsec, tmp, NO_TRACK_SECTORS); 609254721Semaste partp->dp_ecyl = DOSCYL(tcyl); 610254721Semaste partp->dp_esect = DOSSECT(tsec,tcyl); 611254721Semaste partp->dp_ehd = thd; 612254721Semaste } else 613254721Semaste dos(partp); 614254721Semaste 615254721Semaste print_part(partp); 616254721Semaste } while (!ok("Are we happy with this entry?")); 617254721Semaste } 618254721Semaste} 619254721Semaste 620254721Semastestatic void 621254721Semasteprint_params() 622254721Semaste{ 623254721Semaste printf("parameters extracted from in-core disklabel are:\n"); 624254721Semaste printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 625254721Semaste ,cyls,heads,sectors,cylsecs); 626254721Semaste if (dos_cyls > 1023 || dos_heads > 255 || dos_sectors > 63) 627254721Semaste printf("Figures below won't work with BIOS for partitions not in cyl 1\n"); 628254721Semaste printf("parameters to be used for BIOS calculations are:\n"); 629254721Semaste printf("cylinders=%d heads=%d sectors/track=%d (%d blks/cyl)\n\n" 630254721Semaste ,dos_cyls,dos_heads,dos_sectors,dos_cylsecs); 631254721Semaste} 632254721Semaste 633263363Semastestatic void 634263363Semastechange_active(int which) 635263363Semaste{ 636263363Semaste struct dos_partition *partp = &mboot.parts[0]; 637263363Semaste int active, i, new, tmp; 638263363Semaste 639263363Semaste active = -1; 640263363Semaste for (i = 0; i < NDOSPART; i++) { 641263363Semaste if ((partp[i].dp_flag & ACTIVE) == 0) 642263363Semaste continue; 643263363Semaste printf("Partition %d is marked active\n", i + 1); 644263363Semaste if (active == -1) 645263363Semaste active = i + 1; 646263363Semaste } 647263363Semaste if (a_flag && which != -1) 648263363Semaste active = which; 649263363Semaste else if (active == -1) 650263363Semaste active = 1; 651263363Semaste 652263363Semaste if (!ok("Do you want to change the active partition?")) 653254721Semaste return; 654254721Semastesetactive: 655254721Semaste do { 656254721Semaste new = active; 657254721Semaste Decimal("active partition", new, tmp, 0); 658254721Semaste if (new < 1 || new > 4) { 659254721Semaste printf("Active partition number must be in range 1-4." 660254721Semaste " Try again.\n"); 661254721Semaste goto setactive; 662254721Semaste } 663254721Semaste active = new; 664254721Semaste } while (!ok("Are you happy with this choice")); 665254721Semaste for (i = 0; i < NDOSPART; i++) 666254721Semaste partp[i].dp_flag = 0; 667254721Semaste if (active > 0 && active <= NDOSPART) 668254721Semaste partp[active-1].dp_flag = ACTIVE; 669254721Semaste} 670254721Semaste 671254721Semastestatic void 672254721Semastechange_code() 673254721Semaste{ 674254721Semaste if (ok("Do you want to change the boot code?")) 675254721Semaste init_boot(); 676254721Semaste} 677254721Semaste 678254721Semastevoid 679254721Semasteget_params_to_use() 680254721Semaste{ 681254721Semaste int tmp; 682254721Semaste print_params(); 683254721Semaste if (ok("Do you want to change our idea of what BIOS thinks ?")) 684254721Semaste { 685254721Semaste do 686254721Semaste { 687254721Semaste Decimal("BIOS's idea of #cylinders", dos_cyls, tmp, 0); 688254721Semaste Decimal("BIOS's idea of #heads", dos_heads, tmp, 0); 689254721Semaste Decimal("BIOS's idea of #sectors", dos_sectors, tmp, 0); 690254721Semaste dos_cylsecs = dos_heads * dos_sectors; 691254721Semaste print_params(); 692254721Semaste } 693254721Semaste while(!ok("Are you happy with this choice")); 694254721Semaste } 695254721Semaste} 696254721Semaste 697254721Semaste 698254721Semaste/***********************************************\ 699254721Semaste* Change real numbers into strange dos numbers * 700254721Semaste\***********************************************/ 701254721Semastestatic void 702254721Semastedos(struct dos_partition *partp) 703254721Semaste{ 704254721Semaste int cy, sec; 705254721Semaste u_int32_t end; 706254721Semaste 707254721Semaste if (partp->dp_typ == 0 && partp->dp_start == 0 && partp->dp_size == 0) { 708254721Semaste memcpy(partp, &mtpart, sizeof(*partp)); 709254721Semaste return; 710254721Semaste } 711254721Semaste 712254721Semaste /* Start c/h/s. */ 713254721Semaste partp->dp_shd = partp->dp_start % dos_cylsecs / dos_sectors; 714254721Semaste cy = partp->dp_start / dos_cylsecs; 715254721Semaste sec = partp->dp_start % dos_sectors + 1; 716254721Semaste partp->dp_scyl = DOSCYL(cy); 717254721Semaste partp->dp_ssect = DOSSECT(sec, cy); 718254721Semaste 719254721Semaste /* End c/h/s. */ 720254721Semaste end = partp->dp_start + partp->dp_size - 1; 721254721Semaste partp->dp_ehd = end % dos_cylsecs / dos_sectors; 722254721Semaste cy = end / dos_cylsecs; 723254721Semaste sec = end % dos_sectors + 1; 724254721Semaste partp->dp_ecyl = DOSCYL(cy); 725254721Semaste partp->dp_esect = DOSSECT(sec, cy); 726254721Semaste} 727254721Semaste 728254721Semastestatic int 729254721Semasteopen_disk(int flag) 730254721Semaste{ 731254721Semaste int rwmode; 732254721Semaste 733254721Semaste /* Write mode if one of these flags are set. */ 734254721Semaste rwmode = (a_flag || I_flag || B_flag || flag); 735254721Semaste fd = g_open(disk, rwmode); 736254721Semaste /* If the mode fails, try read-only if we didn't. */ 737254721Semaste if (fd == -1 && errno == EPERM && rwmode) 738254721Semaste fd = g_open(disk, 0); 739254721Semaste if (fd == -1 && errno == ENXIO) 740254721Semaste return -2; 741254721Semaste if (fd == -1) { 742254721Semaste warnx("can't open device %s", disk); 743254721Semaste return -1; 744254721Semaste } 745254721Semaste if (get_params() == -1) { 746254721Semaste warnx("can't get disk parameters on %s", disk); 747254721Semaste return -1; 748254721Semaste } 749254721Semaste return fd; 750254721Semaste} 751254721Semaste 752254721Semastestatic ssize_t 753254721Semasteread_disk(off_t sector, void *buf) 754254721Semaste{ 755254721Semaste 756254721Semaste lseek(fd, (sector * 512), 0); 757254721Semaste if (secsize == 0) 758254721Semaste for (secsize = MIN_SEC_SIZE; secsize <= MAX_SEC_SIZE; 759254721Semaste secsize *= 2) { 760254721Semaste /* try the read */ 761254721Semaste int size = read(fd, buf, secsize); 762254721Semaste if (size == secsize) 763254721Semaste /* it worked so return */ 764254721Semaste return secsize; 765254721Semaste } 766254721Semaste else 767254721Semaste return read(fd, buf, secsize); 768254721Semaste 769254721Semaste /* we failed to read at any of the sizes */ 770254721Semaste return -1; 771254721Semaste} 772254721Semaste 773254721Semastestatic int 774254721Semastegeom_class_available(const char *name) 775254721Semaste{ 776254721Semaste struct gclass *class; 777254721Semaste struct gmesh mesh; 778254721Semaste int error; 779254721Semaste 780254721Semaste error = geom_gettree(&mesh); 781254721Semaste if (error != 0) 782254721Semaste errc(1, error, "Cannot get GEOM tree"); 783254721Semaste 784254721Semaste LIST_FOREACH(class, &mesh.lg_class, lg_class) { 785254721Semaste if (strcmp(class->lg_name, name) == 0) { 786254721Semaste geom_deletetree(&mesh); 787254721Semaste return (1); 788254721Semaste } 789254721Semaste } 790254721Semaste 791254721Semaste geom_deletetree(&mesh); 792254721Semaste 793254721Semaste return (0); 794254721Semaste} 795254721Semaste 796254721Semastestatic int 797254721Semastewrite_disk(off_t sector, void *buf) 798254721Semaste{ 799254721Semaste struct gctl_req *grq; 800254721Semaste const char *errmsg; 801254721Semaste char *pname; 802254721Semaste int error; 803254721Semaste 804254721Semaste /* Check that GEOM_MBR is available */ 805254721Semaste if (geom_class_available("MBR") != 0) { 806254721Semaste grq = gctl_get_handle(); 807254721Semaste gctl_ro_param(grq, "verb", -1, "write MBR"); 808254721Semaste gctl_ro_param(grq, "class", -1, "MBR"); 809254721Semaste pname = g_providername(fd); 810254721Semaste if (pname == NULL) { 811254721Semaste warn("Error getting providername for %s", disk); 812254721Semaste return (-1); 813254721Semaste } 814254721Semaste gctl_ro_param(grq, "geom", -1, pname); 815254721Semaste gctl_ro_param(grq, "data", secsize, buf); 816254721Semaste errmsg = gctl_issue(grq); 817254721Semaste free(pname); 818254721Semaste if (errmsg == NULL) { 819254721Semaste gctl_free(grq); 820254721Semaste return(0); 821254721Semaste } 822254721Semaste if (!q_flag) 823254721Semaste warnx("GEOM_MBR: %s", errmsg); 824254721Semaste gctl_free(grq); 825254721Semaste } else { 826254721Semaste /* 827254721Semaste * Try to write MBR directly. This may help when disk 828254721Semaste * is not in use. 829254721Semaste * XXX: hardcoded sectorsize 830254721Semaste */ 831254721Semaste error = pwrite(fd, buf, secsize, (sector * 512)); 832254721Semaste if (error == secsize) 833254721Semaste return (0); 834254721Semaste } 835254721Semaste 836254721Semaste /* 837254721Semaste * GEOM_MBR is not available or failed to write MBR. 838254721Semaste * Now check that we have GEOM_PART and recommend to use gpart (8). 839254721Semaste */ 840254721Semaste if (geom_class_available("PART") != 0) 841254721Semaste warnx("Failed to write MBR. Try to use gpart(8)."); 842254721Semaste else 843254721Semaste warnx("Failed to write sector zero"); 844254721Semaste return(EINVAL); 845254721Semaste} 846254721Semaste 847254721Semastestatic int 848254721Semasteget_params() 849254721Semaste{ 850254721Semaste int error; 851254721Semaste u_int u; 852254721Semaste off_t o; 853254721Semaste 854254721Semaste error = ioctl(fd, DIOCGFWSECTORS, &u); 855254721Semaste if (error == 0) 856254721Semaste sectors = dos_sectors = u; 857254721Semaste else 858254721Semaste sectors = dos_sectors = 63; 859254721Semaste 860254721Semaste error = ioctl(fd, DIOCGFWHEADS, &u); 861254721Semaste if (error == 0) 862254721Semaste heads = dos_heads = u; 863254721Semaste else 864254721Semaste heads = dos_heads = 255; 865254721Semaste 866254721Semaste dos_cylsecs = cylsecs = heads * sectors; 867254721Semaste disksecs = cyls * heads * sectors; 868254721Semaste 869254721Semaste u = g_sectorsize(fd); 870254721Semaste if (u <= 0) 871254721Semaste return (-1); 872254721Semaste 873254721Semaste o = g_mediasize(fd); 874254721Semaste if (o < 0) 875254721Semaste return (-1); 876254721Semaste disksecs = o / u; 877254721Semaste cyls = dos_cyls = o / (u * dos_heads * dos_sectors); 878254721Semaste 879254721Semaste return (disksecs); 880254721Semaste} 881254721Semaste 882254721Semastestatic int 883254721Semasteread_s0() 884254721Semaste{ 885254721Semaste int i; 886254721Semaste 887254721Semaste mboot.bootinst_size = secsize; 888254721Semaste if (mboot.bootinst != NULL) 889254721Semaste free(mboot.bootinst); 890254721Semaste if ((mboot.bootinst = malloc(mboot.bootinst_size)) == NULL) { 891254721Semaste warnx("unable to allocate buffer to read fdisk " 892254721Semaste "partition table"); 893254721Semaste return -1; 894254721Semaste } 895254721Semaste if (read_disk(0, mboot.bootinst) == -1) { 896254721Semaste warnx("can't read fdisk partition table"); 897254721Semaste return -1; 898254721Semaste } 899254721Semaste if (le16dec(&mboot.bootinst[DOSMAGICOFFSET]) != DOSMAGIC) { 900254721Semaste warnx("invalid fdisk partition table found"); 901254721Semaste /* So should we initialize things */ 902254721Semaste return -1; 903254721Semaste } 904254721Semaste for (i = 0; i < NDOSPART; i++) 905254721Semaste dos_partition_dec( 906254721Semaste &mboot.bootinst[DOSPARTOFF + i * DOSPARTSIZE], 907254721Semaste &mboot.parts[i]); 908254721Semaste return 0; 909254721Semaste} 910254721Semaste 911254721Semastestatic int 912254721Semastewrite_s0() 913254721Semaste{ 914254721Semaste int sector, i; 915254721Semaste 916254721Semaste if (iotest) { 917254721Semaste print_s0(); 918254721Semaste return 0; 919254721Semaste } 920254721Semaste for(i = 0; i < NDOSPART; i++) 921254721Semaste dos_partition_enc(&mboot.bootinst[DOSPARTOFF + i * DOSPARTSIZE], 922254721Semaste &mboot.parts[i]); 923254721Semaste le16enc(&mboot.bootinst[DOSMAGICOFFSET], DOSMAGIC); 924254721Semaste for(sector = 0; sector < mboot.bootinst_size / secsize; sector++) 925254721Semaste if (write_disk(sector, 926254721Semaste &mboot.bootinst[sector * secsize]) == -1) { 927254721Semaste warn("can't write fdisk partition table"); 928254721Semaste return -1; 929254721Semaste } 930254721Semaste return(0); 931254721Semaste} 932254721Semaste 933254721Semaste 934254721Semastestatic int 935254721Semasteok(const char *str) 936254721Semaste{ 937254721Semaste printf("%s [n] ", str); 938254721Semaste fflush(stdout); 939254721Semaste if (fgets(lbuf, LBUF, stdin) == NULL) 940254721Semaste exit(1); 941254721Semaste lbuf[strlen(lbuf)-1] = 0; 942254721Semaste 943254721Semaste if (*lbuf && 944254721Semaste (!strcmp(lbuf, "yes") || !strcmp(lbuf, "YES") || 945254721Semaste !strcmp(lbuf, "y") || !strcmp(lbuf, "Y"))) 946254721Semaste return 1; 947254721Semaste else 948254721Semaste return 0; 949254721Semaste} 950254721Semaste 951254721Semastestatic int 952254721Semastedecimal(const char *str, int *num, int deflt, uint32_t maxval) 953254721Semaste{ 954254721Semaste long long acc; 955254721Semaste int c; 956254721Semaste char *cp; 957254721Semaste 958254721Semaste while (1) { 959254721Semaste acc = 0; 960254721Semaste printf("Supply a decimal value for \"%s\" [%d] ", str, deflt); 961254721Semaste fflush(stdout); 962254721Semaste if (fgets(lbuf, LBUF, stdin) == NULL) 963254721Semaste exit(1); 964254721Semaste lbuf[strlen(lbuf)-1] = 0; 965254721Semaste 966254721Semaste if (!*lbuf) 967254721Semaste return 0; 968254721Semaste 969254721Semaste cp = lbuf; 970254721Semaste while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 971254721Semaste if (!c) 972254721Semaste return 0; 973254721Semaste while ((c = *cp++)) { 974254721Semaste if (c <= '9' && c >= '0') { 975254721Semaste if (acc <= maxval || maxval == 0) 976254721Semaste acc = acc * 10 + c - '0'; 977254721Semaste } else 978254721Semaste break; 979254721Semaste } 980254721Semaste if (c == ' ' || c == '\t') 981254721Semaste while ((c = *cp) && (c == ' ' || c == '\t')) cp++; 982254721Semaste if (!c) { 983254721Semaste if (maxval > 0 && acc > maxval) { 984254721Semaste acc = maxval; 985254721Semaste printf("%s exceeds maximum value allowed for " 986254721Semaste "this field. The value has been reduced " 987254721Semaste "to %lld\n", lbuf, acc); 988254721Semaste } 989254721Semaste *num = acc; 990254721Semaste return 1; 991254721Semaste } else 992254721Semaste printf("%s is an invalid decimal number. Try again.\n", 993254721Semaste lbuf); 994254721Semaste } 995254721Semaste} 996254721Semaste 997254721Semaste 998254721Semastestatic void 999254721Semasteparse_config_line(char *line, CMD *command) 1000254721Semaste{ 1001254721Semaste char *cp, *end; 1002254721Semaste 1003254721Semaste cp = line; 1004254721Semaste while (1) { 1005254721Semaste memset(command, 0, sizeof(*command)); 1006254721Semaste 1007254721Semaste while (isspace(*cp)) ++cp; 1008254721Semaste if (*cp == '\0' || *cp == '#') 1009254721Semaste break; 1010254721Semaste command->cmd = *cp++; 1011254721Semaste 1012254721Semaste /* 1013254721Semaste * Parse args 1014254721Semaste */ 1015254721Semaste while (1) { 1016254721Semaste while (isspace(*cp)) ++cp; 1017254721Semaste if (*cp == '\0') 1018254721Semaste break; /* eol */ 1019254721Semaste if (*cp == '#') 1020254721Semaste break; /* found comment */ 1021254721Semaste if (isalpha(*cp)) 1022254721Semaste command->args[command->n_args].argtype = *cp++; 1023254721Semaste end = NULL; 1024254721Semaste command->args[command->n_args].arg_val = strtoul(cp, &end, 0); 1025254721Semaste if (cp == end || (!isspace(*end) && *end != '\0')) { 1026254721Semaste char ch; 1027254721Semaste end = cp; 1028254721Semaste while (!isspace(*end) && *end != '\0') ++end; 1029254721Semaste ch = *end; *end = '\0'; 1030254721Semaste command->args[command->n_args].arg_str = strdup(cp); 1031254721Semaste *end = ch; 1032254721Semaste } else 1033254721Semaste command->args[command->n_args].arg_str = NULL; 1034254721Semaste cp = end; 1035254721Semaste command->n_args++; 1036254721Semaste } 1037254721Semaste break; 1038254721Semaste } 1039254721Semaste} 1040254721Semaste 1041254721Semaste 1042254721Semastestatic int 1043254721Semasteprocess_geometry(CMD *command) 1044254721Semaste{ 1045254721Semaste int status = 1, i; 1046254721Semaste 1047254721Semaste while (1) { 1048254721Semaste geom_processed = 1; 1049254721Semaste if (part_processed) { 1050254721Semaste warnx( 1051254721Semaste "ERROR line %d: the geometry specification line must occur before\n\ 1052254721Semaste all partition specifications", 1053254721Semaste current_line_number); 1054254721Semaste status = 0; 1055254721Semaste break; 1056254721Semaste } 1057254721Semaste if (command->n_args != 3) { 1058254721Semaste warnx("ERROR line %d: incorrect number of geometry args", 1059254721Semaste current_line_number); 1060254721Semaste status = 0; 1061254721Semaste break; 1062254721Semaste } 1063254721Semaste dos_cyls = 0; 1064254721Semaste dos_heads = 0; 1065254721Semaste dos_sectors = 0; 1066254721Semaste for (i = 0; i < 3; ++i) { 1067254721Semaste switch (command->args[i].argtype) { 1068254721Semaste case 'c': 1069254721Semaste dos_cyls = command->args[i].arg_val; 1070254721Semaste break; 1071254721Semaste case 'h': 1072254721Semaste dos_heads = command->args[i].arg_val; 1073254721Semaste break; 1074254721Semaste case 's': 1075254721Semaste dos_sectors = command->args[i].arg_val; 1076254721Semaste break; 1077254721Semaste default: 1078254721Semaste warnx( 1079254721Semaste "ERROR line %d: unknown geometry arg type: '%c' (0x%02x)", 1080254721Semaste current_line_number, command->args[i].argtype, 1081254721Semaste command->args[i].argtype); 1082254721Semaste status = 0; 1083254721Semaste break; 1084254721Semaste } 1085254721Semaste } 1086254721Semaste if (status == 0) 1087254721Semaste break; 1088254721Semaste 1089254721Semaste dos_cylsecs = dos_heads * dos_sectors; 1090254721Semaste 1091254721Semaste /* 1092254721Semaste * Do sanity checks on parameter values 1093254721Semaste */ 1094254721Semaste if (dos_cyls == 0) { 1095254721Semaste warnx("ERROR line %d: number of cylinders not specified", 1096254721Semaste current_line_number); 1097254721Semaste status = 0; 1098254721Semaste } 1099254721Semaste if (dos_cyls > 1024) { 1100254721Semaste warnx( 1101254721Semaste "WARNING line %d: number of cylinders (%d) may be out-of-range\n\ 1102254721Semaste (must be within 1-1024 for normal BIOS operation, unless the entire disk\n\ 1103254721Semaste is dedicated to FreeBSD)", 1104254721Semaste current_line_number, dos_cyls); 1105254721Semaste } 1106254721Semaste 1107254721Semaste if (dos_heads == 0) { 1108254721Semaste warnx("ERROR line %d: number of heads not specified", 1109254721Semaste current_line_number); 1110254721Semaste status = 0; 1111254721Semaste } else if (dos_heads > 256) { 1112254721Semaste warnx("ERROR line %d: number of heads must be within (1-256)", 1113254721Semaste current_line_number); 1114254721Semaste status = 0; 1115254721Semaste } 1116254721Semaste 1117254721Semaste if (dos_sectors == 0) { 1118254721Semaste warnx("ERROR line %d: number of sectors not specified", 1119254721Semaste current_line_number); 1120254721Semaste status = 0; 1121254721Semaste } else if (dos_sectors > 63) { 1122254721Semaste warnx("ERROR line %d: number of sectors must be within (1-63)", 1123254721Semaste current_line_number); 1124254721Semaste status = 0; 1125254721Semaste } 1126254721Semaste 1127254721Semaste break; 1128254721Semaste } 1129254721Semaste return (status); 1130254721Semaste} 1131254721Semaste 1132254721Semastestatic u_int32_t 1133254721Semastestr2sectors(const char *str) 1134254721Semaste{ 1135254721Semaste char *end; 1136254721Semaste unsigned long val; 1137254721Semaste 1138254721Semaste val = strtoul(str, &end, 0); 1139254721Semaste if (str == end || *end == '\0') { 1140254721Semaste warnx("ERROR line %d: unexpected size: \'%s\'", 1141254721Semaste current_line_number, str); 1142254721Semaste return NO_DISK_SECTORS; 1143254721Semaste } 1144254721Semaste 1145254721Semaste if (*end == 'K') 1146254721Semaste val *= 1024UL / secsize; 1147254721Semaste else if (*end == 'M') 1148254721Semaste val *= 1024UL * 1024UL / secsize; 1149254721Semaste else if (*end == 'G') 1150254721Semaste val *= 1024UL * 1024UL * 1024UL / secsize; 1151254721Semaste else { 1152254721Semaste warnx("ERROR line %d: unexpected modifier: %c " 1153254721Semaste "(not K/M/G)", current_line_number, *end); 1154254721Semaste return NO_DISK_SECTORS; 1155254721Semaste } 1156254721Semaste 1157254721Semaste return val; 1158254721Semaste} 1159254721Semaste 1160254721Semastestatic int 1161254721Semasteprocess_partition(CMD *command) 1162254721Semaste{ 1163254721Semaste int status = 0, partition; 1164254721Semaste u_int32_t prev_head_boundary, prev_cyl_boundary; 1165254721Semaste u_int32_t adj_size, max_end; 1166254721Semaste struct dos_partition *partp; 1167254721Semaste 1168254721Semaste while (1) { 1169254721Semaste part_processed = 1; 1170254721Semaste if (command->n_args != 4) { 1171254721Semaste warnx("ERROR line %d: incorrect number of partition args", 1172254721Semaste current_line_number); 1173254721Semaste break; 1174254721Semaste } 1175254721Semaste partition = command->args[0].arg_val; 1176254721Semaste if (partition < 1 || partition > 4) { 1177254721Semaste warnx("ERROR line %d: invalid partition number %d", 1178254721Semaste current_line_number, partition); 1179254721Semaste break; 1180254721Semaste } 1181254721Semaste partp = &mboot.parts[partition - 1]; 1182254721Semaste bzero(partp, sizeof (*partp)); 1183254721Semaste partp->dp_typ = command->args[1].arg_val; 1184254721Semaste if (command->args[2].arg_str != NULL) { 1185254721Semaste if (strcmp(command->args[2].arg_str, "*") == 0) { 1186254721Semaste int i; 1187254721Semaste partp->dp_start = dos_sectors; 1188254721Semaste for (i = 1; i < partition; i++) { 1189254721Semaste struct dos_partition *prev_partp; 1190254721Semaste prev_partp = ((struct dos_partition *) 1191254721Semaste &mboot.parts) + i - 1; 1192254721Semaste if (prev_partp->dp_typ != 0) 1193254721Semaste partp->dp_start = prev_partp->dp_start + 1194254721Semaste prev_partp->dp_size; 1195254721Semaste } 1196254721Semaste if (partp->dp_start % dos_sectors != 0) { 1197254721Semaste prev_head_boundary = partp->dp_start / 1198254721Semaste dos_sectors * dos_sectors; 1199254721Semaste partp->dp_start = prev_head_boundary + 1200254721Semaste dos_sectors; 1201254721Semaste } 1202254721Semaste } else { 1203254721Semaste partp->dp_start = str2sectors(command->args[2].arg_str); 1204254721Semaste if (partp->dp_start == NO_DISK_SECTORS) 1205254721Semaste break; 1206254721Semaste } 1207254721Semaste } else 1208254721Semaste partp->dp_start = command->args[2].arg_val; 1209254721Semaste 1210254721Semaste if (command->args[3].arg_str != NULL) { 1211254721Semaste if (strcmp(command->args[3].arg_str, "*") == 0) 1212254721Semaste partp->dp_size = ((disksecs / dos_cylsecs) * 1213254721Semaste dos_cylsecs) - partp->dp_start; 1214254721Semaste else { 1215254721Semaste partp->dp_size = str2sectors(command->args[3].arg_str); 1216254721Semaste if (partp->dp_size == NO_DISK_SECTORS) 1217254721Semaste break; 1218254721Semaste } 1219254721Semaste prev_cyl_boundary = ((partp->dp_start + partp->dp_size) / 1220254721Semaste dos_cylsecs) * dos_cylsecs; 1221254721Semaste if (prev_cyl_boundary > partp->dp_start) 1222254721Semaste partp->dp_size = prev_cyl_boundary - partp->dp_start; 1223254721Semaste } else 1224254721Semaste partp->dp_size = command->args[3].arg_val; 1225254721Semaste 1226254721Semaste max_end = partp->dp_start + partp->dp_size; 1227254721Semaste 1228254721Semaste if (partp->dp_typ == 0) { 1229254721Semaste /* 1230254721Semaste * Get out, the partition is marked as unused. 1231254721Semaste */ 1232254721Semaste /* 1233254721Semaste * Insure that it's unused. 1234254721Semaste */ 1235254721Semaste bzero(partp, sizeof(*partp)); 1236254721Semaste status = 1; 1237254721Semaste break; 1238254721Semaste } 1239254721Semaste 1240254721Semaste /* 1241254721Semaste * Adjust start upwards, if necessary, to fall on a head boundary. 1242254721Semaste */ 1243254721Semaste if (partp->dp_start % dos_sectors != 0) { 1244254721Semaste prev_head_boundary = partp->dp_start / dos_sectors * dos_sectors; 1245254721Semaste if (max_end < dos_sectors || 1246254721Semaste prev_head_boundary > max_end - dos_sectors) { 1247254721Semaste /* 1248254721Semaste * Can't go past end of partition 1249254721Semaste */ 1250254721Semaste warnx( 1251254721Semaste "ERROR line %d: unable to adjust start of partition %d to fall on\n\ 1252254721Semaste a head boundary", 1253254721Semaste current_line_number, partition); 1254254721Semaste break; 1255254721Semaste } 1256254721Semaste warnx( 1257254721Semaste "WARNING: adjusting start offset of partition %d\n\ 1258254721Semaste from %u to %u, to fall on a head boundary", 1259254721Semaste partition, (u_int)partp->dp_start, 1260254721Semaste (u_int)(prev_head_boundary + dos_sectors)); 1261254721Semaste partp->dp_start = prev_head_boundary + dos_sectors; 1262254721Semaste } 1263254721Semaste 1264254721Semaste /* 1265254721Semaste * Adjust size downwards, if necessary, to fall on a cylinder 1266254721Semaste * boundary. 1267254721Semaste */ 1268254721Semaste prev_cyl_boundary = 1269254721Semaste ((partp->dp_start + partp->dp_size) / dos_cylsecs) * dos_cylsecs; 1270254721Semaste if (prev_cyl_boundary > partp->dp_start) 1271254721Semaste adj_size = prev_cyl_boundary - partp->dp_start; 1272254721Semaste else { 1273254721Semaste warnx( 1274254721Semaste "ERROR: could not adjust partition to start on a head boundary\n\ 1275254721Semaste and end on a cylinder boundary."); 1276254721Semaste return (0); 1277254721Semaste } 1278254721Semaste if (adj_size != partp->dp_size) { 1279254721Semaste warnx( 1280254721Semaste "WARNING: adjusting size of partition %d from %u to %u\n\ 1281254721Semaste to end on a cylinder boundary", 1282254721Semaste partition, (u_int)partp->dp_size, (u_int)adj_size); 1283254721Semaste partp->dp_size = adj_size; 1284254721Semaste } 1285254721Semaste if (partp->dp_size == 0) { 1286254721Semaste warnx("ERROR line %d: size of partition %d is zero", 1287254721Semaste current_line_number, partition); 1288254721Semaste break; 1289254721Semaste } 1290254721Semaste 1291254721Semaste dos(partp); 1292254721Semaste status = 1; 1293254721Semaste break; 1294254721Semaste } 1295254721Semaste return (status); 1296254721Semaste} 1297254721Semaste 1298254721Semaste 1299254721Semastestatic int 1300254721Semasteprocess_active(CMD *command) 1301254721Semaste{ 1302254721Semaste int status = 0, partition, i; 1303254721Semaste struct dos_partition *partp; 1304254721Semaste 1305254721Semaste while (1) { 1306254721Semaste active_processed = 1; 1307254721Semaste if (command->n_args != 1) { 1308254721Semaste warnx("ERROR line %d: incorrect number of active args", 1309254721Semaste current_line_number); 1310254721Semaste status = 0; 1311254721Semaste break; 1312254721Semaste } 1313254721Semaste partition = command->args[0].arg_val; 1314254721Semaste if (partition < 1 || partition > 4) { 1315254721Semaste warnx("ERROR line %d: invalid partition number %d", 1316254721Semaste current_line_number, partition); 1317254721Semaste break; 1318254721Semaste } 1319254721Semaste /* 1320254721Semaste * Reset active partition 1321254721Semaste */ 1322254721Semaste partp = mboot.parts; 1323254721Semaste for (i = 0; i < NDOSPART; i++) 1324254721Semaste partp[i].dp_flag = 0; 1325254721Semaste partp[partition-1].dp_flag = ACTIVE; 1326254721Semaste 1327254721Semaste status = 1; 1328254721Semaste break; 1329254721Semaste } 1330254721Semaste return (status); 1331254721Semaste} 1332254721Semaste 1333254721Semaste 1334254721Semastestatic int 1335254721Semasteprocess_line(char *line) 1336254721Semaste{ 1337254721Semaste CMD command; 1338254721Semaste int status = 1; 1339254721Semaste 1340254721Semaste while (1) { 1341254721Semaste parse_config_line(line, &command); 1342254721Semaste switch (command.cmd) { 1343254721Semaste case 0: 1344254721Semaste /* 1345254721Semaste * Comment or blank line 1346254721Semaste */ 1347254721Semaste break; 1348254721Semaste case 'g': 1349254721Semaste /* 1350254721Semaste * Set geometry 1351254721Semaste */ 1352254721Semaste status = process_geometry(&command); 1353254721Semaste break; 1354254721Semaste case 'p': 1355254721Semaste status = process_partition(&command); 1356254721Semaste break; 1357254721Semaste case 'a': 1358254721Semaste status = process_active(&command); 1359263363Semaste break; 1360254721Semaste default: 1361263363Semaste status = 0; 1362254721Semaste break; 1363254721Semaste } 1364254721Semaste break; 1365254721Semaste } 1366254721Semaste return (status); 1367254721Semaste} 1368254721Semaste 1369254721Semaste 1370254721Semastestatic int 1371254721Semasteread_config(char *config_file) 1372254721Semaste{ 1373254721Semaste FILE *fp = NULL; 1374254721Semaste int status = 1; 1375254721Semaste char buf[1010]; 1376254721Semaste 1377254721Semaste while (1) { 1378254721Semaste if (strcmp(config_file, "-") != 0) { 1379254721Semaste /* 1380254721Semaste * We're not reading from stdin 1381254721Semaste */ 1382254721Semaste if ((fp = fopen(config_file, "r")) == NULL) { 1383254721Semaste status = 0; 1384254721Semaste break; 1385254721Semaste } 1386254721Semaste } else { 1387254721Semaste fp = stdin; 1388254721Semaste } 1389254721Semaste current_line_number = 0; 1390254721Semaste while (!feof(fp)) { 1391254721Semaste if (fgets(buf, sizeof(buf), fp) == NULL) 1392254721Semaste break; 1393254721Semaste ++current_line_number; 1394254721Semaste status = process_line(buf); 1395254721Semaste if (status == 0) 1396254721Semaste break; 1397254721Semaste } 1398254721Semaste break; 1399254721Semaste } 1400254721Semaste if (fp) { 1401254721Semaste /* 1402254721Semaste * It doesn't matter if we're reading from stdin, as we've reached EOF 1403254721Semaste */ 1404254721Semaste fclose(fp); 1405254721Semaste } 1406254721Semaste return (status); 1407254721Semaste} 1408254721Semaste 1409254721Semaste 1410254721Semastestatic void 1411254721Semastereset_boot(void) 1412254721Semaste{ 1413254721Semaste int i; 1414254721Semaste struct dos_partition *partp; 1415254721Semaste 1416254721Semaste init_boot(); 1417254721Semaste for (i = 0; i < 4; ++i) { 1418254721Semaste partp = &mboot.parts[i]; 1419254721Semaste bzero(partp, sizeof(*partp)); 1420254721Semaste } 1421254721Semaste} 1422254721Semaste 1423254721Semastestatic int 1424254721Semastesanitize_partition(struct dos_partition *partp) 1425254721Semaste{ 1426254721Semaste u_int32_t prev_head_boundary, prev_cyl_boundary; 1427254721Semaste u_int32_t max_end, size, start; 1428254721Semaste 1429254721Semaste start = partp->dp_start; 1430254721Semaste size = partp->dp_size; 1431254721Semaste max_end = start + size; 1432254721Semaste /* Only allow a zero size if the partition is being marked unused. */ 1433254721Semaste if (size == 0) { 1434254721Semaste if (start == 0 && partp->dp_typ == 0) 1435254721Semaste return (1); 1436254721Semaste warnx("ERROR: size of partition is zero"); 1437254721Semaste return (0); 1438254721Semaste } 1439254721Semaste /* Return if no adjustment is necessary. */ 1440254721Semaste if (start % dos_sectors == 0 && (start + size) % dos_sectors == 0) 1441254721Semaste return (1); 1442263367Semaste 1443263367Semaste if (start == 0) { 1444263367Semaste warnx("WARNING: partition overlaps with partition table"); 1445263367Semaste if (ok("Correct this automatically?")) 1446263367Semaste start = dos_sectors; 1447263367Semaste } 1448254721Semaste if (start % dos_sectors != 0) 1449254721Semaste warnx("WARNING: partition does not start on a head boundary"); 1450254721Semaste if ((start +size) % dos_sectors != 0) 1451254721Semaste warnx("WARNING: partition does not end on a cylinder boundary"); 1452254721Semaste warnx("WARNING: this may confuse the BIOS or some operating systems"); 1453254721Semaste if (!ok("Correct this automatically?")) 1454254721Semaste return (1); 1455254721Semaste 1456254721Semaste /* 1457254721Semaste * Adjust start upwards, if necessary, to fall on a head boundary. 1458254721Semaste */ 1459254721Semaste if (start % dos_sectors != 0) { 1460254721Semaste prev_head_boundary = start / dos_sectors * dos_sectors; 1461254721Semaste if (max_end < dos_sectors || 1462254721Semaste prev_head_boundary >= max_end - dos_sectors) { 1463254721Semaste /* 1464254721Semaste * Can't go past end of partition 1465254721Semaste */ 1466254721Semaste warnx( 1467254721Semaste "ERROR: unable to adjust start of partition to fall on a head boundary"); 1468254721Semaste return (0); 1469254721Semaste } 1470254721Semaste start = prev_head_boundary + dos_sectors; 1471254721Semaste } 1472254721Semaste 1473254721Semaste /* 1474254721Semaste * Adjust size downwards, if necessary, to fall on a cylinder 1475254721Semaste * boundary. 1476254721Semaste */ 1477254721Semaste prev_cyl_boundary = ((start + size) / dos_cylsecs) * dos_cylsecs; 1478254721Semaste if (prev_cyl_boundary > start) 1479254721Semaste size = prev_cyl_boundary - start; 1480254721Semaste else { 1481254721Semaste warnx("ERROR: could not adjust partition to start on a head boundary\n\ 1482254721Semaste and end on a cylinder boundary."); 1483254721Semaste return (0); 1484254721Semaste } 1485254721Semaste 1486254721Semaste /* Finally, commit any changes to partp and return. */ 1487254721Semaste if (start != partp->dp_start) { 1488254721Semaste warnx("WARNING: adjusting start offset of partition to %u", 1489254721Semaste (u_int)start); 1490254721Semaste partp->dp_start = start; 1491254721Semaste } 1492254721Semaste if (size != partp->dp_size) { 1493254721Semaste warnx("WARNING: adjusting size of partition to %u", (u_int)size); 1494254721Semaste partp->dp_size = size; 1495254721Semaste } 1496254721Semaste 1497254721Semaste return (1); 1498254721Semaste} 1499254721Semaste 1500254721Semaste/* 1501254721Semaste * Try figuring out the root device's canonical disk name. 1502254721Semaste * The following choices are considered: 1503254721Semaste * /dev/ad0s1a => /dev/ad0 1504254721Semaste * /dev/da0a => /dev/da0 1505254721Semaste * /dev/vinum/root => /dev/vinum/root 1506263367Semaste * A ".eli" part is removed if it exists (see geli(8)). 1507263367Semaste * A ".journal" ending is removed if it exists (see gjournal(8)). 1508263367Semaste */ 1509254721Semastestatic char * 1510254721Semasteget_rootdisk(void) 1511254721Semaste{ 1512254721Semaste struct statfs rootfs; 1513254721Semaste regex_t re; 1514254721Semaste#define NMATCHES 2 1515254721Semaste regmatch_t rm[NMATCHES]; 1516254721Semaste char dev[PATH_MAX], *s; 1517254721Semaste int rv; 1518254721Semaste 1519254721Semaste if (statfs("/", &rootfs) == -1) 1520254721Semaste err(1, "statfs(\"/\")"); 1521254721Semaste 1522254721Semaste if ((rv = regcomp(&re, "^(/dev/[a-z/]+[0-9]*)([sp][0-9]+)?[a-h]?(\\.journal)?$", 1523254721Semaste REG_EXTENDED)) != 0) 1524254721Semaste errx(1, "regcomp() failed (%d)", rv); 1525254721Semaste strlcpy(dev, rootfs.f_mntfromname, sizeof (dev)); 1526254721Semaste if ((s = strstr(dev, ".eli")) != NULL) 1527254721Semaste memmove(s, s+4, strlen(s + 4) + 1); 1528254721Semaste 1529254721Semaste if ((rv = regexec(&re, dev, NMATCHES, rm, 0)) != 0) 1530254721Semaste errx(1, 1531254721Semaste"mounted root fs resource doesn't match expectations (regexec returned %d)", 1532254721Semaste rv); 1533254721Semaste if ((s = malloc(rm[1].rm_eo - rm[1].rm_so + 1)) == NULL) 1534254721Semaste errx(1, "out of memory"); 1535254721Semaste memcpy(s, rootfs.f_mntfromname + rm[1].rm_so, 1536254721Semaste rm[1].rm_eo - rm[1].rm_so); 1537254721Semaste s[rm[1].rm_eo - rm[1].rm_so] = 0; 1538254721Semaste 1539254721Semaste return s; 1540254721Semaste} 1541254721Semaste