diff options
Diffstat (limited to 'extlinux/main.c')
-rw-r--r-- | extlinux/main.c | 147 |
1 files changed, 74 insertions, 73 deletions
diff --git a/extlinux/main.c b/extlinux/main.c index 6ba16e1e..a7ebd49a 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -14,7 +14,7 @@ /* * extlinux.c * - * Install the syslinux boot block on an fat, ntfs, ext2/3/4, btrfs, xfs, + * Install the syslinux boot block on a fat, ntfs, ext2/3/4, btrfs, xfs, * and ufs1/2 filesystem. */ @@ -56,6 +56,7 @@ #include "version.h" #include "syslxint.h" #include "syslxcom.h" /* common functions shared with extlinux and syslinux */ +#include "syslxrw.h" #include "syslxfs.h" #include "setadv.h" #include "syslxopt.h" /* unified options */ @@ -337,6 +338,59 @@ static int patch_file_and_bootblock(int fd, const char *dir, int devfd) return rv; } +static int ext_read_adv_offset(int devfd, off_t offset) +{ + const size_t adv_size = 2 * ADV_SIZE; + + if (xpread(devfd, syslinux_adv, adv_size, offset) != adv_size) + return -1; + + return syslinux_validate_adv(syslinux_adv) ? 1 : 0; +} + +static int ext_read_adv(const char *path, int devfd, const char **namep) +{ + int err; + const char *name; + + if (fs_type == BTRFS) { + /* btrfs "ldlinux.sys" is in 64k blank area */ + return ext_read_adv_offset(devfd, BTRFS_ADV_OFFSET); + } else if (fs_type == XFS) { + /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */ + return ext_read_adv_offset(devfd, boot_image_len); + } else { + err = read_adv(path, name = "ldlinux.sys"); + if (err == 2) /* ldlinux.sys does not exist */ + err = read_adv(path, name = "extlinux.sys"); + if (namep) + *namep = name; + return err; + } +} + +static int ext_write_adv_offset(int devfd, off_t offset) +{ + const size_t adv_size = 2 * ADV_SIZE; + + if (xpwrite(devfd, syslinux_adv, adv_size, offset) != adv_size) { + perror("writing adv"); + return 1; + } + + return 0; +} + +static int ext_write_adv(const char *path, const char *cfg, int devfd) +{ + if (fs_type == BTRFS) { + /* btrfs "ldlinux.sys" is in 64k blank area */ + return ext_write_adv_offset(devfd, BTRFS_ADV_OFFSET); + } else { + return write_adv(path, cfg); + } +} + /* * Install the boot block on the specified device. * Must be run AFTER install_file()! @@ -392,11 +446,11 @@ int install_bootblock(int fd, const char *device) if (sb5.sb_magicnum == *(u32 *)XFS_SB_MAGIC) { if (be32_to_cpu(sb5.sb_blocksize) != XFS_SUPPORTED_BLOCKSIZE) { fprintf(stderr, - "You need to have 4 KiB filesystem block size for " - " being able to install Syslinux in your XFS " - "partition (because there is no enough space in MBR to " - "determine where Syslinux bootsector can be installed " - "regardless the filesystem block size)\n"); + "You need to have 4 KiB filesystem block size for" + " being able to install Syslinux in your XFS" + " partition (because there is not enough space in MBR to" + " determine where Syslinux bootsector can be installed" + " regardless of the filesystem block size)\n"); return 1; } @@ -419,8 +473,8 @@ int install_bootblock(int fd, const char *device) if (!ok) { fprintf(stderr, - "no fat, ntfs, ext2/3/4, btrfs, xfs " - "or ufs1/2 superblock found on %s\n", + "no fat, ntfs, ext2/3/4, btrfs, xfs" + " or ufs1/2 superblock found on %s\n", device); return 1; } @@ -483,8 +537,7 @@ static int rewrite_boot_image(int devfd, const char *path, const char *filename) } /* Write ADV */ - ret = xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, boot_image_len); - if (ret != 2 * ADV_SIZE) { + if (ext_write_adv_offset(fd, boot_image_len)) { fprintf(stderr, "%s: write failure on %s\n", program, filename); goto error; } @@ -597,9 +650,12 @@ bail: return 1; } -/* btrfs has to install the ldlinux.sys in the first 64K blank area, which - is not managered by btrfs tree, so actually this is not installed as files. - since the cow feature of btrfs will move the ldlinux.sys every where */ +/* btrfs has to install ldlinux.sys to a boot area, which is not managed by + btrfs tree, so actually this is not installed as a file, since the cow + feature of btrfs would move the ldlinux.sys file everywhere. Older + versions installed it to the first 64kiB (aka Boot Area A) but as of + commit ID 37eef640 (before 6.03-pre12, before 6.03), it is now in Boot + Area B (a 768kiB blank space at offset 256kiB). */ int btrfs_install_file(const char *path, int devfd, struct stat *rst) { char *file; @@ -613,9 +669,7 @@ int btrfs_install_file(const char *path, int devfd, struct stat *rst) return 1; } dprintf("write boot_image to 0x%x\n", BTRFS_EXTLINUX_OFFSET); - if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET) - != 2 * ADV_SIZE) { - perror("writing adv"); + if (ext_write_adv_offset(devfd, BTRFS_ADV_OFFSET)) { return 1; } dprintf("write adv to 0x%x\n", BTRFS_ADV_OFFSET); @@ -661,7 +715,7 @@ int btrfs_install_file(const char *path, int devfd, struct stat *rst) * Due to historical reasons (SGI IRIX's design of disk layouts), the first * sector in the primary AG on XFS filesystems contains the superblock, which is * a problem with bootloaders that rely on BIOSes (that load VBRs which are - * (located in the first sector of the partition). + * located in the first sector of the partition). * * Thus, we need to handle this issue, otherwise Syslinux will damage the XFS's * superblock. @@ -750,7 +804,7 @@ bail: * * test if path is a subvolume: * * this function return * * 0-> path exists but it is not a subvolume - * * 1-> path exists and it is a subvolume + * * 1-> path exists and it is a subvolume * * -1 -> path is unaccessible * */ static int test_issubvolume(char *path) @@ -1384,8 +1438,8 @@ static int open_device(const char *path, struct stat *st, char **_devname) if (!fs_type) { fprintf(stderr, - "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs or" - "ufs1/2 filesystem: %s\n", + "%s: not a fat, ntfs, ext2/3/4, btrfs, xfs" + " or ufs1/2 filesystem: %s\n", program, path); return -1; } @@ -1414,59 +1468,6 @@ static int open_device(const char *path, struct stat *st, char **_devname) return devfd; } -static int btrfs_read_adv(int devfd) -{ - if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, BTRFS_ADV_OFFSET) - != 2 * ADV_SIZE) - return -1; - - return syslinux_validate_adv(syslinux_adv) ? 1 : 0; -} - -static inline int xfs_read_adv(int devfd) -{ - const size_t adv_size = 2 * ADV_SIZE; - - if (xpread(devfd, syslinux_adv, adv_size, boot_image_len) != adv_size) - return -1; - - return syslinux_validate_adv(syslinux_adv) ? 1 : 0; -} - -static int ext_read_adv(const char *path, int devfd, const char **namep) -{ - int err; - const char *name; - - if (fs_type == BTRFS) { - /* btrfs "ldlinux.sys" is in 64k blank area */ - return btrfs_read_adv(devfd); - } else if (fs_type == XFS) { - /* XFS "ldlinux.sys" is in the first 2048 bytes of the primary AG */ - return xfs_read_adv(devfd); - } else { - err = read_adv(path, name = "ldlinux.sys"); - if (err == 2) /* ldlinux.sys does not exist */ - err = read_adv(path, name = "extlinux.sys"); - if (namep) - *namep = name; - return err; - } -} - -static int ext_write_adv(const char *path, const char *cfg, int devfd) -{ - if (fs_type == BTRFS) { /* btrfs "ldlinux.sys" is in 64k blank area */ - if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, - BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) { - perror("writing adv"); - return 1; - } - return 0; - } - return write_adv(path, cfg); -} - static int install_loader(const char *path, int update_only) { struct stat st, fst; |