aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatt Fleming <matt.fleming@intel.com>2013-06-13 11:46:40 +0100
committerMatt Fleming <matt.fleming@intel.com>2013-06-13 11:51:03 +0100
commit19455794d144c2c38f483890e0d384bc43b5fd63 (patch)
treea6929fba7955d1ac5455aca1328d0963d06c84e9
parentec1f4593622bef1b0bf9fdc95f55c520751240bd (diff)
downloadsyslinux-19455794d144c2c38f483890e0d384bc43b5fd63.tar.gz
syslinux-19455794d144c2c38f483890e0d384bc43b5fd63.tar.xz
syslinux-19455794d144c2c38f483890e0d384bc43b5fd63.zip
PATH: use a linked list internallysyslinux-5.11-pre1
In retrospect, choosing the colon character as the entry separator for the PATH directive was not a smart move, as that character is also used in TFTP-style paths. This conflict manifests as PXELINUX being unable to find and load files. An example dnsmasq log looks like, dnsmasq-tftp: sent /arch/boot/syslinux/lpxelinux.0 to 192.168.0.90 dnsmasq-tftp: file /arch/ldlinux.c32 not found dnsmasq-tftp: file /arch//ldlinux.c32 not found dnsmasq-tftp: file /arch//boot/isolinux/ldlinux.c32 not found dnsmasq-tftp: file /arch//isolinux/ldlinux.c32 not found dnsmasq-tftp: file /arch//boot/syslinuxldlinux.c32 not found dnsmasq-tftp: sent /arch//boot/syslinux/ldlinux.c32 to 192.168.0.90 dnsmasq-tftp: error 0 No error, file close received from 192.168.0.90 dnsmasq-tftp: failed sending /arch//boot/syslinux/ldlinux.c32 to 192.168.0.90 dnsmasq-tftp: sent /arch/boot/syslinux/archiso.cfg to 192.168.0.90 dnsmasq-tftp: sent /arch/boot/syslinux/whichsys.c32 to 192.168.0.90 dnsmasq-tftp: file /arch/libcom32.c32 not found dnsmasq-tftp: file /arch//libcom32.c32 not found dnsmasq-tftp: file /arch/libcom32.c32 not found dnsmasq-tftp: file /arch//arch//boot/syslinux/libcom32.c32 not found The last line of the log is the indication that there's a problem. Internally, Syslinux adds the location of ldlinux.c32 to PATH by querying the current working directory once ldlinux.c32 is successfully loaded. Under PXELINUX that means the initial PATH string will be, "::/arch/boot/syslinux/" The PATH parsing code doesn't know how to correctly parse the "::" string and hence, the file is searched for relative to the 210 dhcp option directory - /arch/. Implement PATH with a linked list which *greatly* simplifies the path code, and means we no longer have to parse strings backwards and forwards. Signed-off-by: Matt Fleming <matt.fleming@intel.com>
-rw-r--r--com32/elflink/ldlinux/readconfig.c60
-rw-r--r--com32/lib/sys/module/common.c36
-rw-r--r--core/elflink/load_env32.c26
-rw-r--r--core/fs/fs.c2
-rw-r--r--core/include/fs.h10
-rw-r--r--core/path.c42
6 files changed, 109 insertions, 67 deletions
diff --git a/com32/elflink/ldlinux/readconfig.c b/com32/elflink/ldlinux/readconfig.c
index 35b137ea..ab8e240d 100644
--- a/com32/elflink/ldlinux/readconfig.c
+++ b/com32/elflink/ldlinux/readconfig.c
@@ -770,6 +770,46 @@ extern void loadkeys(char *);
extern char syslinux_banner[];
extern char copyright_str[];
+/*
+ * PATH-based lookup
+ *
+ * Each entry in the PATH directive is separated by a colon, e.g.
+ *
+ * PATH /bar:/bin/foo:/baz/bar/bin
+ */
+static int parse_path(char *p)
+{
+ struct path_entry *entry;
+ const char *str;
+
+ while (*p) {
+ char *c = p;
+
+ /* Find the next directory */
+ while (*c && *c != ':')
+ c++;
+
+ str = refstrndup(p, c - p);
+ if (!str)
+ goto bail;
+
+ entry = path_add(str);
+ refstr_put(str);
+
+ if (!entry)
+ goto bail;
+
+ if (!*c++)
+ break;
+ p = c;
+ }
+
+ return 0;
+
+bail:
+ return -1;
+}
+
static void parse_config_file(FILE * f)
{
char line[MAX_LINE], *p, *ep, ch;
@@ -1337,24 +1377,8 @@ do_include:
} else if (looking_at(p, "say")) {
printf("%s\n", p+4);
} else if (looking_at(p, "path")) {
- /* PATH-based lookup */
- const char *new_path;
- char *_p;
- size_t len, new_len;
-
- new_path = refstrdup(skipspace(p + 4));
- len = strlen(PATH);
- new_len = strlen(new_path);
- _p = malloc(len + new_len + 2);
- if (_p) {
- strncpy(_p, PATH, len);
- _p[len++] = ':';
- strncpy(_p + len, new_path, new_len);
- _p[len + new_len] = '\0';
- free(PATH);
- PATH = _p;
- } else
- printf("Failed to realloc PATH\n");
+ if (parse_path(skipspace(p + 4)))
+ printf("Failed to parse PATH\n");
} else if (looking_at(p, "sendcookies")) {
const union syslinux_derivative_info *sdi;
diff --git a/com32/lib/sys/module/common.c b/com32/lib/sys/module/common.c
index 8547036b..b763704e 100644
--- a/com32/lib/sys/module/common.c
+++ b/com32/lib/sys/module/common.c
@@ -59,40 +59,28 @@ void print_elf_symbols(struct elf_module *module) {
FILE *findpath(char *name)
{
+ struct path_entry *entry;
char path[FILENAME_MAX];
FILE *f;
- char *p, *n;
- int i;
f = fopen(name, "rb"); /* for full path */
if (f)
return f;
- p = PATH;
-again:
- i = 0;
- while (*p && *p != ':' && i < FILENAME_MAX - 1) {
- path[i++] = *p++;
- }
-
- if (*p == ':')
- p++;
+ list_for_each_entry(entry, &PATH, list) {
+ bool slash = false;
- /* Ensure we have a '/' separator */
- if (path[i] != '/' && i < FILENAME_MAX - 1)
- path[i++] = '/';
+ /* Ensure we have a '/' separator */
+ if (entry->str[strlen(entry->str) - 1] != '/')
+ slash = true;
- n = name;
- while (*n && i < FILENAME_MAX - 1)
- path[i++] = *n++;
- path[i] = '\0';
+ snprintf(path, sizeof(path), "%s%s%s",
+ entry->str, slash ? "/" : "", name);
- f = fopen(path, "rb");
- if (f)
- return f;
-
- if (p >= PATH && p < PATH + strlen(PATH))
- goto again;
+ f = fopen(path, "rb");
+ if (f)
+ return f;
+ }
return NULL;
}
diff --git a/core/elflink/load_env32.c b/core/elflink/load_env32.c
index 0483d865..8551831f 100644
--- a/core/elflink/load_env32.c
+++ b/core/elflink/load_env32.c
@@ -124,14 +124,11 @@ void load_env32(com32sys_t * regs __unused)
dprintf("Starting 32 bit elf module subsystem...\n");
- PATH = malloc(strlen(CurrentDirName) + 1);
- if (!PATH) {
+ if (strlen(CurrentDirName) && !path_add(CurrentDirName)) {
printf("Couldn't allocate memory for PATH\n");
goto out;
}
- strcpy(PATH, CurrentDirName);
-
init_module_subsystem(&core_module);
start_ldlinux(1, argv);
@@ -159,30 +156,15 @@ void load_env32(com32sys_t * regs __unused)
if (!core_getcwd(path, sizeof(path)))
goto out;
- if (!strlen(PATH)) {
- PATH = realloc(PATH, strlen(path) + 1);
- if (!PATH) {
- printf("Couldn't allocate memory for PATH\n");
- goto out;
- }
-
- strcpy(PATH, path);
- } else {
- PATH = realloc(PATH, strlen(path) + strlen(PATH) + 2);
- if (!PATH) {
- printf("Couldn't allocate memory for PATH\n");
- goto out;
- }
-
- strcat(PATH, ":");
- strcat(PATH, path);
+ if (!path_add(path)) {
+ printf("Couldn't allocate memory for PATH\n");
+ goto out;
}
start_ldlinux(1, argv);
}
out:
- free(PATH);
writestr("\nFailed to load ldlinux.c32");
}
diff --git a/core/fs/fs.c b/core/fs/fs.c
index 1cb4b00a..b6ee19c2 100644
--- a/core/fs/fs.c
+++ b/core/fs/fs.c
@@ -10,8 +10,6 @@
#include "fs.h"
#include "cache.h"
-__export char *PATH;
-
/* The currently mounted filesystem */
__export struct fs_info *this_fs = NULL; /* Root filesystem */
diff --git a/core/include/fs.h b/core/include/fs.h
index c7d0fd75..b5c7f0d9 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -1,6 +1,7 @@
#ifndef FS_H
#define FS_H
+#include <linux/list.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
@@ -182,7 +183,14 @@ static inline struct file *handle_to_file(uint16_t handle)
return handle ? &files[handle-1] : NULL;
}
-extern char *PATH;
+struct path_entry {
+ struct list_head list;
+ const char *str;
+};
+
+extern struct list_head PATH;
+
+extern struct path_entry *path_add(const char *str);
/* fs.c */
void pm_mangle_name(com32sys_t *);
diff --git a/core/path.c b/core/path.c
new file mode 100644
index 00000000..8e517ca7
--- /dev/null
+++ b/core/path.c
@@ -0,0 +1,42 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2013 Intel Corporation; author: Matt Fleming
+ *
+ * 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., 51 Franklin St, Fifth Floor,
+ * Boston MA 02110-1301, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+#include <klibc/compiler.h>
+#include <linux/list.h>
+#include <fs.h>
+#include <string.h>
+
+__export LIST_HEAD(PATH);
+
+__export struct path_entry *path_add(const char *str)
+{
+ struct path_entry *entry;
+
+ if (!strlen(str))
+ return NULL;
+
+ entry = malloc(sizeof(*entry));
+ if (!entry)
+ return NULL;
+
+ entry->str = strdup(str);
+ if (!entry->str)
+ goto bail;
+
+ list_add(&entry->list, &PATH);
+
+ return entry;
+
+bail:
+ free(entry);
+ return NULL;
+}