diff options
author | Alek Du <alek.du@intel.com> | 2010-05-19 09:39:57 +0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-05-20 19:57:46 -0700 |
commit | e4fc443f9b70f188963ff33e0a16ccb72a553540 (patch) | |
tree | 5abf92a66a5a741e61375478ae41bb3383dcec04 | |
parent | 38eb0724824139a81342e3f676910187bc57ba9d (diff) | |
download | syslinux-e4fc443f9b70f188963ff33e0a16ccb72a553540.tar.gz |
unify common parts of extlinux and syslinux installer
Thus we can share same command line options and reduce a lot of dup
code...
Seems like a big patch, but the changes are quite safe, no much logical
change.
Signed-off-by: Alek Du <alek.du@intel.com>
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r-- | extlinux/Makefile | 4 | ||||
-rw-r--r-- | extlinux/ext2_fs.h | 8 | ||||
-rw-r--r-- | extlinux/main.c | 496 | ||||
-rw-r--r-- | libinstaller/Makefile | 2 | ||||
-rw-r--r-- | libinstaller/setadv.c | 136 | ||||
-rw-r--r-- | libinstaller/setadv.h | 16 | ||||
-rw-r--r-- | libinstaller/syslinux.h | 10 | ||||
-rw-r--r-- | libinstaller/syslxcom.c | 218 | ||||
-rw-r--r-- | libinstaller/syslxcom.h | 20 | ||||
-rw-r--r-- | libinstaller/syslxmod.c | 3 | ||||
-rw-r--r-- | libinstaller/syslxopt.c | 171 | ||||
-rw-r--r-- | libinstaller/syslxopt.h | 30 | ||||
-rw-r--r-- | linux/Makefile | 3 | ||||
-rw-r--r-- | linux/syslinux.c | 295 |
14 files changed, 754 insertions, 658 deletions
diff --git a/extlinux/Makefile b/extlinux/Makefile index 23ffd400..ab92c2c6 100644 --- a/extlinux/Makefile +++ b/extlinux/Makefile @@ -11,7 +11,7 @@ ## ----------------------------------------------------------------------- ## -## Linux ext2/ext3 installer +## Linux vfat, ext2/ext3/ext4 and btrfs installer ## topdir = .. @@ -24,6 +24,8 @@ CFLAGS = $(GCCWARN) -Wno-sign-compare -D_FILE_OFFSET_BITS=64 \ LDFLAGS = # -s SRCS = main.c \ + ../libinstaller/syslxopt.c \ + ../libinstaller/syslxcom.c \ ../libinstaller/setadv.c \ ../libinstaller/extlinux_bss_bin.c \ ../libinstaller/extlinux_sys_bin.c diff --git a/extlinux/ext2_fs.h b/extlinux/ext2_fs.h index 1351d8cd..45f38313 100644 --- a/extlinux/ext2_fs.h +++ b/extlinux/ext2_fs.h @@ -170,14 +170,6 @@ struct ext2_group_desc { #define EXT2_FL_USER_MODIFIABLE 0x000000FF /* User modifiable flags */ /* - * 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) - -/* * Structure of an inode on the disk */ struct ext2_inode { diff --git a/extlinux/main.c b/extlinux/main.c index 6bf6872d..0669bb9c 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -57,6 +57,9 @@ typedef uint64_t u64; #include "fat.h" #include "../version.h" #include "syslxint.h" +#include "syslxcom.h" /* common functions shared with extlinux and syslinux */ +#include "setadv.h" +#include "syslxopt.h" /* unified options */ #ifdef DEBUG # define dprintf printf @@ -64,79 +67,6 @@ typedef uint64_t u64; # define dprintf(...) ((void)0) #endif -/* Global option handling */ -/* Global fs_type for handling fat, ext2/3/4 and btrfs */ -static enum filesystem { - NONE, - EXT2, - BTRFS, - VFAT, -} fs_type; - -const char *program; - -/* These are the options we can set and their values */ -struct my_options { - unsigned int sectors; - unsigned int heads; - int raid_mode; - int stupid_mode; - int reset_adv; - const char *set_once; -} opt = { -.sectors = 0,.heads = 0,.raid_mode = 0,.stupid_mode = 0,.reset_adv = - 0,.set_once = NULL,}; - -static void __attribute__ ((noreturn)) usage(int rv) -{ - fprintf(stderr, - "Usage: %s [options] directory\n" - " --install -i Install over the current bootsector\n" - " --update -U Update a previous EXTLINUX installation\n" - " --zip -z Force zipdrive geometry (-H 64 -S 32)\n" - " --sectors=# -S Force the number of sectors per track\n" - " --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" - " --clear-once -O Clear the boot-once command\n" - " --reset-adv Reset auxilliary data\n" - "\n" - " Note: geometry is determined at boot time for devices which\n" - " are considered hard disks by the BIOS. Unfortunately, this is\n" - " not possible for devices which are considered floppy disks,\n" - " 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", - program); - - exit(rv); -} - -enum long_only_opt { - OPT_NONE, - OPT_RESET_ADV, -}; - -static const struct option long_options[] = { - {"install", 0, NULL, 'i'}, - {"update", 0, NULL, 'U'}, - {"zipdrive", 0, NULL, 'z'}, - {"sectors", 1, NULL, 'S'}, - {"stupid", 0, NULL, 's'}, - {"heads", 1, NULL, 'H'}, - {"raid-mode", 0, NULL, 'r'}, - {"version", 0, NULL, 'v'}, - {"help", 0, NULL, 'h'}, - {"once", 1, NULL, 'o'}, - {"clear-once", 0, NULL, 'O'}, - {"reset-adv", 0, NULL, OPT_RESET_ADV}, - {0, 0, 0, 0} -}; - -static const char short_options[] = "iUuzS:H:rvho:O"; - #if defined(__linux__) && !defined(BLKGETSIZE64) /* This takes a u64, but the size field says size_t. Someone screwed big. */ # define BLKGETSIZE64 _IOR(0x12,114,size_t) @@ -168,169 +98,7 @@ extern unsigned int extlinux_image_len; #define boot_image extlinux_image #define boot_image_len extlinux_image_len -/* - * Common abort function - */ -void __attribute__ ((noreturn)) die(const char *msg) -{ - fputs(msg, stderr); - exit(1); -} - -/* - * read/write wrapper functions - */ -ssize_t xpread(int fd, void *buf, size_t count, off_t offset) -{ - char *bufp = (char *)buf; - ssize_t rv; - ssize_t done = 0; - - while (count) { - rv = pread(fd, bufp, count, offset); - if (rv == 0) { - die("short read"); - } else if (rv == -1) { - if (errno == EINTR) { - continue; - } else { - die(strerror(errno)); - } - } else { - bufp += rv; - offset += rv; - done += rv; - count -= rv; - } - } - - return done; -} - -ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset) -{ - const char *bufp = (const char *)buf; - ssize_t rv; - ssize_t done = 0; - - while (count) { - rv = pwrite(fd, bufp, count, offset); - if (rv == 0) { - die("short write"); - } else if (rv == -1) { - if (errno == EINTR) { - continue; - } else { - die(strerror(errno)); - } - } else { - bufp += rv; - offset += rv; - done += rv; - count -= rv; - } - } - - return done; -} - -/* - * Set and clear file attributes - */ -static void clear_attributes(int fd) -{ - struct stat st; - - if (!fstat(fd, &st)) { - switch (fs_type) { - case EXT2: - { - int flags; - - if (!ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) { - flags &= ~EXT2_IMMUTABLE_FL; - ioctl(fd, EXT2_IOC_SETFLAGS, &flags); - } - break; - } - case VFAT: - { - uint32_t attr = 0x00; /* Clear all attributes */ - ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr); - break; - } - default: - break; - } - fchmod(fd, st.st_mode | S_IWUSR); - } -} - -static void set_attributes(int fd) -{ - struct stat st; - - if (!fstat(fd, &st)) { - fchmod(fd, st.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)); - switch (fs_type) { - case EXT2: - { - int flags; - - if (st.st_uid == 0 && !ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) { - flags |= EXT2_IMMUTABLE_FL; - ioctl(fd, EXT2_IOC_SETFLAGS, &flags); - } - break; - } - case VFAT: - { - uint32_t attr = 0x07; /* Hidden+System+Readonly */ - ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr); - break; - } - default: - break; - } - } -} - -/* - * Produce file map - */ -int sectmap(int fd, uint32_t * sectors, int nsectors) -{ - unsigned int blksize, blk, nblk; - unsigned int i; - - /* Get block size */ - if (ioctl(fd, FIGETBSZ, &blksize)) - return -1; - - /* Number of sectors per block */ - blksize >>= SECTOR_SHIFT; - - nblk = 0; - while (nsectors) { - - blk = nblk++; - dprintf("querying block %u\n", blk); - if (ioctl(fd, FIBMAP, &blk)) - return -1; - - blk *= blksize; - for (i = 0; i < blksize; i++) { - if (!nsectors) - return 0; - - dprintf("Sector: %10u\n", blk); - *sectors++ = blk++; - nsectors--; - } - } - - return 0; -} +#define BTRFS_ADV_OFFSET (BTRFS_EXTLINUX_OFFSET + boot_image_len) /* * Get the size of a block device @@ -600,146 +368,6 @@ int patch_file_and_bootblock(int fd, const char *dir, int devfd) } /* - * 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, int devfd) -{ - char *file; - int fd = -1; - struct stat st; - int err = 0; - - if (fs_type == BTRFS) { /* btrfs "extlinux.sys" is in 64k blank area */ - if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, - BTRFS_EXTLINUX_OFFSET + boot_image_len) != 2 * ADV_SIZE) { - perror("writing adv"); - return 1; - } - return 0; - } - asprintf(&file, "%s%sextlinux.sys", - path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); - - 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, int devfd) -{ - unsigned char advtmp[2 * ADV_SIZE]; - char *file; - int fd = -1; - struct stat st, xst; - int err = 0; - - if (fs_type == BTRFS) { /* btrfs "extlinux.sys" is in 64k blank area */ - if (xpwrite(devfd, syslinux_adv, 2 * ADV_SIZE, - BTRFS_EXTLINUX_OFFSET + boot_image_len) != 2 * ADV_SIZE) { - perror("writing adv"); - return 1; - } - return 0; - } - asprintf(&file, "%s%sextlinux.sys", - path, path[0] && path[strlen(path) - 1] == '/' ? "" : "/"); - - 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; -} - -/* * Make any user-specified ADV modifications */ int modify_adv(void) @@ -1137,6 +765,32 @@ static int open_device(const char *path, struct stat *st, const char **_devname) return devfd; } +static int ext_read_adv(const char *path, const char *cfg, int devfd) +{ + if (fs_type == BTRFS) { /* btrfs "extlinux.sys" is in 64k blank area */ + if (xpread(devfd, syslinux_adv, 2 * ADV_SIZE, + BTRFS_ADV_OFFSET) != 2 * ADV_SIZE) { + perror("btrfs writing adv"); + return 1; + } + return 0; + } + return read_adv(path, cfg); +} + +static int ext_write_adv(const char *path, const char *cfg, int devfd) +{ + if (fs_type == BTRFS) { /* btrfs "extlinux.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); +} + int install_loader(const char *path, int update_only) { struct stat st, fst; @@ -1157,7 +811,7 @@ int install_loader(const char *path, int update_only) /* Read a pre-existing ADV, if already installed */ if (opt.reset_adv) syslinux_reset_adv(syslinux_adv); - else if (read_adv(path, devfd) < 0) { + else if (ext_read_adv(path, "extlinux.sys", devfd) < 0) { close(devfd); return 1; } @@ -1199,7 +853,7 @@ int modify_existing_adv(const char *path) if (opt.reset_adv) syslinux_reset_adv(syslinux_adv); - else if (read_adv(path, devfd) < 0) { + else if (ext_read_adv(path, "extlinux.sys", devfd) < 0) { close(devfd); return 1; } @@ -1207,7 +861,7 @@ int modify_existing_adv(const char *path) close(devfd); return 1; } - if (write_adv(path, devfd) < 0) { + if (ext_write_adv(path, "extlinux.sys", devfd) < 0) { close(devfd); return 1; } @@ -1217,83 +871,17 @@ int modify_existing_adv(const char *path) int main(int argc, char *argv[]) { - int o; - const char *directory; - int update_only = -1; - - program = argv[0]; - - while ((o = getopt_long(argc, argv, short_options, - long_options, NULL)) != EOF) { - switch (o) { - case 'z': - opt.heads = 64; - opt.sectors = 32; - break; - case 'S': - opt.sectors = strtoul(optarg, NULL, 0); - if (opt.sectors < 1 || opt.sectors > 63) { - fprintf(stderr, - "%s: invalid number of sectors: %u (must be 1-63)\n", - program, opt.sectors); - exit(EX_USAGE); - } - break; - case 'H': - opt.heads = strtoul(optarg, NULL, 0); - if (opt.heads < 1 || opt.heads > 256) { - fprintf(stderr, - "%s: invalid number of heads: %u (must be 1-256)\n", - program, opt.heads); - exit(EX_USAGE); - } - break; - case 'r': - opt.raid_mode = 1; - break; - case 's': - opt.stupid_mode = 1; - break; - case 'i': - update_only = 0; - break; - case 'u': - case 'U': - update_only = 1; - break; - case 'h': - usage(0); - break; - case 'o': - opt.set_once = optarg; - break; - case 'O': - opt.set_once = ""; - break; - case OPT_RESET_ADV: - opt.reset_adv = 1; - break; - case 'v': - fputs("extlinux " VERSION_STR - " Copyright 1994-" YEAR_STR " H. Peter Anvin \n", stderr); - exit(0); - default: - usage(EX_USAGE); - } - } - - directory = argv[optind]; + parse_options(argc, argv, 0); - if (!directory) - usage(EX_USAGE); + if (!opt.directory) + usage(EX_USAGE, 0); - if (update_only == -1) { - if (opt.reset_adv || opt.set_once) { - return modify_existing_adv(directory); - } else { - usage(EX_USAGE); - } + if (opt.update_only == -1) { + if (opt.reset_adv || opt.set_once) + return modify_existing_adv(opt.directory); + else + usage(EX_USAGE, 0); } - return install_loader(directory, update_only); + return install_loader(opt.directory, opt.update_only); } diff --git a/libinstaller/Makefile b/libinstaller/Makefile index ef3711dd..82c1990e 100644 --- a/libinstaller/Makefile +++ b/libinstaller/Makefile @@ -11,7 +11,7 @@ bootsect_bin.c: ../core/ldlinux.bss bin2c.pl $(PERL) bin2c.pl syslinux_bootsect < $< > $@ ldlinux_bin.c: ../core/ldlinux.sys bin2c.pl - $(PERL) bin2c.pl syslinux_ldlinux < $< > $@ + $(PERL) bin2c.pl syslinux_ldlinux 512 < $< > $@ extlinux_bss_bin.c: ../core/extlinux.bss bin2c.pl $(PERL) bin2c.pl extlinux_bootsect < $< > $@ diff --git a/libinstaller/setadv.c b/libinstaller/setadv.c index d18ac927..682b883e 100644 --- a/libinstaller/setadv.c +++ b/libinstaller/setadv.c @@ -19,10 +19,22 @@ * Return 0 on success, -1 on error, and set errno. * */ +#define _GNU_SOURCE +#include <stdio.h> +#include <stdlib.h> +#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" unsigned char syslinux_adv[2 * ADV_SIZE]; @@ -158,3 +170,127 @@ 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/setadv.h b/libinstaller/setadv.h new file mode 100644 index 00000000..32bdfec1 --- /dev/null +++ b/libinstaller/setadv.h @@ -0,0 +1,16 @@ +#ifndef _H_SET_ADV_ +#define _H_SET_ADV_ + +/* ADV information */ +#define ADV_SIZE 512 /* Total size */ +#define ADV_LEN (ADV_SIZE-3*4) /* Usable data size */ + +extern unsigned char syslinux_adv[2 * ADV_SIZE]; + +int syslinux_setadv(int tag, size_t size, const void *data); +void syslinux_reset_adv(unsigned char *advbuf); +int syslinux_validate_adv(unsigned char *advbuf); +int read_adv(const char *path, const char *cfg); +int write_adv(const char *path, const char *cfg); + +#endif diff --git a/libinstaller/syslinux.h b/libinstaller/syslinux.h index 8ed1edbe..8d0212c8 100644 --- a/libinstaller/syslinux.h +++ b/libinstaller/syslinux.h @@ -15,6 +15,7 @@ #include <inttypes.h> #include "advconst.h" +#include "setadv.h" /* The standard boot sector and ldlinux image */ extern unsigned char syslinux_bootsect[]; @@ -43,13 +44,4 @@ const char *syslinux_check_bootsect(const void *bs); int syslinux_patch(const uint32_t * sectors, int nsectors, int stupid, int raid_mode); -/* ADV information */ -#define ADV_SIZE 512 /* Total size */ -#define ADV_LEN (ADV_SIZE-3*4) /* Usable data size */ -extern unsigned char syslinux_adv[2 * ADV_SIZE]; - -int syslinux_setadv(int tag, size_t size, const void *data); -void syslinux_reset_adv(unsigned char *advbuf); -int syslinux_validate_adv(unsigned char *advbuf); - #endif diff --git a/libinstaller/syslxcom.c b/libinstaller/syslxcom.c new file mode 100644 index 00000000..825419b4 --- /dev/null +++ b/libinstaller/syslxcom.c @@ -0,0 +1,218 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2010 Intel Corp. - All Rights Reserved + * + * 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 + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * syslxcom.c + * + * common functions for extlinux & syslinux installer + * + */ +#define _GNU_SOURCE + +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> +#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 "syslxcom.h" + +const char *program; + +int fs_type; + +#ifdef DEBUG +# define dprintf printf +#else +# define dprintf(...) ((void)0) +#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) +{ + fputs(msg, stderr); + exit(1); +} + +/* + * read/write wrapper functions + */ +ssize_t xpread(int fd, void *buf, size_t count, off_t offset) +{ + char *bufp = (char *)buf; + ssize_t rv; + ssize_t done = 0; + + while (count) { + rv = pread(fd, bufp, count, offset); + if (rv == 0) { + die("short read"); + } else if (rv == -1) { + if (errno == EINTR) { + continue; + } else { + die(strerror(errno)); + } + } else { + bufp += rv; + offset += rv; + done += rv; + count -= rv; + } + } + + return done; +} + +ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset) +{ + const char *bufp = (const char *)buf; + ssize_t rv; + ssize_t done = 0; + + while (count) { + rv = pwrite(fd, bufp, count, offset); + if (rv == 0) { + die("short write"); + } else if (rv == -1) { + if (errno == EINTR) { + continue; + } else { + die(strerror(errno)); + } + } else { + bufp += rv; + offset += rv; + done += rv; + count -= rv; + } + } + + return done; +} + +/* + * Set and clear file attributes + */ +void clear_attributes(int fd) +{ + struct stat st; + + if (!fstat(fd, &st)) { + switch (fs_type) { + case EXT2: + { + int flags; + + if (!ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) { + flags &= ~EXT2_IMMUTABLE_FL; + ioctl(fd, EXT2_IOC_SETFLAGS, &flags); + } + break; + } + case VFAT: + { + uint32_t attr = 0x00; /* Clear all attributes */ + ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr); + break; + } + default: + break; + } + fchmod(fd, st.st_mode | S_IWUSR); + } +} + +void set_attributes(int fd) +{ + struct stat st; + + if (!fstat(fd, &st)) { + fchmod(fd, st.st_mode & (S_IRUSR | S_IRGRP | S_IROTH)); + switch (fs_type) { + case EXT2: + { + int flags; + + if (st.st_uid == 0 && !ioctl(fd, EXT2_IOC_GETFLAGS, &flags)) { + flags |= EXT2_IMMUTABLE_FL; + ioctl(fd, EXT2_IOC_SETFLAGS, &flags); + } + break; + } + case VFAT: + { + uint32_t attr = 0x07; /* Hidden+System+Readonly */ + ioctl(fd, FAT_IOCTL_SET_ATTRIBUTES, &attr); + break; + } + default: + break; + } + } +} + +/* + * Produce file map + */ +int sectmap(int fd, uint32_t * sectors, int nsectors) +{ + unsigned int blksize, blk, nblk; + unsigned int i; + + /* Get block size */ + if (ioctl(fd, FIGETBSZ, &blksize)) + return -1; + + /* Number of sectors per block */ + blksize >>= SECTOR_SHIFT; + + nblk = 0; + while (nsectors) { + + blk = nblk++; + dprintf("querying block %u\n", blk); + if (ioctl(fd, FIBMAP, &blk)) + return -1; + + blk *= blksize; + for (i = 0; i < blksize; i++) { + if (!nsectors) + return 0; + + dprintf("Sector: %10u\n", blk); + *sectors++ = blk++; + nsectors--; + } + } + + return 0; +} diff --git a/libinstaller/syslxcom.h b/libinstaller/syslxcom.h new file mode 100644 index 00000000..ba4f1d00 --- /dev/null +++ b/libinstaller/syslxcom.h @@ -0,0 +1,20 @@ +#ifndef _H_SYSLXCOM_ +#define _H_SYSLXCOM_ + +/* Global fs_type for handling fat, ext2/3/4 and btrfs */ +enum filesystem { + NONE, + EXT2, + BTRFS, + VFAT, +}; + +extern int fs_type; +extern const char *program; +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); + +#endif diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c index be06b9a2..9ab139c6 100644 --- a/libinstaller/syslxmod.c +++ b/libinstaller/syslxmod.c @@ -261,7 +261,7 @@ int syslinux_patch(const uint32_t * sectors, int nsectors, /* Set up the totals */ dw = syslinux_ldlinux_len >> 2; /* COMPLETE dwords, excluding ADV */ set_16_sl(&patcharea->data_sectors, nsect); /* Not including ADVs */ - set_16_sl(&patcharea->adv_sectors, 0); /* ADVs not supported yet */ + set_16_sl(&patcharea->adv_sectors, 2); /* ADVs need 2 sectors */ set_32_sl(&patcharea->dwords, dw); /* Set the sector pointers */ @@ -269,6 +269,7 @@ int syslinux_patch(const uint32_t * sectors, int nsectors, get_16_sl(&patcharea->secptroffset)); nptrs = get_16_sl(&patcharea->secptrcnt); + nsect += 2; while (--nsect) { /* the first sector is in bs->NextSector */ set_32_sl(wp++, *sectors++); nptrs--; diff --git a/libinstaller/syslxopt.c b/libinstaller/syslxopt.c new file mode 100644 index 00000000..7718de3a --- /dev/null +++ b/libinstaller/syslxopt.c @@ -0,0 +1,171 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2010 Intel Corp. - All Rights Reserved + * + * 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 + * the Free Software Foundation, Inc., 53 Temple Place Ste 330, + * Boston MA 02111-1307, USA; either version 2 of the License, or + * (at your option) any later version; incorporated herein by reference. + * + * ----------------------------------------------------------------------- */ + +/* + * syslxopt.c + * + * parse cmdline for extlinux and syslinux installer + * + */ +#include <stdio.h> +#include <stdlib.h> +#include <stddef.h> +#include <stdint.h> +#include <getopt.h> +#include <sysexits.h> +#include "../version.h" +#include "syslxcom.h" +#include "syslxopt.h" + +/* These are the options we can set their values */ +struct sys_options opt = { + .sectors = 0, + .heads = 0, + .raid_mode = 0, + .stupid_mode = 0, + .reset_adv = 0, + .set_once = NULL, + .update_only = -1, + .directory = NULL, + .device = NULL, + .offset = 0, +}; + +const struct option long_options[] = { + {"install", 0, NULL, 'i'}, + {"directory", 1, NULL, 'd'}, + {"offset", 1, NULL, 'f'}, + {"update", 0, NULL, 'U'}, + {"zipdrive", 0, NULL, 'z'}, + {"sectors", 1, NULL, 'S'}, + {"stupid", 0, NULL, 's'}, + {"heads", 1, NULL, 'H'}, + {"raid-mode", 0, NULL, 'r'}, + {"version", 0, NULL, 'v'}, + {"help", 0, NULL, 'h'}, + {"once", 1, NULL, 'o'}, + {"clear-once", 0, NULL, 'O'}, + {"reset-adv", 0, NULL, OPT_RESET_ADV}, + {0, 0, 0, 0} +}; + +const char short_options[] = "id:f:UuzS:H:rvho:O"; + +void __attribute__ ((noreturn)) usage(int rv, int mode) +{ + if (mode) /* for unmounted fs installation */ + fprintf(stderr, + "Usage: %s [options] device\n" + " --offset -f 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 */ + fprintf(stderr, + "Usage: %s [options] directory\n", + program); + fprintf(stderr, + " --install -i Install over the current bootsector\n" + " --update -U Update a previous EXTLINUX installation\n" + " --zip -z Force zipdrive geometry (-H 64 -S 32)\n" + " --sectors=# -S Force the number of sectors per track\n" + " --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" + " --clear-once -O Clear the boot-once command\n" + " --reset-adv Reset auxilliary data\n" + "\n" + " Note: geometry is determined at boot time for devices which\n" + " are considered hard disks by the BIOS. Unfortunately, this is\n" + " not possible for devices which are considered floppy disks,\n" + " 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" + ); + + exit(rv); +} + +void parse_options(int argc, char *argv[], int mode) +{ + int o; + + program = argv[0]; + while ((o = getopt_long(argc, argv, short_options, + long_options, NULL)) != EOF) { + switch (o) { + case 'z': + opt.heads = 64; + opt.sectors = 32; + break; + case 'S': + opt.sectors = strtoul(optarg, NULL, 0); + if (opt.sectors < 1 || opt.sectors > 63) { + fprintf(stderr, + "%s: invalid number of sectors: %u (must be 1-63)\n", + program, opt.sectors); + exit(EX_USAGE); + } + break; + case 'H': + opt.heads = strtoul(optarg, NULL, 0); + if (opt.heads < 1 || opt.heads > 256) { + fprintf(stderr, + "%s: invalid number of heads: %u (must be 1-256)\n", + program, opt.heads); + exit(EX_USAGE); + } + break; + case 'r': + opt.raid_mode = 1; + break; + case 's': + opt.stupid_mode = 1; + break; + case 'i': + opt.update_only = 0; + break; + case 'u': + case 'U': + opt.update_only = 1; + break; + case 'h': + usage(0, mode); + break; + case 'o': + opt.set_once = optarg; + break; + case 'f': + opt.offset = strtoul(optarg, NULL, 0); + case 'O': + opt.set_once = ""; + break; + case 'd': + opt.directory = optarg; + case OPT_RESET_ADV: + opt.reset_adv = 1; + break; + case 'v': + fputs(program, stderr); + fputs(" " VERSION_STR + " Copyright 1994-" YEAR_STR " H. Peter Anvin \n", stderr); + exit(0); + default: + usage(EX_USAGE, mode); + } + } + if (mode) + opt.device = argv[optind]; + else if (!opt.directory) + opt.directory = argv[optind]; +} diff --git a/libinstaller/syslxopt.h b/libinstaller/syslxopt.h new file mode 100644 index 00000000..d925fa34 --- /dev/null +++ b/libinstaller/syslxopt.h @@ -0,0 +1,30 @@ +#ifndef _H_SYSLXOPT_ +#define _H_SYSLXOPT_ + +/* These are the options we can set and their values */ +struct sys_options { + unsigned int sectors; + unsigned int heads; + int raid_mode; + int stupid_mode; + int reset_adv; + const char *set_once; + int update_only; + const char *directory; + const char *device; + unsigned int offset; +}; + +enum long_only_opt { + OPT_NONE, + OPT_RESET_ADV, +}; + +void __attribute__ ((noreturn)) usage(int rv, int mode); +void parse_options(int argc, char *argv[], int mode); + +extern struct sys_options opt; +extern const struct option long_options[]; +extern const char short_options[]; + +#endif diff --git a/linux/Makefile b/linux/Makefile index 8872c0fc..9bf56d12 100644 --- a/linux/Makefile +++ b/linux/Makefile @@ -23,6 +23,9 @@ CFLAGS = $(GCCWARN) -D_FILE_OFFSET_BITS=64 $(OPTFLAGS) $(INCLUDES) LDFLAGS = -s SRCS = syslinux.c \ + ../libinstaller/syslxopt.c \ + ../libinstaller/syslxcom.c \ + ../libinstaller/setadv.c \ ../libinstaller/syslxmod.c \ ../libinstaller/bootsect_bin.c \ ../libinstaller/ldlinux_bin.c diff --git a/linux/syslinux.c b/linux/syslinux.c index 0ac9de92..3032edce 100644 --- a/linux/syslinux.c +++ b/linux/syslinux.c @@ -72,22 +72,27 @@ # include <linux/loop.h> #endif -const char *program; /* Name of program */ -const char *device; /* Device to install to */ +#include <getopt.h> +#include <sysexits.h> +#include "syslxcom.h" +#include "setadv.h" +#include "syslxopt.h" /* unified options */ + +extern const char *program; /* Name of program */ + pid_t mypid; char *mntpath = NULL; /* Path on which to mount */ -off_t filesystem_offset = 0; /* Filesystem offset */ + +/* + * Image file + */ +#define boot_image syslinux_ldlinux +#define boot_image_len syslinux_ldlinux_len + #if DO_DIRECT_MOUNT int loop_fd = -1; /* Loop device */ #endif -void __attribute__ ((noreturn)) usage(void) -{ - fprintf(stderr, "Usage: %s [-sfr][-d directory][-o offset] device\n", - program); - exit(1); -} - void __attribute__ ((noreturn)) die(const char *msg) { fprintf(stderr, "%s: %s\n", program, msg); @@ -107,98 +112,6 @@ void __attribute__ ((noreturn)) die(const char *msg) } /* - * read/write wrapper functions - */ -ssize_t xpread(int fd, void *buf, size_t count, off_t offset) -{ - char *bufp = (char *)buf; - ssize_t rv; - ssize_t done = 0; - - while (count) { - rv = pread(fd, bufp, count, offset); - if (rv == 0) { - die("short read"); - } else if (rv == -1) { - if (errno == EINTR) { - continue; - } else { - die(strerror(errno)); - } - } else { - bufp += rv; - offset += rv; - done += rv; - count -= rv; - } - } - - return done; -} - -ssize_t xpwrite(int fd, const void *buf, size_t count, off_t offset) -{ - const char *bufp = (const char *)buf; - ssize_t rv; - ssize_t done = 0; - - while (count) { - rv = pwrite(fd, bufp, count, offset); - if (rv == 0) { - die("short write"); - } else if (rv == -1) { - if (errno == EINTR) { - continue; - } else { - die(strerror(errno)); - } - } else { - bufp += rv; - offset += rv; - done += rv; - count -= rv; - } - } - - return done; -} - -/* - * Create a block map for ldlinux.sys - */ -int make_block_map(uint32_t * sectors, int len, int dev_fd, int fd) -{ - int nsectors = 0; - int blocksize, nblock, block; - int i; - - (void)dev_fd; - - if (ioctl(fd, FIGETBSZ, &blocksize) < 0) - die("ioctl FIGETBSZ failed"); - - blocksize >>= SECTOR_SHIFT; /* sectors/block */ - - nblock = 0; - while (len > 0) { - block = nblock++; - if (ioctl(fd, FIBMAP, &block) < 0) - die("ioctl FIBMAP failed"); - - for (i = 0; i < blocksize; i++) { - if (len <= 0) - break; - - *sectors++ = (block * blocksize) + i; - nsectors++; - len -= (1 << SECTOR_SHIFT); - } - } - - return nsectors; -} - -/* * Mount routine */ int do_mount(int dev_fd, int *cookie, const char *mntpath, const char *fstype) @@ -234,7 +147,7 @@ int do_mount(int dev_fd, int *cookie, const char *mntpath, const char *fstype) } if (ioctl(loop_fd, LOOP_GET_STATUS64, &loopinfo) || - (loopinfo.lo_offset = filesystem_offset, + (loopinfo.lo_offset = opt.offset, ioctl(loop_fd, LOOP_SET_STATUS64, &loopinfo))) die("cannot set up loopback device"); } @@ -265,7 +178,7 @@ int do_mount(int dev_fd, int *cookie, const char *mntpath, const char *fstype) if (!S_ISBLK(st.st_mode)) { snprintf(mnt_opts, sizeof mnt_opts, "rw,nodev,noexec,loop,offset=%llu,umask=077,quiet", - (unsigned long long)filesystem_offset); + (unsigned long long)opt.offset); } else { snprintf(mnt_opts, sizeof mnt_opts, "rw,nodev,noexec,umask=077,quiet"); @@ -317,79 +230,76 @@ void do_umount(const char *mntpath, int cookie) #endif } +/* + * Make any user-specified ADV modifications + */ +int modify_adv(void) +{ + int rv = 0; + + 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; + } + } + + return rv; +} + +/* + * Modify the ADV of an existing installation + */ +int modify_existing_adv(const char *path) +{ + if (opt.reset_adv) + syslinux_reset_adv(syslinux_adv); + else if (read_adv(path, "ldlinux.sys") < 0) + return 1; + + if (modify_adv() < 0) + return 1; + + if (write_adv(path, "ldlinux.sys") < 0) + return 1; + + return 0; +} + int main(int argc, char *argv[]) { static unsigned char sectbuf[SECTOR_SIZE]; - unsigned char *dp; - const unsigned char *cdp; int dev_fd, fd; struct stat st; - int nb, left; int err = 0; char mntname[128]; - char *ldlinux_name, **argp, *opt; - const char *subdir = NULL; + char *ldlinux_name; + char *ldlinux_path; + const char *subdir; uint32_t *sectors = NULL; - int ldlinux_sectors; - int nsectors = 0; + int ldlinux_sectors = (boot_image_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT; const char *errmsg; int mnt_cookie; int patch_sectors; int i; - int force = 0; /* -f (force) option */ - int stupid = 0; /* -s (stupid) option */ - int raid_mode = 0; /* -r (RAID) option */ - - (void)argc; /* Unused */ - - program = argv[0]; mypid = getpid(); - - device = NULL; - umask(077); + parse_options(argc, argv, 1); - for (argp = argv + 1; *argp; argp++) { - if (**argp == '-') { - opt = *argp + 1; - if (!*opt) - usage(); - - while (*opt) { - if (*opt == 's') { - stupid = 1; - } else if (*opt == 'r') { - raid_mode = 1; - } else if (*opt == 'f') { - force = 1; /* Force install */ - } else if (*opt == 'd' && argp[1]) { - subdir = *++argp; - } else if (*opt == 'o' && argp[1]) { - /* Byte offset */ - filesystem_offset = (off_t) strtoull(*++argp, NULL, 0); - } else { - usage(); - } - opt++; - } - } else { - if (device) - usage(); - device = *argp; - } - } + subdir = opt.directory; - if (!device) - usage(); + if (!opt.device) + usage(EX_USAGE, 1); /* * First make sure we can open the device at all, and that we have * read/write permission. */ - dev_fd = open(device, O_RDWR); + dev_fd = open(opt.device, O_RDWR); if (dev_fd < 0 || fstat(dev_fd, &st) < 0) { - perror(device); + perror(opt.device); exit(1); } @@ -397,18 +307,19 @@ int main(int argc, char *argv[]) die("not a device or regular file"); } - if (filesystem_offset && S_ISBLK(st.st_mode)) { + if (opt.offset && S_ISBLK(st.st_mode)) { die("can't combine an offset with a block device"); } - xpread(dev_fd, sectbuf, SECTOR_SIZE, filesystem_offset); + fs_type = VFAT; + xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset); fsync(dev_fd); /* * Check to see that what we got was indeed an MS-DOS boot sector/superblock */ if ((errmsg = syslinux_check_bootsect(sectbuf))) { - fprintf(stderr, "%s: %s\n", device, errmsg); + fprintf(stderr, "%s: %s\n", opt.device, errmsg); exit(1); } @@ -468,15 +379,37 @@ int main(int argc, char *argv[]) die("mount failed"); } - ldlinux_name = alloca(strlen(mntpath) + 14 + - (subdir ? strlen(subdir) + 2 : 0)); + ldlinux_path = alloca(strlen(mntpath) + (subdir ? strlen(subdir) + 2 : 0)); + sprintf(ldlinux_path, "%s%s%s", + mntpath, subdir ? "//" : "", subdir ? subdir : ""); + + ldlinux_name = alloca(strlen(ldlinux_path) + 14); if (!ldlinux_name) { perror(program); err = 1; goto umount; } - sprintf(ldlinux_name, "%s%s%s//ldlinux.sys", - mntpath, subdir ? "//" : "", subdir ? subdir : ""); + sprintf(ldlinux_name, "%s//ldlinux.sys", ldlinux_path); + + /* update ADV only ? */ + if (opt.update_only == -1) { + if (opt.reset_adv || opt.set_once) { + modify_existing_adv(ldlinux_path); + do_umount(mntpath, mnt_cookie); + sync(); + rmdir(mntpath); + exit(0); + } else + usage(EX_USAGE, 0); + } + + /* Read a pre-existing ADV, if already installed */ + if (opt.reset_adv) + syslinux_reset_adv(syslinux_adv); + else if (read_adv(ldlinux_path, "ldlinux.sys") < 0) + syslinux_reset_adv(syslinux_adv); + if (modify_adv() < 0) + exit(1); if ((fd = open(ldlinux_name, O_RDONLY)) >= 0) { uint32_t zero_attr = 0; @@ -487,25 +420,17 @@ int main(int argc, char *argv[]) unlink(ldlinux_name); fd = open(ldlinux_name, O_WRONLY | O_CREAT | O_TRUNC, 0444); if (fd < 0) { - perror(device); + perror(opt.device); err = 1; goto umount; } - cdp = syslinux_ldlinux; - left = syslinux_ldlinux_len; - while (left) { - nb = write(fd, cdp, left); - if (nb == -1 && errno == EINTR) - continue; - else if (nb <= 0) { - perror(device); - err = 1; - goto umount; - } - - dp += nb; - left -= nb; + /* Write it the first time */ + if (xpwrite(fd, boot_image, boot_image_len, 0) != (int)boot_image_len || + xpwrite(fd, syslinux_adv, 2 * ADV_SIZE, + boot_image_len) != 2 * ADV_SIZE) { + fprintf(stderr, "%s: write failure on %s\n", program, ldlinux_name); + exit(1); } fsync(fd); @@ -520,10 +445,12 @@ int main(int argc, char *argv[]) /* * Create a block map. */ - ldlinux_sectors = (syslinux_ldlinux_len + SECTOR_SIZE - 1) >> SECTOR_SHIFT; + ldlinux_sectors += 2; /* 2 ADV sectors */ sectors = calloc(ldlinux_sectors, sizeof *sectors); - nsectors = make_block_map(sectors, syslinux_ldlinux_len, dev_fd, fd); - + if (sectmap(fd, sectors, ldlinux_sectors)) { + perror("bmap"); + exit(1); + } close(fd); sync(); @@ -538,15 +465,15 @@ umount: /* * Patch ldlinux.sys and the boot sector */ - i = syslinux_patch(sectors, nsectors, stupid, raid_mode); + i = syslinux_patch(sectors, ldlinux_sectors, opt.stupid_mode, opt.raid_mode); patch_sectors = (i + SECTOR_SIZE - 1) >> SECTOR_SHIFT; /* * Write the now-patched first sectors of ldlinux.sys */ for (i = 0; i < patch_sectors; i++) { - xpwrite(dev_fd, syslinux_ldlinux + i * SECTOR_SIZE, SECTOR_SIZE, - filesystem_offset + ((off_t) sectors[i] << SECTOR_SHIFT)); + xpwrite(dev_fd, boot_image + i * SECTOR_SIZE, SECTOR_SIZE, + opt.offset + ((off_t) sectors[i] << SECTOR_SHIFT)); } /* @@ -554,13 +481,13 @@ umount: */ /* Read the superblock again since it might have changed while mounted */ - xpread(dev_fd, sectbuf, SECTOR_SIZE, filesystem_offset); + xpread(dev_fd, sectbuf, SECTOR_SIZE, opt.offset); /* Copy the syslinux code into the boot sector */ syslinux_make_bootsect(sectbuf); /* Write new boot sector */ - xpwrite(dev_fd, sectbuf, SECTOR_SIZE, filesystem_offset); + xpwrite(dev_fd, sectbuf, SECTOR_SIZE, opt.offset); close(dev_fd); sync(); |