summaryrefslogtreecommitdiff
path: root/linux
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 /linux
parent38eb0724824139a81342e3f676910187bc57ba9d (diff)
downloadsyslinux-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/Makefile3
-rw-r--r--linux/syslinux.c295
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();