summaryrefslogtreecommitdiff
path: root/libinstaller
diff options
context:
space:
mode:
authorFeng Tang <feng.tang@intel.com>2010-07-12 15:45:05 +0800
committerFeng Tang <feng.tang@intel.com>2010-07-20 11:10:04 +0800
commitfe87f81f3ba8dc1828965fe2cd113dbdfd2248bf (patch)
tree3f4469512474b5297776a4d4f869892dfe1da7e5 /libinstaller
parent3b04c7baad33e5ac7750ab2ce3c207492faa7ea8 (diff)
downloadsyslinux-fe87f81f3ba8dc1828965fe2cd113dbdfd2248bf.tar.gz
elflink: merge these files
com32/include/sys/times.h com32/include/syslinux/config.h com32/include/syslinux/pmapi.h com32/include/unistd.h com32/include/zconf.h com32/include/zlib.h dos/Makefile dos/errno.h dos/string.h dos/syslinux.c dosutil/eltorito.asm dosutil/mdiskchk.c dosutil/mdiskchk.com extlinux/Makefile extlinux/fat.h extlinux/main.c libfat/libfat.h libfat/open.c libinstaller/Makefile libinstaller/setadv.c libinstaller/syslinux.h libinstaller/syslxcom.c libinstaller/syslxcom.h libinstaller/syslxint.h libinstaller/syslxmod.c libinstaller/syslxopt.c libinstaller/syslxopt.h linux/Makefile linux/syslinux.c
Diffstat (limited to 'libinstaller')
-rw-r--r--libinstaller/Makefile7
-rw-r--r--libinstaller/setadv.c131
-rw-r--r--libinstaller/syslinux.h11
-rw-r--r--libinstaller/syslxcom.c120
-rw-r--r--libinstaller/syslxcom.h4
-rw-r--r--libinstaller/syslxint.h142
-rw-r--r--libinstaller/syslxmod.c327
-rw-r--r--libinstaller/syslxopt.c104
-rw-r--r--libinstaller/syslxopt.h12
9 files changed, 435 insertions, 423 deletions
diff --git a/libinstaller/Makefile b/libinstaller/Makefile
index 82c1990e..2beb9315 100644
--- a/libinstaller/Makefile
+++ b/libinstaller/Makefile
@@ -1,6 +1,5 @@
# _bin.c files required by both BTARGET and ITARGET installers
BINFILES = bootsect_bin.c ldlinux_bin.c \
- extlinux_bss_bin.c extlinux_sys_bin.c \
mbr_bin.c gptmbr_bin.c
PERL = perl
@@ -13,12 +12,6 @@ bootsect_bin.c: ../core/ldlinux.bss bin2c.pl
ldlinux_bin.c: ../core/ldlinux.sys bin2c.pl
$(PERL) bin2c.pl syslinux_ldlinux 512 < $< > $@
-extlinux_bss_bin.c: ../core/extlinux.bss bin2c.pl
- $(PERL) bin2c.pl extlinux_bootsect < $< > $@
-
-extlinux_sys_bin.c: ../core/extlinux.sys bin2c.pl
- $(PERL) bin2c.pl extlinux_image 512 < $< > $@
-
mbr_bin.c: ../mbr/mbr.bin bin2c.pl
$(PERL) bin2c.pl syslinux_mbr < $< > $@
diff --git a/libinstaller/setadv.c b/libinstaller/setadv.c
index 682b883e..9cf6f188 100644
--- a/libinstaller/setadv.c
+++ b/libinstaller/setadv.c
@@ -1,6 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
+ * Copyright 2010 Intel Corporation; author: H. Peter Anvin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,13 +27,7 @@
#include <stddef.h>
#include <stdint.h>
#include <string.h>
-#include <getopt.h>
-#include <unistd.h>
#include <errno.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
#include "syslxint.h"
#include "syslxcom.h"
@@ -170,127 +165,3 @@ int syslinux_validate_adv(unsigned char *advbuf)
return -1;
}
}
-
-/*
- * Read the ADV from an existing instance, or initialize if invalid.
- * Returns -1 on fatal errors, 0 if ADV is okay, and 1 if no valid
- * ADV was found.
- */
-int read_adv(const char *path, const char *cfg)
-{
- char *file;
- int fd = -1;
- struct stat st;
- int err = 0;
-
- err = asprintf(&file, "%s%s%s",
- path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/", cfg);
-
- if (!file) {
- perror(program);
- return -1;
- }
-
- fd = open(file, O_RDONLY);
- if (fd < 0) {
- if (errno != ENOENT) {
- err = -1;
- } else {
- syslinux_reset_adv(syslinux_adv);
- }
- } else if (fstat(fd, &st)) {
- err = -1;
- } else if (st.st_size < 2 * ADV_SIZE) {
- /* Too small to be useful */
- syslinux_reset_adv(syslinux_adv);
- err = 0; /* Nothing to read... */
- } else if (xpread(fd, syslinux_adv, 2 * ADV_SIZE,
- st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
- err = -1;
- } else {
- /* We got it... maybe? */
- err = syslinux_validate_adv(syslinux_adv) ? 1 : 0;
- }
-
- if (err < 0)
- perror(file);
-
- if (fd >= 0)
- close(fd);
- if (file)
- free(file);
-
- return err;
-}
-
-/*
- * Update the ADV in an existing installation.
- */
-int write_adv(const char *path, const char *cfg)
-{
- unsigned char advtmp[2 * ADV_SIZE];
- char *file;
- int fd = -1;
- struct stat st, xst;
- int err = 0;
-
- err = asprintf(&file, "%s%s%s",
- path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/", cfg);
-
- if (!file) {
- perror(program);
- return -1;
- }
-
- fd = open(file, O_RDONLY);
- if (fd < 0) {
- err = -1;
- } else if (fstat(fd, &st)) {
- err = -1;
- } else if (st.st_size < 2 * ADV_SIZE) {
- /* Too small to be useful */
- err = -2;
- } else if (xpread(fd, advtmp, 2 * ADV_SIZE,
- st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
- err = -1;
- } else {
- /* We got it... maybe? */
- err = syslinux_validate_adv(advtmp) ? -2 : 0;
- if (!err) {
- /* Got a good one, write our own ADV here */
- clear_attributes(fd);
-
- /* Need to re-open read-write */
- close(fd);
- fd = open(file, O_RDWR | O_SYNC);
- if (fd < 0) {
- err = -1;
- } else if (fstat(fd, &xst) || xst.st_ino != st.st_ino ||
- xst.st_dev != st.st_dev || xst.st_size != st.st_size) {
- fprintf(stderr, "%s: race condition on write\n", file);
- err = -2;
- }
- /* Write our own version ... */
- if (xpwrite(fd, syslinux_adv, 2 * ADV_SIZE,
- st.st_size - 2 * ADV_SIZE) != 2 * ADV_SIZE) {
- err = -1;
- }
-
- sync();
- set_attributes(fd);
- }
- }
-
- if (err == -2)
- fprintf(stderr, "%s: cannot write auxilliary data (need --update)?\n",
- file);
- else if (err == -1)
- perror(file);
-
- if (fd >= 0)
- close(fd);
- if (file)
- free(file);
-
- return err;
-}
diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h
index 8d0212c8..710d30e5 100644
--- a/libinstaller/syslinux.h
+++ b/libinstaller/syslinux.h
@@ -26,6 +26,11 @@ extern unsigned char syslinux_ldlinux[];
extern const unsigned int syslinux_ldlinux_len;
extern const int syslinux_ldlinux_mtime;
+#define boot_sector syslinux_bootsect
+#define boot_sector_len syslinux_bootsect_len
+#define boot_image syslinux_ldlinux
+#define boot_image_len syslinux_ldlinux_len
+
extern unsigned char syslinux_mbr[];
extern const unsigned int syslinux_mbr_len;
extern const int syslinux_mbr_mtime;
@@ -41,7 +46,9 @@ void syslinux_make_bootsect(void *);
const char *syslinux_check_bootsect(const void *bs);
/* This patches the boot sector and ldlinux.sys based on a sector map */
-int syslinux_patch(const uint32_t * sectors, int nsectors,
- int stupid, int raid_mode);
+typedef uint64_t sector_t;
+int syslinux_patch(const sector_t *sectors, int nsectors,
+ int stupid, int raid_mode,
+ const char *subdir, const char *subvol);
#endif
diff --git a/libinstaller/syslxcom.c b/libinstaller/syslxcom.c
index 825419b4..b176f6d7 100644
--- a/libinstaller/syslxcom.c
+++ b/libinstaller/syslxcom.c
@@ -26,13 +26,11 @@
#include <getopt.h>
#include <unistd.h>
#include <errno.h>
-#include <sys/ioctl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/mount.h>
#include <sys/vfs.h>
-#include <linux/fs.h> /* FIGETBSZ, FIBMAP */
-#include <linux/msdos_fs.h> /* FAT_IOCTL_SET_ATTRIBUTES */
+#include "linuxioctl.h"
#include "syslxcom.h"
const char *program;
@@ -46,15 +44,6 @@ int fs_type;
#endif
#define SECTOR_SHIFT 9
-#define EXT2_IMMUTABLE_FL 0x00000010 /* Immutable file */
-
-/*
- * ioctl commands
- */
-#define EXT2_IOC_GETFLAGS _IOR('f', 1, long)
-#define EXT2_IOC_SETFLAGS _IOW('f', 2, long)
-#define EXT2_IOC_GETVERSION _IOR('v', 1, long)
-#define EXT2_IOC_SETVERSION _IOW('v', 2, long)
static void die(const char *msg)
{
@@ -180,13 +169,86 @@ void set_attributes(int fd)
}
}
-/*
- * Produce file map
- */
-int sectmap(int fd, uint32_t * sectors, int nsectors)
+/* New FIEMAP based mapping */
+static int sectmap_fie(int fd, sector_t *sectors, int nsectors)
+{
+ struct fiemap *fm;
+ struct fiemap_extent *fe;
+ unsigned int i, nsec;
+ sector_t sec, *secp, *esec;
+ struct stat st;
+ uint64_t maplen;
+
+ if (fstat(fd, &st))
+ return -1;
+
+ fm = alloca(sizeof(struct fiemap)
+ + nsectors * sizeof(struct fiemap_extent));
+
+ memset(fm, 0, sizeof *fm);
+
+ maplen = (uint64_t)nsectors << SECTOR_SHIFT;
+ if (maplen > (uint64_t)st.st_size)
+ maplen = st.st_size;
+
+ fm->fm_start = 0;
+ fm->fm_length = maplen;
+ fm->fm_flags = FIEMAP_FLAG_SYNC;
+ fm->fm_extent_count = nsectors;
+
+ if (ioctl(fd, FS_IOC_FIEMAP, fm))
+ return -1;
+
+ memset(sectors, 0, nsectors * sizeof *sectors);
+ esec = sectors + nsectors;
+
+ fe = fm->fm_extents;
+
+ if (fm->fm_mapped_extents < 1 ||
+ !(fe[fm->fm_mapped_extents-1].fe_flags & FIEMAP_EXTENT_LAST))
+ return -1;
+
+ for (i = 0; i < fm->fm_mapped_extents; i++) {
+ if (fe->fe_flags & FIEMAP_EXTENT_LAST) {
+ /* If this is the *final* extent, pad the length */
+ fe->fe_length = (fe->fe_length + SECTOR_SIZE - 1)
+ & ~(SECTOR_SIZE - 1);
+ }
+
+ if ((fe->fe_logical | fe->fe_physical| fe->fe_length) &
+ (SECTOR_SIZE - 1))
+ return -1;
+
+ if (fe->fe_flags & (FIEMAP_EXTENT_UNKNOWN|
+ FIEMAP_EXTENT_DELALLOC|
+ FIEMAP_EXTENT_ENCODED|
+ FIEMAP_EXTENT_DATA_ENCRYPTED|
+ FIEMAP_EXTENT_UNWRITTEN))
+ return -1;
+
+ secp = sectors + (fe->fe_logical >> SECTOR_SHIFT);
+ sec = fe->fe_physical >> SECTOR_SHIFT;
+ nsec = fe->fe_length >> SECTOR_SHIFT;
+
+ while (nsec--) {
+ if (secp >= esec)
+ break;
+ *secp++ = sec++;
+ }
+
+ fe++;
+ }
+
+ return 0;
+}
+
+/* Legacy FIBMAP based mapping */
+static int sectmap_fib(int fd, sector_t *sectors, int nsectors)
{
- unsigned int blksize, blk, nblk;
+ unsigned int blk, nblk;
unsigned int i;
+ unsigned int blksize;
+ sector_t sec;
/* Get block size */
if (ioctl(fd, FIGETBSZ, &blksize))
@@ -197,22 +259,28 @@ int sectmap(int fd, uint32_t * sectors, int nsectors)
nblk = 0;
while (nsectors) {
-
blk = nblk++;
- dprintf("querying block %u\n", blk);
if (ioctl(fd, FIBMAP, &blk))
return -1;
- blk *= blksize;
+ sec = (sector_t)blk * blksize;
for (i = 0; i < blksize; i++) {
- if (!nsectors)
- return 0;
-
- dprintf("Sector: %10u\n", blk);
- *sectors++ = blk++;
- nsectors--;
+ *sectors++ = sec++;
+ if (! --nsectors)
+ break;
}
}
return 0;
}
+
+/*
+ * Produce file map
+ */
+int sectmap(int fd, sector_t *sectors, int nsectors)
+{
+ if (!sectmap_fie(fd, sectors, nsectors))
+ return 0;
+
+ return sectmap_fib(fd, sectors, nsectors);
+}
diff --git a/libinstaller/syslxcom.h b/libinstaller/syslxcom.h
index ba4f1d00..39ca09d3 100644
--- a/libinstaller/syslxcom.h
+++ b/libinstaller/syslxcom.h
@@ -1,6 +1,8 @@
#ifndef _H_SYSLXCOM_
#define _H_SYSLXCOM_
+#include "syslinux.h"
+
/* Global fs_type for handling fat, ext2/3/4 and btrfs */
enum filesystem {
NONE,
@@ -15,6 +17,6 @@ ssize_t xpread(int fd, void *buf, size_t count, off_t offset);
ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset);
void clear_attributes(int fd);
void set_attributes(int fd);
-int sectmap(int fd, uint32_t * sectors, int nsectors);
+int sectmap(int fd, sector_t *sectors, int nsectors);
#endif
diff --git a/libinstaller/syslxint.h b/libinstaller/syslxint.h
index 2276bfed..f16c2e5c 100644
--- a/libinstaller/syslxint.h
+++ b/libinstaller/syslxint.h
@@ -15,6 +15,12 @@
#include "syslinux.h"
+#if defined(__386__) || defined(__i386__) || defined(__x86_64__)
+# define X86_MEM 1 /* Littleendian and unaligned safe */
+#else
+# define X86_MEM 0
+#endif
+
/*
* Access functions for littleendian numbers, possibly misaligned.
*/
@@ -25,37 +31,47 @@ static inline uint8_t get_8(const uint8_t * p)
static inline uint16_t get_16(const uint16_t * p)
{
-#if defined(__i386__) || defined(__x86_64__)
+#if X86_MEM
/* Littleendian and unaligned-capable */
return *p;
#else
const uint8_t *pp = (const uint8_t *)p;
- return (uint16_t) pp[0] + ((uint16_t) pp[1] << 8);
+ return pp[0] + ((uint16_t)pp[1] << 8);
#endif
}
static inline uint32_t get_32(const uint32_t * p)
{
-#if defined(__i386__) || defined(__x86_64__)
+#if X86_MEM
/* Littleendian and unaligned-capable */
return *p;
#else
- const uint8_t *pp = (const uint8_t *)p;
- return (uint32_t) pp[0] + ((uint32_t) pp[1] << 8) +
- ((uint32_t) pp[2] << 16) + ((uint32_t) pp[3] << 24);
+ const uint16_t *pp = (const uint16_t *)p;
+ return get_16(pp[0]) + (uint32_t)get_16(pp[1]);
+#endif
+}
+
+static inline uint64_t get_64(const uint64_t * p)
+{
+#if X86_MEM
+ /* Littleendian and unaligned-capable */
+ return *p;
+#else
+ const uint32_t *pp = (const uint32_t *)p;
+ return get_32(pp[0]) + (uint64_t)get_32(pp[1]);
#endif
}
-static inline void set_8(uint8_t * p, uint8_t v)
+static inline void set_8(uint8_t *p, uint8_t v)
{
*p = v;
}
-static inline void set_16(uint16_t * p, uint16_t v)
+static inline void set_16(uint16_t *p, uint16_t v)
{
-#if defined(__i386__) || defined(__x86_64__)
+#if X86_MEM
/* Littleendian and unaligned-capable */
- *(uint16_t *) p = v;
+ *p = v;
#else
uint8_t *pp = (uint8_t *) p;
pp[0] = (v & 0xff);
@@ -63,11 +79,11 @@ static inline void set_16(uint16_t * p, uint16_t v)
#endif
}
-static inline void set_32(uint32_t * p, uint32_t v)
+static inline void set_32(uint32_t *p, uint32_t v)
{
-#if defined(__i386__) || defined(__x86_64__)
+#if X86_MEM
/* Littleendian and unaligned-capable */
- *(uint32_t *) p = v;
+ *p = v;
#else
uint8_t *pp = (uint8_t *) p;
pp[0] = (v & 0xff);
@@ -77,6 +93,68 @@ static inline void set_32(uint32_t * p, uint32_t v)
#endif
}
+static inline void set_64(uint64_t *p, uint64_t v)
+{
+#if X86_MEM
+ /* Littleendian and unaligned-capable */
+ *p = v;
+#else
+ uint32_t *pp = (uint32_t *) p;
+ set_32(pp[0], v);
+ set_32(pp[1], v >> 32);
+#endif
+}
+
+/*
+ * Special handling for the MS-DOS derivative: syslinux_ldlinux
+ * is a "far" object...
+ */
+#ifdef __MSDOS__
+
+extern uint16_t ldlinux_seg; /* Defined in dos/syslinux.c */
+
+static inline __attribute__ ((const))
+uint16_t ds(void)
+{
+ uint16_t v;
+ asm("movw %%ds,%0":"=rm"(v));
+ return v;
+}
+
+static inline void *set_fs(const void *p)
+{
+ uint16_t seg;
+
+ seg = ldlinux_seg + ((size_t) p >> 4);
+ asm volatile ("movw %0,%%fs"::"rm" (seg));
+ return (void *)((size_t) p & 0xf);
+}
+
+uint8_t get_8_sl(const uint8_t * p);
+uint16_t get_16_sl(const uint16_t * p);
+uint32_t get_32_sl(const uint32_t * p);
+uint64_t get_64_sl(const uint64_t * p);
+void set_8_sl(uint8_t * p, uint8_t v);
+void set_16_sl(uint16_t * p, uint16_t v);
+void set_32_sl(uint32_t * p, uint32_t v);
+void set_64_sl(uint64_t * p, uint64_t v);
+void memcpy_to_sl(void *dst, const void *src, size_t len);
+
+#else
+
+/* Sane system ... */
+#define get_8_sl(x) get_8(x)
+#define get_16_sl(x) get_16(x)
+#define get_32_sl(x) get_32(x)
+#define get_64_sl(x) get_64(x)
+#define set_8_sl(x,y) set_8(x,y)
+#define set_16_sl(x,y) set_16(x,y)
+#define set_32_sl(x,y) set_32(x,y)
+#define set_64_sl(x,y) set_64(x,y)
+#define memcpy_to_sl(d,s,l) memcpy(d,s,l)
+
+#endif
+
#define LDLINUX_MAGIC 0x3eb202fe
/* Patch area for disk-based installers */
@@ -87,15 +165,31 @@ struct patch_area {
uint16_t adv_sectors;
uint32_t dwords;
uint32_t checksum;
- uint16_t diroffset;
- uint16_t dirlen;
- uint16_t subvoloffset;
- uint16_t subvollen;
- uint16_t secptroffset;
- uint16_t secptrcnt;
+ uint16_t maxtransfer;
+ uint16_t epaoffset; /* Pointer to the extended patch area */
};
- /* FAT bootsector format, also used by other disk-based derivatives */
+struct ext_patch_area {
+ uint16_t advptroffset; /* ADV pointers */
+ uint16_t diroffset; /* Current directory field */
+ uint16_t dirlen; /* Length of current directory field */
+ uint16_t subvoloffset; /* Subvolume field */
+ uint16_t subvollen; /* Length of subvolume field */
+ uint16_t secptroffset; /* Sector extent pointers */
+ uint16_t secptrcnt; /* Number of sector extent pointers */
+
+ uint16_t sect1ptr0; /* Boot sector offset of sector 1 ptr LSW */
+ uint16_t sect1ptr1; /* Boot sector offset of sector 1 ptr MSW */
+ uint16_t raidpatch; /* Boot sector RAID mode patch pointer */
+};
+
+/* Sector extent */
+struct syslinux_extent {
+ uint64_t lba;
+ uint16_t len;
+} __attribute__((packed));
+
+/* FAT bootsector format, also used by other disk-based derivatives */
struct boot_sector {
uint8_t bsJump[3];
char bsOemName[8];
@@ -120,7 +214,7 @@ struct boot_sector {
uint32_t VolumeID;
char VolumeLabel[11];
char FileSysType[8];
- uint8_t Code[442];
+ uint8_t Code[448];
} __attribute__ ((packed)) bs16;
struct {
uint32_t FATSz32;
@@ -136,17 +230,15 @@ struct boot_sector {
uint32_t VolumeID;
char VolumeLabel[11];
char FileSysType[8];
- uint8_t Code[414];
+ uint8_t Code[420];
} __attribute__ ((packed)) bs32;
} __attribute__ ((packed));
- uint32_t NextSector; /* Pointer to the first unused sector */
- uint16_t MaxTransfer; /* Max sectors per transfer */
uint16_t bsSignature;
} __attribute__ ((packed));
#define bsHead bsJump
-#define bsHeadLen offsetof(struct boot_sector, bsOemName)
+#define bsHeadLen offsetof(struct boot_sector, bsBytesPerSec)
#define bsCode bs32.Code /* The common safe choice */
#define bsCodeLen (offsetof(struct boot_sector, bsSignature) - \
offsetof(struct boot_sector, bsCode))
diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c
index 9ab139c6..a68f19fb 100644
--- a/libinstaller/syslxmod.c
+++ b/libinstaller/syslxmod.c
@@ -1,7 +1,7 @@
/* ----------------------------------------------------------------------- *
*
* Copyright 1998-2008 H. Peter Anvin - All Rights Reserved
- * Copyright 2009 Intel Corporation; author H. Peter Anvin
+ * Copyright 2009-2010 Intel Corporation; author H. Peter Anvin
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,200 +21,67 @@
#include <inttypes.h>
#include <string.h>
#include <stddef.h>
+#include <stdlib.h>
#include "syslinux.h"
#include "syslxint.h"
-void syslinux_make_bootsect(void *bs)
-{
- struct boot_sector *bootsect = bs;
- const struct boot_sector *sbs =
- (const struct boot_sector *)syslinux_bootsect;
-
- memcpy(&bootsect->bsHead, &sbs->bsHead, bsHeadLen);
- memcpy(&bootsect->bsCode, &sbs->bsCode, bsCodeLen);
-}
/*
- * Check to see that what we got was indeed an MS-DOS boot sector/superblock;
- * Return NULL if OK and otherwise an error message;
+ * Generate sector extents
*/
-const char *syslinux_check_bootsect(const void *bs)
-{
- int veryold;
- int sectorsize;
- long long sectors, fatsectors, dsectors;
- long long clusters;
- int rootdirents, clustersize;
- const struct boot_sector *sectbuf = bs;
-
- veryold = 0;
-
- /* Must be 0xF0 or 0xF8..0xFF */
- if (get_8(&sectbuf->bsMedia) != 0xF0 && get_8(&sectbuf->bsMedia) < 0xF8)
- return "invalid media signature (not a FAT filesystem?)";
-
- sectorsize = get_16(&sectbuf->bsBytesPerSec);
- if (sectorsize == SECTOR_SIZE)
- ; /* ok */
- else if (sectorsize >= 512 && sectorsize <= 4096 &&
- (sectorsize & (sectorsize - 1)) == 0)
- return "unsupported sectors size";
- else
- return "impossible sector size";
-
- clustersize = get_8(&sectbuf->bsSecPerClust);
- if (clustersize == 0 || (clustersize & (clustersize - 1)))
- return "impossible cluster size";
-
- sectors = get_16(&sectbuf->bsSectors);
- sectors = sectors ? sectors : get_32(&sectbuf->bsHugeSectors);
-
- dsectors = sectors - get_16(&sectbuf->bsResSectors);
-
- fatsectors = get_16(&sectbuf->bsFATsecs);
- fatsectors = fatsectors ? fatsectors : get_32(&sectbuf->bs32.FATSz32);
- fatsectors *= get_8(&sectbuf->bsFATs);
- dsectors -= fatsectors;
-
- rootdirents = get_16(&sectbuf->bsRootDirEnts);
- dsectors -= (rootdirents + sectorsize / 32 - 1) / sectorsize;
-
- if (dsectors < 0)
- return "negative number of data sectors";
-
- if (fatsectors == 0)
- return "zero FAT sectors";
-
- clusters = dsectors / clustersize;
-
- if (clusters < 0xFFF5) {
- /* FAT12 or FAT16 */
-
- if (!get_16(&sectbuf->bsFATsecs))
- return "zero FAT sectors (FAT12/16)";
-
- if (get_8(&sectbuf->bs16.BootSignature) == 0x29) {
- if (!memcmp(&sectbuf->bs16.FileSysType, "FAT12 ", 8)) {
- if (clusters >= 0xFF5)
- return "more than 4084 clusters but claims FAT12";
- } else if (!memcmp(&sectbuf->bs16.FileSysType, "FAT16 ", 8)) {
- if (clusters < 0xFF5)
- return "less than 4084 clusters but claims FAT16";
- } else if (!memcmp(&sectbuf->bs16.FileSysType, "FAT32 ", 8)) {
- return "less than 65525 clusters but claims FAT32";
- } else if (memcmp(&sectbuf->bs16.FileSysType, "FAT ", 8)) {
- static char fserr[] =
- "filesystem type \"????????\" not supported";
- memcpy(fserr + 17, &sectbuf->bs16.FileSysType, 8);
- return fserr;
- }
- }
- } else if (clusters < 0x0FFFFFF5) {
- /*
- * FAT32...
- *
- * Moving the FileSysType and BootSignature was a lovely stroke
- * of M$ idiocy...
- */
- if (get_8(&sectbuf->bs32.BootSignature) != 0x29 ||
- memcmp(&sectbuf->bs32.FileSysType, "FAT32 ", 8))
- return "missing FAT32 signature";
- } else {
- return "impossibly large number of clusters";
- }
-
- return NULL;
-}
-
-/*
- * Special handling for the MS-DOS derivative: syslinux_ldlinux
- * is a "far" object...
- */
-#ifdef __MSDOS__
-
-#define __noinline __attribute__((noinline))
-
-extern uint16_t ldlinux_seg; /* Defined in dos/syslinux.c */
-
-static inline __attribute__ ((const))
-uint16_t ds(void)
-{
- uint16_t v;
-asm("movw %%ds,%0":"=rm"(v));
- return v;
-}
-
-static inline void *set_fs(const void *p)
+static void generate_extents(struct syslinux_extent *ex, int nptrs,
+ const sector_t *sectp, int nsect)
{
- uint16_t seg;
-
- seg = ldlinux_seg + ((size_t) p >> 4);
- asm volatile ("movw %0,%%fs"::"rm" (seg));
- return (void *)((size_t) p & 0xf);
-}
+ uint32_t addr = 0x7c00 + 2*SECTOR_SIZE;
+ uint32_t base;
+ sector_t sect, lba;
+ unsigned int len;
-#if 0 /* unused */
-static __noinline uint8_t get_8_sl(const uint8_t * p)
-{
- uint8_t v;
+ len = lba = base = 0;
- p = set_fs(p);
- asm volatile ("movb %%fs:%1,%0":"=q" (v):"m"(*p));
- return v;
-}
-#endif
+ memset(ex, 0, nptrs * sizeof *ex);
-static __noinline uint16_t get_16_sl(const uint16_t * p)
-{
- uint16_t v;
+ while (nsect) {
+ sect = *sectp++;
- p = set_fs(p);
- asm volatile ("movw %%fs:%1,%0":"=r" (v):"m"(*p));
- return v;
-}
+ if (len && sect == lba + len &&
+ ((addr ^ (base + len * SECTOR_SIZE)) & 0xffff0000) == 0) {
+ /* We can add to the current extent */
+ len++;
+ goto next;
+ }
-static __noinline uint32_t get_32_sl(const uint32_t * p)
-{
- uint32_t v;
+ if (len) {
+ set_64_sl(&ex->lba, lba);
+ set_16_sl(&ex->len, len);
+ ex++;
+ }
- p = set_fs(p);
- asm volatile ("movl %%fs:%1,%0":"=r" (v):"m"(*p));
- return v;
-}
+ base = addr;
+ lba = sect;
+ len = 1;
-#if 0 /* unused */
-static __noinline void set_8_sl(uint8_t * p, uint8_t v)
-{
- p = set_fs(p);
- asm volatile ("movb %1,%%fs:%0":"=m" (*p):"qi"(v));
-}
-#endif
+ next:
+ addr += SECTOR_SIZE;
+ nsect--;
+ }
-static __noinline void set_16_sl(uint16_t * p, uint16_t v)
-{
- p = set_fs(p);
- asm volatile ("movw %1,%%fs:%0":"=m" (*p):"ri"(v));
+ if (len) {
+ set_64_sl(&ex->lba, lba);
+ set_16_sl(&ex->len, len);
+ ex++;
+ }
}
-static __noinline void set_32_sl(uint32_t * p, uint32_t v)
+/*
+ * Form a pointer based on a 16-bit patcharea/epa field
+ */
+static inline void *ptr(void *img, uint16_t *offset_p)
{
- p = set_fs(p);
- asm volatile ("movl %1,%%fs:%0":"=m" (*p):"ri"(v));
+ return (char *)img + get_16_sl(offset_p);
}
-#else
-
-/* Sane system ... */
-#define get_8_sl(x) get_8(x)
-#define get_16_sl(x) get_16(x)
-#define get_32_sl(x) get_32(x)
-#define set_8_sl(x,y) set_8(x,y)
-#define set_16_sl(x,y) set_16(x,y)
-#define set_32_sl(x,y) set_32(x,y)
-
-#endif
-
/*
* This patches the boot sector and the beginning of ldlinux.sys
* based on an ldlinux.sys sector map passed in. Typically this is
@@ -226,67 +93,105 @@ static __noinline void set_32_sl(uint32_t * p, uint32_t v)
* Returns the number of modified bytes in ldlinux.sys if successful,
* otherwise -1.
*/
-int syslinux_patch(const uint32_t * sectors, int nsectors,
- int stupid, int raid_mode)
+#define NADV 2
+
+int syslinux_patch(const sector_t *sectp, int nsectors,
+ int stupid, int raid_mode,
+ const char *subdir, const char *subvol)
{
struct patch_area *patcharea;
+ struct ext_patch_area *epa;
+ struct syslinux_extent *ex;
uint32_t *wp;
- int nsect = (syslinux_ldlinux_len + 511) >> 9;
+ int nsect = ((boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT) + 2;
uint32_t csum;
- int i, dw, nptrs, rv;
- struct boot_sector *sbs = (struct boot_sector *)syslinux_bootsect;
+ int i, dw, nptrs;
+ struct boot_sector *sbs = (struct boot_sector *)boot_sector;
+ uint64_t *advptrs;
if (nsectors < nsect)
- return -1;
-
- /* Patch in options, as appropriate */
- if (stupid) {
- /* Access only one sector at a time */
- set_16(&sbs->MaxTransfer, 1);
- }
-
- i = get_16(&sbs->bsSignature);
- if (raid_mode)
- set_16((uint16_t *) ((char *)sbs + i), 0x18CD); /* INT 18h */
- set_16(&sbs->bsSignature, 0xAA55);
-
- /* First sector need pointer in boot sector */
- set_32(&sbs->NextSector, *sectors++);
+ return -1; /* The actual file is too small for content */
/* Search for LDLINUX_MAGIC to find the patch area */
- for (wp = (uint32_t *) syslinux_ldlinux; get_32_sl(wp) != LDLINUX_MAGIC;
- wp++) ;
+ for (wp = (uint32_t *)boot_image; get_32_sl(wp) != LDLINUX_MAGIC;
+ wp++)
+ ;
patcharea = (struct patch_area *)wp;
+ epa = ptr(boot_image, &patcharea->epaoffset);
+
+ /* First sector need pointer in boot sector */
+ set_32(ptr(sbs, &epa->sect1ptr0), sectp[0]);
+ set_32(ptr(sbs, &epa->sect1ptr1), sectp[0] >> 32);
+ sectp++;
+
+ /* Handle RAID mode */
+ if (raid_mode) {
+ /* Patch in INT 18h = CD 18 */
+ set_16(ptr(sbs, &epa->raidpatch), 0x18CD);
+ }
/* Set up the totals */
- dw = syslinux_ldlinux_len >> 2; /* COMPLETE dwords, excluding ADV */
- set_16_sl(&patcharea->data_sectors, nsect); /* Not including ADVs */
+ dw = boot_image_len >> 2; /* COMPLETE dwords, excluding ADV */
+ set_16_sl(&patcharea->data_sectors, nsect - 2); /* Not including ADVs */
set_16_sl(&patcharea->adv_sectors, 2); /* ADVs need 2 sectors */
set_32_sl(&patcharea->dwords, dw);
- /* Set the sector pointers */
- wp = (uint32_t *) ((char *)syslinux_ldlinux +
- get_16_sl(&patcharea->secptroffset));
- nptrs = get_16_sl(&patcharea->secptrcnt);
+ /* Handle Stupid mode */
+ if (stupid) {
+ /* Access only one sector at a time */
+ set_16_sl(&patcharea->maxtransfer, 1);
+ }
+
+ /* Set the sector extents */
+ ex = ptr(boot_image, &epa->secptroffset);
+ nptrs = get_16_sl(&epa->secptrcnt);
- nsect += 2;
- while (--nsect) { /* the first sector is in bs->NextSector */
- set_32_sl(wp++, *sectors++);
- nptrs--;
+ if (nsect > nptrs) {
+ /* Not necessarily an error in this case, but a general problem */
+ fprintf(stderr, "Insufficient extent space, build error!\n");
+ exit(1);
}
- while (nptrs--)
- set_32_sl(wp++, 0);
- rv = (char *)wp - (char *)syslinux_ldlinux;
+ /* -1 for the pointer in the boot sector, -2 for the two ADVs */
+ generate_extents(ex, nptrs, sectp, nsect-1-2);
+
+ /* ADV pointers */
+ advptrs = ptr(boot_image, &epa->advptroffset);
+ set_64_sl(&advptrs[0], sectp[nsect-1-2]);
+ set_64_sl(&advptrs[1], sectp[nsect-1-1]);
+
+ /* Poke in the base directory path */
+ if (subdir) {
+ int sublen = strlen(subdir) + 1;
+ if (get_16_sl(&epa->dirlen) < sublen) {
+ fprintf(stderr, "Subdirectory path too long... aborting install!\n");
+ exit(1);
+ }
+ memcpy_to_sl(ptr(boot_image, &epa->diroffset), subdir, sublen);
+ }
+
+ /* Poke in the subvolume information */
+ if (subvol) {
+ int sublen = strlen(subvol) + 1;
+ if (get_16_sl(&epa->subvollen) < sublen) {
+ fprintf(stderr, "Subvol name too long... aborting install!\n");
+ exit(1);
+ }
+ memcpy_to_sl(ptr(boot_image, &epa->subvoloffset), subvol, sublen);
+ }
/* Now produce a checksum */
set_32_sl(&patcharea->checksum, 0);
csum = LDLINUX_MAGIC;
- for (i = 0, wp = (uint32_t *) syslinux_ldlinux; i < dw; i++, wp++)
+ for (i = 0, wp = (uint32_t *)boot_image; i < dw; i++, wp++)
csum -= get_32_sl(wp); /* Negative checksum */
set_32_sl(&patcharea->checksum, csum);
- return rv;
+ /*
+ * Assume all bytes modified. This can be optimized at the expense
+ * of keeping track of what the highest modified address ever was.
+ */
+ return dw << 2;
}
diff --git a/libinstaller/syslxopt.c b/libinstaller/syslxopt.c
index 7718de3a..0ff2efbb 100644
--- a/libinstaller/syslxopt.c
+++ b/libinstaller/syslxopt.c
@@ -20,6 +20,7 @@
#include <stdlib.h>
#include <stddef.h>
#include <stdint.h>
+#include <string.h>
#include <getopt.h>
#include <sysexits.h>
#include "../version.h"
@@ -38,12 +39,14 @@ struct sys_options opt = {
.directory = NULL,
.device = NULL,
.offset = 0,
+ .menu_save = NULL,
};
const struct option long_options[] = {
+ {"force", 0, NULL, 'f'}, /* dummy option for compatibility */
{"install", 0, NULL, 'i'},
{"directory", 1, NULL, 'd'},
- {"offset", 1, NULL, 'f'},
+ {"offset", 1, NULL, 't'},
{"update", 0, NULL, 'U'},
{"zipdrive", 0, NULL, 'z'},
{"sectors", 1, NULL, 'S'},
@@ -52,26 +55,36 @@ const struct option long_options[] = {
{"raid-mode", 0, NULL, 'r'},
{"version", 0, NULL, 'v'},
{"help", 0, NULL, 'h'},
- {"once", 1, NULL, 'o'},
+ {"once", 1, NULL, OPT_ONCE},
{"clear-once", 0, NULL, 'O'},
{"reset-adv", 0, NULL, OPT_RESET_ADV},
+ {"menu-save", 1, NULL, 'M'},
{0, 0, 0, 0}
};
-const char short_options[] = "id:f:UuzS:H:rvho:O";
+const char short_options[] = "t:fid:UuzS:H:rvho:OM:";
-void __attribute__ ((noreturn)) usage(int rv, int mode)
+void __attribute__ ((noreturn)) usage(int rv, enum syslinux_mode mode)
{
- if (mode) /* for unmounted fs installation */
+ switch (mode) {
+ case MODE_SYSLINUX:
+ /* For unmounted fs installation (syslinux) */
fprintf(stderr,
"Usage: %s [options] device\n"
- " --offset -f Offset of the file system on the device \n"
+ " --offset -t Offset of the file system on the device \n"
" --directory -d Directory for installation target\n",
program);
- else /* actually extlinux can also use -d to provide directory too */
+ break;
+
+ case MODE_EXTLINUX:
+ /* Mounted fs installation (extlinux) */
+ /* Actually extlinux can also use -d to provide a directory too... */
fprintf(stderr,
"Usage: %s [options] directory\n",
program);
+ break;
+ }
+
fprintf(stderr,
" --install -i Install over the current bootsector\n"
" --update -U Update a previous EXTLINUX installation\n"
@@ -80,9 +93,10 @@ void __attribute__ ((noreturn)) usage(int rv, int mode)
" --heads=# -H Force number of heads\n"
" --stupid -s Slow, safe and stupid mode\n"
" --raid -r Fall back to the next device on boot failure\n"
- " --once=... -o Execute a command once upon boot\n"
+ " --once=... %s Execute a command once upon boot\n"
" --clear-once -O Clear the boot-once command\n"
" --reset-adv Reset auxilliary data\n"
+ " --menu-save= -M Set the label to select as default on the next boot\n"
"\n"
" Note: geometry is determined at boot time for devices which\n"
" are considered hard disks by the BIOS. Unfortunately, this is\n"
@@ -90,13 +104,13 @@ void __attribute__ ((noreturn)) usage(int rv, int mode)
" which includes zipdisks and LS-120 superfloppies.\n"
"\n"
" The -z option is useful for USB devices which are considered\n"
- " hard disks by some BIOSes and zipdrives by other BIOSes.\n"
- );
+ " hard disks by some BIOSes and zipdrives by other BIOSes.\n",
+ mode == MODE_SYSLINUX ? " " : "-o");
exit(rv);
}
-void parse_options(int argc, char *argv[], int mode)
+void parse_options(int argc, char *argv[], enum syslinux_mode mode)
{
int o;
@@ -104,6 +118,8 @@ void parse_options(int argc, char *argv[], int mode)
while ((o = getopt_long(argc, argv, short_options,
long_options, NULL)) != EOF) {
switch (o) {
+ case 'f':
+ break;
case 'z':
opt.heads = 64;
opt.sectors = 32;
@@ -143,29 +159,79 @@ void parse_options(int argc, char *argv[], int mode)
usage(0, mode);
break;
case 'o':
+ if (mode == MODE_SYSLINUX) {
+ fprintf(stderr, "%s: -o will change meaning in a future version, use -t or --offset\n", program);
+ goto opt_offset;
+ }
+ /* else fall through */
+ case OPT_ONCE:
opt.set_once = optarg;
break;
- case 'f':
+ case 't':
+ opt_offset:
opt.offset = strtoul(optarg, NULL, 0);
+ break;
case 'O':
opt.set_once = "";
break;
case 'd':
opt.directory = optarg;
+ break;
case OPT_RESET_ADV:
opt.reset_adv = 1;
break;
+ case 'M':
+ opt.menu_save = optarg;
+ break;
case 'v':
- fputs(program, stderr);
- fputs(" " VERSION_STR
- " Copyright 1994-" YEAR_STR " H. Peter Anvin \n", stderr);
+ fprintf(stderr,
+ "%s " VERSION_STR " Copyright 1994-" YEAR_STR
+ " H. Peter Anvin et al\n", program);
exit(0);
default:
+ fprintf(stderr, "%s: Unknown option: -%c\n", program, optopt);
usage(EX_USAGE, mode);
}
}
- if (mode)
- opt.device = argv[optind];
- else if (!opt.directory)
- opt.directory = argv[optind];
+
+ switch (mode) {
+ case MODE_SYSLINUX:
+ opt.device = argv[optind++];
+ break;
+ case MODE_EXTLINUX:
+ if (!opt.directory)
+ opt.directory = argv[optind++];
+ break;
+ }
+
+ if (argv[optind])
+ usage(EX_USAGE, mode); /* Excess arguments */
+}
+
+/*
+ * Make any user-specified ADV modifications in memory
+ */
+int modify_adv(void)
+{
+ int rv = 0;
+
+ if (opt.reset_adv)
+ syslinux_reset_adv(syslinux_adv);
+
+ if (opt.set_once) {
+ if (syslinux_setadv(ADV_BOOTONCE, strlen(opt.set_once), opt.set_once)) {
+ fprintf(stderr, "%s: not enough space for boot-once command\n",
+ program);
+ rv = -1;
+ }
+ }
+ if (opt.menu_save) {
+ if (syslinux_setadv(ADV_MENUSAVE, strlen(opt.menu_save), opt.menu_save)) {
+ fprintf(stderr, "%s: not enough space for menu-save label\n",
+ program);
+ rv = -1;
+ }
+ }
+
+ return rv;
}
diff --git a/libinstaller/syslxopt.h b/libinstaller/syslxopt.h
index d925fa34..446ab9af 100644
--- a/libinstaller/syslxopt.h
+++ b/libinstaller/syslxopt.h
@@ -13,15 +13,23 @@ struct sys_options {
const char *directory;
const char *device;
unsigned int offset;
+ const char *menu_save;
};
enum long_only_opt {
OPT_NONE,
OPT_RESET_ADV,
+ OPT_ONCE,
};
-void __attribute__ ((noreturn)) usage(int rv, int mode);
-void parse_options(int argc, char *argv[], int mode);
+enum syslinux_mode {
+ MODE_SYSLINUX, /* Unmounted filesystem */
+ MODE_EXTLINUX,
+};
+
+void __attribute__ ((noreturn)) usage(int rv, enum syslinux_mode mode);
+void parse_options(int argc, char *argv[], enum syslinux_mode mode);
+int modify_adv(void);
extern struct sys_options opt;
extern const struct option long_options[];