aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorH. Peter Anvin <hpa@zytor.com>2009-02-16 22:52:01 -0800
committerH. Peter Anvin <hpa@zytor.com>2009-02-16 22:52:01 -0800
commit1b90fba407546b72dad8d0c8c4729ef8ab5c32fc (patch)
tree2cf5b5f64f9d75450ae405d48aa9e7021900f425
parentd7cb344206117dd22afbde6df56e8b81d47718ae (diff)
parent53daea0916af7b874f830bd0428da2be4e1bc3b3 (diff)
downloadsyslinux-elf-1b90fba407546b72dad8d0c8c4729ef8ab5c32fc.tar.gz
syslinux-elf-1b90fba407546b72dad8d0c8c4729ef8ab5c32fc.tar.xz
syslinux-elf-1b90fba407546b72dad8d0c8c4729ef8ab5c32fc.zip
Merge branch 'dir'
-rwxr-xr-xcodepage/cptable.pl5
-rw-r--r--com32/Makefile2
-rw-r--r--com32/include/dirent.h36
-rw-r--r--com32/include/unistd.h3
-rw-r--r--com32/lib/Makefile2
-rw-r--r--com32/lib/chdir.c13
-rw-r--r--com32/lib/closedir.c29
-rw-r--r--com32/lib/fdopendir.c13
-rw-r--r--com32/lib/getcwd.c29
-rw-r--r--com32/lib/opendir.c41
-rw-r--r--com32/lib/readdir.c54
-rw-r--r--com32/rosh/MCONFIG27
-rw-r--r--com32/rosh/Makefile38
-rw-r--r--com32/rosh/rosh.c810
-rw-r--r--com32/rosh/rosh.h148
-rw-r--r--core/comboot.inc71
-rw-r--r--core/extlinux.asm8
-rw-r--r--core/isolinux.asm20
-rw-r--r--core/ldlinux.asm349
-rw-r--r--core/pxelinux.asm7
-rw-r--r--doc/comboot.txt43
21 files changed, 1742 insertions, 6 deletions
diff --git a/codepage/cptable.pl b/codepage/cptable.pl
index c7e20023..05cfc3eb 100755
--- a/codepage/cptable.pl
+++ b/codepage/cptable.pl
@@ -118,6 +118,7 @@ for ($i = 0; $i < 256; $i++) {
# Unicode (longname) matching table.
# This only depends on the console codepage.
#
+$pp0 = ''; $pp1 = '';
for ($i = 0; $i < 256; $i++) {
if (!defined($ytab[$i])) {
$p0 = $p1 = 0xffff;
@@ -136,8 +137,10 @@ for ($i = 0; $i < 256; $i++) {
# Only the BMP is supported...
$p0 = 0xffff if ($p0 > 0xffff);
$p1 = 0xffff if ($p1 > 0xffff);
- print CPOUT pack("vv", $p0, $p1);
+ $pp0 .= pack("v", $p0);
+ $pp1 .= pack("v", $p1);
}
+print CPOUT $pp0, $pp1;
close (CPOUT);
diff --git a/com32/Makefile b/com32/Makefile
index bfb8e3a6..9dee9684 100644
--- a/com32/Makefile
+++ b/com32/Makefile
@@ -1,4 +1,4 @@
-SUBDIRS = lib libutil modules menu samples
+SUBDIRS = lib libutil modules menu samples rosh
all tidy dist clean spotless install:
set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done
diff --git a/com32/include/dirent.h b/com32/include/dirent.h
new file mode 100644
index 00000000..956b911d
--- /dev/null
+++ b/com32/include/dirent.h
@@ -0,0 +1,36 @@
+/*
+ * dirent.h
+ */
+
+#ifndef _DIRENT_H
+#define _DIRENT_H
+
+#include <klibc/extern.h>
+#include <klibc/compiler.h>
+#include <stddef.h>
+#include <sys/types.h>
+
+#ifndef NAME_MAX
+#define NAME_MAX 255
+#endif
+
+struct dirent {
+ long d_ino; /* Inode/File number */
+ off_t d_size; /* Size of file */
+ mode_t d_mode; /* Type of file */
+ char d_name[NAME_MAX + 1];
+};
+
+typedef struct {
+ short dd_stat; /* status return from last lookup */
+ uint16_t dd_fd;
+ size_t dd_sect;
+ char dd_name[NAME_MAX + 1]; /* directory */
+} DIR;
+
+__extern DIR *opendir(const char *);
+__extern struct dirent *readdir(DIR *);
+__extern int closedir(DIR *);
+__extern DIR *fdopendir(int);
+
+#endif /* Not _DIRENT_H */
diff --git a/com32/include/unistd.h b/com32/include/unistd.h
index d0b8309c..c0b52d60 100644
--- a/com32/include/unistd.h
+++ b/com32/include/unistd.h
@@ -22,6 +22,9 @@ __extern int isatty(int);
__extern int getscreensize(int, int *, int *);
+__extern char *getcwd(char *, int);
+__extern int chdir(const char *);
+
/* Standard file descriptor numbers. */
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
diff --git a/com32/lib/Makefile b/com32/lib/Makefile
index 91405a06..0cc40617 100644
--- a/com32/lib/Makefile
+++ b/com32/lib/Makefile
@@ -21,6 +21,8 @@ LIBOBJS = \
asprintf.o vasprintf.o strlcpy.o strlcat.o \
vsscanf.o zalloc.o \
\
+ opendir.o readdir.o closedir.o getcwd.o chdir.o fdopendir.o \
+ \
libgcc/__ashldi3.o libgcc/__udivdi3.o \
libgcc/__negdi2.o libgcc/__ashrdi3.o libgcc/__lshrdi3.o \
libgcc/__muldi3.o libgcc/__udivmoddi4.o libgcc/__umoddi3.o \
diff --git a/com32/lib/chdir.c b/com32/lib/chdir.c
new file mode 100644
index 00000000..88dceece
--- /dev/null
+++ b/com32/lib/chdir.c
@@ -0,0 +1,13 @@
+/*
+ * chdir.c
+ */
+
+#include <dirent.h>
+#include <stdio.h>
+#include <errno.h>
+
+int chdir(const char *path)
+{
+ errno = ENOSYS;
+ return -1;
+}
diff --git a/com32/lib/closedir.c b/com32/lib/closedir.c
new file mode 100644
index 00000000..8a0430e6
--- /dev/null
+++ b/com32/lib/closedir.c
@@ -0,0 +1,29 @@
+/*
+ * closedir.c
+ */
+
+#include <dirent.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <com32.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+int closedir(DIR *dir)
+{
+ int rv;
+ com32sys_t regs;
+ if (dir == NULL) {
+ rv = 0;
+ } else {
+ memset(&regs, 0, sizeof regs); /* ?Needed? */
+ regs.eax.w[0] = 0x0022;
+ regs.esi.w[0] = dir->dd_fd;
+ __com32.cs_intcall(0x22, &regs, &regs);
+ free(dir); /* garbage collection? */
+ rv = 0;
+ }
+ return rv;
+}
diff --git a/com32/lib/fdopendir.c b/com32/lib/fdopendir.c
new file mode 100644
index 00000000..83a7ac6f
--- /dev/null
+++ b/com32/lib/fdopendir.c
@@ -0,0 +1,13 @@
+/*
+ * fdopendir.c
+ */
+
+#include <dirent.h>
+#include <stdio.h>
+#include <errno.h>
+
+DIR *fdopendir(int __fd)
+{
+ errno = ENOSYS;
+ return NULL;
+}
diff --git a/com32/lib/getcwd.c b/com32/lib/getcwd.c
new file mode 100644
index 00000000..95008bb2
--- /dev/null
+++ b/com32/lib/getcwd.c
@@ -0,0 +1,29 @@
+/*
+ * getcwd.c
+ */
+
+#include <syslinux/config.h>
+#include <klibc/compiler.h>
+#include <com32.h>
+
+#include <dirent.h>
+#include <stdio.h>
+#include <errno.h>
+
+char *getcwd(char *buf, size_t size)
+{
+ static com32sys_t reg;
+ char *pwdstr, *ret;
+
+ reg.eax.w[0] = 0x001f;
+ __intcall(0x22, &reg, &reg);
+ pwdstr = MK_PTR(reg.es, reg.ebx.w[0]);
+ if ((strlen(pwdstr) < size) && (buf != NULL)) {
+ strcpy(buf, pwdstr);
+ ret = buf;
+ } else {
+ ret = NULL;
+ errno = ERANGE;
+ }
+ return ret;
+}
diff --git a/com32/lib/opendir.c b/com32/lib/opendir.c
new file mode 100644
index 00000000..aa2ba5b9
--- /dev/null
+++ b/com32/lib/opendir.c
@@ -0,0 +1,41 @@
+/*
+ * opendir.c
+ */
+
+#include <dirent.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <com32.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+
+DIR *opendir(const char *pathname)
+{
+ DIR *newdir;
+ com32sys_t regs;
+
+ newdir = NULL;
+
+ strlcpy(__com32.cs_bounce, pathname, __com32.cs_bounce_size);
+
+ regs.eax.w[0] = 0x0020;
+ regs.esi.w[0] = OFFS(__com32.cs_bounce);
+ regs.es = SEG(__com32.cs_bounce);
+
+ __com32.cs_intcall(0x22, &regs, &regs);
+
+ if (!(regs.eflags.l & EFLAGS_CF)) {
+ /* Initialization: malloc() then zero */
+ newdir = calloc(1, sizeof(DIR));
+ strcpy(newdir->dd_name, pathname);
+ newdir->dd_fd = regs.esi.w[0];
+ newdir->dd_sect = regs.eax.l;
+ newdir->dd_stat = 0;
+ }
+
+ /* We're done */
+ return newdir;
+}
diff --git a/com32/lib/readdir.c b/com32/lib/readdir.c
new file mode 100644
index 00000000..bfa52526
--- /dev/null
+++ b/com32/lib/readdir.c
@@ -0,0 +1,54 @@
+/*
+ * readdir.c
+ */
+
+#include <dirent.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include <com32.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+struct dirent *readdir(DIR *dir)
+{
+ struct dirent *newde;
+ com32sys_t regs;
+
+ newde = NULL;
+ if ((dir != NULL) && (dir->dd_fd != 0) && (dir->dd_stat >= 0)) {
+ memset(__com32.cs_bounce, 0, 32);
+ memset(&regs, 0, sizeof(regs));
+
+ regs.eax.w[0] = 0x0021;
+ regs.esi.w[0] = dir->dd_fd;
+ regs.edi.w[0] = OFFS(__com32.cs_bounce);
+ regs.es = SEG(__com32.cs_bounce);
+
+ __com32.cs_intcall(0x22, &regs, &regs);
+
+ /* Don't do this as we won't be able to rewind.
+ dir->dd_fd = regs.esi.w[0]; /* Shouldn't be needed? */
+ if ((!(regs.eflags.l & EFLAGS_CF)) && (regs.esi.w[0] != 0)) {
+ newde = calloc(1, sizeof(newde));
+ if (newde != NULL) {
+ strcpy(newde->d_name, __com32.cs_bounce);
+ newde->d_mode = regs.edx.b[0];
+ newde->d_size = regs.eax.l;
+ newde->d_ino = regs.ebx.l;
+ dir->dd_stat = 1;
+ } else {
+ dir->dd_stat = -2;
+ errno = ENOMEM;
+ }
+ } else {
+ dir->dd_stat = -1;
+ errno = EIO; /* Is this the right nmber? */
+ }
+ } else {
+ errno = EBADF;
+ }
+
+ return newde;
+}
diff --git a/com32/rosh/MCONFIG b/com32/rosh/MCONFIG
new file mode 100644
index 00000000..30029d15
--- /dev/null
+++ b/com32/rosh/MCONFIG
@@ -0,0 +1,27 @@
+## -*- makefile -*- -------------------------------------------------------
+##
+## Copyright 2008 H. Peter Anvin - All Rights Reserved
+##
+## 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.
+##
+## -----------------------------------------------------------------------
+
+##
+## COM32 GRC configurables
+##
+
+## Include the COM32 common configurables
+include ../MCONFIG
+
+# CFLAGS = $(GCCOPT) -W -Wall -march=i386 \
+# -fomit-frame-pointer -D__COM32__ \
+# -nostdinc -iwithprefix include \
+# -I$(com32)/libutil/include -I$(com32)/include
+# -g3 -dD
+
+# LNXCFLAGS = -I$(com32)/libutil/include -W -Wall -O -g3 -D_GNU_SOURCE -dD
+# -U__GNUC__
diff --git a/com32/rosh/Makefile b/com32/rosh/Makefile
new file mode 100644
index 00000000..30dc7d39
--- /dev/null
+++ b/com32/rosh/Makefile
@@ -0,0 +1,38 @@
+## -----------------------------------------------------------------------
+##
+## Copyright 2001-2008 H. Peter Anvin - All Rights Reserved
+##
+## 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., 53 Temple Place Ste 330,
+## Boston MA 02111-1307, USA; either version 2 of the License, or
+## (at your option) any later version; incorporated herein by reference.
+##
+## -----------------------------------------------------------------------
+
+##
+## samples for syslinux users
+##
+
+topdir = ../..
+include MCONFIG
+
+rosh.o: rosh.h
+
+rosh.lo: rosh.h
+
+all: rosh.lnx rosh.c32
+
+tidy dist:
+ rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp
+
+clean: tidy
+ rm -f *.lnx
+
+spotless: clean
+ rm -f *.lss *.c32 *.com
+ rm -f *~ \#*
+
+install: # Don't install samples
+
+-include .*.d
diff --git a/com32/rosh/rosh.c b/com32/rosh/rosh.c
new file mode 100644
index 00000000..5eaa47df
--- /dev/null
+++ b/com32/rosh/rosh.c
@@ -0,0 +1,810 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 Gene Cumm - All Rights Reserved
+ *
+ * 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., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * rosh.c
+ *
+ * Read-Only shell; Simple shell system designed for SYSLINUX-derivitives.
+ * Provides minimal commands utilizing the console via stdout/stderr as the
+ * sole output devices. Designed to compile for Linux for testing/debugging.
+ */
+
+/*
+ * ToDos:
+ * Change functions to use pwdstr
+ * In rosh_run() Reparse cmdstr relative to pwdstr
+ */
+
+// #define DO_DEBUG 1
+ /* Uncomment the above line for debugging output; Comment to remove */
+// #define DO_DEBUG2 1
+ /* Uncomment the above line for super-debugging output; Must have regular debugging enabled; Comment to remove */
+
+#include "rosh.h"
+
+#define APP_LONGNAME "Read-Only Shell"
+#define APP_NAME "rosh"
+#define APP_AUTHOR "Gene Cumm"
+#define APP_YEAR "2008"
+#define APP_VER "beta-b032"
+
+void rosh_version()
+{
+ printf("%s v %s; (c) %s %s.\n", APP_LONGNAME, APP_VER, APP_YEAR, \
+ APP_AUTHOR);
+}
+
+void rosh_help(int type)
+{
+ rosh_version();
+ switch (type) {
+ case 2: puts(rosh_help_str2);
+ break;
+ case 1: default:
+ puts(rosh_help_str1);
+ }
+}
+
+/* Determine if a character is whitespace
+ * inc input character
+ * returns 0 if not whitespace
+ */
+int rosh_issp(char inc)
+{
+ int rv;
+ switch (inc){
+ case ' ': case '\t':
+ rv = 1; break;
+ default: rv = 0;
+ }
+ return rv;
+} /* ros_issp */
+
+/* Search a string for first non-space (' ') character, starting at ipos
+ * istr input string to parse
+ * ipos input position to start at
+ */
+int rosh_search_nonsp(const char *istr, const int ipos)
+{
+ int curpos;
+ char c;
+
+ curpos = ipos;
+ c = istr[curpos];
+ while (rosh_issp(c) && c != 0)
+ c = istr[++curpos];
+ return curpos;
+}
+
+/* Search a string for space (' '), returning the position of the next space
+ * or the '\0' at end of string
+ * istr input string to parse
+ * ipos input position to start at
+ */
+int rosh_search_sp(const char *istr, const int ipos)
+{
+ int curpos;
+ char c;
+
+ curpos = ipos;
+ c = istr[curpos];
+ while (!(rosh_issp(c)) && c != 0)
+ c = istr[++curpos];
+ return curpos;
+}
+
+/* Parse a string for the first non-space string, returning the end position
+ * from src
+ * dest string to contain the first non-space string
+ * src string to parse
+ * ipos Position to start in src
+ */
+int rosh_parse_sp_1(char *dest, const char *src, const int ipos)
+{
+ int bpos, epos; /* beginning and ending position of source string
+ to copy to destination string */
+
+ bpos = 0;
+ epos = 0;
+/* //HERE-error condition checking */
+ bpos = rosh_search_nonsp(src, ipos);
+ epos = rosh_search_sp(src, bpos);
+ if (epos > bpos) {
+ memcpy(dest, src + bpos, epos-bpos);
+ if (dest[epos - bpos] != 0)
+ dest[epos - bpos] = 0;
+ } else {
+ epos = strlen(src);
+ dest[0] = 0;
+ }
+ return epos;
+}
+
+/* Handle most/all errors
+ * ierrno Input Error number
+ * cmdstr Command being executed to cause error
+ * filestr File/parameter causing error
+ */
+void rosh_error(const int ierrno, const char *cmdstr, const char *filestr)
+{
+ printf("--ERROR: %s '%s': ", cmdstr, filestr);
+ switch (ierrno) {
+ case EACCES: printf("Access DENIED\n");
+ break;
+ case ENOENT: printf("not found\n");
+ /* SYSLinux-3.72 COM32 API returns this for a
+ directory or empty file */
+ ROSH_COM32(" (COM32) could be a directory or empty file\n");
+ break;
+ case ENOTDIR: printf("not a directory\n");
+ ROSH_COM32(" (COM32) could be directory\n");
+ break;
+ case ENOSYS: printf("not implemented");
+ break;
+ default: printf("returns error; errno=%d\n", ierrno);
+ }
+}
+
+/* Concatenate command line arguments into one string
+ * cmdstr Output command string
+ * argc Argument Count
+ * argv Argument Values
+ * barg Beginning Argument
+ */
+int rosh_argcat(char *cmdstr, const int argc, char *argv[], const int barg)
+{
+ int i, arglen, curpos; /* index, argument length, current position
+ in cmdstr */
+ curpos = 0;
+ cmdstr[0] = '\0'; /* Nullify string just to be sure */
+ for (i = barg; i < argc; i++) {
+ arglen = strlen(argv[i]);
+ /* Theoretically, this should never be met in SYSLINUX */
+ if ((curpos + arglen) > (ROSH_CMD_SZ - 1))
+ arglen = (ROSH_CMD_SZ - 1) - curpos;
+ memcpy(cmdstr + curpos, argv[i], arglen);
+ curpos += arglen;
+ if (curpos >= (ROSH_CMD_SZ - 1)) {
+ /* Hopefully, curpos should not be greater than
+ (ROSH_CMD_SZ - 1) */
+ /* Still need a '\0' at the last character */
+ cmdstr[(ROSH_CMD_SZ - 1)] = 0;
+ break; /* Escape out of the for() loop;
+ We can no longer process anything more */
+ } else {
+ cmdstr[curpos] = ' ';
+ curpos += 1;
+ cmdstr[curpos] = 0;
+ }
+ }
+ /* If there's a ' ' at the end, remove it. This is normal unless
+ the maximum length is met/exceeded. */
+ if (cmdstr[curpos - 1] == ' ')
+ cmdstr[--curpos] = 0;
+ return curpos;
+} /* rosh_argcat */
+
+/*
+ * Prints a lot of the data in a struct termios
+ */
+/*
+void rosh_print_tc(struct termios *tio)
+{
+ printf(" -- termios: ");
+ printf(".c_iflag=%04X ", tio->c_iflag);
+ printf(".c_oflag=%04X ", tio->c_oflag);
+ printf(".c_cflag=%04X ", tio->c_cflag);
+ printf(".c_lflag=%04X ", tio->c_lflag);
+ printf(".c_cc[VTIME]='%d' ", tio->c_cc[VTIME]);
+ printf(".c_cc[VMIN]='%d'", tio->c_cc[VMIN]);
+ printf("\n");
+}
+*/
+
+/*
+ * Switches console over to raw input mode. Allows get_key to get just
+ * 1 key sequence (without delay or display)
+ */
+void rosh_console_raw()
+{
+// struct termios itio, ntio;
+// tcgetattr(0, &itio);
+// rosh_print_tc(&itio);
+/* ntio = itio;
+ ntio.c_lflag &= ~(ICANON|ECHO);
+ tcsetattr(0, TCSAFLUSH, &ntio);*/
+ console_ansi_raw(); /* Allows get_key to get just 1 key sequence
+ (w/o delay or display */
+// tcgetattr(0, &ntio);
+// rosh_print_tc(&ntio);
+}
+
+/*
+ * Switches back to standard getline mode.
+ */
+void rosh_console_std()
+{
+// struct termios itio, ntio;
+ console_ansi_std();
+// tcsetattr(0, TCSANOW, &itio);
+}
+
+/*
+ * Attempts to get a single key from the console
+ * returns key pressed
+ */
+int rosh_getkey()
+{
+ int inc;
+
+ inc = KEY_NONE;
+// rosh_console_raw();
+ while (inc == KEY_NONE){
+ inc = get_key(stdin, 6000);
+ }
+// rosh_console_std();
+ return inc;
+} /* rosh_getkey */
+
+/* Template for command functions
+ * cmdstr command string to process
+ * pwdstr Present Working Directory string
+ * ipwdstr Initial PWD
+ */
+void rosh_1(const char *cmdstr, const char *pwdstr, const char *ipwdstr)
+{
+ ROSH_DEBUG("CMD: '%s'\npwd: '%s'\npwd: '%s'\n", cmdstr, pwdstr, \
+ ipwdstr);
+} /* rosh_1 */
+
+/* Concatenate multiple files to stdout
+ * cmdstr command string to process
+ * pwdstr Present Working Directory string
+ */
+void rosh_cat(const char *cmdstr, const char *pwdstr)
+{
+ FILE *f;
+ char filestr[ROSH_PATH_SZ + 1];
+ char buf[ROSH_BUF_SZ];
+ int numrd;
+ int cmdpos;
+
+ ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+ /* Initialization */
+ filestr[0] = 0;
+ cmdpos = 0;
+ /* skip the first word */
+ cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+ cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+ while (strlen(filestr) > 0) {
+ printf("--File = '%s'\n", filestr);
+ f = fopen(filestr, "r");
+ if (f != NULL) {
+ numrd = fread(buf, 1, ROSH_BUF_SZ, f);
+ while (numrd > 0) {
+ fwrite(buf, 1, numrd, stdout);
+ numrd = fread(buf, 1, ROSH_BUF_SZ, f);
+ }
+ fclose(f);
+ } else {
+ rosh_error(errno, "cat", filestr);
+ }
+ cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+ }
+} /* rosh_cat */
+
+/* Change PWD (Present Working Directory)
+ * cmdstr command string to process
+ * pwdstr Present Working Directory string
+ * ipwdstr Initial PWD
+ */
+void rosh_cd(const char *cmdstr, char *pwdstr, const char *ipwdstr)
+{
+ int rv;
+ char filestr[ROSH_PATH_SZ + 1];
+ int cmdpos;
+ ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+ /* Initialization */
+ filestr[0] = 0;
+ cmdpos = 0;
+ rv = 0;
+ /* skip the first word */
+ cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+ cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+ ROSH_COM32(" -- cd (Change Directory) not implemented for use with run and exit.\n");
+ if (strlen(filestr) != 0)
+ rv = chdir(filestr);
+ else
+ rv = chdir(ipwdstr);
+ if (rv != 0) {
+ rosh_error(errno, "cd", filestr);
+ } else {
+ getcwd(pwdstr, ROSH_PATH_SZ + 1);
+ printf(" %s\n", pwdstr);
+ }
+} /* rosh_cd */
+
+/* Print the syslinux config file name
+ * cmdstr command string to process
+ * pwdstr Present Working Directory string
+ */
+void rosh_cfg(const char *cmdstr, const char *pwdstr)
+{
+ ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+ printf("CFG: '%s'\n", syslinux_config_file());
+} /* rosh_cfg */
+
+/* Simple directory listing for one argument (file/directory) based on
+ * filestr and pwdstr
+ * ifilstr input filename/directory name to list
+ * pwdstr Present Working Directory string
+ */
+void rosh_dir_arg(const char *ifilstr, const char *pwdstr)
+{
+ struct stat fdstat;
+ int status;
+ int fd;
+ char filestr[ROSH_PATH_SZ + 1];
+ int filepos;
+ DIR *d;
+ struct dirent *de;
+#ifdef DO_DEBUG
+ char filestr2[ROSH_PATH_SZ + 1];
+ int fd2, file2pos;
+#ifdef __COM32__
+// int inchar;
+ char ty;
+#endif /* __COM32__ */
+#endif /* DO_DEBUG */
+
+ /* Initialization; make filestr based on leading character of ifilstr
+ and pwdstr */
+ if (ifilstr[0] == SEP) {
+ strcpy(filestr, ifilstr);
+ } else {
+ strcpy(filestr, pwdstr);
+ filepos = strlen(pwdstr);
+ if (filestr[filepos-1] != SEP)
+ filestr[filepos++] = SEP;
+ strcpy(filestr + filepos, ifilstr);
+ROSH_DEBUG("--'%s'\n", filestr);
+ }
+ fd = open(filestr, O_RDONLY);
+ if (fd != -1) {
+ status = fstat(fd, &fdstat);
+ if (S_ISDIR(fdstat.st_mode)) {
+ ROSH_DEBUG("PATH '%s' is a directory\n", ifilstr);
+ d = fdopendir(fd);
+ de = readdir(d);
+ while (de != NULL) {
+#ifdef DO_DEBUG
+ filestr2[0] = 0;
+ file2pos = strlen(filestr);
+ memcpy(filestr2, filestr, file2pos);
+ filestr2[file2pos] = '/';
+ strcpy(filestr2+file2pos+1, de->d_name);
+ fd2 = open(filestr2, O_RDONLY);
+ status = fstat(fd2, &fdstat);
+ printf("@%8d:%8d:", (int)de->d_ino, (int)fdstat.st_size);
+ fd2 = close(fd2);
+#endif /* DO_DEBUG */
+ printf("%s\n", de->d_name);
+#ifdef DO_DEBUG
+// inchar = fgetc(stdin);
+#endif /* DO_DEBUG */
+ de = readdir(d);
+ }
+ closedir(d);
+ } else if (S_ISREG(fdstat.st_mode)) {
+ ROSH_DEBUG("PATH '%s' is a regular file\n", ifilstr);
+ printf("%8d:%s\n", (int)fdstat.st_size, ifilstr);
+ } else {
+ ROSH_DEBUG("PATH '%s' is some other file\n", ifilstr);
+ printf(" :%s\n", ifilstr);
+ }
+ } else {
+#ifdef __COM32__
+ if (filestr[strlen(filestr)-1] == SEP) {
+ /* Directory */
+ filepos = 0;
+ d = opendir(filestr);
+ if (d != NULL) {
+printf("DIR:'%s' %8d %8d\n", d->dd_name, d->dd_fd, d->dd_sect);
+ de = readdir(d);
+ while (de != NULL) {
+ filepos++;
+#ifdef DO_DEBUG
+// if (strlen(de->d_name) > 25) de->d_name[25] = 0;
+ switch (de->d_mode) {
+ case 16 : ty = 'D'; break;
+ case 32 : ty = 'F'; break;
+ default : ty = '*';
+ }
+ printf("@%8d:%8d:%4d ", (int)de->d_ino, (int)de->d_size, de->d_mode);
+#endif /* DO_DEBUG */
+// printf("%s\n", de->d_name);
+printf("'%s'\n", de->d_name);
+#ifdef DO_DEBUG
+// inchar = fgetc(stdin);
+// fgets(instr, ROSH_CMD_SZ, stdin);
+#endif /* DO_DEBUG */
+ free(de);
+ de = readdir(d);
+// if(filepos>15){ de = NULL; printf("Force Break\n");}
+ }
+printf("Dir.dd_fd: '%8d'\n", d->dd_fd);
+ closedir(d);
+ } else {
+ rosh_error(0, "dir:NULL", filestr);
+ }
+ } else {
+ rosh_error(errno, "dir_c32", filestr);
+ }
+#else
+ rosh_error(errno, "dir", filestr);
+#endif /* __COM32__ */
+ }
+} /* rosh_dir_arg */
+
+/* Simple directory listing based on cmdstr and pwdstr
+ * cmdstr command string to process
+ * pwdstr Present Working Directory string
+ */
+void rosh_dir(const char *cmdstr, const char *pwdstr)
+{
+ char filestr[ROSH_PATH_SZ + 1];
+ int cmdpos; /* Position within cmdstr */
+
+ ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+ /* Initialization */
+ filestr[0] = 0;
+ cmdpos = 0;
+ /* skip the first word */
+ cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+ cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+ /* If there are no real arguments, substitute PWD */
+ if (strlen(filestr) == 0)
+ strcpy(filestr, pwdstr);
+ while (strlen(filestr) > 0) {
+ rosh_dir_arg(filestr, pwdstr);
+ cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+ }
+} /* rosh_dir */
+
+/* List Directory; Calls rosh_dir() for now.
+ * cmdstr command string to process
+ * pwdstr Present Working Directory string
+ */
+void rosh_ls(const char *cmdstr, const char *pwdstr)
+{
+ printf(" ls implemented as dir (for now)\n");
+ rosh_dir(cmdstr, pwdstr);
+} /* rosh_ls */
+
+/* Page through a buffer string
+ * buf Buffer to page through
+ */
+void rosh_more_buf(char *buf, int buflen, int rows, int cols)
+{
+ char *bufp, *bufeol; /* Pointer to current and next end-of-line
+ position in buffer */
+ int bufpos, bufcnt; /* current position, count characters */
+ char scrbuf[ROSH_SBUF_SZ];
+ int inc;
+ int i, numln; /* Index, Number of lines */
+
+ bufpos = 0;
+ bufp = buf + bufpos;
+ bufeol = bufp;
+ numln = rows - 1;
+printf("--(%d)\n", buflen);
+// printf("--termIOS CONSTS: ");
+// printf("ISIG=%08X ", ISIG);
+// printf("ICANON=%08X ", ICANON);
+// printf("ECHO=%08X ", ECHO);
+// printf("=%08X", );
+// printf("\n");
+ while (bufpos < buflen) {
+ for (i=0; i<numln; i++){
+ bufeol = strchr(bufeol, '\n');
+ if (bufeol == NULL) {
+ bufeol = buf + buflen;
+ i = numln;
+ } else {
+ bufeol++;
+ }
+// printf("--readln\n");
+ }
+ bufcnt = bufeol - bufp;
+printf("--(%d/%d @%d)\n", bufcnt, buflen, bufpos);
+ memcpy(scrbuf, bufp, bufcnt);
+ scrbuf[bufcnt] = 0;
+ printf("%s", scrbuf);
+ bufp = bufeol;
+ bufpos += bufcnt;
+ if (bufpos == buflen) break;
+ inc = rosh_getkey();
+ numln = 1;
+ switch (inc){
+ case KEY_CTRL('c'): case 'q': case 'Q':
+ bufpos = buflen; break;
+ case ' ':
+ numln = rows - 1;
+// default:
+ }
+ }
+/*tcgetattr(0, &tio);
+rosh_print_tc(&tio);
+printf("\n--END\n");*/
+} /* rosh_more_buf */
+
+/* Page through a single file using the open file stream
+ * fd File Descriptor
+ */
+void rosh_more_fd(int fd, int rows, int cols)
+{
+ struct stat fdstat;
+ int status;
+ char *buf;
+ int bufpos;
+ int numrd;
+ FILE *f;
+
+ status = fstat(fd, &fdstat);
+ if (S_ISREG(fdstat.st_mode)) {
+ buf = malloc((int)fdstat.st_size);
+ if (buf != NULL) {
+ f = fdopen(fd, "r");
+ bufpos = 0;
+ numrd = fread(buf, 1, (int)fdstat.st_size, f);
+ while (numrd > 0) {
+ bufpos += numrd;
+ numrd = fread(buf+bufpos, 1, \
+ ((int)fdstat.st_size - bufpos), f);
+ }
+ fclose(f);
+ rosh_more_buf(buf, bufpos, rows, cols);
+ }
+ } else {
+ }
+
+} /* rosh_more_fd */
+
+/* Page through a file like the more command
+ * cmdstr command string to process
+ * pwdstr Present Working Directory string
+ * ipwdstr Initial PWD
+ */
+void rosh_more(const char *cmdstr, const char *pwdstr)
+ /*, const char *ipwdstr)*/
+{
+ int fd;
+ char filestr[ROSH_PATH_SZ + 1];
+ int cmdpos;
+ int rows, cols;
+
+ ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+ /* Initialization */
+ filestr[0] = 0;
+ cmdpos = 0;
+ if (getscreensize(1, &rows, &cols)) {
+ ROSH_DEBUG("getscreensize() fail; fall back\n");
+ ROSH_DEBUG("\tROWS='%d'\tCOLS='%d'\n", rows, cols);
+ /* If either fail, go under normal size, just in case */
+ if (!rows)
+ rows = 20;
+ if (!cols)
+ cols = 75;
+ }
+ ROSH_DEBUG("\tROWS='%d'\tCOLS='%d'\n", rows, cols);
+
+ /* skip the first word */
+ cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+ cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+ if (strlen(filestr) > 0) {
+ /* There is no need to mess up the console if we don't have a
+ file */
+ rosh_console_raw();
+ while (strlen(filestr) > 0) {
+ printf("--File = '%s'\n", filestr);
+ fd = open(filestr, O_RDONLY);
+ if (fd != -1) {
+ rosh_more_fd(fd, rows, cols);
+ close(fd);
+ } else {
+ rosh_error(errno, "more", filestr);
+ }
+ cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos);
+ }
+ rosh_console_std();
+ }
+} /* rosh_more */
+
+/* Page a file with rewind
+ * cmdstr command string to process
+ * pwdstr Present Working Directory string
+ * ipwdstr Initial PWD
+ */
+void rosh_less(const char *cmdstr, const char *pwdstr)
+{
+ printf(" less implemented as more (for now)\n");
+ rosh_more(cmdstr, pwdstr);
+} /* rosh_less */
+
+/* Show PWD
+ * cmdstr command string to process
+ * pwdstr Present Working Directory string
+ */
+void rosh_pwd(const char *cmdstr, const char *pwdstr)
+{
+ int istr;
+ ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+ printf("%s\n", pwdstr);
+ istr = htonl(*(int*)pwdstr);
+ ROSH_DEBUG(" --%08X\n", istr);
+} /* rosh_pwd */
+
+/* Run a boot string, calling syslinux_run_command
+ * cmdstr command string to process
+ * pwdstr Present Working Directory string
+ * ipwdstr Initial PWD
+ */
+void rosh_run(const char *cmdstr, const char *pwdstr, const char *ipwdstr)
+{
+ int cmdpos;
+ char *cmdptr;
+ char istr[ROSH_CMD_SZ]; /* input command string */
+
+ cmdpos = 0;
+ ROSH_DEBUG("CMD: '%s'\npwd: '%s'\n", cmdstr, pwdstr);
+ /* skip the first word */
+ cmdpos = rosh_search_sp(cmdstr, cmdpos);
+ /* skip spaces */
+ cmdpos = rosh_search_nonsp(cmdstr, cmdpos);
+ cmdptr = (char *)(cmdstr + cmdpos);
+ printf("--run: '%s'\n", cmdptr);
+ /* //HERE--Reparse if pwdstr != ipwdstr; seems a little daunting as
+ detecting params vs filenames is difficult/impossible */
+ if (strcmp(pwdstr, ipwdstr) != 0) {
+ /* For now, just prompt for verification */
+ printf(" from directory '%s'? (y/N):", pwdstr);
+ fgets(istr, ROSH_CMD_SZ, stdin);
+ if ((istr[0] != 'y') && (istr[0] != 'Y')) {
+ printf("Aborting run\n");
+ return;
+ }
+ printf("Run anyways\n");
+ }
+ syslinux_run_command(cmdptr);
+} /* rosh_run */
+
+/* Process a single command string and call handling function
+ * cmdstr command string to process
+ * pwdstr Present Working Directory string
+ * ipwdstr Initial Present Working Directory string
+ * returns Whether to exit prompt
+ */
+char rosh_command(const char *cmdstr, char *pwdstr, const char *ipwdstr)
+{
+ char do_exit;
+ do_exit = false;
+ ROSH_DEBUG("--cmd:'%s'\n", cmdstr);
+ switch (cmdstr[0]) {
+ case 'e': case 'E': case 'q': case 'Q':
+ do_exit = true; break;
+ case 'c': case 'C': /* run 'cd' 'cat' 'cfg' */
+ switch (cmdstr[1]) {
+ case 'a': case 'A':
+ rosh_cat(cmdstr, pwdstr); break;
+ case 'd': case 'D':
+ rosh_cd(cmdstr, pwdstr, ipwdstr); break;
+ case 'f': case 'F':
+ rosh_cfg(cmdstr, pwdstr); break;
+ default: rosh_help(1);
+ }
+ break;
+ case 'd': case 'D': /* run 'dir' */
+ rosh_dir(cmdstr, pwdstr); break;
+ case 'h': case 'H': case '?': rosh_help(2);
+ break;
+ case 'l': case 'L': /* run 'ls' 'less' */
+ switch (cmdstr[1]) {
+ case 0: case 's': case 'S':
+ rosh_ls(cmdstr, pwdstr); break;
+ case 'e': case 'E':
+ rosh_less(cmdstr, pwdstr); break;
+ default: rosh_help(1);
+ }
+ break;
+ case 'm': case 'M':
+ switch (cmdstr[1]) {
+ case 'a': case 'A':
+ rosh_help(2);
+ break;
+ case 'o': case 'O':
+ rosh_more(cmdstr, pwdstr);
+ break;
+ default: rosh_help(1);
+ }
+ break;
+ case 'p': case 'P': /* run 'pwd' */
+ rosh_pwd(cmdstr, pwdstr); break;
+ case 'r': case 'R': /* run 'run' */
+ rosh_run(cmdstr, pwdstr, ipwdstr); break;
+ case 'v': case 'V':
+ rosh_version(); break;
+ case 0: case '\n': break;
+ default : rosh_help(1);
+ } /* switch(cmdstr[0]) */
+ return do_exit;
+} /* rosh_command */
+
+/* Process the prompt for commands as read from stdin and call rosh_command
+ * to process command line string
+ * icmdstr Initial command line string
+ * returns Exit status
+ */
+int rosh_prompt(const char *icmdstr)
+{
+ int rv;
+ char cmdstr[ROSH_CMD_SZ];
+ char pwdstr[ROSH_PATH_SZ + 1], ipwdstr[ROSH_PATH_SZ + 1];
+/* int numchar;
+*/ char do_exit;
+ char *c;
+
+ rv = 0;
+ do_exit = false;
+ strcpy(pwdstr, "/");
+ getcwd(pwdstr, ROSH_PATH_SZ + 1);
+ strcpy(ipwdstr, pwdstr); /* Retain the original PWD */
+ if (icmdstr[0] != '\0')
+ do_exit = rosh_command(icmdstr, pwdstr, ipwdstr);
+ while (!(do_exit)) {
+ console_ansi_std();
+ printf("\nrosh: ");
+ /* Read a line from console */
+ fgets(cmdstr, ROSH_CMD_SZ, stdin);
+ /* remove newline from input string */
+ c = strchr(cmdstr, '\n');
+ *c = 0;
+ do_exit = rosh_command(cmdstr, pwdstr, ipwdstr);
+ }
+ if (strcmp(pwdstr, ipwdstr) != 0) {
+ /* Change directory to the original directory */
+ strcpy(cmdstr, "cd ");
+ strcpy(cmdstr + 3, ipwdstr);
+ rosh_cd(cmdstr, pwdstr, ipwdstr);
+ }
+ return rv;
+}
+
+int main(int argc, char *argv[])
+{
+ int rv;
+ char cmdstr[ROSH_CMD_SZ];
+
+ /* Initialization */
+ rv = 0;
+ console_ansi_std();
+// console_ansi_raw();
+ if (argc != 1) {
+ rv = rosh_argcat(cmdstr, argc, argv, 1);
+ } else {
+ rosh_version();
+ cmdstr[0] = '\0';
+ }
+ rv = rosh_prompt(cmdstr);
+ printf("--Exiting '%s'\n", APP_NAME);
+ console_ansi_std();
+ return rv;
+}
diff --git a/com32/rosh/rosh.h b/com32/rosh/rosh.h
new file mode 100644
index 00000000..d7296e1a
--- /dev/null
+++ b/com32/rosh/rosh.h
@@ -0,0 +1,148 @@
+/* ----------------------------------------------------------------------- *
+ *
+ * Copyright 2008 Gene Cumm - All Rights Reserved
+ *
+ * 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., 53 Temple Place Ste 330,
+ * Boston MA 02111-1307, USA; either version 2 of the License, or
+ * (at your option) any later version; incorporated herein by reference.
+ *
+ * ----------------------------------------------------------------------- */
+
+/*
+ * rosh.h
+ *
+ * Read-Only shell; Header
+ */
+
+/*
+ * History
+ * b021 Move much PreProcessing stuff to rosh.h
+ * b018 Create rosh_debug() macro
+ * b012 Version of rosh.c at time of creating this file.
+ */
+
+#ifndef ROSH_H
+#define ROSH_H
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h> /* macro: true false */
+#include <string.h> /* strcpy() strlen() memcpy() strchr() */
+#include <sys/types.h>
+#include <sys/stat.h> /* fstat() */
+#include <fcntl.h> /* open(); open mode macros */
+#include <dirent.h> /* fdopendir() opendir() readdir() closedir() DIR */
+#include <unistd.h> /* getcwd() */
+#include <errno.h> /* errno; error macros */
+#include <netinet/in.h> /* For htonl/ntohl/htons/ntohs */
+
+#include <getkey.h>
+#include <consoles.h>
+
+/* A GNUC extension to void out unused functions are used */
+/* Plus, there seem to be other references for SYSLINUX to __GNUC__ */
+#ifndef __GNUC__
+#error SYSLINUX (I believe) requires __GNUC__
+#endif /* __GNUC__ */
+
+#ifdef DO_DEBUG
+#define ROSH_DEBUG(f, ...) printf (f, ## __VA_ARGS__)
+#ifdef DO_DEBUG2
+#define ROSH_DEBUG2(f, ...) printf (f, ## __VA_ARGS__)
+#else /* DO_DEBUG2 */
+#define ROSH_DEBUG2(f, ...) ((void)0)
+#endif /* DO_DEBUG2 */
+#else /* DO_DEBUG */
+#define ROSH_DEBUG(f, ...) ((void)0)
+#define ROSH_DEBUG2(f, ...) ((void)0)
+#endif /* DO_DEBUG */
+
+#ifdef __COM32__
+#define ROSH_IS_COM32 1
+#include <console.h> /* openconsole() */
+#include <syslinux/config.h> /* Has info on the SYSLINUX variant */
+#include <syslinux/boot.h> /* syslinux_run_command() */
+#define ROSH_COM32(f, ...) printf (f, ## __VA_ARGS__)
+#else
+#include <termios.h>
+#define ROSH_IS_COM32 0
+static inline char *syslinux_config_file()
+{
+ return "";
+}
+static inline int getscreensize(int fd, int *rows, int *cols)
+{
+ char *str;
+ int rv;
+ *rows = 0;
+ *cols = 0;
+ if (rows) {
+ str = getenv("LINES");
+ if (str) {
+ *rows = atoi(str);
+ }
+ }
+ if (cols) {
+ str = getenv("COLUMNS");
+ if (str) {
+ *cols = atoi(str);
+ }
+ }
+ if (!rows || !cols)
+ rv = -1;
+ else if (!*rows || !*cols)
+ rv = -2;
+ else
+ rv = 0;
+ return rv;
+}
+#define ROSH_COM32(f, ...) ((void)0)
+#define syslinux_run_command(f) ((void)0)
+#endif /* __COM32__ */
+
+#define SEP '/'
+
+/* Size of buffer string */
+#define ROSH_BUF_SZ 16384
+/* Size of screen output buffer (80*40) */
+#define ROSH_SBUF_SZ 1200
+
+/* Size of command buffer string */
+#ifdef MAX_CMDLINE_LEN
+#define ROSH_CMD_SZ MAX_CMDLINE_LEN
+#else
+#ifdef COMMAND_LINE_SIZE
+#define ROSH_CMD_SZ COMMAND_LINE_SIZE
+#else
+#define ROSH_CMD_SZ 2048
+#endif /* COMMAND_LINE_SIZE */
+#endif /* MAX_CMDLINE_LEN */
+
+/* Size of path buffer string */
+#ifdef PATH_MAX
+#define ROSH_PATH_SZ PATH_MAX
+#elif NAME_MAX
+#define ROSH_PATH_SZ NAME_MAX
+#else
+#define ROSH_PATH_SZ 255
+#endif /* NAME_MAX */
+
+const char rosh_help_str1[] =
+"Commands: ? cat cd cfg dir exit help less ls man more pwd run quit ver";
+
+const char rosh_help_str2[] =
+"Commands: (some 1-letter abreviations also allowed)\n\
+ h HELP\n ALSO ? help man\n\
+ cat Concatenate file to console\n cat <file>\n\
+ cd Change to directory <dir>\n cd <dir>\n\
+ less Page a file with rewind\n\
+ ls List contents of current directory\n ls <dir>\n\
+ ALSO dir\n\
+ more Page a file\n\
+ pwd display Present Working Directory\n\
+ run Run a program/kernel with options\n\
+ exit Exit to previous environment\n ALSO quit";
+
+#endif /* Not ROSH_H */
diff --git a/core/comboot.inc b/core/comboot.inc
index 7210b8b8..2ff5f33e 100644
--- a/core/comboot.inc
+++ b/core/comboot.inc
@@ -1047,6 +1047,72 @@ comapi_kbdtable:
stc
ret
+;
+; INT 22h AX=001Fh Get current working directory
+;
+comapi_getcwd:
+ mov P_ES,cs
+ mov P_BX,CurrentDirName
+ clc
+ ret
+
+;
+; INT 22h AX=0020h Open directory
+;
+%if IS_SYSLINUX
+comapi_opendir:
+ push ds
+ mov ds,P_ES
+ mov si,P_SI
+ mov di,InitRD
+ call mangle_name
+ pop ds
+ call searchdir
+ jnz comapi_err ; Didn't find a directory
+ cmp eax,0
+ jz comapi_err ; Found nothing
+ ;ZF is unset
+ call alloc_fill_dir
+ mov P_EAX,eax
+ mov P_CX,SECTOR_SIZE
+ mov P_SI,si
+ clc
+ ret
+%else
+comapi_opendir equ comapi_err
+%endif
+
+;
+; INT 22h AX=0021h Read directory
+;
+%if IS_SYSLINUX
+comapi_readdir:
+ mov es,P_ES
+ mov di,P_DI
+ mov si,P_SI
+ call readdir
+ mov P_EAX,eax
+ mov P_DL,dl
+ mov P_EBX,ebx
+ mov P_SI,si
+ ret
+%else
+comapi_readdir equ comapi_err
+%endif
+
+;
+; INT 22h AX=0022h Close directory
+;
+%if IS_SYSLINUX
+comapi_closedir:
+ mov si,P_SI
+ call close_dir
+ clc
+ ret
+%else
+comapi_closedir equ comapi_err
+%endif
+
section .data
%macro int21 2
@@ -1100,6 +1166,10 @@ int22_table:
dw comapi_getadv ; 001C get pointer to ADV
dw comapi_writeadv ; 001D write ADV to disk
dw comapi_kbdtable ; 001E keyboard remapping table
+ dw comapi_getcwd ; 001F get current working directory
+ dw comapi_opendir ; 0020 open directory
+ dw comapi_readdir ; 0021 read directory
+ dw comapi_closedir ; 0022 close directory
int22_count equ ($-int22_table)/2
APIKeyWait db 0
@@ -1124,3 +1194,4 @@ err_comlarge db 'COMBOOT image too large.', CR, LF, 0
alignb 4
DOSErrTramp resd 33 ; Error trampolines
ConfigName resb FILENAME_MAX
+CurrentDirName resb FILENAME_MAX
diff --git a/core/extlinux.asm b/core/extlinux.asm
index 24d0d926..c7a51e94 100644
--- a/core/extlinux.asm
+++ b/core/extlinux.asm
@@ -42,6 +42,9 @@ MAX_SYMLINKS equ 64 ; Maximum number of symlinks per lookup
SYMLINK_SECTORS equ 2 ; Max number of sectors in a symlink
; (should be >= FILENAME_MAX)
+ROOT_DIR_WORD equ 0x002F
+CUR_DIR_DWORD equ 0x00002F2E
+
;
; This is what we need to do when idle
;
@@ -843,6 +846,8 @@ load_config:
mov si,config_name ; Save config file name
mov di,ConfigName
call strcpy
+ mov dword [CurrentDirName],CUR_DIR_DWORD ; Write './',0,0 to the CurrentDirName
+ call build_curdir_str
mov di,ConfigName
call open
@@ -1515,6 +1520,9 @@ getfssec:
pop ebp
ret
+build_curdir_str:
+ ret
+
; -----------------------------------------------------------------------------
; Common modules
; -----------------------------------------------------------------------------
diff --git a/core/isolinux.asm b/core/isolinux.asm
index 3b970053..2c6d9702 100644
--- a/core/isolinux.asm
+++ b/core/isolinux.asm
@@ -36,6 +36,8 @@ MAX_OPEN equ (1 << MAX_OPEN_LG2)
SECTOR_SHIFT equ 11 ; 2048 bytes/sector (El Torito requirement)
SECTOR_SIZE equ (1 << SECTOR_SHIFT)
+ROOT_DIR_WORD equ 0x002F
+
;
; This is what we need to do when idle
;
@@ -1147,15 +1149,33 @@ get_fs_structures:
; Look for an isolinux directory, and if found,
; make it the current directory instead of the root
; directory.
+ ; Also copy the name of the directory to CurrentDirName
+ mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName
mov di,boot_dir ; Search for /boot/isolinux
mov al,02h
+ push di
call searchdir_iso
+ pop di
jnz .found_dir
mov di,isolinux_dir
mov al,02h ; Search for /isolinux
+ push di
call searchdir_iso
+ pop di
jz .no_isolinux_dir
.found_dir:
+ ; Copy current directory name to CurrentDirName
+ push si
+ push di
+ mov si,di
+ mov di,CurrentDirName
+ call strcpy
+ mov byte [di],0 ;done in case it's not word aligned
+ dec di
+ mov byte [di],'/'
+ pop di
+ pop si
+
mov [CurrentDir+dir_len],eax
mov eax,[si+file_left]
mov [CurrentDir+dir_clust],eax
diff --git a/core/ldlinux.asm b/core/ldlinux.asm
index c7f6577c..da1ddde2 100644
--- a/core/ldlinux.asm
+++ b/core/ldlinux.asm
@@ -44,6 +44,11 @@ MAX_OPEN equ (1 << MAX_OPEN_LG2)
SECTOR_SHIFT equ 9
SECTOR_SIZE equ (1 << SECTOR_SHIFT)
+DIRENT_SHIFT equ 5
+DIRENT_SIZE equ (1 << DIRENT_SHIFT)
+
+ROOT_DIR_WORD equ 0x002F
+
;
; This is what we need to do when idle
;
@@ -100,7 +105,8 @@ file_left resd 1 ; Number of sectors left
.magic resd 2 ; 8-byte magic number
.reserved resd 6 ; Reserved for future use
.uppercase resb 256 ; Internal upper-case table
-.unicode resw 2*256 ; Unicode matching table
+.unicode resw 256 ; Unicode matching table
+.unicode_alt resw 256 ; Alternate Unicode matching table
endstruc
%ifndef DEPEND
@@ -900,19 +906,40 @@ getfattype:
mov si,config_name ; Save configuration file name
mov di,ConfigName
call strcpy
+ mov word [CurrentDirName],ROOT_DIR_WORD ; Write '/',0 to the CurrentDirName
mov eax,[RootDir] ; Make the root directory ...
mov [CurrentDir],eax ; ... the current directory
mov di,syslinux_cfg1
+ push di
call open
+ pop di
jnz .config_open
mov di,syslinux_cfg2
+ push di
call open
+ pop di
jnz .config_open
mov di,syslinux_cfg3
+ push di
call open
+ pop di
jz no_config_file
.config_open:
+ push si
+ mov si,di
+ push si
+ mov di,CurrentDirName
+ ; This is inefficient as it will copy more than needed
+ ; but not by too much
+ call strcpy
+ mov ax,config_name ;Cut it down
+ pop si
+ sub ax,si
+ mov di,CurrentDirName
+ add di,ax
+ mov byte [di],0
+ pop si
mov eax,[PrevDir] ; Make the directory with syslinux.cfg ...
mov [CurrentDir],eax ; ... the current directory
@@ -945,6 +972,37 @@ allocate_file:
ret
;
+; alloc_fill_dir:
+; Allocate then fill a file structure for a directory starting in
+; sector EAX.
+;
+; Assumes DS == ES == CS.
+;
+; If successful:
+; ZF clear
+; SI = file pointer
+; If unsuccessful
+; ZF set
+; EAX clobbered
+;
+alloc_fill_dir:
+ push bx
+ call allocate_file
+ jnz .alloc_failure
+.found:
+ mov si,bx
+ mov [si+file_sector],eax ; Current sector
+ mov dword [si+file_bytesleft],0 ; Current offset
+ mov [si+file_left],eax ; Beginning sector
+ pop bx
+ ret
+
+.alloc_failure:
+ pop bx
+ xor eax,eax ; ZF <- 1
+ ret
+
+;
; search_dos_dir:
; Search a specific directory for a pre-mangled filename in
; MangledBuf, in the directory starting in sector EAX.
@@ -1040,10 +1098,10 @@ search_dos_dir:
cmp bx,[NameLen]
jae .vfat_tail
movzx bx,byte [bx+di]
- shl bx,2
+ add bx,bx
cmp ax,[cp_unicode+bx] ; Primary case
je .ucs_ok
- cmp ax,[cp_unicode+bx+2] ; Alternate case
+ cmp ax,[cp_unicode_alt+bx] ; Alternate case
je .ucs_ok
; Mismatch...
jmp .not_us_pop
@@ -1170,8 +1228,31 @@ codepage equ $-(32+32)
codepage_data: incbin "codepage.cp",32+32
cp_uppercase equ codepage+cp.uppercase
cp_unicode equ codepage+cp.unicode
+cp_unicode_alt equ codepage+cp.unicode_alt
codepage_end equ $
+ section .text
+;
+; Input: UCS-2 character in AX
+; Output: Single byte character in AL, ZF = 1
+; On failure, returns ZF = 0
+;
+ucs2_to_cp:
+ push es
+ push di
+ push cx
+ push cs
+ pop es
+ mov di,cp_unicode
+ mov cx,512
+ repne scasw
+ xchg ax,cx
+ pop cx
+ pop di
+ pop es
+ not ax ; Doesn't change the flags!
+ ret
+
section .bss
VFATInit resb 1
VFATNext resb 1
@@ -1191,6 +1272,18 @@ close_file:
.closed: ret
;
+; close_dir:
+; Deallocates a directory structure (pointer in SI)
+; Assumes CS == DS.
+;
+close_dir:
+ and si,si
+ jz .closed
+ mov dword [si],0 ; First dword == file_sector
+ xor si,si
+.closed: ret
+
+;
; searchdir:
;
; Open a file
@@ -1224,9 +1317,17 @@ searchdir:
cmp al,'/'
jne .findend
.endpath:
- xchg si,di
+ xchg si,di ; GRC: si begin; di end[ /]+1
pop eax ; <A> Current directory sector
+ ; GRC Here I need to check if di-1 = si which signifies
+ ; we have the desired directory in EAX
+ ; What about where the file name = "."; later
+ mov dx,di
+ dec dx
+ cmp dx,si
+ jz .founddir
+
mov [PrevDir],eax ; Remember last directory searched
push di
@@ -1263,12 +1364,252 @@ searchdir:
xchg eax,[si+file_sector] ; Get sector number and free file structure
jmp .pathwalk ; Walk the next bit of the path
+ ; Found the desired directory; ZF set but EAX not 0
+.founddir:
+ ret
+
.badfile:
xor eax,eax
mov [si],eax ; Free file structure
.notfound:
+ xor eax,eax ; Zero out EAX
+ ret
+
+;
+; readdir: Read one file from a directory
+;
+; ES:DI -> String buffer (filename)
+; DS:SI -> Pointer to open_file_t
+; DS Must be the SYSLINUX Data Segment
+;
+; Returns the file's name in the filename string buffer
+; EAX returns the file size
+; EBX returns the beginning sector (currently without offsetting)
+; DL returns the file type
+; The directory handle's data is incremented to reflect a name read.
+;
+readdir:
+ push ecx
+ push bp ; Using bp to transfer between segment registers
+ push si
+ push es
+ push fs ; Using fs to store the current es (from COMBOOT)
+ push gs
+ mov bp,es
+ mov fs,bp
+ cmp si,0
+ jz .fail
+.load_handle:
+ mov eax,[ds:si+file_sector] ; Current sector
+ mov ebx,[ds:si+file_bytesleft] ; Current offset
+ cmp eax,0
+ jz .fail
+.fetch_cache:
+ call getcachesector
+.move_current:
+ add si,bx ; Resume last position in sector
+ mov ecx,SECTOR_SIZE ; 0 out high part
+ sub cx,bx
+ shr cx,5 ; Number of entries left
+.scanentry:
+ cmp byte [gs:si],0
+ jz .fail
+ cmp word [gs:si+11],0Fh ; Long filename
+ jne .short_entry
+
+.vfat_entry:
+ push eax
+ push ecx
+ push si
+ push di
+.vfat_ln_info: ; Get info about the line that we're on
+ mov al,[gs:si]
+ test al,40h
+ jz .vfat_tail_ln
+ and al,03Fh
+ mov ah,1 ; On beginning line
+ jmp .vfat_ck_ln
+
+.vfat_tail_ln: ; VFAT tail line processing (later in VFAT, head in name)
+ test al,80h ; Invalid data?
+ jnz .vfat_abort
+ mov ah,0 ; Not on beginning line
+ cmp dl,al
+ jne .vfat_abort ; Is this the entry we need?
+ mov bl,[gs:si+13]
+ cmp bl,[VFATCsum]
+ je .vfat_cp_ln
+ jmp .vfat_abort
+
+.vfat_ck_ln: ; Load this line's VFAT CheckSum
+ mov bl,[gs:si+13]
+ mov [VFATCsum],bl
+.vfat_cp_ln: ; Copy VFAT line
+ dec al ; Store the next line we need
+ mov dx,ax ; Use DX to store the progress
+ mov cx,13 ; 13 characters per VFAT DIRENT
+ cbw ; AH <- 0
+ mul cl ; Offset for DI
+ add di,ax ; Increment DI
+ inc si ; Align to the real characters
+.vfat_cp_chr:
+ gs lodsw ; Unicode here!!
+ call ucs2_to_cp ; Convert to local codepage
+ jnz .vfat_abort ; Use short name if character not on codepage
+ stosb ; CAN NOT OVERRIDE es
+ cmp al,0
+ jz .vfat_find_next ; Null-terminated string; don't process more
+ cmp cx,3
+ je .vfat_adj_add2
+ cmp cx,9
+ jne .vfat_adj_add0
+.vfat_adj_add3: inc si
+.vfat_adj_add2: inc si
+.vfat_adj_add1: inc si
+.vfat_adj_add0:
+ loop .vfat_cp_chr
+ cmp dh,1 ; Is this the first round?
+ jnz .vfat_find_next
+.vfat_null_term: ; Need to null-terminate if first line as we rolled over the end
+ mov al,0
+ stosb
+
+.vfat_find_next: ;Find the next part of the name
+ pop di
+ pop si
+ pop ecx
+ pop eax
+ cmp dl,0
+ jz .vfat_find_info ; We're done with the name
+ add si,DIRENT_SIZE
+ dec cx
+ jnz .vfat_entry
+ call nextsector
+ jnc .vfat_entry ; CF is set if we're at end
+ jmp .fail
+.vfat_find_info: ; Fetch next entry for the size/"INode"
+ add si,DIRENT_SIZE
+ dec cx
+ jnz .get_info
+ call nextsector
+ jnc .get_info ; CF is set if we're at end
+ jmp .fail
+.vfat_abort: ; Something went wrong, skip
+ pop di
+ pop si
+ pop ecx
+ pop eax
+ jmp .skip_entry
+
+.short_entry:
+ test byte [gs:si+11],8 ; Ignore volume labels //HERE
+ jnz .skip_entry
+ mov edx,eax ;Save current sector
+ push cx
+ push si
+ push di
+ mov cx,8
+.short_file:
+ gs lodsb
+ cmp al,'.'
+ jz .short_dot
+.short_file_loop:
+ cmp al,' '
+ jz .short_skip_bs
+ stosb
+ loop .short_file_loop
+ jmp .short_period
+.short_skip_bs: ; skip blank spaces in FILENAME (before EXT)
+ add si,cx
+ dec si
+.short_period:
+ mov al,'.'
+ stosb
+ mov cx,3
+.short_ext:
+ gs lodsb
+ cmp al,' '
+ jz .short_done
+ stosb
+ loop .short_ext
+ jmp .short_done
+.short_dot:
+ stosb
+ gs lodsb
+ cmp al,' '
+ jz .short_done
+ stosb
+.short_done:
+ mov al,0 ; Null-terminate the short strings
+ stosb
+ pop di
+ pop si
+ pop cx
+ mov eax,edx
+.get_info:
+ mov ebx,[gs:si+28] ; length
+ mov dl,[gs:si+11] ; type
+.next_entry:
+ add si,DIRENT_SIZE
+ dec cx
+ jnz .store_offset
+ call nextsector
+ jnc .store_sect ; CF is set if we're at end
+ jmp .fail
+
+.skip_entry:
+ add si,DIRENT_SIZE
+ dec cx
+ jnz .scanentry
+ call nextsector
+ jnc .scanentry ; CF is set if we're at end
+ jmp .fail
+
+.store_sect:
+ pop gs
+ pop fs
+ pop es
+ pop si
+ mov [ds:si+file_sector],eax
+ mov eax,0 ; Now at beginning of new sector
+ jmp .success
+
+.store_offset:
+ pop gs
+ pop fs
+ pop es
+ pop si ; cx=num remain; SECTOR_SIZE-(cx*32)=cur pos
+ shl ecx,DIRENT_SHIFT
+ mov eax,SECTOR_SIZE
+ sub eax,ecx
+ and eax,0ffffh
+
+.success:
+ mov [ds:si+file_bytesleft],eax
+ ; "INode" number = ((CurSector-RootSector)*SECTOR_SIZE + Offset)/DIRENT_SIZE)
+ mov ecx,eax
+ mov eax,[ds:si+file_sector]
+ sub eax,[RootDir]
+ shl eax,SECTOR_SHIFT
+ add eax,ecx
+ shr eax,DIRENT_SHIFT
+ dec eax
+ xchg eax,ebx ; -> EBX=INode, EAX=FileSize
+ jmp .done
+
+.fail:
+ pop gs
+ pop fs
+ pop es
+ pop si
+ call close_dir
xor eax,eax
+ stc
+.done:
+ pop bp
+ pop ecx
+.end:
ret
section .bss
diff --git a/core/pxelinux.asm b/core/pxelinux.asm
index 57de536f..944ba86c 100644
--- a/core/pxelinux.asm
+++ b/core/pxelinux.asm
@@ -734,6 +734,13 @@ prefix: test byte [DHCPMagic], 04h ; Did we get a path prefix option
call writestr_early
call crlf
+ ; Set CurrentDirName
+ push di
+ mov si,PathPrefix
+ mov di,CurrentDirName
+ call strcpy
+ pop di
+
;
; Load configuration file
;
diff --git a/doc/comboot.txt b/doc/comboot.txt
index 53295020..387303d3 100644
--- a/doc/comboot.txt
+++ b/doc/comboot.txt
@@ -921,3 +921,46 @@ AX=001Eh [3.74] Keyboard remapping table
version, the format code is always 1 and the length is always
256. This version can be updated simply by overwriting the version
in memory; this may not be true in the future.
+
+
+AX=001Fh [BETA-3.74+] Get current working directory
+ Input: AX 0001Eh
+ Output: ES:BX null-terminated directory name string
+
+ Returns the current working directory. For SYSLINUX, ISOLINUX,
+ and PXELINUX, this will be an absolute path. For EXTLINUX, it
+ currently returns "./".
+
+
+AX=0020h [BETA-3.74+] Open directory
+ Input: AX 001Fh
+ ES:SI /-null-terminated directory name
+ Output: SI directory handle
+ EAX clobbered
+
+ Open a directory for reading. Directory name must have a trailing
+ "/" before the null (otherwise, you're looking for a file)(This
+ may change as this is a BETA call).
+
+
+AX=0021h [BETA-3.74+] Read directory
+ Input: AX 0020h
+ SI directory handle
+ ES:DI buffer for file name
+ Output: DL Type of file
+ SI directory handle, or 0 if end of directory was reached
+ EAX Size of file
+ EBX Inode of file
+
+ Read one filename from the directory, incrementing the directory
+ structure at SI as appropriate, storing the filename into the buffer
+ at ES:DI, and returning the type of the file in DL, the file length
+ in EAX, the INode/file number in EBX and the updated directory handle.
+
+
+AX=0022h [BETA-3.74+] Close directory
+ Input: AX 001Fh
+ SI directory handle
+ Output SI 0
+
+ Closes a directory.