1From acfc8214d3d60b7e251ae66a59b81cdd1ff7a6dc Mon Sep 17 00:00:00 2001 2From: Robert Yang <liezhi.yang@windriver.com> 3Date: Fri, 2 Jan 2015 12:26:46 +0800 4Subject: [PATCH] libinstaller/syslinuxext: implement syslinux_patch_bootsect() 5 6Move the related from extlinux/main.c to libinstaller/syslinuxext.c, the 7syslinux_patch_bootsect() are used by both extlinux/main.c and 8linux/syslinux.c. 9 10Upstream-Status: Submitted 11 12Signed-off-by: Robert Yang <liezhi.yang@windriver.com> 13Tested-by: Du Dolpher <dolpher.du@intel.com> 14 15Edited to include sysmacros.h 16 17Signed-off-by: Anuj Mittal <anuj.mittal@intel.com> 18--- 19 extlinux/Makefile | 3 +- 20 extlinux/main.c | 167 +----------------------------------- 21 libinstaller/syslinuxext.c | 171 +++++++++++++++++++++++++++++++++++++ 22 3 files changed, 176 insertions(+), 165 deletions(-) 23 24diff --git a/extlinux/Makefile b/extlinux/Makefile 25index 1721ee5..62a4972 100644 26--- a/extlinux/Makefile 27+++ b/extlinux/Makefile 28@@ -32,7 +32,8 @@ SRCS = main.c \ 29 ../libinstaller/advio.c \ 30 ../libinstaller/bootsect_bin.c \ 31 ../libinstaller/ldlinuxc32_bin.c \ 32- ../libinstaller/ldlinux_bin.c 33+ ../libinstaller/ldlinux_bin.c \ 34+ ../libinstaller/syslinuxext.c 35 OBJS = $(patsubst %.c,%.o,$(notdir $(SRCS))) 36 37 .SUFFIXES: .c .o .i .s .S 38diff --git a/extlinux/main.c b/extlinux/main.c 39index ebff7ea..9add50f 100644 40--- a/extlinux/main.c 41+++ b/extlinux/main.c 42@@ -62,6 +62,7 @@ 43 #include "setadv.h" 44 #include "syslxopt.h" /* unified options */ 45 #include "mountinfo.h" 46+#include "syslinuxext.h" 47 48 #ifdef DEBUG 49 # define dprintf printf 50@@ -69,10 +70,6 @@ 51 # define dprintf(...) ((void)0) 52 #endif 53 54-#ifndef EXT2_SUPER_OFFSET 55-#define EXT2_SUPER_OFFSET 1024 56-#endif 57- 58 /* Since we have unused 2048 bytes in the primary AG of an XFS partition, 59 * we will use the first 0~512 bytes starting from 2048 for the Syslinux 60 * boot sector. 61@@ -93,136 +90,6 @@ static char subvol[BTRFS_SUBVOL_MAX]; 62 #define BTRFS_ADV_OFFSET (BTRFS_BOOT_AREA_A_OFFSET + BTRFS_BOOT_AREA_A_SIZE \ 63 - 2*ADV_SIZE) 64 65-/* 66- * Get the size of a block device 67- */ 68-static uint64_t get_size(int devfd) 69-{ 70- uint64_t bytes; 71- uint32_t sects; 72- struct stat st; 73- 74-#ifdef BLKGETSIZE64 75- if (!ioctl(devfd, BLKGETSIZE64, &bytes)) 76- return bytes; 77-#endif 78- if (!ioctl(devfd, BLKGETSIZE, §s)) 79- return (uint64_t) sects << 9; 80- else if (!fstat(devfd, &st) && st.st_size) 81- return st.st_size; 82- else 83- return 0; 84-} 85- 86-/* 87- * Get device geometry and partition offset 88- */ 89-struct geometry_table { 90- uint64_t bytes; 91- struct hd_geometry g; 92-}; 93- 94-static int sysfs_get_offset(int devfd, unsigned long *start) 95-{ 96- struct stat st; 97- char sysfs_name[128]; 98- FILE *f; 99- int rv; 100- 101- if (fstat(devfd, &st)) 102- return -1; 103- 104- if ((size_t)snprintf(sysfs_name, sizeof sysfs_name, 105- "/sys/dev/block/%u:%u/start", 106- major(st.st_rdev), minor(st.st_rdev)) 107- >= sizeof sysfs_name) 108- return -1; 109- 110- f = fopen(sysfs_name, "r"); 111- if (!f) 112- return -1; 113- 114- rv = fscanf(f, "%lu", start); 115- fclose(f); 116- 117- return (rv == 1) ? 0 : -1; 118-} 119- 120-/* Standard floppy disk geometries, plus LS-120. Zipdisk geometry 121- (x/64/32) is the final fallback. I don't know what LS-240 has 122- as its geometry, since I don't have one and don't know anyone that does, 123- and Google wasn't helpful... */ 124-static const struct geometry_table standard_geometries[] = { 125- {360 * 1024, {2, 9, 40, 0}}, 126- {720 * 1024, {2, 9, 80, 0}}, 127- {1200 * 1024, {2, 15, 80, 0}}, 128- {1440 * 1024, {2, 18, 80, 0}}, 129- {1680 * 1024, {2, 21, 80, 0}}, 130- {1722 * 1024, {2, 21, 80, 0}}, 131- {2880 * 1024, {2, 36, 80, 0}}, 132- {3840 * 1024, {2, 48, 80, 0}}, 133- {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */ 134- {0, {0, 0, 0, 0}} 135-}; 136- 137-int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) 138-{ 139- struct floppy_struct fd_str; 140- struct loop_info li; 141- struct loop_info64 li64; 142- const struct geometry_table *gp; 143- int rv = 0; 144- 145- memset(geo, 0, sizeof *geo); 146- 147- if (!ioctl(devfd, HDIO_GETGEO, geo)) { 148- goto ok; 149- } else if (!ioctl(devfd, FDGETPRM, &fd_str)) { 150- geo->heads = fd_str.head; 151- geo->sectors = fd_str.sect; 152- geo->cylinders = fd_str.track; 153- geo->start = 0; 154- goto ok; 155- } 156- 157- /* Didn't work. Let's see if this is one of the standard geometries */ 158- for (gp = standard_geometries; gp->bytes; gp++) { 159- if (gp->bytes == totalbytes) { 160- memcpy(geo, &gp->g, sizeof *geo); 161- goto ok; 162- } 163- } 164- 165- /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is 166- what zipdisks use, so this would help if someone has a USB key that 167- they're booting in USB-ZIP mode. */ 168- 169- geo->heads = opt.heads ? : 64; 170- geo->sectors = opt.sectors ? : 32; 171- geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT); 172- geo->start = 0; 173- 174- if (!opt.sectors && !opt.heads) { 175- fprintf(stderr, 176- "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n" 177- " (on hard disks, this is usually harmless.)\n", 178- geo->heads, geo->sectors); 179- rv = 1; /* Suboptimal result */ 180- } 181- 182-ok: 183- /* If this is a loopback device, try to set the start */ 184- if (!ioctl(devfd, LOOP_GET_STATUS64, &li64)) 185- geo->start = li64.lo_offset >> SECTOR_SHIFT; 186- else if (!ioctl(devfd, LOOP_GET_STATUS, &li)) 187- geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT; 188- else if (!sysfs_get_offset(devfd, &geo->start)) { 189- /* OK */ 190- } 191- 192- return rv; 193-} 194- 195 /* 196 * Query the device geometry and put it into the boot sector. 197 * Map the file and put the map in the boot sector and file. 198@@ -233,11 +100,8 @@ ok: 199 static int patch_file_and_bootblock(int fd, const char *dir, int devfd) 200 { 201 struct stat dirst, xdst; 202- struct hd_geometry geo; 203 sector_t *sectp; 204- uint64_t totalbytes, totalsectors; 205 int nsect; 206- struct fat_boot_sector *sbs; 207 char *dirpath, *subpath, *xdirpath; 208 int rv; 209 210@@ -281,33 +145,8 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) 211 /* Now subpath should contain the path relative to the fs base */ 212 dprintf("subpath = %s\n", subpath); 213 214- totalbytes = get_size(devfd); 215- get_geometry(devfd, totalbytes, &geo); 216- 217- if (opt.heads) 218- geo.heads = opt.heads; 219- if (opt.sectors) 220- geo.sectors = opt.sectors; 221- 222- /* Patch this into a fake FAT superblock. This isn't because 223- FAT is a good format in any way, it's because it lets the 224- early bootstrap share code with the FAT version. */ 225- dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors); 226- 227- sbs = (struct fat_boot_sector *)syslinux_bootsect; 228- 229- totalsectors = totalbytes >> SECTOR_SHIFT; 230- if (totalsectors >= 65536) { 231- set_16(&sbs->bsSectors, 0); 232- } else { 233- set_16(&sbs->bsSectors, totalsectors); 234- } 235- set_32(&sbs->bsHugeSectors, totalsectors); 236- 237- set_16(&sbs->bsBytesPerSec, SECTOR_SIZE); 238- set_16(&sbs->bsSecPerTrack, geo.sectors); 239- set_16(&sbs->bsHeads, geo.heads); 240- set_32(&sbs->bsHiddenSecs, geo.start); 241+ /* Patch syslinux_bootsect */ 242+ syslinux_patch_bootsect(devfd); 243 244 /* Construct the boot file map */ 245 246diff --git a/libinstaller/syslinuxext.c b/libinstaller/syslinuxext.c 247index bb54cef..9ae8288 100644 248--- a/libinstaller/syslinuxext.c 249+++ b/libinstaller/syslinuxext.c 250@@ -1,7 +1,178 @@ 251 #define _GNU_SOURCE 252 253+#include <sys/stat.h> 254+#include <sys/types.h> 255+#include <sys/sysmacros.h> 256+#include <getopt.h> 257+#include <ext2fs/ext2fs.h> 258+ 259+#include "linuxioctl.h" 260+#include "syslinux.h" 261+#include "syslxint.h" 262+#include "syslxopt.h" 263+ 264+/* 265+ * Get the size of a block device 266+ */ 267+static uint64_t get_size(int dev_fd) 268+{ 269+ uint64_t bytes; 270+ uint32_t sects; 271+ struct stat st; 272+ 273+#ifdef BLKGETSIZE64 274+ if (!ioctl(dev_fd, BLKGETSIZE64, &bytes)) 275+ return bytes; 276+#endif 277+ if (!ioctl(dev_fd, BLKGETSIZE, §s)) 278+ return (uint64_t) sects << 9; 279+ else if (!fstat(dev_fd, &st) && st.st_size) 280+ return st.st_size; 281+ else 282+ return 0; 283+} 284+ 285+/* 286+ * Get device geometry and partition offset 287+ */ 288+static struct geometry_table { 289+ uint64_t bytes; 290+ struct hd_geometry g; 291+}; 292+ 293+static int sysfs_get_offset(int dev_fd, unsigned long *start) 294+{ 295+ struct stat st; 296+ char sysfs_name[128]; 297+ FILE *f; 298+ int rv; 299+ 300+ if (fstat(dev_fd, &st)) 301+ return -1; 302+ 303+ if ((size_t)snprintf(sysfs_name, sizeof sysfs_name, 304+ "/sys/dev/block/%u:%u/start", 305+ major(st.st_rdev), minor(st.st_rdev)) 306+ >= sizeof sysfs_name) 307+ return -1; 308+ 309+ f = fopen(sysfs_name, "r"); 310+ if (!f) 311+ return -1; 312+ 313+ rv = fscanf(f, "%lu", start); 314+ fclose(f); 315+ 316+ return (rv == 1) ? 0 : -1; 317+} 318+ 319+/* Standard floppy disk geometries, plus LS-120. Zipdisk geometry 320+ (x/64/32) is the final fallback. I don't know what LS-240 has 321+ as its geometry, since I don't have one and don't know anyone that does, 322+ and Google wasn't helpful... */ 323+static const struct geometry_table standard_geometries[] = { 324+ {360 * 1024, {2, 9, 40, 0}}, 325+ {720 * 1024, {2, 9, 80, 0}}, 326+ {1200 * 1024, {2, 15, 80, 0}}, 327+ {1440 * 1024, {2, 18, 80, 0}}, 328+ {1680 * 1024, {2, 21, 80, 0}}, 329+ {1722 * 1024, {2, 21, 80, 0}}, 330+ {2880 * 1024, {2, 36, 80, 0}}, 331+ {3840 * 1024, {2, 48, 80, 0}}, 332+ {123264 * 1024, {8, 32, 963, 0}}, /* LS120 */ 333+ {0, {0, 0, 0, 0}} 334+}; 335+ 336+static int get_geometry(int dev_fd, uint64_t totalbytes, struct hd_geometry *geo) 337+{ 338+ struct floppy_struct fd_str; 339+ struct loop_info li; 340+ struct loop_info64 li64; 341+ const struct geometry_table *gp; 342+ int rv = 0; 343+ 344+ memset(geo, 0, sizeof *geo); 345+ 346+ if (!ioctl(dev_fd, HDIO_GETGEO, geo)) { 347+ goto ok; 348+ } else if (!ioctl(dev_fd, FDGETPRM, &fd_str)) { 349+ geo->heads = fd_str.head; 350+ geo->sectors = fd_str.sect; 351+ geo->cylinders = fd_str.track; 352+ geo->start = 0; 353+ goto ok; 354+ } 355+ 356+ /* Didn't work. Let's see if this is one of the standard geometries */ 357+ for (gp = standard_geometries; gp->bytes; gp++) { 358+ if (gp->bytes == totalbytes) { 359+ memcpy(geo, &gp->g, sizeof *geo); 360+ goto ok; 361+ } 362+ } 363+ 364+ /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is 365+ what zipdisks use, so this would help if someone has a USB key that 366+ they're booting in USB-ZIP mode. */ 367+ 368+ geo->heads = opt.heads ? : 64; 369+ geo->sectors = opt.sectors ? : 32; 370+ geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT); 371+ geo->start = 0; 372+ 373+ if (!opt.sectors && !opt.heads) { 374+ fprintf(stderr, 375+ "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n" 376+ " (on hard disks, this is usually harmless.)\n", 377+ geo->heads, geo->sectors); 378+ rv = 1; /* Suboptimal result */ 379+ } 380+ 381+ok: 382+ /* If this is a loopback device, try to set the start */ 383+ if (!ioctl(dev_fd, LOOP_GET_STATUS64, &li64)) 384+ geo->start = li64.lo_offset >> SECTOR_SHIFT; 385+ else if (!ioctl(dev_fd, LOOP_GET_STATUS, &li)) 386+ geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT; 387+ else if (!sysfs_get_offset(dev_fd, &geo->start)) { 388+ /* OK */ 389+ } 390+ 391+ return rv; 392+} 393+ 394+ 395 /* Patch syslinux_bootsect */ 396 void syslinux_patch_bootsect(int dev_fd) 397 { 398+ uint64_t totalbytes, totalsectors; 399+ struct hd_geometry geo; 400+ struct fat_boot_sector *sbs; 401+ 402+ totalbytes = get_size(dev_fd); 403+ get_geometry(dev_fd, totalbytes, &geo); 404+ 405+ if (opt.heads) 406+ geo.heads = opt.heads; 407+ if (opt.sectors) 408+ geo.sectors = opt.sectors; 409+ 410+ /* Patch this into a fake FAT superblock. This isn't because 411+ FAT is a good format in any way, it's because it lets the 412+ early bootstrap share code with the FAT version. */ 413+ sbs = (struct fat_boot_sector *)syslinux_bootsect; 414+ 415+ totalsectors = totalbytes >> SECTOR_SHIFT; 416+ if (totalsectors >= 65536) { 417+ set_16(&sbs->bsSectors, 0); 418+ } else { 419+ set_16(&sbs->bsSectors, totalsectors); 420+ } 421+ set_32(&sbs->bsHugeSectors, totalsectors); 422+ 423+ set_16(&sbs->bsBytesPerSec, SECTOR_SIZE); 424+ set_16(&sbs->bsSecPerTrack, geo.sectors); 425+ set_16(&sbs->bsHeads, geo.heads); 426+ set_32(&sbs->bsHiddenSecs, geo.start); 427 } 428 429