diff options
author | H. Peter Anvin <hpa@zytor.com> | 2009-02-16 22:52:01 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2009-02-16 22:52:01 -0800 |
commit | 1b90fba407546b72dad8d0c8c4729ef8ab5c32fc (patch) | |
tree | 2cf5b5f64f9d75450ae405d48aa9e7021900f425 | |
parent | d7cb344206117dd22afbde6df56e8b81d47718ae (diff) | |
parent | 53daea0916af7b874f830bd0428da2be4e1bc3b3 (diff) | |
download | syslinux-elf-1b90fba407546b72dad8d0c8c4729ef8ab5c32fc.tar.gz syslinux-elf-1b90fba407546b72dad8d0c8c4729ef8ab5c32fc.tar.xz syslinux-elf-1b90fba407546b72dad8d0c8c4729ef8ab5c32fc.zip |
Merge branch 'dir'
-rwxr-xr-x | codepage/cptable.pl | 5 | ||||
-rw-r--r-- | com32/Makefile | 2 | ||||
-rw-r--r-- | com32/include/dirent.h | 36 | ||||
-rw-r--r-- | com32/include/unistd.h | 3 | ||||
-rw-r--r-- | com32/lib/Makefile | 2 | ||||
-rw-r--r-- | com32/lib/chdir.c | 13 | ||||
-rw-r--r-- | com32/lib/closedir.c | 29 | ||||
-rw-r--r-- | com32/lib/fdopendir.c | 13 | ||||
-rw-r--r-- | com32/lib/getcwd.c | 29 | ||||
-rw-r--r-- | com32/lib/opendir.c | 41 | ||||
-rw-r--r-- | com32/lib/readdir.c | 54 | ||||
-rw-r--r-- | com32/rosh/MCONFIG | 27 | ||||
-rw-r--r-- | com32/rosh/Makefile | 38 | ||||
-rw-r--r-- | com32/rosh/rosh.c | 810 | ||||
-rw-r--r-- | com32/rosh/rosh.h | 148 | ||||
-rw-r--r-- | core/comboot.inc | 71 | ||||
-rw-r--r-- | core/extlinux.asm | 8 | ||||
-rw-r--r-- | core/isolinux.asm | 20 | ||||
-rw-r--r-- | core/ldlinux.asm | 349 | ||||
-rw-r--r-- | core/pxelinux.asm | 7 | ||||
-rw-r--r-- | doc/comboot.txt | 43 |
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(®s, 0, sizeof regs); /* ?Needed? */ + regs.eax.w[0] = 0x0022; + regs.esi.w[0] = dir->dd_fd; + __com32.cs_intcall(0x22, ®s, ®s); + 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, ®, ®); + 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, ®s, ®s); + + 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(®s, 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, ®s, ®s); + + /* 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. |