From acfc8214d3d60b7e251ae66a59b81cdd1ff7a6dc Mon Sep 17 00:00:00 2001
From: Robert Yang <liezhi.yang@windriver.com>
Date: Fri, 2 Jan 2015 12:26:46 +0800
Subject: [PATCH] libinstaller/syslinuxext: implement syslinux_patch_bootsect()

Move the related from extlinux/main.c to libinstaller/syslinuxext.c, the
syslinux_patch_bootsect() are used by both extlinux/main.c and
linux/syslinux.c.

Upstream-Status: Submitted

Signed-off-by: Robert Yang <liezhi.yang@windriver.com>
Tested-by: Du Dolpher <dolpher.du@intel.com>

Edited to include sysmacros.h

Signed-off-by: Anuj Mittal <anuj.mittal@intel.com>
---
 extlinux/Makefile          |   3 +-
 extlinux/main.c            | 167 +-----------------------------------
 libinstaller/syslinuxext.c | 171 +++++++++++++++++++++++++++++++++++++
 3 files changed, 176 insertions(+), 165 deletions(-)

diff --git a/extlinux/Makefile b/extlinux/Makefile
index 1721ee5..62a4972 100644
--- a/extlinux/Makefile
+++ b/extlinux/Makefile
@@ -32,7 +32,8 @@ SRCS     = main.c \
 	   ../libinstaller/advio.c \
 	   ../libinstaller/bootsect_bin.c \
 	   ../libinstaller/ldlinuxc32_bin.c \
-	   ../libinstaller/ldlinux_bin.c
+	   ../libinstaller/ldlinux_bin.c \
+	   ../libinstaller/syslinuxext.c
 OBJS	 = $(patsubst %.c,%.o,$(notdir $(SRCS)))
 
 .SUFFIXES: .c .o .i .s .S
diff --git a/extlinux/main.c b/extlinux/main.c
index ebff7ea..9add50f 100644
--- a/extlinux/main.c
+++ b/extlinux/main.c
@@ -62,6 +62,7 @@
 #include "setadv.h"
 #include "syslxopt.h" /* unified options */
 #include "mountinfo.h"
+#include "syslinuxext.h"
 
 #ifdef DEBUG
 # define dprintf printf
@@ -69,10 +70,6 @@
 # define dprintf(...) ((void)0)
 #endif
 
-#ifndef EXT2_SUPER_OFFSET
-#define EXT2_SUPER_OFFSET 1024
-#endif
-
 /* Since we have unused 2048 bytes in the primary AG of an XFS partition,
  * we will use the first 0~512 bytes starting from 2048 for the Syslinux
  * boot sector.
@@ -93,136 +90,6 @@ static char subvol[BTRFS_SUBVOL_MAX];
 #define BTRFS_ADV_OFFSET (BTRFS_BOOT_AREA_A_OFFSET + BTRFS_BOOT_AREA_A_SIZE \
 			  - 2*ADV_SIZE)
 
-/*
- * Get the size of a block device
- */
-static uint64_t get_size(int devfd)
-{
-    uint64_t bytes;
-    uint32_t sects;
-    struct stat st;
-
-#ifdef BLKGETSIZE64
-    if (!ioctl(devfd, BLKGETSIZE64, &bytes))
-	return bytes;
-#endif
-    if (!ioctl(devfd, BLKGETSIZE, &sects))
-	return (uint64_t) sects << 9;
-    else if (!fstat(devfd, &st) && st.st_size)
-	return st.st_size;
-    else
-	return 0;
-}
-
-/*
- * Get device geometry and partition offset
- */
-struct geometry_table {
-    uint64_t bytes;
-    struct hd_geometry g;
-};
-
-static int sysfs_get_offset(int devfd, unsigned long *start)
-{
-    struct stat st;
-    char sysfs_name[128];
-    FILE *f;
-    int rv;
-
-    if (fstat(devfd, &st))
-	return -1;
-
-    if ((size_t)snprintf(sysfs_name, sizeof sysfs_name,
-			 "/sys/dev/block/%u:%u/start",
-			 major(st.st_rdev), minor(st.st_rdev))
-	>= sizeof sysfs_name)
-	return -1;
-
-    f = fopen(sysfs_name, "r");
-    if (!f)
-	return -1;
-
-    rv = fscanf(f, "%lu", start);
-    fclose(f);
-
-    return (rv == 1) ? 0 : -1;
-}
-
-/* Standard floppy disk geometries, plus LS-120.  Zipdisk geometry
-   (x/64/32) is the final fallback.  I don't know what LS-240 has
-   as its geometry, since I don't have one and don't know anyone that does,
-   and Google wasn't helpful... */
-static const struct geometry_table standard_geometries[] = {
-    {360 * 1024, {2, 9, 40, 0}},
-    {720 * 1024, {2, 9, 80, 0}},
-    {1200 * 1024, {2, 15, 80, 0}},
-    {1440 * 1024, {2, 18, 80, 0}},
-    {1680 * 1024, {2, 21, 80, 0}},
-    {1722 * 1024, {2, 21, 80, 0}},
-    {2880 * 1024, {2, 36, 80, 0}},
-    {3840 * 1024, {2, 48, 80, 0}},
-    {123264 * 1024, {8, 32, 963, 0}},	/* LS120 */
-    {0, {0, 0, 0, 0}}
-};
-
-int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo)
-{
-    struct floppy_struct fd_str;
-    struct loop_info li;
-    struct loop_info64 li64;
-    const struct geometry_table *gp;
-    int rv = 0;
-
-    memset(geo, 0, sizeof *geo);
-
-    if (!ioctl(devfd, HDIO_GETGEO, geo)) {
-	goto ok;
-    } else if (!ioctl(devfd, FDGETPRM, &fd_str)) {
-	geo->heads = fd_str.head;
-	geo->sectors = fd_str.sect;
-	geo->cylinders = fd_str.track;
-	geo->start = 0;
-	goto ok;
-    }
-
-    /* Didn't work.  Let's see if this is one of the standard geometries */
-    for (gp = standard_geometries; gp->bytes; gp++) {
-	if (gp->bytes == totalbytes) {
-	    memcpy(geo, &gp->g, sizeof *geo);
-	    goto ok;
-	}
-    }
-
-    /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
-       what zipdisks use, so this would help if someone has a USB key that
-       they're booting in USB-ZIP mode. */
-
-    geo->heads = opt.heads ? : 64;
-    geo->sectors = opt.sectors ? : 32;
-    geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
-    geo->start = 0;
-
-    if (!opt.sectors && !opt.heads) {
-	fprintf(stderr,
-		"Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
-		"         (on hard disks, this is usually harmless.)\n",
-		geo->heads, geo->sectors);
-	rv = 1;			/* Suboptimal result */
-    }
-
-ok:
-    /* If this is a loopback device, try to set the start */
-    if (!ioctl(devfd, LOOP_GET_STATUS64, &li64))
-	geo->start = li64.lo_offset >> SECTOR_SHIFT;
-    else if (!ioctl(devfd, LOOP_GET_STATUS, &li))
-	geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT;
-    else if (!sysfs_get_offset(devfd, &geo->start)) {
-	/* OK */
-    }
-
-    return rv;
-}
-
 /*
  * Query the device geometry and put it into the boot sector.
  * Map the file and put the map in the boot sector and file.
@@ -233,11 +100,8 @@ ok:
 static int patch_file_and_bootblock(int fd, const char *dir, int devfd)
 {
     struct stat dirst, xdst;
-    struct hd_geometry geo;
     sector_t *sectp;
-    uint64_t totalbytes, totalsectors;
     int nsect;
-    struct fat_boot_sector *sbs;
     char *dirpath, *subpath, *xdirpath;
     int rv;
 
@@ -281,33 +145,8 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd)
     /* Now subpath should contain the path relative to the fs base */
     dprintf("subpath = %s\n", subpath);
 
-    totalbytes = get_size(devfd);
-    get_geometry(devfd, totalbytes, &geo);
-
-    if (opt.heads)
-	geo.heads = opt.heads;
-    if (opt.sectors)
-	geo.sectors = opt.sectors;
-
-    /* Patch this into a fake FAT superblock.  This isn't because
-       FAT is a good format in any way, it's because it lets the
-       early bootstrap share code with the FAT version. */
-    dprintf("heads = %u, sect = %u\n", geo.heads, geo.sectors);
-
-    sbs = (struct fat_boot_sector *)syslinux_bootsect;
-
-    totalsectors = totalbytes >> SECTOR_SHIFT;
-    if (totalsectors >= 65536) {
-	set_16(&sbs->bsSectors, 0);
-    } else {
-	set_16(&sbs->bsSectors, totalsectors);
-    }
-    set_32(&sbs->bsHugeSectors, totalsectors);
-
-    set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
-    set_16(&sbs->bsSecPerTrack, geo.sectors);
-    set_16(&sbs->bsHeads, geo.heads);
-    set_32(&sbs->bsHiddenSecs, geo.start);
+    /* Patch syslinux_bootsect */
+    syslinux_patch_bootsect(devfd);
 
     /* Construct the boot file map */
 
diff --git a/libinstaller/syslinuxext.c b/libinstaller/syslinuxext.c
index bb54cef..9ae8288 100644
--- a/libinstaller/syslinuxext.c
+++ b/libinstaller/syslinuxext.c
@@ -1,7 +1,178 @@
 #define _GNU_SOURCE
 
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/sysmacros.h>
+#include <getopt.h>
+#include <ext2fs/ext2fs.h>
+
+#include "linuxioctl.h"
+#include "syslinux.h"
+#include "syslxint.h"
+#include "syslxopt.h"
+
+/*
+ * Get the size of a block device
+ */
+static uint64_t get_size(int dev_fd)
+{
+    uint64_t bytes;
+    uint32_t sects;
+    struct stat st;
+
+#ifdef BLKGETSIZE64
+    if (!ioctl(dev_fd, BLKGETSIZE64, &bytes))
+	return bytes;
+#endif
+    if (!ioctl(dev_fd, BLKGETSIZE, &sects))
+	return (uint64_t) sects << 9;
+    else if (!fstat(dev_fd, &st) && st.st_size)
+	return st.st_size;
+    else
+	return 0;
+}
+
+/*
+ * Get device geometry and partition offset
+ */
+static struct geometry_table {
+    uint64_t bytes;
+    struct hd_geometry g;
+};
+
+static int sysfs_get_offset(int dev_fd, unsigned long *start)
+{
+    struct stat st;
+    char sysfs_name[128];
+    FILE *f;
+    int rv;
+
+    if (fstat(dev_fd, &st))
+	return -1;
+
+    if ((size_t)snprintf(sysfs_name, sizeof sysfs_name,
+			 "/sys/dev/block/%u:%u/start",
+			 major(st.st_rdev), minor(st.st_rdev))
+	>= sizeof sysfs_name)
+	return -1;
+
+    f = fopen(sysfs_name, "r");
+    if (!f)
+	return -1;
+
+    rv = fscanf(f, "%lu", start);
+    fclose(f);
+
+    return (rv == 1) ? 0 : -1;
+}
+
+/* Standard floppy disk geometries, plus LS-120.  Zipdisk geometry
+   (x/64/32) is the final fallback.  I don't know what LS-240 has
+   as its geometry, since I don't have one and don't know anyone that does,
+   and Google wasn't helpful... */
+static const struct geometry_table standard_geometries[] = {
+    {360 * 1024, {2, 9, 40, 0}},
+    {720 * 1024, {2, 9, 80, 0}},
+    {1200 * 1024, {2, 15, 80, 0}},
+    {1440 * 1024, {2, 18, 80, 0}},
+    {1680 * 1024, {2, 21, 80, 0}},
+    {1722 * 1024, {2, 21, 80, 0}},
+    {2880 * 1024, {2, 36, 80, 0}},
+    {3840 * 1024, {2, 48, 80, 0}},
+    {123264 * 1024, {8, 32, 963, 0}},	/* LS120 */
+    {0, {0, 0, 0, 0}}
+};
+
+static int get_geometry(int dev_fd, uint64_t totalbytes, struct hd_geometry *geo)
+{
+    struct floppy_struct fd_str;
+    struct loop_info li;
+    struct loop_info64 li64;
+    const struct geometry_table *gp;
+    int rv = 0;
+
+    memset(geo, 0, sizeof *geo);
+
+    if (!ioctl(dev_fd, HDIO_GETGEO, geo)) {
+	goto ok;
+    } else if (!ioctl(dev_fd, FDGETPRM, &fd_str)) {
+	geo->heads = fd_str.head;
+	geo->sectors = fd_str.sect;
+	geo->cylinders = fd_str.track;
+	geo->start = 0;
+	goto ok;
+    }
+
+    /* Didn't work.  Let's see if this is one of the standard geometries */
+    for (gp = standard_geometries; gp->bytes; gp++) {
+	if (gp->bytes == totalbytes) {
+	    memcpy(geo, &gp->g, sizeof *geo);
+	    goto ok;
+	}
+    }
+
+    /* Didn't work either... assign a geometry of 64 heads, 32 sectors; this is
+       what zipdisks use, so this would help if someone has a USB key that
+       they're booting in USB-ZIP mode. */
+
+    geo->heads = opt.heads ? : 64;
+    geo->sectors = opt.sectors ? : 32;
+    geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT);
+    geo->start = 0;
+
+    if (!opt.sectors && !opt.heads) {
+	fprintf(stderr,
+		"Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n"
+		"         (on hard disks, this is usually harmless.)\n",
+		geo->heads, geo->sectors);
+	rv = 1;			/* Suboptimal result */
+    }
+
+ok:
+    /* If this is a loopback device, try to set the start */
+    if (!ioctl(dev_fd, LOOP_GET_STATUS64, &li64))
+	geo->start = li64.lo_offset >> SECTOR_SHIFT;
+    else if (!ioctl(dev_fd, LOOP_GET_STATUS, &li))
+	geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT;
+    else if (!sysfs_get_offset(dev_fd, &geo->start)) {
+	/* OK */
+    }
+
+    return rv;
+}
+
+
 /* Patch syslinux_bootsect */
 void syslinux_patch_bootsect(int dev_fd)
 {
+    uint64_t totalbytes, totalsectors;
+    struct hd_geometry geo;
+    struct fat_boot_sector *sbs;
+
+    totalbytes = get_size(dev_fd);
+    get_geometry(dev_fd, totalbytes, &geo);
+
+    if (opt.heads)
+	geo.heads = opt.heads;
+    if (opt.sectors)
+	geo.sectors = opt.sectors;
+
+    /* Patch this into a fake FAT superblock.  This isn't because
+       FAT is a good format in any way, it's because it lets the
+       early bootstrap share code with the FAT version. */
+    sbs = (struct fat_boot_sector *)syslinux_bootsect;
+
+    totalsectors = totalbytes >> SECTOR_SHIFT;
+    if (totalsectors >= 65536) {
+	set_16(&sbs->bsSectors, 0);
+    } else {
+	set_16(&sbs->bsSectors, totalsectors);
+    }
+    set_32(&sbs->bsHugeSectors, totalsectors);
+
+    set_16(&sbs->bsBytesPerSec, SECTOR_SIZE);
+    set_16(&sbs->bsSecPerTrack, geo.sectors);
+    set_16(&sbs->bsHeads, geo.heads);
+    set_32(&sbs->bsHiddenSecs, geo.start);
 }
 
