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 /linux | |
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>
Diffstat (limited to 'linux')
-rw-r--r-- | linux/Makefile | 3 | ||||
-rw-r--r-- | linux/syslinux.c | 295 |
2 files changed, 114 insertions, 184 deletions
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(); |