summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2010-02-13 23:42:59 -0800
committerH. Peter Anvin <hpa@zytor.com>2010-02-13 23:45:02 -0800
commit3399f97a70cdca0cb05129ea3fb5e9dd42c35d9c (patch)
tree529fd2403efa2dc6177495a827a64c776518d1de
parent3db9073fdd604c253ab0ea0ce83373dc89f633f3 (diff)
downloadsyslinux-3399f97a70cdca0cb05129ea3fb5e9dd42c35d9c.tar.gz
fs: move to a chdir()-based mechanism for managing cwdsyslinux-4.00-pre19
Introduce a chdir() system and a way to obtain absolute pathnames. This should allow us to set the current base directory (filename prefix for PXE) without breaking access to the configuration file. As a side benefit, for the "normal" filesystems we no longer need magic hacks to figure out where we should set our current working directory. Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--core/chdir.c66
-rw-r--r--core/comboot.inc4
-rw-r--r--core/extern.inc7
-rw-r--r--core/fs.c104
-rw-r--r--core/fs/ext2/ext2.c18
-rw-r--r--core/fs/fat/fat.c55
-rw-r--r--core/fs/iso9660/iso9660.c30
-rw-r--r--core/fs/lib/loadconfig.c21
-rw-r--r--core/fs/pxe/dhcp_option.c2
-rw-r--r--core/fs/pxe/dnsresolv.c1
-rw-r--r--core/fs/pxe/pxe.c382
-rw-r--r--core/getc.inc2
-rw-r--r--core/include/fs.h53
-rw-r--r--core/parseconfig.inc2
-rw-r--r--core/pxelinux.asm2
-rw-r--r--core/readdir.c (renamed from core/dir.c)2
-rw-r--r--core/runkernel.inc2
-rw-r--r--core/ui.inc12
18 files changed, 412 insertions, 353 deletions
diff --git a/core/chdir.c b/core/chdir.c
new file mode 100644
index 00000000..c5c4d589
--- /dev/null
+++ b/core/chdir.c
@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include "fs.h"
+#include "cache.h"
+
+/*
+ * Convert a relative pathname to an absolute pathname
+ * In the future this might also resolve symlinks...
+ */
+void pm_realpath(com32sys_t *regs)
+{
+ const char *src = MK_PTR(regs->ds, regs->esi.w[0]);
+ char *dst = MK_PTR(regs->es, regs->edi.w[0]);
+
+ realpath(dst, src, FILENAME_MAX);
+}
+
+size_t realpath(char *dst, const char *src, size_t bufsize)
+{
+ if (this_fs->fs_ops->realpath) {
+ return this_fs->fs_ops->realpath(this_fs, dst, src, bufsize);
+ } else {
+ /* Filesystems with "common" pathname resolution */
+ return snprintf(dst, bufsize, "%s%s",
+ src[0] == '/' ? "" : this_fs->cwd_name,
+ src);
+ }
+}
+
+int chdir(const char *src)
+{
+ int rv;
+ struct file *file;
+ char *p;
+
+ if (this_fs->fs_ops->chdir)
+ return this_fs->fs_ops->chdir(this_fs, src);
+
+ /* Otherwise it is a "conventional filesystem" */
+ rv = searchdir(src);
+ if (rv < 0)
+ return rv;
+
+ file = handle_to_file(rv);
+ if (file->inode->mode != I_DIR) {
+ _close_file(file);
+ return -1;
+ }
+
+ this_fs->cwd = file->inode;
+ file->inode = NULL; /* "Steal" the inode */
+ _close_file(file);
+
+ /* Save the current working directory */
+ realpath(this_fs->cwd_name, src, CURRENTDIR_MAX);
+ p = strchr(this_fs->cwd_name, '\0');
+
+ /* Make sure the cwd_name ends in a slash, it's supposed to be a prefix */
+ if (p < this_fs->cwd_name + CURRENTDIR_MAX - 1 &&
+ (p == this_fs->cwd_name || p[1] != '/')) {
+ p[0] = '/';
+ p[1] = '\0';
+ }
+ return 0;
+}
diff --git a/core/comboot.inc b/core/comboot.inc
index 03507c89..e271b9ec 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -519,7 +519,7 @@ comapi_open:
mov di,InitRD
pm_call mangle_name
pop ds
- pm_call searchdir
+ pm_call pm_searchdir
jz comapi_err
mov P_EAX,eax
mov P_CX,SECTOR_SIZE
@@ -751,7 +751,7 @@ comapi_runkernel:
mov di,KernelName
pm_call mangle_name
pop ds
- pm_call searchdir
+ pm_call pm_searchdir
jz comapi_err
; The kernel image was found, so we can load it...
diff --git a/core/extern.inc b/core/extern.inc
index 95a9c88d..da6c675b 100644
--- a/core/extern.inc
+++ b/core/extern.inc
@@ -13,10 +13,13 @@
extern hello
; fs.c
- extern fs_init, searchdir, getfssec, mangle_name, load_config
+ extern fs_init, pm_searchdir, getfssec, mangle_name, load_config
extern unmangle_name, close_file
- ; dir.c
+ ; chdir.c
+ extern pm_realpath
+
+ ; readdir.c
extern opendir, readdir, closedir
%if IS_PXELINUX
; pxe.c
diff --git a/core/fs.c b/core/fs.c
index ecd5257d..6acfd3be 100644
--- a/core/fs.c
+++ b/core/fs.c
@@ -1,23 +1,17 @@
#include <stdio.h>
#include <stdbool.h>
#include <string.h>
-#include <fs.h>
-#include <cache.h>
+#include "fs.h"
+#include "cache.h"
/* The currently mounted filesystem */
struct fs_info *this_fs = NULL; /* Root filesystem */
-static struct fs_info fs;
static struct inode *this_inode = NULL; /* Current working directory */
/* Actual file structures (we don't have malloc yet...) */
struct file files[MAX_OPEN];
/*
- * Set to FS_THISIND during the execution of load_config.
- */
-enum fs_flags is_load_config = 0;
-
-/*
* Get a new inode structure
*/
struct inode *alloc_inode(struct fs_info *fs, uint32_t ino, size_t data)
@@ -65,26 +59,15 @@ void _close_file(struct file *file)
/*
* Convert between a 16-bit file handle and a file structure
*/
-inline uint16_t file_to_handle(struct file *file)
-{
- return file ? (file - files)+1 : 0;
-}
-inline struct file *handle_to_file(uint16_t handle)
-{
- return handle ? &files[handle-1] : NULL;
-}
void load_config(void)
{
int err;
- is_load_config = FS_THISIND;
err = this_fs->fs_ops->load_config();
- is_load_config = 0;
-#if 0
- printf("Loading config file %s\n", err ? "failed" : "successed");
-#endif
+ if (err)
+ printf("ERROR: No configuration file found\n");
}
void mangle_name(com32sys_t *regs)
@@ -107,7 +90,6 @@ void unmangle_name(com32sys_t *regs)
regs->edi.w[0] = OFFS_WRT(dst, regs->es);
}
-
void getfssec(com32sys_t *regs)
{
int sectors;
@@ -137,16 +119,32 @@ void getfssec(com32sys_t *regs)
regs->ecx.l = bytes_read;
}
-
-void searchdir(com32sys_t *regs)
+void pm_searchdir(com32sys_t *regs)
{
char *name = MK_PTR(regs->ds, regs->edi.w[0]);
+ int rv;
+
+ rv = searchdir(name);
+ if (rv < 0) {
+ regs->esi.w[0] = 0;
+ regs->eax.l = 0;
+ regs->eflags.l |= EFLAGS_ZF;
+ } else {
+ regs->esi.w[0] = rv;
+ regs->eax.l = handle_to_file(rv)->file_len;
+ regs->eflags.l &= ~EFLAGS_ZF;
+ }
+}
+
+int searchdir(const char *name)
+{
struct inode *inode;
struct inode *parent;
struct file *file;
char part[256];
char *p;
int symlink_count = 6;
+ bool got_parent;
#if 0
printf("filename: %s\n", name);
@@ -160,26 +158,22 @@ void searchdir(com32sys_t *regs)
if (file->fs->fs_ops->searchdir) {
file->fs->fs_ops->searchdir(name, file);
- if (file->open_file) {
- regs->esi.w[0] = file_to_handle(file);
- regs->eax.l = file->file_len;
- regs->eflags.l &= ~EFLAGS_ZF;
- return;
- }
-
- goto err;
+ if (file->open_file)
+ return file_to_handle(file);
+ else
+ goto err;
}
-
/* else, try the generic-path-lookup method */
if (*name == '/') {
inode = this_fs->fs_ops->iget_root(this_fs);
- while(*name == '/')
+ while (*name == '/')
name++;
} else {
- inode = this_inode;
+ inode = this_fs->cwd;
}
parent = inode;
+ got_parent = false;
while (*name) {
p = part;
@@ -199,20 +193,10 @@ void searchdir(com32sys_t *regs)
free_inode(inode);
continue;
}
-
- /*
- * For the relative path searching used in FAT and ISO fs.
- */
- if ((this_fs->fs_ops->fs_flags & is_load_config) &&
- (this_inode != parent)){
- if (this_inode)
- free_inode(this_inode);
- this_inode = parent;
- }
-
- if (parent != this_inode)
+ if (got_parent)
free_inode(parent);
parent = inode;
+ got_parent = true;
}
if (!*name)
break;
@@ -220,20 +204,19 @@ void searchdir(com32sys_t *regs)
name++;
}
+ if (got_parent)
+ free_inode(parent);
+
file->inode = inode;
file->offset = 0;
+ file->file_len = inode->size;
- regs->esi.w[0] = file_to_handle(file);
- regs->eax.l = inode->size;
- regs->eflags.l &= ~EFLAGS_ZF;
- return;
+ return file_to_handle(file);
err:
_close_file(file);
-err_no_close:
- regs->esi.w[0] = 0;
- regs->eax.l = 0;
- regs->eflags.l |= EFLAGS_ZF;
+err_no_close:
+ return -1;
}
void close_file(com32sys_t *regs)
@@ -259,6 +242,7 @@ void close_file(com32sys_t *regs)
*/
void fs_init(com32sys_t *regs)
{
+ static struct fs_info fs; /* The actual filesystem buffer */
uint8_t disk_devno = regs->edx.b[0];
uint8_t disk_cdrom = regs->edx.b[1];
sector_t disk_offset = regs->ecx.l | ((sector_t)regs->ebx.l << 32);
@@ -271,6 +255,9 @@ void fs_init(com32sys_t *regs)
/* Initialize malloc() */
mem_init();
+
+ /* Default name for the root directory */
+ fs.cwd_name[0] = '/';
while ((blk_shift < 0) && *ops) {
/* set up the fs stucture */
@@ -303,8 +290,7 @@ void fs_init(com32sys_t *regs)
if (fs.fs_dev && fs.fs_dev->cache_data)
cache_init(fs.fs_dev, blk_shift);
- if (fs.fs_ops->iget_current)
- this_inode = fs.fs_ops->iget_current(&fs);
- else
- this_inode = fs.fs_ops->iget_root(&fs); /* Will be set later */
+ /* start out in the root directory */
+ if (fs.fs_ops->iget_root)
+ fs.cwd = fs.fs_ops->iget_root(&fs);
}
diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c
index 9cdbb3b7..c794300b 100644
--- a/core/fs/ext2/ext2.c
+++ b/core/fs/ext2/ext2.c
@@ -386,21 +386,6 @@ static struct dirent * ext2_readdir(struct file *file)
return dirent;
}
-/* Load the config file, return 1 if failed, or 0 */
-static int ext2_load_config(void)
-{
- char *config_name = "extlinux.conf";
- com32sys_t regs;
-
- memset(&regs, 0, sizeof regs);
- snprintf(ConfigName, FILENAME_MAX, "%s/extlinux.conf", CurrentDirName);
- regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
- call16(core_open, &regs, &regs);
-
- return !!(regs.eflags.l & EFLAGS_ZF);
-}
-
-
/*
* init. the fs meta data, return the block size bits.
*/
@@ -458,9 +443,8 @@ const struct fs_ops ext2_fs_ops = {
.close_file = ext2_close_file,
.mangle_name = generic_mangle_name,
.unmangle_name = generic_unmangle_name,
- .load_config = ext2_load_config,
+ .load_config = generic_load_config,
.iget_root = ext2_iget_root,
- .iget_current = NULL,
.iget = ext2_iget,
.follow_symlink = ext2_follow_symlink,
.readdir = ext2_readdir
diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c
index c388dba7..97dd715c 100644
--- a/core/fs/fat/fat.c
+++ b/core/fs/fat/fat.c
@@ -741,45 +741,33 @@ got:
/* Load the config file, return 1 if failed, or 0 */
static int vfat_load_config(void)
{
- const char * const syslinux_cfg[] = {
- "/boot/syslinux/syslinux.cfg",
- "/syslinux/syslinux.cfg",
- "/syslinux.cfg"
+ const char *search_directories[] = {
+ "/boot/syslinux",
+ "/syslinux",
+ "/",
+ NULL
};
com32sys_t regs;
- char *p;
- int i = 0;
+ int i;
- /*
- * we use the ConfigName to pass the config path because
- * it is under the address 0xffff
- */
- memset(&regs, 0, sizeof regs);
- regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
- if (*CurrentDirName) { /* installed by extlinux not syslinux */
- sprintf(ConfigName, "%s/extlinux.conf", CurrentDirName);
- call16(core_open, &regs, &regs);
- return regs.eflags.l & EFLAGS_ZF;
- }
- /* installed by syslinux */
- for (; i < 3; i++) {
- strcpy(ConfigName, syslinux_cfg[i]);
- call16(core_open, &regs, &regs);
+ /* If installed by extlinux, try the extlinux filename */
+ if (*CurrentDirName && !generic_load_config())
+ return 0;
- /* if zf flag set, then failed; try another */
- if (! (regs.eflags.l & EFLAGS_ZF))
- break;
- }
- if (i == 3) {
- printf("no config file found\n");
- return 1; /* no config file */
+ for (i = 0; search_directories[i]; i++) {
+ memset(&regs, 0, sizeof regs);
+ snprintf(ConfigName, FILENAME_MAX, "%s/syslinux.cfg",
+ search_directories[i]);
+ regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
+ call16(core_open, &regs, &regs);
+ if (!(regs.eflags.l & EFLAGS_ZF))
+ break;
}
+ if (!search_directories[i])
+ return -1;
- strcpy(ConfigName, "syslinux.cfg");
- strcpy(CurrentDirName, syslinux_cfg[i]);
- p = strrchr(CurrentDirName, '/');
- *(p + 1) = '\0'; /* In case we met '/syslinux.cfg' */
-
+ /* Set the current working directory */
+ chdir(search_directories[i]);
return 0;
}
@@ -864,6 +852,5 @@ const struct fs_ops vfat_fs_ops = {
.load_config = vfat_load_config,
.readdir = vfat_readdir,
.iget_root = vfat_iget_root,
- .iget_current = NULL,
.iget = vfat_iget,
};
diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c
index e6911644..06caedd9 100644
--- a/core/fs/iso9660/iso9660.c
+++ b/core/fs/iso9660/iso9660.c
@@ -382,32 +382,29 @@ static struct dirent *iso_readdir(struct file *file)
/* Load the config file, return 1 if failed, or 0 */
static int iso_load_config(void)
{
- const char *config_file[] = {
- "/boot/isolinux/isolinux.cfg",
- "/isolinux/isolinux.cfg"
+ const char *search_directories[] = {
+ "/boot/isolinux",
+ "/isolinux",
+ "/",
+ NULL
};
com32sys_t regs;
- int i = 0;
- char *p;
+ int i;
- for (; i < 2; i++) {
+ for (i = 0; search_directories[i]; i++) {
memset(&regs, 0, sizeof regs);
- strcpy(ConfigName, config_file[i]);
+ snprintf(ConfigName, FILENAME_MAX, "%s/isolinux.cfg",
+ search_directories[i]);
regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
call16(core_open, &regs, &regs);
if (!(regs.eflags.l & EFLAGS_ZF))
break;
}
- if (i == 2) {
- printf("No config file found\n");
- return 1;
- }
-
- strcpy(ConfigName, "isolinux.cfg");
- strcpy(CurrentDirName, config_file[i]);
- p = strrchr(CurrentDirName, '/');
- *p = '\0';
+ if (!search_directories[i])
+ return -1;
+ /* Set the current working directory */
+ chdir(search_directories[i]);
return 0;
}
@@ -446,7 +443,6 @@ const struct fs_ops iso_fs_ops = {
.unmangle_name = generic_unmangle_name,
.load_config = iso_load_config,
.iget_root = iso_iget_root,
- .iget_current = NULL,
.iget = iso_iget,
.readdir = iso_readdir
};
diff --git a/core/fs/lib/loadconfig.c b/core/fs/lib/loadconfig.c
new file mode 100644
index 00000000..da2ba50c
--- /dev/null
+++ b/core/fs/lib/loadconfig.c
@@ -0,0 +1,21 @@
+#include <stdio.h>
+#include <string.h>
+#include <core.h>
+#include <fs.h>
+
+/*
+ * Standard version of load_config for extlinux-installed filesystems
+ */
+int generic_load_config(void)
+{
+ com32sys_t regs;
+
+ chdir(CurrentDirName);
+
+ memset(&regs, 0, sizeof regs);
+ snprintf(ConfigName, FILENAME_MAX, "%s/extlinux.conf", CurrentDirName);
+ regs.edi.w[0] = OFFS_WRT(ConfigName, 0);
+ call16(core_open, &regs, &regs);
+
+ return (regs.eflags.l & EFLAGS_ZF) ? -1 : 0;
+}
diff --git a/core/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c
index 0787078a..150290ae 100644
--- a/core/fs/pxe/dhcp_option.c
+++ b/core/fs/pxe/dhcp_option.c
@@ -130,7 +130,7 @@ static void pxelinux_configfile(void *data, int opt_len)
ConfigName[opt_len] = 0;
}
-static void pxelinux_pathprefix(void *data,int opt_len)
+static void pxelinux_pathprefix(void *data, int opt_len)
{
DHCPMagic |= 4;
strncpy(path_prefix, data, opt_len);
diff --git a/core/fs/pxe/dnsresolv.c b/core/fs/pxe/dnsresolv.c
index 15560447..18cfc486 100644
--- a/core/fs/pxe/dnsresolv.c
+++ b/core/fs/pxe/dnsresolv.c
@@ -168,6 +168,7 @@ static char *dns_skiplabel(char *label)
* and returns the ip addr in _ip_ if it exists and can be found.
* If _ip_ = 0 on exit, the lookup failed. _name_ will be updated
*
+ * XXX: probably need some caching here.
*/
uint32_t dns_resolv(const char *name)
{
diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c
index ea26ef61..56f8ee41 100644
--- a/core/fs/pxe/pxe.c
+++ b/core/fs/pxe/pxe.c
@@ -19,8 +19,8 @@ char MAC[MAC_MAX + 1]; /* Actual MAC address */
uint8_t MAC_len; /* MAC address len */
uint8_t MAC_type; /* MAC address type */
-char boot_file[256];
-char path_prefix[256];
+char boot_file[256]; /* From DHCP */
+char path_prefix[256]; /* From DHCP */
char dot_quad_buf[16];
static struct open_file_t Files[MAX_OPEN];
@@ -229,11 +229,11 @@ static int gendotquad(char *dst, uint32_t ip)
static const char *parse_dotquad(const char *ip_str, uint32_t *res)
{
const char *p = ip_str;
- int i = 0;
uint8_t part = 0;
- uint32_t ip = 0;
+ uint32_t ip = 0;
+ int i;
- for (; i < 4; i++) {
+ for (i = 0; i < 4; i++) {
while (is_digit(*p)) {
part = part * 10 + *p - '0';
p++;
@@ -245,7 +245,7 @@ static const char *parse_dotquad(const char *ip_str, uint32_t *res)
part = 0;
p++;
}
- p --;
+ p--;
*res = ip;
return p;
@@ -365,42 +365,50 @@ static int pxe_get_cached_info(int type)
}
-
-#if GPXE
-
/*
- * Return true if and only if the buffer pointed to by
- * url is a URL -- it must contain :// and it must be the
- * first colon.
+ * Return the type of pathname passed.
*/
-static inline bool is_url(const char *url)
-{
- const char *p = strchr(url, ':');
-
- return p && p[1] == '/' && p[2] == '/';
-}
-
+enum pxe_path_type {
+ PXE_RELATIVE, /* No :: or URL */
+ PXE_HOMESERVER, /* Starting with :: */
+ PXE_TFTP, /* host:: */
+ PXE_URL, /* Absolute URL syntax */
+};
-/*
- * Return CF=0 if and only if the buffer pointed to by DS:SI is a URL
- * (contains ://) *and* the gPXE extensions API is available. No
- * registers modified.
- */
-static bool is_gpxe(const char *url)
+static enum pxe_path_type pxe_path_type(const char *str)
{
- static bool already;
-
- if (!is_url(url))
- return false;
-
- if (!has_gpxe && !already) {
- fputs("URL syntax, but gPXE extensions not detected, tring plain TFTP...\n", stdout);
- already = true;
+ const char *p;
+
+ p = str;
+ while (1) {
+ switch (*p) {
+ case ':':
+ if (p[1] == ':') {
+ if (p == str)
+ return PXE_HOMESERVER;
+ else
+ return PXE_TFTP;
+ } else if (p > str && p[1] == '/' && p[2] == '/')
+ return PXE_URL;
+
+ /* else fall through */
+ case '/': case '!': case '@': case '#': case '%':
+ case '^': case '&': case '*': case '(': case ')':
+ case '[': case ']': case '{': case '}': case '\\':
+ case '|': case '=': case '`': case '~': case '\'':
+ case '\"': case ';': case '>': case '<': case '?':
+ case '\0':
+ /* Any of these characters terminate the colon search */
+ return PXE_RELATIVE;
+ default:
+ break;
+ }
+ p++;
}
-
- return has_gpxe;
}
+#if GPXE
+
/**
* Get a fresh packet from a gPXE socket
* @param: file -> socket structure
@@ -446,85 +454,15 @@ static void get_packet_gpxe(struct open_file_t *file)
* mangle a filename pointed to by _src_ into a buffer pointed
* to by _dst_; ends on encountering any whitespace.
*
- * The first four bytes of the manged name is the IP address of
- * the download host, 0 for no host, or -1 for a gPXE URL.
- *
*/
static void pxe_mangle_name(char *dst, const char *src)
{
- const char *p = src;
- uint32_t ip = server_ip;
- int i = 0;
-
-#if GPXE
- if (is_url(src)) {
- ip = -1;
- goto store;
- }
-#endif
-
- if (*p == 0 || !(p = strstr(src, "::"))) {
- /* seems no ip, so make ip to 0 */
- p = src;
- ip = 0;
- } else if (p == src) {
- /* skip the first two-colon */
- p += 2;
- } else {
- /*
- * we have a :: prefix of some sort, it could be either a DNS
- * name or dot-quad IP address. Try the dot-quad first.
- */
- p = src;
- if ((p = parse_dotquad(p, &ip)) && !strncmp(p, "::", 2)) {
- p += 2;
- } else {
- ip = dns_resolv(p);
- if (ip && (p = strchr(p, ':')) && p[1] == ':') {
- p += 2;
- } else {
- /* no ip, too */
- p = src;
- ip = 0;
- }
- }
- }
-
- store:
- *(uint32_t *)dst = ip;
- dst += 4;
- i = FILENAME_MAX - 5;
-
- do {
- if (!not_whitespace(*p))
- break;
- *dst++ = *p++;
- } while (i--);
+ size_t len = FILENAME_MAX-1;
- i++;
- while (i) {
- *dst++ = 0;
- i--;
- }
-}
-
-
-/*
- * Does the opposite of mangle_name; converts a DOS-mangled
- * filename to the conventional representation. This is
- * needed for the BOOT_IMAGE= parameter for the kernel.
- */
-static char *pxe_unmangle_name(char *dst, const char *src)
-{
- uint32_t ip = *(uint32_t *)src;
- int ip_len = 0;
+ while (len-- && not_whitespace(*src))
+ *dst++ = *src++;
- if (ip != 0 && ip != -1) {
- ip_len = gendotquad(dst, *(uint32_t *)src);
- dst += ip_len;
- }
- src += 4;
- return stpcpy(dst, src);
+ *dst = '\0';
}
/*
@@ -552,7 +490,6 @@ static void fill_buffer(struct open_file_t *file)
}
#endif
-
/*
* Start by ACKing the previous packet; this should cause
* the next packet to be sent.
@@ -683,22 +620,8 @@ static uint32_t pxe_getfssec(struct file *gfile, char *buf,
}
return bytes_read;
- }
-
-
-
-/*
- * Fill the packet tail with the tftp informations then retures the lenght
- */
-static int fill_tail(char *dst)
-{
- static const char tail[] = "octet\0""tsize\0""0\0""blksize\0""1408";
-
- memcpy(dst, tail, sizeof tail);
- return sizeof tail;
}
-
/**
* Open a TFTP connection to the server
*
@@ -708,16 +631,20 @@ static int fill_tail(char *dst)
* @ouT: the lenght of this file, stores in file->file_len
*
*/
-static void pxe_searchdir(char *filename, struct file *file)
+static void pxe_searchdir(const char *filename, struct file *file)
{
- char *buf = packet_buf;
- char *p = filename;
+ struct fs_info *fs = file->fs;
+ char *buf;
+ const char *np;
+ char *p;
char *options;
char *data;
struct open_file_t *open_file;
static __lowmem struct s_PXENV_UDP_WRITE udp_write;
static __lowmem struct s_PXENV_UDP_READ udp_read;
static __lowmem struct s_PXENV_FILE_OPEN file_open;
+ static const char rrq_tail[] = "octet\0""tsize\0""0\0""blksize\0""1408";
+ static __lowmem char rrq_packet_buf[2+2*FILENAME_MAX+sizeof rrq_tail];
const struct tftp_options *tftp_opt;
int i = 0;
int err;
@@ -728,68 +655,102 @@ static void pxe_searchdir(char *filename, struct file *file)
uint16_t tid;
uint16_t opcode;
uint16_t blk_num;
- uint32_t ip;
+ uint32_t ip = 0;
uint32_t opdata, *opdata_ptr;
+ enum pxe_path_type path_type;
+ char fullpath[2*FILENAME_MAX];
- open_file = allocate_socket();
- if (!open_file) {
- file->file_len = 0;
- file->open_file = NULL;
- return;
+ file->file_len = 0;
+ file->open_file = NULL;
+
+ buf = rrq_packet_buf;
+ *(uint16_t *)buf = TFTP_RRQ; /* TFTP opcode */
+ buf += 2;
+
+ path_type = pxe_path_type(filename);
+ if (path_type == PXE_RELATIVE) {
+ snprintf(fullpath, sizeof fullpath, "%s%s", fs->cwd_name, filename);
+ path_type = pxe_path_type(filename = fullpath);
}
- timeout_ptr = TimeoutTable; /* Reset timeout */
+ switch (path_type) {
+ case PXE_RELATIVE: /* Really shouldn't happen... */
+ case PXE_URL:
+ buf = stpcpy(buf, filename);
+ ip = server_ip; /* Default server */
+ break;
- sendreq:
- udp_write.buffer.offs = OFFS_WRT(buf, 0);
- udp_write.buffer.seg = 0;
- *(uint16_t *)buf = TFTP_RRQ; /* TFTP opcode */
- buf += 2;
+ case PXE_HOMESERVER:
+ buf = stpcpy(buf, filename+2);
+ ip = server_ip;
+ break;
- ip = *(uint32_t *)p; /* ip <- server override (if any) */
- p += 4;
- if (ip == 0) {
- /* Have prefix */
- strcpy(buf, path_prefix);
- buf += strlen(path_prefix);
- ip = server_ip; /* Get the default server */
+ case PXE_TFTP:
+ np = strchr(filename, ':');
+ buf = stpcpy(buf, np+2);
+ if (parse_dotquad(filename, &ip) != np)
+ ip = dns_resolv(filename);
+ break;
}
- strcpy(buf, p); /* Copy the filename */
- buf += strlen(p) + 1; /* advance the pointer, null char included */
+ if (!ip)
+ return; /* No server */
+ buf++; /* Point *past* the final NULL */
+ memcpy(buf, rrq_tail, sizeof rrq_tail);
+ buf += sizeof rrq_tail;
+
+ open_file = allocate_socket();
+ if (!open_file)
+ return; /* Allocation failure */
+
+ timeout_ptr = TimeoutTable; /* Reset timeout */
+
+ sendreq:
#if GPXE
- if (is_gpxe(packet_buf + 2)) {
- file_open.Status = PXENV_STATUS_BAD_FUNC;
- file_open.FileName.offs = OFFS(packet_buf + 2);
- file_open.FileName.seg = SEG(packet_buf + 2);
- err = pxe_call(PXENV_FILE_OPEN, &file_open);
- if (err)
- goto done;
-
- open_file->tftp_localport = -1;
- open_file->tftp_remoteport = file_open.FileHandle;
- open_file->tftp_filesize = -1;
- goto done;
+ if (path_type == PXE_URL) {
+ if (has_gpxe) {
+ file_open.Status = PXENV_STATUS_BAD_FUNC;
+ file_open.FileName.offs = OFFS(rrq_packet_buf + 2);
+ file_open.FileName.seg = SEG(rrq_packet_buf + 2);
+ err = pxe_call(PXENV_FILE_OPEN, &file_open);
+ if (err)
+ goto done;
+
+ open_file->tftp_localport = -1;
+ open_file->tftp_remoteport = file_open.FileHandle;
+ open_file->tftp_filesize = -1;
+ goto done;
+ } else {
+ static bool already = false;
+ if (!already) {
+ fputs("URL syntax, but gPXE extensions not detected, "
+ "tryng plain TFTP...\n", stdout);
+ already = true;
+ }
+ }
}
#endif /* GPXE */
open_file->tftp_remoteip = ip;
tid = open_file->tftp_localport; /* TID(local port No) */
+ udp_write.buffer.offs = OFFS(rrq_packet_buf);
+ udp_write.buffer.seg = SEG(rrq_packet_buf);
udp_write.ip = ip;
udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0;
udp_write.src_port = tid;
udp_write.dst_port = server_port;
- buf += fill_tail(buf);
- udp_write.buffer_size = buf - packet_buf;
+ udp_write.buffer_size = buf - rrq_packet_buf;
err = pxe_call(PXENV_UDP_WRITE, &udp_write);
- if (err || udp_write.status != 0)
- goto failure; /*
- * In fact, the 'failure' target will not do
- * a failure thing; it will move on to the
- * next timeout, then tries again until
- * _real_ time out
- */
+ if (err || udp_write.status != 0) {
+ /*
+ * In fact, the 'failure' target will not do
+ * a failure thing; it will move on to the
+ * next timeout, then tries again until
+ * _real_ time out
+ */
+ goto failure;
+ }
/*
* Danger, Will Robinson! We need to support tiemout
@@ -888,7 +849,7 @@ static void pxe_searchdir(char *filename, struct file *file)
p = options;
while (buffersize) {
- char *opt = p;
+ const char *opt = p;
/*
* If we find an option which starts with a NUL byte,
@@ -957,8 +918,6 @@ static void pxe_searchdir(char *filename, struct file *file)
done:
if (!open_file->tftp_filesize) {
free_socket(open_file);
- file->file_len = 0;
- file->open_file = NULL;
return;
}
file->open_file = (void *)open_file;
@@ -987,32 +946,61 @@ static void get_prefix(void)
char *p;
char c;
- if (DHCPMagic & 0x04) /* Did we get a path prefix option */
- goto got_prefix;
+ if (!(DHCPMagic & 0x04)) {
+ /* No path prefix option, derive from boot file */
+
+ strlcpy(path_prefix, boot_file, sizeof path_prefix);
+ len = strlen(path_prefix);
+ p = &path_prefix[len - 1];
+
+ while (len--) {
+ c = *p--;
+ c |= 0x20;
+
+ c = (c >= '0' && c <= '9') ||
+ (c >= 'a' && c <= 'z') ||
+ (c == '.' || c == '-');
+ if (!c)
+ break;
+ };
+
+ if (len < 0)
+ p --;
+
+ *(p + 2) = 0; /* Zero-terminate after delimiter */
+ }
- strcpy(path_prefix, boot_file);
- len = strlen(path_prefix);
- p = &path_prefix[len - 1];
+ printf("TFTP prefix: %s\n", path_prefix);
+ chdir(path_prefix);
+}
- while (len--) {
- c = *p--;
- c |= 0x20;
+/*
+ * realpath for PXE
+ */
+static size_t pxe_realpath(struct fs_info *fs, char *dst, const char *src,
+ size_t bufsize)
+{
+ enum pxe_path_type path_type = pxe_path_type(src);
- c = (c >= '0' && c <= '9') ||
- (c >= 'a' && c <= 'z') ||
- (c == '.' || c == '-');
- if (!c)
- break;
- };
+ return snprintf(dst, bufsize, "%s%s",
+ path_type == PXE_RELATIVE ? fs->cwd_name : "", src);
+}
- if (len < 0)
- p --;
+/*
+ * chdir for PXE
+ */
+static int pxe_chdir(struct fs_info *fs, const char *src)
+{
+ /* The cwd for PXE is just a text prefix */
+ enum pxe_path_type path_type = pxe_path_type(src);
- *(p + 2) = 0; /* Zero-terminate after delimiter */
+ if (path_type == PXE_RELATIVE)
+ strlcat(fs->cwd_name, src, sizeof fs->cwd_name);
+ else
+ strlcpy(fs->cwd_name, src, sizeof fs->cwd_name);
- got_prefix:
- printf("TFTP prefix: %s\n", path_prefix);
- strcpy(CurrentDirName, path_prefix);
+ printf("cwd = \"%s\"\n", fs->cwd_name);
+ return 0;
}
/*
@@ -1501,6 +1489,9 @@ static int pxe_fs_init(struct fs_info *fs)
/* Initialize network-card-specific idle handling */
pxe_idle_init();
+ /* Our name for the root */
+ strcpy(fs->cwd_name, "::");
+
return 0;
}
@@ -1645,17 +1636,16 @@ cant_free:
return;
}
-
-
const struct fs_ops pxe_fs_ops = {
.fs_name = "pxe",
.fs_flags = FS_NODEV,
.fs_init = pxe_fs_init,
.searchdir = pxe_searchdir,
+ .chdir = pxe_chdir,
+ .realpath = pxe_realpath,
.getfssec = pxe_getfssec,
.close_file = pxe_close_file,
.mangle_name = pxe_mangle_name,
- .unmangle_name = pxe_unmangle_name,
+ .unmangle_name = stpcpy,
.load_config = pxe_load_config,
- .iget_current = NULL
};
diff --git a/core/getc.inc b/core/getc.inc
index 48b9f774..47dca1e6 100644
--- a/core/getc.inc
+++ b/core/getc.inc
@@ -62,7 +62,7 @@ getc_file_lg2 equ 4 ; Size of getc_file as a power of 2
;
global core_open
core_open:
- pm_call searchdir
+ pm_call pm_searchdir
jz openfd.ret
openfd:
push bx
diff --git a/core/include/fs.h b/core/include/fs.h
index 2477e4e3..124a8161 100644
--- a/core/include/fs.h
+++ b/core/include/fs.h
@@ -21,6 +21,8 @@
#define FILENAME_MAX_LG2 8
#define FILENAME_MAX (1 << FILENAME_MAX_LG2)
+#define CURRENTDIR_MAX FILENAME_MAX
+
#define BLOCK_SIZE(fs) ((fs)->block_size)
#define BLOCK_SHIFT(fs) ((fs)->block_shift)
#define SECTOR_SIZE(fs) ((fs)->sector_size)
@@ -32,6 +34,8 @@ struct fs_info {
void *fs_info; /* The fs-specific information */
int sector_shift, sector_size;
int block_shift, block_size;
+ struct inode *cwd; /* Current directory */
+ char cwd_name[CURRENTDIR_MAX]; /* Current directory by name */
};
extern struct fs_info *this_fs;
@@ -50,15 +54,16 @@ struct fs_ops {
enum fs_flags fs_flags;
int (*fs_init)(struct fs_info *);
- void (*searchdir)(char *, struct file *);
+ void (*searchdir)(const char *, struct file *);
uint32_t (*getfssec)(struct file *, char *, int, bool *);
void (*close_file)(struct file *);
void (*mangle_name)(char *, const char *);
char * (*unmangle_name)(char *, const char *);
+ size_t (*realpath)(struct fs_info *, char *, const char *, size_t);
+ int (*chdir)(struct fs_info *, const char *);
int (*load_config)(void);
struct inode * (*iget_root)(struct fs_info *);
- struct inode * (*iget_current)(struct fs_info *);
struct inode * (*iget)(char *, struct inode *);
char * (*follow_symlink)(struct inode *, const char *);
@@ -90,6 +95,7 @@ struct open_file_t;
struct file {
struct fs_info *fs;
+ uint32_t file_len;
union {
/* For the new universal-path_lookup */
struct {
@@ -100,7 +106,6 @@ struct file {
/* For the old searhdir method */
struct {
struct open_file_t *open_file;/* The fs-specific open file struct */
- uint32_t file_len;
};
};
};
@@ -109,12 +114,6 @@ struct file {
enum dev_type {CHS, EDD};
/*
- * Generic functions that filesystem drivers may choose to use
- */
-void generic_mangle_name(char *, const char *);
-#define generic_unmangle_name stpcpy
-
-/*
* Struct device contains:
* the pointer points to the disk structure,
* the cache stuff.
@@ -153,13 +152,39 @@ static inline void malloc_error(char *obj)
kaboom();
}
-/*
- * functions
+/*
+ * File handle conversion functions
*/
+extern struct file files[];
+static inline uint16_t file_to_handle(struct file *file)
+{
+ return file ? (file - files)+1 : 0;
+}
+static inline struct file *handle_to_file(uint16_t handle)
+{
+ return handle ? &files[handle-1] : NULL;
+}
+
+/* fs.c */
void mangle_name(com32sys_t *);
-void searchdir(com32sys_t *);
+void pm_searchdir(com32sys_t *);
+int searchdir(const char *name);
void _close_file(struct file *);
-inline uint16_t file_to_handle(struct file *);
-inline struct file *handle_to_file(uint16_t);
+
+/* chdir.c */
+void pm_realpath(com32sys_t *regs);
+size_t realpath(char *dst, const char *src, size_t bufsize);
+int chdir(const char *src);
+
+/*
+ * Generic functions that filesystem drivers may choose to use
+ */
+
+/* mangle.c */
+void generic_mangle_name(char *, const char *);
+#define generic_unmangle_name stpcpy
+
+/* loadconfig.c */
+int generic_load_config(void);
#endif /* FS_H */
diff --git a/core/parseconfig.inc b/core/parseconfig.inc
index af7d514f..ad89f58d 100644
--- a/core/parseconfig.inc
+++ b/core/parseconfig.inc
@@ -148,7 +148,7 @@ pc_filecmd: push ax ; Function to tailcall
call pc_getline
mov di,MNameBuf
pm_call mangle_name
- pm_call searchdir
+ pm_call pm_searchdir
jnz .ok
pop ax ; Drop the successor function
.ok: ret ; Tailcall if OK, error return
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index 58f76ce9..8884e030 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -30,7 +30,7 @@
;
my_id equ pxelinux_id
NULLFILE equ 0 ; Zero byte == null file name
-NULLOFFSET equ 4 ; Position in which to look
+NULLOFFSET equ 0 ; Position in which to look
REBOOT_TIME equ 5*60 ; If failure, time until full reset
%assign HIGHMEM_SLOP 128*1024 ; Avoid this much memory near the top
TFTP_BLOCKSIZE_LG2 equ 9 ; log2(bytes/block)
diff --git a/core/dir.c b/core/readdir.c
index 4013280a..7a58edac 100644
--- a/core/dir.c
+++ b/core/readdir.c
@@ -12,7 +12,7 @@ void opendir(com32sys_t *regs)
char *src = MK_PTR(regs->es, regs->esi.w[0]);
char *dst = MK_PTR(regs->ds, regs->edi.w[0]);
strcpy(dst, src);
- searchdir(regs);
+ pm_searchdir(regs);
regs->eax.l = (uint32_t)handle_to_file(regs->esi.w[0]);
}
diff --git a/core/runkernel.inc b/core/runkernel.inc
index 74f23c45..f07c70f6 100644
--- a/core/runkernel.inc
+++ b/core/runkernel.inc
@@ -597,7 +597,7 @@ loadinitrd:
sub di,InitRDCName
mov [InitRDCNameLen],di
mov di,InitRD
- pm_call searchdir ; Look for it in directory
+ pm_call pm_searchdir ; Look for it in directory
pop edi
jz .notthere
diff --git a/core/ui.inc b/core/ui.inc
index ec9190a9..827710f2 100644
--- a/core/ui.inc
+++ b/core/ui.inc
@@ -451,7 +451,7 @@ vk_check:
; Find the kernel on disk
;
get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/extension
- mov di,KernelName+4*IS_PXELINUX
+ mov di,KernelName
cmp byte [di],' '
jbe bad_kernel ; Missing kernel name
xor al,al
@@ -463,7 +463,7 @@ get_kernel: mov byte [KernelName+FILENAME_MAX],0 ; Zero-terminate filename/e
mov bx,exten_table
.search_loop: push bx
mov di,KernelName ; Search on disk
- pm_call searchdir
+ pm_call pm_searchdir
pop bx
jnz kernel_good
mov eax,[bx] ; Try a different extension
@@ -628,7 +628,7 @@ kernel_good:
push di
push ax
- mov di,KernelName+4*IS_PXELINUX
+ mov di,KernelName
xor al,al
mov cx,FILENAME_MAX
repne scasb
@@ -674,11 +674,11 @@ is_unknown_filetype:
jmp is_linux_kernel
is_config_file:
- pusha
+ push si
mov si,KernelCName ; Save the config file name, for posterity
mov di,ConfigName
- call strcpy
- popa
+ pm_call pm_realpath
+ pop si
call openfd
call reset_config
jmp load_config_file