[syslinux:elflink] ldlinux: Loading a config file should cause re-initialisation

syslinux-bot for Matt Fleming matt.fleming at intel.com
Mon Mar 26 15:36:05 PDT 2012


Commit-ID:  3a316db137afe3b4c9d7f04fcf47921f509ef36c
Gitweb:     http://www.syslinux.org/commit/3a316db137afe3b4c9d7f04fcf47921f509ef36c
Author:     Matt Fleming <matt.fleming at intel.com>
AuthorDate: Tue, 13 Mar 2012 09:37:57 +0000
Committer:  Matt Fleming <matt.fleming at intel.com>
CommitDate: Fri, 23 Mar 2012 16:56:15 +0000

ldlinux: Loading a config file should cause re-initialisation

There are a number of initialisation steps that need to be performed
*every* time a config file is loaded. Reload ldlinux.c32 so that we
can re-initialise the environment whenever a new config file is
loaded. This involves unloading all the modules that have been loaded
since ldlinux.c32. Luckily the list of loaded modules is sorted by
load order, which means it's trivial to "pop" them from the front of
the list.

Signed-off-by: Matt Fleming <matt.fleming at intel.com>

---
 com32/elflink/ldlinux/execute.c   |   14 +++++++---
 com32/elflink/ldlinux/ldlinux.c   |    6 ++++-
 com32/include/linux/list.h        |   13 ++++++++++
 com32/include/sys/module.h        |    6 ++++
 com32/lib/sys/module/elf_module.c |    4 +-
 core/elflink/config.c             |   41 -------------------------------
 core/elflink/load_env32.c         |   48 +++++++++++++++++++++++++++++++++++-
 7 files changed, 82 insertions(+), 50 deletions(-)

diff --git a/com32/elflink/ldlinux/execute.c b/com32/elflink/ldlinux/execute.c
index 2b265a1..c01d63f 100644
--- a/com32/elflink/ldlinux/execute.c
+++ b/com32/elflink/ldlinux/execute.c
@@ -19,6 +19,7 @@
 #include <sys/exec.h>
 #include "core.h"
 #include "menu.h"
+#include "fs.h"
 
 /* Must match enum kernel_type */
 const char *const kernel_types[] = {
@@ -74,8 +75,10 @@ void execute(const char *cmdline, enum kernel_type type)
 		/* It might be a type specifier */
 		enum kernel_type type = KT_NONE;
 		for (pp = kernel_types; *pp; pp++, type++) {
-			if (!strcmp(kernel + 1, *pp))
-				execute(p, type);	/* Strip the type specifier and retry */
+			if (!strcmp(kernel + 1, *pp)) {
+				/* Strip the type specifier and retry */
+				execute(p, type);
+			}
 		}
 	}
 
@@ -88,9 +91,12 @@ void execute(const char *cmdline, enum kernel_type type)
 		* the assembly runkernel.inc any more */
 		new_linux_kernel(kernel, cmdline);
 	} else if (type == KT_CONFIG) {
+		char *argv[] = { "ldlinux.c32", NULL };
+
 		/* kernel contains the config file name */
-		char *spawn_load_param[2] = { args, NULL };
-		spawn_load(kernel, 1, spawn_load_param);
+		realpath(ConfigName, kernel, FILENAME_MAX);
+
+		start_ldlinux("ldlinux.c32", 1, argv);
 	} else {
 		/* process the image need int 22 support */
 		if (type == KT_LOCALBOOT) {
diff --git a/com32/elflink/ldlinux/ldlinux.c b/com32/elflink/ldlinux/ldlinux.c
index 03e2f60..6c306ad 100644
--- a/com32/elflink/ldlinux/ldlinux.c
+++ b/com32/elflink/ldlinux/ldlinux.c
@@ -118,10 +118,14 @@ int main(int argc, char **argv)
 	com32sys_t ireg, oreg;
 	uint8_t *adv;
 	int count = 0;
+	char *config_argv[2] = { NULL, NULL };
 
 	openconsole(&dev_rawcon_r, &dev_ansiserial_w);
 
-	parse_configs(NULL);
+	if (ConfigName[0])
+		config_argv[0] = ConfigName;
+
+	parse_configs(config_argv);
 
 	__syslinux_init();
 	adv = syslinux_getadv(ADV_BOOTONCE, &count);
diff --git a/com32/include/linux/list.h b/com32/include/linux/list.h
index 3b92e25..afe8980 100644
--- a/com32/include/linux/list.h
+++ b/com32/include/linux/list.h
@@ -338,6 +338,19 @@ static inline void list_splice_init(struct list_head *list,
 	     pos = list_entry(pos->member.next, typeof(*pos), member))
 
 /**
+ * list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
+* @pos:        the type * to use as a loop cursor.
+* @n:          another type * to use as temporary storage
+* @head:       the head for your list.
+* @member:     the name of the list_struct within the struct.
+*/
+#define list_for_each_entry_safe(pos, n, head, member)                  \
+	for (pos = list_entry((head)->next, typeof(*pos), member),      \
+		n = list_entry(pos->member.next, typeof(*pos), member); \
+             &pos->member != (head);					\
+             pos = n, n = list_entry(n->member.next, typeof(*n), member))
+
+/**
  * list_for_each_entry_reverse - iterate backwards over list of given type.
  * @pos:	the type * to use as a loop cursor.
  * @head:	the head for your list.
diff --git a/com32/include/sys/module.h b/com32/include/sys/module.h
index d10eae9..a9ddb60 100644
--- a/com32/include/sys/module.h
+++ b/com32/include/sys/module.h
@@ -199,6 +199,12 @@ extern struct list_head modules_head;
 #define for_each_module(m)	list_for_each_entry(m, &modules_head, list)
 
 /**
+ * for_each_module - iterator loop through the list of loaded modules safe against removal.
+ */
+#define for_each_module_safe(m, n)				\
+	list_for_each_entry_safe(m, n, &modules_head, list)
+
+/**
  * modules_init - initialize the module subsystem.
  *
  * This function must be called before any module operation is to be performed.
diff --git a/com32/lib/sys/module/elf_module.c b/com32/lib/sys/module/elf_module.c
index ffdcd52..6b4d548 100644
--- a/com32/lib/sys/module/elf_module.c
+++ b/com32/lib/sys/module/elf_module.c
@@ -5,7 +5,7 @@
  *      Author: Stefan Bucur <stefanb at zytor.com>
  */
 
-
+#include <errno.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdio.h>
@@ -475,7 +475,7 @@ int module_load(struct elf_module *module) {
 	// Do not allow duplicate modules
 	if (module_find(module->name) != NULL) {
 		DBG_PRINT("Module %s is already loaded.\n", module->name);
-		return -1;
+		return EEXIST;
 	}
 
 	// Get a mapping/copy of the ELF file in memory
diff --git a/core/elflink/config.c b/core/elflink/config.c
deleted file mode 100644
index b27aa82..0000000
--- a/core/elflink/config.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/* ----------------------------------------------------------------------- *
- *
- *   Copyright 2007-2008 H. Peter Anvin - All Rights Reserved
- *
- *   Permission is hereby granted, free of charge, to any person
- *   obtaining a copy of this software and associated documentation
- *   files (the "Software"), to deal in the Software without
- *   restriction, including without limitation the rights to use,
- *   copy, modify, merge, publish, distribute, sublicense, and/or
- *   sell copies of the Software, and to permit persons to whom
- *   the Software is furnished to do so, subject to the following
- *   conditions:
- *
- *   The above copyright notice and this permission notice shall
- *   be included in all copies or substantial portions of the Software.
- *
- *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
- *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
- *   OTHER DEALINGS IN THE SOFTWARE.
- *
- * ----------------------------------------------------------------------- */
-
-#include <syslinux/config.h>
-#include <klibc/compiler.h>
-#include <com32.h>
-
-const char *__syslinux_config_file;
-
-void __constructor __syslinux_get_config_file_name(void)
-{
-    static com32sys_t reg;
-
-    reg.eax.w[0] = 0x000e;
-    __intcall(0x22, &reg, &reg);
-    __syslinux_config_file = MK_PTR(reg.es, reg.ebx.w[0]);
-}
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
index 7ffe185..75f5629 100644
--- a/core/elflink/load_env32.c
+++ b/core/elflink/load_env32.c
@@ -71,6 +71,50 @@ static void call_constr(void)
 		(*p) ();
 }
 
+int start_ldlinux(char **argv)
+{
+	int rv;
+
+again:
+	rv = spawn_load(LDLINUX, 1, argv);
+	if (rv == EEXIST) {
+		struct elf_module *m, *mod, *begin = NULL;
+
+		/*
+		 * If a COM32 module calls execute() we may need to
+		 * unload all the modules loaded since ldlinux.c32,
+		 * and restart initialisation. This is especially
+		 * important for config files.
+		 */
+		for_each_module(mod) {
+			if (!strcmp(mod->name, LDLINUX)) {
+				begin = mod;
+				break;
+			}
+		}
+
+		for_each_module_safe(mod, m) {
+			if (mod == begin)
+				break;
+
+			if (mod != begin)
+				module_unload(mod);
+		}
+
+		/*
+		 * Finally unload LDLINUX.
+		 *
+		 * We'll reload it when we jump to 'again' which will
+		 * cause all the initialsation steps to be executed
+		 * again.
+		 */
+		module_unload(begin);
+		goto again;
+	}
+
+	return rv;
+}
+
 /* note to self: do _*NOT*_ use static key word on this function */
 void load_env32(com32sys_t * regs)
 {
@@ -97,7 +141,7 @@ void load_env32(com32sys_t * regs)
 
 	init_module_subsystem(&core_module);
 
-	spawn_load(LDLINUX, 1, argv);
+	start_ldlinux(argv);
 
 	/*
 	 * If we failed to load LDLINUX it could be because our
@@ -112,7 +156,7 @@ void load_env32(com32sys_t * regs)
 	fp = &__file_info[fd];
 
 	if (!search_config(&fp->i.fd, search_directories, filenames))
-		spawn_load(LDLINUX, 1, argv);
+		start_ldlinux(argv);
 }
 
 int create_args_and_load(char *cmdline)


More information about the Syslinux-commits mailing list