aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlek Du <alek.du@intel.com>2010-05-19 09:39:57 +0800
committerH. Peter Anvin <hpa@zytor.com>2010-05-20 19:57:46 -0700
commite4fc443f9b70f188963ff33e0a16ccb72a553540 (patch)
tree5abf92a66a5a741e61375478ae41bb3383dcec04
parent38eb0724824139a81342e3f676910187bc57ba9d (diff)
downloadsyslinux-e4fc443f9b70f188963ff33e0a16ccb72a553540.tar.gz
syslinux-e4fc443f9b70f188963ff33e0a16ccb72a553540.tar.xz
syslinux-e4fc443f9b70f188963ff33e0a16ccb72a553540.zip
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/Makefile4
-rw-r--r--extlinux/ext2_fs.h8
-rw-r--r--extlinux/main.c496
-rw-r--r--libinstaller/Makefile2
-rw-r--r--libinstaller/setadv.c136
-rw-r--r--libinstaller/setadv.h16
-rw-r--r--libinstaller/syslinux.h10
-rw-r--r--libinstaller/syslxcom.c218
-rw-r--r--libinstaller/syslxcom.h20
-rw-r--r--libinstaller/syslxmod.c3
-rw-r--r--libinstaller/syslxopt.c171
-rw-r--r--libinstaller/syslxopt.h30
-rw-r--r--linux/Makefile3
-rw-r--r--linux/syslinux.c295
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();