Robert Yang
2015-Jan-02 05:05 UTC
[syslinux] [PATCH 0/9] linux/syslinux: support ext2/3/4 device
Hello, Happy New Year! These patches make syslinux/linux support ext2/3/4, and it doesn't require the root privilege, I'd like to add a separate e2fs/syslinux, if that is more appropriate, it should be easy to do that. I put these patches on github so that you can easily get them in case you'd like to test them. (The repo's name is sys_tmp, which avoids confusing others, I will remove the repo when these patches are reviewed). Please feel free to give your comments, any suggestion is appreciated. // Robert The following changes since commit 81ad566f155fac31089fde69c87059b217e7e9b6: NEWS: Update for 6.03 release (2014-10-06 09:27:44 -0700) are available in the git repository at: https://github.com/robertlinux/sys_tmp.git syslinux_ext234 for you to fetch changes up to 76c465e87312dbc6cffd05427f1f4d2ebdee4f13: linux/syslinux: implement install_bootblock() (2015-01-02 12:28:35 +0800) ---------------------------------------------------------------- Robert Yang (9): linux/syslinux: support ext2/3/4 device linux/syslinux: implement open_ext2_fs() linux/syslinux: implement install_to_ext2() linux/syslinux: add ext_file_read() and ext_file_write() linux/syslinux: implement handle_adv_on_ext() linux/syslinux: implement write_to_ext() and add syslinuxext.c linux/syslinux: implement ext_construct_sectmap_fs() libinstaller/syslinuxext: implement syslinux_patch_bootsect() linux/syslinux: implement install_bootblock() extlinux/Makefile | 3 +- extlinux/main.c | 167 +------------- libinstaller/syslinuxext.c | 177 +++++++++++++++ libinstaller/syslinuxext.h | 5 + linux/Makefile | 5 +- linux/syslinux.c | 542 +++++++++++++++++++++++++++++++++++++++++++++ 6 files changed, 732 insertions(+), 167 deletions(-) create mode 100644 libinstaller/syslinuxext.c create mode 100644 libinstaller/syslinuxext.h
Robert Yang
2015-Jan-02 05:05 UTC
[syslinux] [PATCH 1/9] linux/syslinux: support ext2/3/4 device
* Support ext2/3/4 deivce. * The open_ext2_fs() checks whether it is an ext2/3/4 device, do the ext2/3/4 installation (install_to_ext2()) if yes, otherwise go on to the fat/ntfs. * The ext2/3/4 support doesn't require root privileges since it doesn't need mount (but write permission is required). Signed-off-by: Robert Yang <liezhi.yang at windriver.com> --- linux/syslinux.c | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/linux/syslinux.c b/linux/syslinux.c index 912de71..36fc202 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -256,6 +256,23 @@ int do_open_file(char *name) return fd; } +/* + * Check whether the device contains an ext2, ext3 or ext4 fs and open it if + * true. + * return value: + * 0: Everything is OK + * 1: Not an ext2, ext3 or ext4 + * -1: unexpected error + */ +static int open_ext2_fs(const char *device, const char *subdir) +{ +} + +/* The install func for ext2, ext3 and ext4 */ +static int install_to_ext2(const char *device, int dev_fd, const char *subdir) +{ +} + int main(int argc, char *argv[]) { static unsigned char sectbuf[SECTOR_SIZE]; @@ -313,6 +330,24 @@ int main(int argc, char *argv[]) die("can't combine an offset with a block device"); } + /* + * Check if it is an ext2, ext3 or ext4 + */ + rv = open_ext2_fs(opt.device, subdir); + if (rv == 0) { + if (install_to_ext2(opt.device, dev_fd, subdir)) { + fprintf(stderr, "%s: installation failed\n", opt.device); + exit(1); + } + return 0; + /* Unexpected errors */ + } else if (rv == -1) { + exit(1); + } + + /* Reset rv */ + rv = 0; + xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset); fsync(dev_fd); @@ -322,6 +357,7 @@ int main(int argc, char *argv[]) */ if ((errmsg = syslinux_check_bootsect(sectbuf, &fs_type))) { fprintf(stderr, "%s: %s\n", opt.device, errmsg); + fprintf(stderr, "%s: supported fs: fat/ntfs/ext2/ex3/ext4\n", program); exit(1); } -- 1.9.1
Robert Yang
2015-Jan-02 05:05 UTC
[syslinux] [PATCH 2/9] linux/syslinux: implement open_ext2_fs()
The open_ext2_fs() checks whether it is an ext2/ext3/ext4 device, and return: 0: It is an ext2, ext3 or ext4. 1: Not an ext2, ext3 or ext4. -1: unexpected error. Signed-off-by: Robert Yang <liezhi.yang at windriver.com> --- linux/Makefile | 2 +- linux/syslinux.c | 80 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 81 insertions(+), 1 deletion(-) diff --git a/linux/Makefile b/linux/Makefile index 11667e1..ac1ac58 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -51,7 +51,7 @@ spotless: clean installer: syslinux syslinux-nomtools syslinux: $(OBJS) - $(CC) $(LDFLAGS) -o $@ $^ + $(CC) $(LDFLAGS) -o $@ $^ -lext2fs syslinux-nomtools: syslinux ln -f $< $@ diff --git a/linux/syslinux.c b/linux/syslinux.c index 36fc202..cc4e7da 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -72,6 +72,7 @@ #include "syslxfs.h" #include "setadv.h" #include "syslxopt.h" /* unified options */ +#include <ext2fs/ext2fs.h> extern const char *program; /* Name of program */ @@ -82,6 +83,9 @@ char *mntpath = NULL; /* Path on which to mount */ int loop_fd = -1; /* Loop device */ #endif +ext2_filsys e2fs = NULL; /* Ext2/3/4 filesystem */ +ext2_ino_t root, cwd; /* The root and cwd of e2fs */ + void __attribute__ ((noreturn)) die(const char *msg) { fprintf(stderr, "%s: %s\n", program, msg); @@ -266,6 +270,82 @@ int do_open_file(char *name) */ static int open_ext2_fs(const char *device, const char *subdir) { + int retval; + int open_flag = EXT2_FLAG_RW, mount_flags; + ext2_ino_t dirino; + char opt_string[40]; + + if (opt.offset) { + sprintf(opt_string, "offset=%llu", (unsigned long long)opt.offset); + retval = ext2fs_open2(device, opt_string, open_flag, 0, 0, unix_io_manager, &e2fs); + } else + retval = ext2fs_open(device, open_flag, 0, 0, unix_io_manager, &e2fs); + if (retval) { + /* It might not be an extN fs, so we need check magic firstly */ + if (retval == EXT2_ET_BAD_MAGIC) { + /* Do nothing, return silently */ + return 1; + } else { + fprintf(stderr, "%s: error while trying to open: %s\n", + program, device); + return -1; + } + } + + /* Stop if it is mounted */ + retval = ext2fs_check_if_mounted(device, &mount_flags); + if (retval) { + fprintf(stderr, "%s: ext2fs_check_if_mount() error on %s\n", + program, device); + goto fail; + } + + if (mount_flags & EXT2_MF_MOUNTED) { + fprintf(stderr, "%s: %s is mounted\n", program, device); + goto fail; + } + + e2fs->default_bitmap_type = EXT2FS_BMAP64_RBTREE; + + /* Read the inode map */ + retval = ext2fs_read_inode_bitmap(e2fs); + if (retval) { + fprintf(stderr, "%s: while reading inode bitmap: %s\n", + program, device); + goto fail; + } + + /* Read the block map */ + retval = ext2fs_read_block_bitmap(e2fs); + if (retval) { + fprintf(stderr, "%s: while reading block bitmap: %s\n", + program, device); + goto fail; + } + + root = cwd = EXT2_ROOT_INO; + /* Check the subdir */ + if (strcmp(subdir, "/")) { + retval = ext2fs_namei(e2fs, root, cwd, subdir, &dirino); + if (retval) { + fprintf(stderr, "%s: failed to find dir %s on %s\n", + program, subdir, device); + goto fail; + } + + retval = ext2fs_check_directory(e2fs, dirino); + if (retval) { + fprintf(stderr, "%s: failed to cd to: %s\n", program, subdir); + goto fail; + } + cwd = dirino; + } + + return 0; + +fail: + (void) ext2fs_close(e2fs); + return -1; } /* The install func for ext2, ext3 and ext4 */ -- 1.9.1
Robert Yang
2015-Jan-02 05:05 UTC
[syslinux] [PATCH 3/9] linux/syslinux: implement install_to_ext2()
* The handle_adv_on_ext() checks whether we only need update adv. * The write_to_ext() installs files (ldlinux.sys or ldlinux.c32) to the device. * The install_bootblock() installs the boot block. Signed-off-by: Robert Yang <liezhi.yang at windriver.com> --- linux/syslinux.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/linux/syslinux.c b/linux/syslinux.c index cc4e7da..45f080d 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -346,11 +346,90 @@ static int open_ext2_fs(const char *device, const char *subdir) fail: (void) ext2fs_close(e2fs); return -1; + +} + +/* + * Install the boot block on the specified device. + * Must be run AFTER file installed. + */ +int install_bootblock(int fd, const char *device) +{ +} + +static int handle_adv_on_ext(void) +{ +} + +/* Write files, adv, boot sector */ +static int write_to_ext(const char *filename, const char *str, int length, + int i_flags, int dev_fd, const char *subdir) +{ } /* The install func for ext2, ext3 and ext4 */ static int install_to_ext2(const char *device, int dev_fd, const char *subdir) { + int retval; + ext2_ino_t oldino; + + const char *file = "ldlinux.sys"; + const char *oldfile = "extlinux.sys"; + const char *c32file = "ldlinux.c32"; + + /* Handle the adv */ + if (handle_adv_on_ext() < 0) { + fprintf(stderr, "%s: error while handling ADV on %s\n", + program, device); + retval = 1; + goto fail; + } + + /* Return if only need update the adv */ + if (opt.update_only == -1) { + return ext2fs_close(e2fs); + } + + /* Write ldlinux.sys, adv, boot sector */ + retval = write_to_ext(file, (const char _force *)boot_image, + boot_image_len, EXT2_IMMUTABLE_FL, dev_fd, subdir); + if (retval) { + fprintf(stderr, "%s: ERROR: while writing: %s.\n", + program, file); + goto fail; + } + + /* Write ldlinux.c32 */ + retval = write_to_ext(c32file, + (const char _force *)syslinux_ldlinuxc32, + syslinux_ldlinuxc32_len, 0, dev_fd, subdir); + if (retval) { + fprintf(stderr, "%s: ERROR: while writing: %s.\n", + program, c32file); + goto fail; + } + + /* Look if we have the extlinux.sys and remove it*/ + retval = ext2fs_namei(e2fs, root, cwd, oldfile, &oldino); + if (retval == 0) { + retval = ext2fs_unlink(e2fs, cwd, oldfile, oldino, 0); + if (retval) { + fprintf(stderr, "%s: ERROR: failed to unlink: %s\n", + program, oldfile); + goto fail; + } + } else { + retval = 0; + } + + sync(); + retval = install_bootblock(dev_fd, device); + close(dev_fd); + sync(); + +fail: + (void) ext2fs_close(e2fs); + return retval; } int main(int argc, char *argv[]) -- 1.9.1
Robert Yang
2015-Jan-02 05:05 UTC
[syslinux] [PATCH 4/9] linux/syslinux: add ext_file_read() and ext_file_write()
Will use them to read and write on the extX device. Signed-off-by: Robert Yang <liezhi.yang at windriver.com> --- linux/syslinux.c | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/linux/syslinux.c b/linux/syslinux.c index 45f080d..247c86a 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -349,6 +349,68 @@ fail: } +/* Read from an ext2_file */ +static int ext_file_read(ext2_file_t e2_file, void *buf, size_t count, + off_t offset, const char *msg) +{ + int retval; + char *ptr = (char *) buf; + unsigned int got = 0; + size_t done = 0; + + /* Always lseek since e2_file is uncontrolled by this func */ + if (ext2fs_file_lseek(e2_file, offset, EXT2_SEEK_SET, NULL)) { + fprintf(stderr, "%s: ext2fs_file_lseek() failed.\n", + program); + return -1; + } + + while (1) { + retval = ext2fs_file_read(e2_file, ptr, count, &got); + if (retval) { + fprintf(stderr, "%s: error while reading %s\n", + program, msg); + return -1; + } + count -= got; + ptr += got; + done += got; + if (got == 0 || count == 0) + break; + } + + return done; +} + +/* Write to an ext2_file */ +static int ext_file_write(ext2_file_t e2_file, const void *buf, size_t count, + off_t offset) +{ + const char *ptr = (const char *) buf; + unsigned int written = 0; + size_t done = 0; + + /* Always lseek since e2_file is uncontrolled by this func */ + if (ext2fs_file_lseek(e2_file, offset, EXT2_SEEK_SET, NULL)) { + fprintf(stderr, "%s: ext2fs_file_lseek() failed.\n", + program); + return -1; + } + + while (count > 0) { + if (ext2fs_file_write(e2_file, ptr, count, &written)) { + fprintf(stderr, "%s: failed to write syslinux adv.\n", + program); + return -1; + } + count -= written; + ptr += written; + done += written; + } + + return done; +} + /* * Install the boot block on the specified device. * Must be run AFTER file installed. -- 1.9.1
Robert Yang
2015-Jan-02 05:05 UTC
[syslinux] [PATCH 5/9] linux/syslinux: implement handle_adv_on_ext()
It reads adv if found on the device, or resets syslinux_adv, or update the adv if update adv only. Signed-off-by: Robert Yang <liezhi.yang at windriver.com> --- linux/syslinux.c | 97 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/linux/syslinux.c b/linux/syslinux.c index 247c86a..de5d272 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -421,6 +421,103 @@ int install_bootblock(int fd, const char *device) static int handle_adv_on_ext(void) { + int i, retval, found_file; + int need_close = 2; /* 2 means no need extra close */ + char *filenames[2] = {"ldlinux.sys", "extlinux.sys"}; + char *filename; + ext2_ino_t newino; + ext2_file_t e2_file; + struct ext2_inode inode; + + for (i = 0; i < 2; i++) { + filename = filenames[i]; + found_file = 0; + retval = ext2fs_namei(e2fs, root, cwd, filename, &newino); + if (retval == 0) { + found_file = 1; + } else + continue; + + need_close = i; + + retval = ext2fs_file_open(e2fs, newino, EXT2_FLAG_RW, &e2_file); + if (retval) { + fprintf(stderr, "%s: failed to open %s\n", + program, filename); + goto fail; + } + + retval = ext2fs_read_inode(e2fs, newino, &inode); + if (retval) { + fprintf(stderr, "%s: error while reading inode: %u, file: %s\n", + program, newino, filename); + goto fail; + } + + /* Check the size to see if too small to read */ + if (inode.i_size < 2 * ADV_SIZE) { + if (opt.update_only == -1) { + fprintf(stderr, "%s: failed to write auxilliary data\n\ + the size of %s is too small (need --update)?\n", + program, filename); + retval = -1; + goto fail; + } + syslinux_reset_adv(syslinux_adv); + found_file = 0; + break; + } + + /* Read the adv */ + retval = ext_file_read(e2_file, syslinux_adv, 2 * ADV_SIZE, + inode.i_size - 2 * ADV_SIZE, "ADV"); + if (retval == -1) + goto fail; + if (retval == 2 * ADV_SIZE) { + retval = syslinux_validate_adv(syslinux_adv); + /* Read the adv successfully */ + if (retval == 0) + break; + } + + /* Close the file if reaches here, otherwise we leave the file + * open in case we need write it */ + need_close = 2; + retval = ext2fs_file_close(e2_file); + if (retval) { + fprintf(stderr, "%s: error while closing %s\n", + program, filename); + return retval; + } + } + + if (!found_file) { + if (opt.update_only == -1) { + fprintf(stderr, "%s: no ldlinux.sys or extlinux.sys found on the device\n", + program); + return -1; + } + syslinux_reset_adv(syslinux_adv); + } + + /* The modify_adv will reset the adv if opt.reset_adv */ + if (modify_adv() < 0) { + fprintf(stderr, "%s: error while modifying adv\n", program); + retval = -1; + goto fail; + } + + /* Write adv if update_only == -1 and found file */ + if (opt.update_only == -1 && found_file) { + if (ext_file_write(e2_file, syslinux_adv, 2 * ADV_SIZE , + inode.i_size - 2 * ADV_SIZE) == -1) + goto fail; + } + +fail: + if (need_close != 2) + (void) ext2fs_file_close(e2_file); + return retval; } /* Write files, adv, boot sector */ -- 1.9.1
Robert Yang
2015-Jan-02 05:05 UTC
[syslinux] [PATCH 6/9] linux/syslinux: implement write_to_ext() and add syslinuxext.c
* The write_to_ext() write file to the extX device, and handle the boot sector. * The syslinuxext.c is used for placing the code which are used by extlinux and syslinux (which is syslinux_patch_bootsect()). Signed-off-by: Robert Yang <liezhi.yang at windriver.com> --- libinstaller/syslinuxext.c | 7 +++ libinstaller/syslinuxext.h | 5 ++ linux/Makefile | 3 +- linux/syslinux.c | 118 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 libinstaller/syslinuxext.c create mode 100644 libinstaller/syslinuxext.h diff --git a/libinstaller/syslinuxext.c b/libinstaller/syslinuxext.c new file mode 100644 index 0000000..bb54cef --- /dev/null +++ b/libinstaller/syslinuxext.c @@ -0,0 +1,7 @@ +#define _GNU_SOURCE + +/* Patch syslinux_bootsect */ +void syslinux_patch_bootsect(int dev_fd) +{ +} + diff --git a/libinstaller/syslinuxext.h b/libinstaller/syslinuxext.h new file mode 100644 index 0000000..8abd8b9 --- /dev/null +++ b/libinstaller/syslinuxext.h @@ -0,0 +1,5 @@ +#ifndef EXT2_SUPER_OFFSET +#define EXT2_SUPER_OFFSET 1024 +#endif + +void syslinux_patch_bootsect(int dev_fd); diff --git a/linux/Makefile b/linux/Makefile index ac1ac58..3b23867 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -30,7 +30,8 @@ SRCS = syslinux.c \ ../libinstaller/syslxmod.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/linux/syslinux.c b/linux/syslinux.c index de5d272..f0c97a8 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -46,6 +46,7 @@ #include <sys/types.h> #include <sys/wait.h> #include <sys/mount.h> +#include <time.h> #include "linuxioctl.h" @@ -72,6 +73,7 @@ #include "syslxfs.h" #include "setadv.h" #include "syslxopt.h" /* unified options */ +#include "syslinuxext.h" #include <ext2fs/ext2fs.h> extern const char *program; /* Name of program */ @@ -419,6 +421,12 @@ int install_bootblock(int fd, const char *device) { } +/* Construct the boot file map */ +int ext_construct_sectmap_fs(ext2_filsys fs, ext2_ino_t newino, + sector_t *sectors, int nsect) +{ +} + static int handle_adv_on_ext(void) { int i, retval, found_file; @@ -524,6 +532,116 @@ fail: static int write_to_ext(const char *filename, const char *str, int length, int i_flags, int dev_fd, const char *subdir) { + ext2_ino_t newino; + struct ext2_inode inode; + int retval, i, modbytes, nsect; + ext2_file_t e2_file; + sector_t *sectors; + + /* Remove it if it is already exists */ + retval = ext2fs_namei(e2fs, root, cwd, filename, &newino); + if (retval == 0) { + retval = ext2fs_unlink(e2fs, cwd, filename, newino, 0); + if (retval) { + fprintf(stderr, "%s: failed to unlink: %s\n", program, filename); + return retval; + } + } + + /* Create new inode */ + retval = ext2fs_new_inode(e2fs, cwd, 010755, 0, &newino); + if (retval) { + fprintf(stderr, "%s: ERROR: failed to create inode for: %s\n", + program, filename); + return retval; + } + + /* Link the inode and the filename */ + retval = ext2fs_link(e2fs, cwd, filename, newino, EXT2_FT_REG_FILE); + if (retval) { + fprintf(stderr, "%s: ERROR: failed to link inode for: %s.\n", + program, filename); + return retval; + } + + if (ext2fs_test_inode_bitmap2(e2fs->inode_map, newino)) + fprintf(stderr, "%s: warning: inode already set %s.\n", + program, filename); + + ext2fs_inode_alloc_stats2(e2fs, newino, +1, 0); + memset(&inode, 0, sizeof(inode)); + inode.i_mode = LINUX_S_IFREG | LINUX_S_IRUSR | LINUX_S_IRGRP + | LINUX_S_IROTH; + inode.i_flags |= i_flags; + inode.i_atime = inode.i_ctime = inode.i_mtime + e2fs->now ? e2fs->now : time(0); + inode.i_links_count = 1; + if (e2fs->super->s_feature_incompat & + EXT3_FEATURE_INCOMPAT_EXTENTS) { + struct ext3_extent_header *eh; + + eh = (struct ext3_extent_header *) &inode.i_block[0]; + eh->eh_depth = 0; + eh->eh_entries = 0; + eh->eh_magic = ext2fs_cpu_to_le16(EXT3_EXT_MAGIC); + i = (sizeof(inode.i_block) - sizeof(*eh)) / + sizeof(struct ext3_extent); + eh->eh_max = ext2fs_cpu_to_le16(i); + inode.i_flags |= EXT4_EXTENTS_FL; + } + + retval = ext2fs_write_new_inode(e2fs, newino, &inode); + if (retval) { + fprintf(stderr, "%s: ERROR: while writting inode %d.\n", + program, newino); + return 1; + } + + retval = ext2fs_file_open(e2fs, newino, EXT2_FILE_WRITE, &e2_file); + if (retval) { + fprintf(stderr, "%s: ERROR: failed to open %s.\n", + program, filename); + return 1; + } + + /* Write to file */ + if (ext_file_write(e2_file, str, length, 0) == -1) + goto fail; + + if (strcmp(filename, "ldlinux.sys") == 0) { + /* Write ADV */ + if (ext_file_write(e2_file, syslinux_adv, 2 * ADV_SIZE, + boot_image_len) == -1) + goto fail; + + /* Patch syslinux_bootsect */ + syslinux_patch_bootsect(dev_fd); + + /* Patch ldlinux.sys */ + nsect = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + nsect += 2; /* Two sectors for the ADV */ + sectors = alloca(sizeof(sector_t) * nsect); + memset(sectors, 0, nsect * sizeof *sectors); + /* The sectors will be modified and used by syslinux_patch() */ + retval = ext_construct_sectmap_fs(e2fs, newino, sectors, nsect); + if (retval) + goto fail; + + /* Create the modified image in memory */ + modbytes = syslinux_patch(sectors, nsect, opt.stupid_mode, + opt.raid_mode, subdir, NULL); + + /* Rewrite the first modbytes of ldlinux.sys */ + if (ext_file_write(e2_file, str, modbytes, 0) == -1) { + fprintf(stderr, "%s: ERROR: failed to patch %s.\n", program, + filename); + goto fail; + } + } + +fail: + (void) ext2fs_file_close(e2_file); + return retval; } /* The install func for ext2, ext3 and ext4 */ -- 1.9.1
Robert Yang
2015-Jan-02 05:06 UTC
[syslinux] [PATCH 7/9] linux/syslinux: implement ext_construct_sectmap_fs()
The ext_construct_sectmap_fs() constucts the sector according to the bmap. Signed-off-by: Robert Yang <liezhi.yang at windriver.com> --- linux/syslinux.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/linux/syslinux.c b/linux/syslinux.c index f0c97a8..c741750 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -421,10 +421,60 @@ int install_bootblock(int fd, const char *device) { } +/* The file's block count */ +int block_count = 0; +static int get_block_count(ext2_filsys fs EXT2FS_ATTR((unused)), + blk64_t *blocknr EXT2FS_ATTR((unused)), + e2_blkcnt_t blockcnt EXT2FS_ATTR((unused)), + blk64_t ref_block EXT2FS_ATTR((unused)), + int ref_offset EXT2FS_ATTR((unused)), + void *private EXT2FS_ATTR((unused))) +{ + block_count++; + return 0; +} + /* Construct the boot file map */ int ext_construct_sectmap_fs(ext2_filsys fs, ext2_ino_t newino, sector_t *sectors, int nsect) { + blk64_t pblk, blksize, blk = 0; + sector_t sec; + unsigned int i; + int retval; + + blksize = fs->blocksize; + blksize >>= SECTOR_SHIFT; + + /* Get the total blocks no. */ + retval = ext2fs_block_iterate3(fs, newino, BLOCK_FLAG_READ_ONLY, + NULL, get_block_count, NULL); + if (retval) { + fprintf(stderr, "%s: ERROR: ext2fs_block_iterate3() failed.\n", program); + return -1; + } + + while (nsect) { + if (block_count-- == 0) + break; + + /* Get the physical block no. (bmap) */ + retval = ext2fs_bmap2(fs, newino, 0, 0, 0, blk, 0, &pblk); + if (retval) { + fprintf(stderr, "%s: ERROR: ext2fs_bmap2() failed.\n", program); + return -1; + } + + blk++; + sec = (sector_t)pblk * blksize; + for (i = 0; i < blksize; i++) { + *sectors++ = sec++; + if (! --nsect) + break; + } + } + + return 0; } static int handle_adv_on_ext(void) -- 1.9.1
Robert Yang
2015-Jan-02 05:06 UTC
[syslinux] [PATCH 8/9] 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. Signed-off-by: Robert Yang <liezhi.yang at windriver.com> --- extlinux/Makefile | 3 +- extlinux/main.c | 167 +------------------------------------------- libinstaller/syslinuxext.c | 170 +++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 175 insertions(+), 165 deletions(-) diff --git a/extlinux/Makefile b/extlinux/Makefile index 02d1db5..90dd92f 100644 --- a/extlinux/Makefile +++ b/extlinux/Makefile @@ -31,7 +31,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 09740bd..6fe026e 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -60,6 +60,7 @@ #include "setadv.h" #include "syslxopt.h" /* unified options */ #include "mountinfo.h" +#include "syslinuxext.h" #ifdef DEBUG # define dprintf printf @@ -67,10 +68,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. @@ -92,136 +89,6 @@ static char subvol[BTRFS_SUBVOL_MAX]; - 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, §s)) - 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. * Stick the "current directory" inode number into the file. @@ -231,11 +98,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; @@ -279,33 +143,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..5a4423b 100644 --- a/libinstaller/syslinuxext.c +++ b/libinstaller/syslinuxext.c @@ -1,7 +1,177 @@ #define _GNU_SOURCE +#include <sys/stat.h> +#include <sys/types.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, §s)) + 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); } -- 1.9.1
Robert Yang
2015-Jan-02 05:06 UTC
[syslinux] [PATCH 9/9] linux/syslinux: implement install_bootblock()
Refer to the install_bootblock() in extlinux/main.c to make linux/syslinux.c's install_bootblock() which only supports ext2/3/4. Signed-off-by: Robert Yang <liezhi.yang at windriver.com> --- linux/syslinux.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/linux/syslinux.c b/linux/syslinux.c index c741750..917f83a 100755 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -419,6 +419,26 @@ static int ext_file_write(ext2_file_t e2_file, const void *buf, size_t count, */ int install_bootblock(int fd, const char *device) { + struct ext2_super_block sb; + + if (xpread(fd, &sb, sizeof sb, EXT2_SUPER_OFFSET + opt.offset) != sizeof sb) { + perror("reading superblock"); + return 1; + } + + if (sb.s_magic != EXT2_SUPER_MAGIC) { + fprintf(stderr, + "no ext2/3/4 superblock found on %s\n", device); + return 1; + } + + if (xpwrite(fd, syslinux_bootsect, syslinux_bootsect_len, 0) + != (signed)syslinux_bootsect_len) { + perror("writing bootblock"); + return 1; + } + + return 0; } /* The file's block count */ -- 1.9.1
> Hello, > > Happy New Year! > > These patches make syslinux/linux support ext2/3/4, and it doesn't > require the root privilege, I'd like to add a separate e2fs/syslinux, if > that is more appropriate, it should be easy to do that. >> > Please feel free to give your comments, any suggestion is appreciated. > > // Robert >Thank you Robert for this patch. Just to ease readers, specially for Peter (summing up from prior discussions about this [1]): A_ linux/syslinux should not require dependencies; that's why it requires root privileges instead (before this path). B_ mtools/syslinux requires dependencies, but can run with unprivileged write permissions. C_ With this proposed patch, linux/syslinux would have a mix case: C.1_ linux/syslinux would still require root privileges (for FAT); and C.2_ linux/syslinux would have dependencies. To maintain the current use-cases and the reasoning/goals for having different installers, a new installer should be created (instead of modifying the current use-case of linux/syslinux): D_ A new e2fs/syslinux installer would be for ext2/3/4 what mtools/syslinux is for FAT, thus maintaining use-cases. For more details, see [1]. [1] http://www.syslinux.org/archives/2014-December/023006.html Regards, Ady.
H. Peter Anvin
2015-Jan-06 00:04 UTC
[syslinux] [PATCH 0/9] linux/syslinux: support ext2/3/4 device
On 01/01/2015 09:05 PM, Robert Yang wrote:> Hello, > > Happy New Year! > > These patches make syslinux/linux support ext2/3/4, and it doesn't > require the root privilege, I'd like to add a separate e2fs/syslinux, if > that is more appropriate, it should be easy to do that. > > I put these patches on github so that you can easily get them in case > you'd like to test them. (The repo's name is sys_tmp, which avoids > confusing others, I will remove the repo when these patches are > reviewed). >In my opinion, linux/syslinux really should just be part of extlinux, since it is exactly equivalent to mounting the filesystem, running extlinux, and unmounting the filesystem. That automatically adds support for all filesystems. mtools/syslinux is the one that doesn't require root privileges, and where libext2fs belongs. Ideally the FAT support ought to be internalized into a library, too. The one thing with mtools/syslinux is that some people like to compile it for non-Linux platforms (how successfully, I don't know) and so ext*fs support should probably be conditionalized. -hpa
Robert Yang
2015-Jan-06 00:14 UTC
[syslinux] [PATCH 0/9] linux/syslinux: support ext2/3/4 device
On 01/06/2015 08:04 AM, H. Peter Anvin wrote:> On 01/01/2015 09:05 PM, Robert Yang wrote: >> Hello, >> >> Happy New Year! >> >> These patches make syslinux/linux support ext2/3/4, and it doesn't >> require the root privilege, I'd like to add a separate e2fs/syslinux, if >> that is more appropriate, it should be easy to do that. >> >> I put these patches on github so that you can easily get them in case >> you'd like to test them. (The repo's name is sys_tmp, which avoids >> confusing others, I will remove the repo when these patches are >> reviewed). >> > > In my opinion, linux/syslinux really should just be part of extlinux, > since it is exactly equivalent to mounting the filesystem, running > extlinux, and unmounting the filesystem. That automatically adds > support for all filesystems. > > mtools/syslinux is the one that doesn't require root privileges, and > where libext2fs belongs. Ideally the FAT support ought to be > internalized into a library, too. > > The one thing with mtools/syslinux is that some people like to compile > it for non-Linux platforms (how successfully, I don't know) and so > ext*fs support should probably be conditionalized.Thanks for the reply, how about: 1) Add the libext2fs' syslinux to mtools/syslinux 2) The "make" will compile libext2fs by default, and make EXT2FS=0 will disable the compile ? // Robert> > -hpa > > >
> On 01/01/2015 09:05 PM, Robert Yang wrote: > > Hello, > > > > Happy New Year! > > > > These patches make syslinux/linux support ext2/3/4, and it doesn't > > require the root privilege, I'd like to add a separate e2fs/syslinux, if > > that is more appropriate, it should be easy to do that. > > > > I put these patches on github so that you can easily get them in case > > you'd like to test them. (The repo's name is sys_tmp, which avoids > > confusing others, I will remove the repo when these patches are > > reviewed). > > > > In my opinion, linux/syslinux really should just be part of extlinux, > since it is exactly equivalent to mounting the filesystem, running > extlinux, and unmounting the filesystem. That automatically adds > support for all filesystems. > > mtools/syslinux is the one that doesn't require root privileges, and > where libext2fs belongs. Ideally the FAT support ought to be > internalized into a library, too. > > The one thing with mtools/syslinux is that some people like to compile > it for non-Linux platforms (how successfully, I don't know) and so > ext*fs support should probably be conditionalized. > > -hpa > > _______________________________________________ > Syslinux mailing list > Submissions to Syslinux at zytor.com > Unsubscribe or set options at: > http://www.zytor.com/mailman/listinfo/syslinux >The use-case of linux/syslinux is that it doesn't have/need dependencies (other than root privileges). This is supposed to be useful, for instance for smaller OS installers or alike. If it were to be merged with the extlinux command, wouldn't this use-case change (or get lost)? Also, please let's not forget that most users don't rebuild Syslinux with specific flags, so whatever ends up being the standard, that's what users are "forced" to use. As I said before (but probably most members decided tl;dr), I'd rather see a separate installer rather than reducing the use-case alternatives (not that I have a say in the matter). If the use-cases can be maintain while also reducing the amount of alternative installers available for common users (and not having to rebuild official upstream Syslinux), that would be ideal. Regards, Ady.