summaryrefslogtreecommitdiff
path: root/libinstaller
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2010-08-12 20:48:33 -0700
committerH. Peter Anvin <hpa@zytor.com>2010-08-12 20:52:53 -0700
commita104d9a4fd0762b4167668bb43eaeef10469ee9c (patch)
tree397f11badacb1c864e689a0aaaba17e051cff171 /libinstaller
parent0fb20934d2145e43f08650dbbf6613f24f2df8c6 (diff)
parentf3ab4925bd8c5c42cf17a34377f82b53b48b132e (diff)
downloadsyslinux-a104d9a4fd0762b4167668bb43eaeef10469ee9c.tar.gz
Merge branch 'master' into elflink-merge
Resolved Conflicts: core/diskfs.inc core/mem/free.c Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'libinstaller')
-rw-r--r--libinstaller/getopt/getopt.h25
-rw-r--r--libinstaller/getopt/getopt_long.c152
-rw-r--r--libinstaller/syslxint.h6
-rw-r--r--libinstaller/syslxopt.c58
-rw-r--r--libinstaller/syslxopt.h5
5 files changed, 229 insertions, 17 deletions
diff --git a/libinstaller/getopt/getopt.h b/libinstaller/getopt/getopt.h
new file mode 100644
index 00000000..a1b74b10
--- /dev/null
+++ b/libinstaller/getopt/getopt.h
@@ -0,0 +1,25 @@
+#ifndef _GETOPT_H
+#define _GETOPT_H
+
+/* (Very slightly) adapted from klibc */
+
+struct option {
+ const char *name;
+ int has_arg;
+ int *flag;
+ int val;
+};
+
+enum {
+ no_argument = 0,
+ required_argument = 1,
+ optional_argument = 2,
+};
+
+extern char *optarg;
+extern int optind, opterr, optopt;
+
+extern int getopt_long(int, char *const *, const char *,
+ const struct option *, int *);
+
+#endif /* _GETOPT_H */
diff --git a/libinstaller/getopt/getopt_long.c b/libinstaller/getopt/getopt_long.c
new file mode 100644
index 00000000..cd7fef5a
--- /dev/null
+++ b/libinstaller/getopt/getopt_long.c
@@ -0,0 +1,152 @@
+/*
+ * getopt.c
+ *
+ * getopt_long(), or at least a common subset thereof:
+ *
+ * - Option reordering is not supported
+ * - -W foo is not supported
+ * - First optstring character "-" not supported.
+ */
+
+#include <stdint.h>
+#include <string.h>
+#include <stddef.h>
+#include <getopt.h>
+
+char *optarg;
+int optind, opterr, optopt;
+static struct getopt_private_state {
+ const char *optptr;
+ const char *last_optstring;
+ char *const *last_argv;
+} pvt;
+
+static inline const char *option_matches(const char *arg_str,
+ const char *opt_name)
+{
+ while (*arg_str != '\0' && *arg_str != '=') {
+ if (*arg_str++ != *opt_name++)
+ return NULL;
+ }
+
+ if (*opt_name)
+ return NULL;
+
+ return arg_str;
+}
+
+int getopt_long(int argc, char *const *argv, const char *optstring,
+ const struct option *longopts, int *longindex)
+{
+ const char *carg;
+ const char *osptr;
+ int opt;
+
+ /* getopt() relies on a number of different global state
+ variables, which can make this really confusing if there is
+ more than one use of getopt() in the same program. This
+ attempts to detect that situation by detecting if the
+ "optstring" or "argv" argument have changed since last time
+ we were called; if so, reinitialize the query state. */
+
+ if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
+ optind < 1 || optind > argc) {
+ /* optind doesn't match the current query */
+ pvt.last_optstring = optstring;
+ pvt.last_argv = argv;
+ optind = 1;
+ pvt.optptr = NULL;
+ }
+
+ carg = argv[optind];
+
+ /* First, eliminate all non-option cases */
+
+ if (!carg || carg[0] != '-' || !carg[1])
+ return -1;
+
+ if (carg[1] == '-') {
+ const struct option *lo;
+ const char *opt_end = NULL;
+
+ optind++;
+
+ /* Either it's a long option, or it's -- */
+ if (!carg[2]) {
+ /* It's -- */
+ return -1;
+ }
+
+ for (lo = longopts; lo->name; lo++) {
+ if ((opt_end = option_matches(carg+2, lo->name)))
+ break;
+ }
+ if (!opt_end)
+ return '?';
+
+ if (longindex)
+ *longindex = lo-longopts;
+
+ if (*opt_end == '=') {
+ if (lo->has_arg)
+ optarg = (char *)opt_end+1;
+ else
+ return '?';
+ } else if (lo->has_arg == 1) {
+ if (!(optarg = argv[optind]))
+ return '?';
+ optind++;
+ }
+
+ if (lo->flag) {
+ *lo->flag = lo->val;
+ return 0;
+ } else {
+ return lo->val;
+ }
+ }
+
+ if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
+ /* Someone frobbed optind, change to new opt. */
+ pvt.optptr = carg + 1;
+ }
+
+ opt = *pvt.optptr++;
+
+ if (opt != ':' && (osptr = strchr(optstring, opt))) {
+ if (osptr[1] == ':') {
+ if (*pvt.optptr) {
+ /* Argument-taking option with attached
+ argument */
+ optarg = (char *)pvt.optptr;
+ optind++;
+ } else {
+ /* Argument-taking option with non-attached
+ argument */
+ if (argv[optind + 1]) {
+ optarg = (char *)argv[optind+1];
+ optind += 2;
+ } else {
+ /* Missing argument */
+ optind++;
+ return (optstring[0] == ':')
+ ? ':' : '?';
+ }
+ }
+ return opt;
+ } else {
+ /* Non-argument-taking option */
+ /* pvt.optptr will remember the exact position to
+ resume at */
+ if (!*pvt.optptr)
+ optind++;
+ return opt;
+ }
+ } else {
+ /* Unknown option */
+ optopt = opt;
+ if (!*pvt.optptr)
+ optind++;
+ return '?';
+ }
+}
diff --git a/libinstaller/syslxint.h b/libinstaller/syslxint.h
index f16c2e5c..14a7fc2b 100644
--- a/libinstaller/syslxint.h
+++ b/libinstaller/syslxint.h
@@ -111,8 +111,6 @@ static inline void set_64(uint64_t *p, uint64_t v)
*/
#ifdef __MSDOS__
-extern uint16_t ldlinux_seg; /* Defined in dos/syslinux.c */
-
static inline __attribute__ ((const))
uint16_t ds(void)
{
@@ -125,7 +123,7 @@ static inline void *set_fs(const void *p)
{
uint16_t seg;
- seg = ldlinux_seg + ((size_t) p >> 4);
+ seg = ds() + ((size_t) p >> 4);
asm volatile ("movw %0,%%fs"::"rm" (seg));
return (void *)((size_t) p & 0xf);
}
@@ -139,6 +137,7 @@ void set_16_sl(uint16_t * p, uint16_t v);
void set_32_sl(uint32_t * p, uint32_t v);
void set_64_sl(uint64_t * p, uint64_t v);
void memcpy_to_sl(void *dst, const void *src, size_t len);
+void memcpy_from_sl(void *dst, const void *src, size_t len);
#else
@@ -152,6 +151,7 @@ void memcpy_to_sl(void *dst, const void *src, size_t len);
#define set_32_sl(x,y) set_32(x,y)
#define set_64_sl(x,y) set_64(x,y)
#define memcpy_to_sl(d,s,l) memcpy(d,s,l)
+#define memcpy_from_sl(d,s,l) memcpy(d,s,l)
#endif
diff --git a/libinstaller/syslxopt.c b/libinstaller/syslxopt.c
index 0ff2efbb..9b42c66f 100644
--- a/libinstaller/syslxopt.c
+++ b/libinstaller/syslxopt.c
@@ -40,10 +40,14 @@ struct sys_options opt = {
.device = NULL,
.offset = 0,
.menu_save = NULL,
+ .install_mbr = 0,
+ .activate_partition = 0,
+ .force = 0,
+ .bootsecfile = NULL,
};
const struct option long_options[] = {
- {"force", 0, NULL, 'f'}, /* dummy option for compatibility */
+ {"force", 0, NULL, 'f'}, /* DOS/Win32/mtools only */
{"install", 0, NULL, 'i'},
{"directory", 1, NULL, 'd'},
{"offset", 1, NULL, 't'},
@@ -59,10 +63,12 @@ const struct option long_options[] = {
{"clear-once", 0, NULL, 'O'},
{"reset-adv", 0, NULL, OPT_RESET_ADV},
{"menu-save", 1, NULL, 'M'},
+ {"mbr", 0, NULL, 'm'}, /* DOS/Win32 only */
+ {"active", 0, NULL, 'a'}, /* DOS/Win32 only */
{0, 0, 0, 0}
};
-const char short_options[] = "t:fid:UuzS:H:rvho:OM:";
+const char short_options[] = "t:fid:UuzS:H:rvho:OM:ma";
void __attribute__ ((noreturn)) usage(int rv, enum syslinux_mode mode)
{
@@ -83,11 +89,19 @@ void __attribute__ ((noreturn)) usage(int rv, enum syslinux_mode mode)
"Usage: %s [options] directory\n",
program);
break;
+
+ case MODE_SYSLINUX_DOSWIN:
+ /* For fs installation under Windows (syslinux.exe) */
+ fprintf(stderr,
+ "Usage: %s [options] <drive>: [bootsecfile]\n"
+ " --directory -d Directory for installation target\n",
+ program);
+ break;
}
fprintf(stderr,
" --install -i Install over the current bootsector\n"
- " --update -U Update a previous EXTLINUX installation\n"
+ " --update -U Update a previous 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"
@@ -95,17 +109,22 @@ void __attribute__ ((noreturn)) usage(int rv, enum syslinux_mode mode)
" --raid -r Fall back to the next device on boot failure\n"
" --once=... %s Execute a command once upon boot\n"
" --clear-once -O Clear the boot-once command\n"
- " --reset-adv Reset auxilliary data\n"
- " --menu-save= -M Set the label to select as default on the next boot\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",
- mode == MODE_SYSLINUX ? " " : "-o");
+ " --reset-adv Reset auxilliary data\n",
+ mode == MODE_SYSLINUX ? " " : "-o");
+ /*
+ * Have to chop this roughly in half for the DOS installer due
+ * to limited output buffer size
+ */
+ fprintf(stderr,
+ " --menu-save= -M Set the label to select as default on the next boot\n");
+ if (mode == MODE_SYSLINUX_DOSWIN)
+ fprintf(stderr,
+ " --mbr -m Install an MBR\n"
+ " --active -a Mark partition as active\n");
+
+ if (mode == MODE_SYSLINUX_DOSWIN || mode == MODE_SYSLINUX)
+ fprintf(stderr,
+ " --force -f Ignore precautions\n");
exit(rv);
}
@@ -119,6 +138,7 @@ void parse_options(int argc, char *argv[], enum syslinux_mode mode)
long_options, NULL)) != EOF) {
switch (o) {
case 'f':
+ opt.force = 1;
break;
case 'z':
opt.heads = 64;
@@ -183,6 +203,12 @@ void parse_options(int argc, char *argv[], enum syslinux_mode mode)
case 'M':
opt.menu_save = optarg;
break;
+ case 'm':
+ opt.install_mbr = 1;
+ break;
+ case 'a':
+ opt.activate_partition = 1;
+ break;
case 'v':
fprintf(stderr,
"%s " VERSION_STR " Copyright 1994-" YEAR_STR
@@ -196,6 +222,7 @@ void parse_options(int argc, char *argv[], enum syslinux_mode mode)
switch (mode) {
case MODE_SYSLINUX:
+ case MODE_SYSLINUX_DOSWIN:
opt.device = argv[optind++];
break;
case MODE_EXTLINUX:
@@ -204,6 +231,9 @@ void parse_options(int argc, char *argv[], enum syslinux_mode mode)
break;
}
+ if (argv[optind] && (mode == MODE_SYSLINUX_DOSWIN))
+ /* Allow for the boot-sector argument */
+ opt.bootsecfile = argv[optind++];
if (argv[optind])
usage(EX_USAGE, mode); /* Excess arguments */
}
diff --git a/libinstaller/syslxopt.h b/libinstaller/syslxopt.h
index 446ab9af..bcbe0352 100644
--- a/libinstaller/syslxopt.h
+++ b/libinstaller/syslxopt.h
@@ -14,6 +14,10 @@ struct sys_options {
const char *device;
unsigned int offset;
const char *menu_save;
+ int force;
+ int install_mbr;
+ int activate_partition;
+ const char *bootsecfile;
};
enum long_only_opt {
@@ -25,6 +29,7 @@ enum long_only_opt {
enum syslinux_mode {
MODE_SYSLINUX, /* Unmounted filesystem */
MODE_EXTLINUX,
+ MODE_SYSLINUX_DOSWIN,
};
void __attribute__ ((noreturn)) usage(int rv, enum syslinux_mode mode);