From 582645e269ee82d544ab8b8b913c8364f3178484 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Sun, 25 Jan 2009 17:23:32 -0800 Subject: Reorganize the codepage handling to allow ucs2 -> codepage conversion Reorganize the codepage handling to make it easier to do ucs2 -> codepage conversion, this will be used for a future directory lister. --- codepage/cptable.pl | 5 ++++- core/ldlinux.asm | 28 +++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 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/core/ldlinux.asm b/core/ldlinux.asm index c7f6577c..e9d0573f 100644 --- a/core/ldlinux.asm +++ b/core/ldlinux.asm @@ -100,7 +100,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 @@ -1040,10 +1041,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 +1171,29 @@ 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 +; +; Assumes CS == ES == 0. +; +ucs2_to_cp: + push di + push cx + mov di,cp_unicode + mov cx,512 + repne scasw + xchg ax,cx + pop cx + pop di + not ax ; Doesn't change the flags! + ret + section .bss VFATInit resb 1 VFATNext resb 1 -- cgit v1.2.3 From c1def425e3eeb245da7a59025f2fa37f02368504 Mon Sep 17 00:00:00 2001 From: Gene Cumm Date: Sun, 8 Feb 2009 09:36:59 -0500 Subject: COMBOOT API: Add calls for directory functions; Implement for FAT COMBOOT API: Add calls for directory functions; Implement most only for FAT (SYSLINUX). Uses INT 22h AX= 001Fh, 0020h, 0021h and 0022h to prepare for the COM32 C functions getcwd(), opendir(), readdir(), and closedir(), respectively. INT22h, AX=001Fh will return a valid value for all variants. INT22h, AX= 0020h, 0021h, and 0022h are only implemented for SYSLINUX while other variants will call comapi_err for these 3. Signed-off-by: Gene Cumm Signed-off-by: H. Peter Anvin --- core/comboot.inc | 71 ++++++++++++ core/extlinux.asm | 8 ++ core/isolinux.asm | 20 ++++ core/ldlinux.asm | 324 +++++++++++++++++++++++++++++++++++++++++++++++++++++- core/pxelinux.asm | 7 ++ doc/comboot.txt | 43 ++++++++ 6 files changed, 472 insertions(+), 1 deletion(-) 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..61ce1a0e 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 ; @@ -900,19 +905,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 @@ -944,6 +970,37 @@ allocate_file: .found: pop cx 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 @@ -1190,6 +1247,18 @@ close_file: xor si,si .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: ; @@ -1224,9 +1293,17 @@ searchdir: cmp al,'/' jne .findend .endpath: - xchg si,di + xchg si,di ; GRC: si begin; di end[ /]+1 pop eax ; 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 +1340,257 @@ 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] + jne .vfat_abort + jmp .vfat_cp_ln + +.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 bx,13 + mov ah,0 + mul bl ; Offset for DI + add di,ax ; Increment DI + inc si ; Align to the real characters + mov cx,13 ; 13 characters per VFAT DIRENT +.vfat_cp_chr: + gs lodsw ; Unicode here!! + mov bp,ds + mov es,bp + call ucs2_to_cp ; Convert to local codepage + mov bp,fs + mov es,bp + jc .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 aac1ec27..94f23afb 100644 --- a/core/pxelinux.asm +++ b/core/pxelinux.asm @@ -704,6 +704,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. -- cgit v1.2.3 From 3d17ee8d11838b6380818f144ed04c188c775df5 Mon Sep 17 00:00:00 2001 From: Gene Cumm Date: Tue, 10 Feb 2009 22:18:18 -0500 Subject: COM32 API: Add functions for directory use COM32: Add directory functions getcwd(), opendir(), readdir() and closedir(). This depends on the patch that I just submitted creating the COMBOOT API calls. Signed-off-by: Gene Cumm Signed-off-by: H. Peter Anvin --- com32/include/dirent.h | 36 +++++++++++++++++++++++++++++++++ com32/include/unistd.h | 3 +++ com32/lib/Makefile | 2 ++ com32/lib/chdir.c | 13 ++++++++++++ com32/lib/closedir.c | 29 +++++++++++++++++++++++++++ com32/lib/fdopendir.c | 13 ++++++++++++ com32/lib/getcwd.c | 29 +++++++++++++++++++++++++++ com32/lib/opendir.c | 41 ++++++++++++++++++++++++++++++++++++++ com32/lib/readdir.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 9 files changed, 220 insertions(+) create mode 100644 com32/include/dirent.h create mode 100644 com32/lib/chdir.c create mode 100644 com32/lib/closedir.c create mode 100644 com32/lib/fdopendir.c create mode 100644 com32/lib/getcwd.c create mode 100644 com32/lib/opendir.c create mode 100644 com32/lib/readdir.c 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 +#include +#include +#include + +#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 +#include +#include + +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 +#include +#include + +#include +#include +#include +#include + +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 +#include +#include + +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 +#include +#include + +#include +#include +#include + +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 +#include +#include + +#include +#include +#include +#include + + +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 +#include +#include + +#include +#include +#include +#include + +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; +} -- cgit v1.2.3 From 8814df6683dca8e6a54da61d8afd88372d99047d Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 10 Feb 2009 22:22:23 -0800 Subject: ldlinux: fix interface to ucs2_to_cp The interface to ucs2_to_cp has changed slightly, it now returns ZF=0 on failure, not CF=1. --- core/ldlinux.asm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/core/ldlinux.asm b/core/ldlinux.asm index 29f3b3b4..a06e727c 100644 --- a/core/ldlinux.asm +++ b/core/ldlinux.asm @@ -1437,8 +1437,8 @@ readdir: jne .vfat_abort ; Is this the entry we need? mov bl,[gs:si+13] cmp bl,[VFATCsum] - jne .vfat_abort - jmp .vfat_cp_ln + je .vfat_cp_ln + jmp .vfat_abort .vfat_ck_ln: ; Load this line's VFAT CheckSum mov bl,[gs:si+13] @@ -1459,10 +1459,10 @@ readdir: call ucs2_to_cp ; Convert to local codepage mov bp,fs mov es,bp - jc .vfat_abort ;-; Use short name if character not on 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 + jz .vfat_find_next ; Null-terminated string; don't process more cmp cx,3 je .vfat_adj_add2 cmp cx,9 -- cgit v1.2.3 From 9485c9742fcc2c499fed98057c3ef44f67fda91b Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 10 Feb 2009 22:37:16 -0800 Subject: ldlinux: readdir: trivial optimization Trivially optimize the readdir code Signed-off-by: H. Peter Anvin --- core/ldlinux.asm | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/core/ldlinux.asm b/core/ldlinux.asm index a06e727c..21a3a352 100644 --- a/core/ldlinux.asm +++ b/core/ldlinux.asm @@ -1446,12 +1446,11 @@ readdir: .vfat_cp_ln: ; Copy VFAT line dec al ; Store the next line we need mov dx,ax ; Use DX to store the progress - mov bx,13 - mov ah,0 - mul bl ; Offset for DI + 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 - mov cx,13 ; 13 characters per VFAT DIRENT .vfat_cp_chr: gs lodsw ; Unicode here!! mov bp,ds -- cgit v1.2.3 From 6174d35033800faa87c208683d26d3a2e1ae5156 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 10 Feb 2009 22:39:52 -0800 Subject: ldlinux: move es manipulation into ucs2_to_cp If currently the only caller of ucs2_to_cp wants to use ES, we might as well move the ES set/restore into ucs2_to_cp. Signed-off-by: H. Peter Anvin --- core/ldlinux.asm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/core/ldlinux.asm b/core/ldlinux.asm index 21a3a352..da1ddde2 100644 --- a/core/ldlinux.asm +++ b/core/ldlinux.asm @@ -1237,17 +1237,19 @@ codepage_end equ $ ; Output: Single byte character in AL, ZF = 1 ; On failure, returns ZF = 0 ; -; Assumes CS == ES == 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 @@ -1453,11 +1455,7 @@ readdir: inc si ; Align to the real characters .vfat_cp_chr: gs lodsw ; Unicode here!! - mov bp,ds - mov es,bp call ucs2_to_cp ; Convert to local codepage - mov bp,fs - mov es,bp jnz .vfat_abort ; Use short name if character not on codepage stosb ; CAN NOT OVERRIDE es cmp al,0 -- cgit v1.2.3 From 53daea0916af7b874f830bd0428da2be4e1bc3b3 Mon Sep 17 00:00:00 2001 From: Gene Cumm Date: Sun, 15 Feb 2009 17:26:37 -0500 Subject: COM32 module: Read-Only shell Well, here's the read-only shell (rosh) that I've been working on. It's functional but still quite rough. My primary intention of posting it at this time is such that people have an easy way to demonstrate to themselves that the library calls I made work. This should apply as a patch to the head of the "dir" branch and the patch for c_cflag/c_lflag. The patch is only needed for Linux(without it, segfaults will occur). I've designed it to compile as a COM32 module and Linux binary when using GNU C (as Syslinux currently requires GNU C, if I read the Makefiles correctly). --- com32/Makefile | 2 +- com32/rosh/MCONFIG | 27 ++ com32/rosh/Makefile | 38 +++ com32/rosh/rosh.c | 810 ++++++++++++++++++++++++++++++++++++++++++++++++++++ com32/rosh/rosh.h | 148 ++++++++++ 5 files changed, 1024 insertions(+), 1 deletion(-) create mode 100644 com32/rosh/MCONFIG create mode 100644 com32/rosh/Makefile create mode 100644 com32/rosh/rosh.c create mode 100644 com32/rosh/rosh.h 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/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 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 +#include +#include /* macro: true false */ +#include /* strcpy() strlen() memcpy() strchr() */ +#include +#include /* fstat() */ +#include /* open(); open mode macros */ +#include /* fdopendir() opendir() readdir() closedir() DIR */ +#include /* getcwd() */ +#include /* errno; error macros */ +#include /* For htonl/ntohl/htons/ntohs */ + +#include +#include + +/* 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 /* openconsole() */ +#include /* Has info on the SYSLINUX variant */ +#include /* syslinux_run_command() */ +#define ROSH_COM32(f, ...) printf (f, ## __VA_ARGS__) +#else +#include +#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 \n\ + cd Change to directory \n cd \n\ + less Page a file with rewind\n\ + ls List contents of current directory\n ls \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 */ -- cgit v1.2.3