diff options
author | Liu Aleaxander <Aleaxander@gmail.com> | 2010-12-17 22:31:21 +0800 |
---|---|---|
committer | Liu Aleaxander <Aleaxander@gmail.com> | 2010-12-17 22:31:21 +0800 |
commit | eaf68081e8efef04086368ad18f60b53d0360311 (patch) | |
tree | 6e44925ad970ddf61d0c3392e8ffc2b3e695b2e3 | |
parent | c36818139752b4505459b094061b7d1f8ccf3c4f (diff) | |
parent | ac7b5736554bcdf5ba06ac637d1028dd7ddc25db (diff) | |
download | syslinux-elflink.tar.gz syslinux-elflink.tar.xz syslinux-elflink.zip |
Merge branch 'master' into elflinkelflink
Conflicts:
com32/lib/sys/open.c
core/keywords.inc
version
Signed-off-by: Liu Aleaxander <Aleaxander@gmail.com>
36 files changed, 1483 insertions, 406 deletions
@@ -2,6 +2,38 @@ Starting with 1.47, changes marked with SYSLINUX, PXELINUX, ISOLINUX or EXTLINUX apply to that specific program only; other changes apply to all derivatives. +Changes in 4.04: + * PXELINUX: Fix handling of unqualified DNS names. + * PXELINUX: Fix timer bug when PXELINUX might be unloaded + (Gene Cumm). + * core/writedec.inc: Fix duplicate declaration and overflow + (Gene Cumm). + * GCC 4.5 fixes. + * sample directory: Fix Makefile include (Gene Cumm). + * ver.com: New universal DOS/COMBOOT application to display + version information (includes DRMK) (Gene Cumm). + * rosh.c32: updated; Using getopt() for internal commands to aid + parsing options; Fix bugs in ls; add warm reboot and echo + (Gene Cumm). + * com32: fix a file descriptor leak. + * gfxboot.c32: handle TEXT..ENDTEXT; error out on no LABELs + found (Sebastian Herbszt). + * Fix booting on non-partitioned devices. + +Changes in 4.03: + * Don't hang if no configuration file is found. + * Better support for booting from MBRs which don't pass + handover information. + * EXTLINUX: Try to be smarter about finding the partition + offset. + * chain.c32: support chainloading Dell Real Mode Kernel (Gene + Cumm). + * chain.c32: fix booting in CHS mode. + * rosh.c32 updated (Gene Cumm). + * Fix the -s option to the syslinux/extlinux installer (Arwin + Vosselman). + * isohybrid: fix padding of large images (PJ Pandit). + Changes in 4.02: * SYSLINUX: correctly handle the case where the -d option is specified with a non-absolute path, i.e. "syslinux -d diff --git a/com32/gfxboot/gfxboot.c b/com32/gfxboot/gfxboot.c index dd4d6410..552728fd 100644 --- a/com32/gfxboot/gfxboot.c +++ b/com32/gfxboot/gfxboot.c @@ -21,6 +21,7 @@ #include <fcntl.h> #include <sys/types.h> #include <sys/stat.h> +#include <minmax.h> #include <syslinux/loadfile.h> #include <syslinux/config.h> @@ -60,7 +61,7 @@ #define GFX_CB_PASSWORD_DONE 11 // real mode code chunk, will be placed into bounce buffer -extern void realmode_callback_start, realmode_callback_end; +extern const char realmode_callback_start[], realmode_callback_end[]; // gets in the way #undef linux @@ -134,6 +135,7 @@ gfx_menu_t gfx_menu; menu_t *menu; menu_t *menu_default; +static menu_t *menu_ptr, **menu_next; struct { uint32_t jmp_table[12]; @@ -161,7 +163,7 @@ char *get_config_file_name(void); char *skip_spaces(char *s); char *skip_nonspaces(char *s); void chop_line(char *s); -int read_config_file(void); +int read_config_file(const char *filename); unsigned magic_ok(unsigned char *buf, unsigned *code_size); unsigned find_file(unsigned char *buf, unsigned len, unsigned *gfx_file_start, unsigned *file_len, unsigned *code_size); int gfx_init(char *file); @@ -219,7 +221,7 @@ int main(int argc, char **argv) return 0; } - if(read_config_file()) { + if(read_config_file("~")) { printf("Error reading config file\n"); if(argc > 2) show_message(argv[2]); @@ -313,16 +315,24 @@ void chop_line(char *s) // return: // 0: ok, 1: error // -int read_config_file(void) +int read_config_file(const char *filename) { FILE *f; char *s, *t, buf[MAX_CONFIG_LINE_LEN]; - unsigned u, menu_idx = 0, label_size = 0, append_size = 0; - menu_t *menu_ptr = NULL, **menu_next = &menu; + unsigned u, top_level = 0, text = 0; - menu_default = calloc(1, sizeof *menu_default); + if(!strcmp(filename, "~")) { + top_level = 1; + filename = syslinux_config_file(); + gfx_menu.entries = 0; + gfx_menu.label_size = 0; + gfx_menu.arg_size = 0; + menu_ptr = NULL; + menu_next = &menu; + menu_default = calloc(1, sizeof *menu_default); + } - if(!(f = fopen(syslinux_config_file(), "r"))) return 1; + if(!(f = fopen(filename, "r"))) return 1; while((s = fgets(buf, sizeof buf, f))) { chop_line(s); @@ -332,6 +342,14 @@ int read_config_file(void) if(*t) *t++ = 0; t = skip_spaces(t); + if(!strcasecmp(s, "endtext")) { + text = 0; + continue; + } + + if (text) + continue; + if(!strcasecmp(s, "timeout")) { timeout = atoi(t); continue; @@ -340,17 +358,17 @@ int read_config_file(void) if(!strcasecmp(s, "default")) { menu_default->label = strdup(t); u = strlen(t); - if(u > label_size) label_size = u; + if(u > gfx_menu.label_size) gfx_menu.label_size = u; continue; } if(!strcasecmp(s, "label")) { menu_ptr = *menu_next = calloc(1, sizeof **menu_next); menu_next = &menu_ptr->next; - menu_idx++; + gfx_menu.entries++; menu_ptr->label = menu_ptr->menu_label = strdup(t); u = strlen(t); - if(u > label_size) label_size = u; + if(u > gfx_menu.label_size) gfx_menu.label_size = u; continue; } @@ -377,7 +395,7 @@ int read_config_file(void) if(!strcasecmp(s, "append")) { (menu_ptr ?: menu_default)->append = strdup(t); u = strlen(t); - if(u > append_size) append_size = u; + if(u > gfx_menu.arg_size) gfx_menu.arg_size = u; continue; } @@ -386,6 +404,11 @@ int read_config_file(void) continue; } + if(!strcasecmp(s, "text")) { + text = 1; + continue; + } + if(!strcasecmp(s, "menu") && menu_ptr) { s = skip_spaces(t); t = skip_nonspaces(s); @@ -395,17 +418,37 @@ int read_config_file(void) if(!strcasecmp(s, "label")) { menu_ptr->menu_label = strdup(t); u = strlen(t); - if(u > label_size) label_size = u; + if(u > gfx_menu.label_size) gfx_menu.label_size = u; continue; } + + if(!strcasecmp(s, "include")) { + goto do_include; + } + } + + if (!strcasecmp(s, "include")) { +do_include: + s = t; + t = skip_nonspaces(s); + if (*t) *t = 0; + read_config_file(s); } } fclose(f); + if (!top_level) + return 0; + + if (gfx_menu.entries == 0) { + printf("No LABEL keywords found.\n"); + return 1; + } + // final '\0' - label_size++; - append_size++; + gfx_menu.label_size++; + gfx_menu.arg_size++; // ensure we have a default entry if(!menu_default->label) menu_default->label = menu->label; @@ -419,19 +462,16 @@ int read_config_file(void) } } - gfx_menu.entries = menu_idx; - gfx_menu.label_size = label_size; - gfx_menu.arg_size = append_size; gfx_menu.default_entry = menu_default->menu_label; - gfx_menu.label_list = calloc(menu_idx, label_size); - gfx_menu.arg_list = calloc(menu_idx, append_size); + gfx_menu.label_list = calloc(gfx_menu.entries, gfx_menu.label_size); + gfx_menu.arg_list = calloc(gfx_menu.entries, gfx_menu.arg_size); for(u = 0, menu_ptr = menu; menu_ptr; menu_ptr = menu_ptr->next, u++) { if(!menu_ptr->append) menu_ptr->append = menu_default->append; if(!menu_ptr->ipappend) menu_ptr->ipappend = menu_default->ipappend; - if(menu_ptr->menu_label) strcpy(gfx_menu.label_list + u * label_size, menu_ptr->menu_label); - if(menu_ptr->append) strcpy(gfx_menu.arg_list + u * append_size, menu_ptr->append); + if(menu_ptr->menu_label) strcpy(gfx_menu.label_list + u * gfx_menu.label_size, menu_ptr->menu_label); + if(menu_ptr->append) strcpy(gfx_menu.arg_list + u * gfx_menu.arg_size, menu_ptr->append); } return 0; @@ -535,7 +575,7 @@ int gfx_init(char *file) gfx_config.file = gfx_config.archive_start + file_start; - u = &realmode_callback_end - &realmode_callback_start; + u = realmode_callback_end - realmode_callback_start; u = (u + REALMODE_BUF_SIZE + 0xf) & ~0xf; if(u + code_size > lowmem_size) { @@ -543,7 +583,8 @@ int gfx_init(char *file) return 1; } - memcpy(lowmem + REALMODE_BUF_SIZE, &realmode_callback_start, &realmode_callback_end - &realmode_callback_start); + memcpy(lowmem + REALMODE_BUF_SIZE, realmode_callback_start, + realmode_callback_end - realmode_callback_start); // fill in buffer size and location *(uint16_t *) (lowmem + REALMODE_BUF_SIZE) = REALMODE_BUF_SIZE; @@ -749,7 +790,7 @@ void *load_one(char *file, ssize_t *file_size) if(size) { buf = malloc(size); for(i = 1, cur = 0 ; cur < size && i > 0; cur += i) { - i = save_read(fd, buf + cur, CHUNK_SIZE); + i = save_read(fd, buf + cur, min(CHUNK_SIZE, size - cur)); if(i == -1) break; gfx_progress_update(i); } diff --git a/com32/gplinclude/cpuid.h b/com32/gplinclude/cpuid.h index bc9df171..53a08085 100644 --- a/com32/gplinclude/cpuid.h +++ b/com32/gplinclude/cpuid.h @@ -19,6 +19,7 @@ #include <stdbool.h> #include <stdint.h> #include <cpufeature.h> +#include <sys/bitops.h> #include <sys/cpu.h> #include <klibc/compiler.h> @@ -173,11 +174,6 @@ typedef struct { #define X86_VENDOR_NUM 9 #define X86_VENDOR_UNKNOWN 0xff -static inline __purefunc bool test_bit(int nr, const uint32_t * addr) -{ - return ((1UL << (nr & 31)) & (addr[nr >> 5])) != 0; -} - #define cpu_has(c, bit) test_bit(bit, (c)->x86_capability) /* diff --git a/com32/gpllib/disk/msdos.c b/com32/gpllib/disk/msdos.c index affec43b..a4ee60fb 100644 --- a/com32/gpllib/disk/msdos.c +++ b/com32/gpllib/disk/msdos.c @@ -20,13 +20,13 @@ #include <disk/partition.h> #include <disk/read.h> -static inline int is_extended_partition(struct part_entry *ptab) +static int is_extended_partition(struct part_entry *ptab) { return (ptab->ostype == 0x05 || ptab->ostype == 0x0f || ptab->ostype == 0x85); } -static inline int msdos_magic_present(const char *ptab) +static int msdos_magic_present(const char *ptab) { return (*(uint16_t *) (ptab + 0x1fe) == 0xaa55); } diff --git a/com32/include/sys/bitops.h b/com32/include/sys/bitops.h new file mode 100644 index 00000000..06cf9f3e --- /dev/null +++ b/com32/include/sys/bitops.h @@ -0,0 +1,58 @@ +/* ----------------------------------------------------------------------- * + * + * Copyright 2010 Intel Corporation; author: H. Peter Anvin + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom + * the Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall + * be included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * ----------------------------------------------------------------------- */ + +/* + * bitops.h + * + * Simple bitwise operations + */ + +#ifndef _BITOPS_H +#define _BITOPS_H + +#include <klibc/compiler.h> + +static inline void set_bit(long __bit, void *__bitmap) +{ + asm volatile("btsl %1,%0" : "+m" (__bitmap) : "Ir" (__bit) : "memory"); +} + +static inline void clr_bit(long __bit, void *__bitmap) +{ + asm volatile("btcl %1,%0" : "+m" (__bitmap) : "Ir" (__bit) : "memory"); +} + +static inline int __purefunc test_bit(long __bit, const void *__bitmap) +{ + unsigned char __r; + asm("btl %2,%1; setnz %0" + : "=r" (__r) + : "m" (__bitmap), "Ir" (__bit)); + return __r; +} + +#endif /* _BITOPS_H */ diff --git a/com32/include/unistd.h b/com32/include/unistd.h index fc514f10..9e13381a 100644 --- a/com32/include/unistd.h +++ b/com32/include/unistd.h @@ -28,6 +28,10 @@ __extern int chdir(const char *); __extern unsigned int sleep(unsigned int); __extern unsigned int msleep(unsigned int); +__extern int getopt(int, char *const *, const char *); +__extern char *optarg; +__extern int optind, opterr, optopt; + /* Standard file descriptor numbers. */ #define STDIN_FILENO 0 #define STDOUT_FILENO 1 diff --git a/com32/lib/memmem.c b/com32/lib/memmem.c index 8558a80d..7c42f1c3 100644 --- a/com32/lib/memmem.c +++ b/com32/lib/memmem.c @@ -18,26 +18,35 @@ void *memmem(const void *haystack, size_t n, const void *needle, size_t m) size_t j, k, l; - if (m > n) - return NULL; + if (m > n || !m || !n) + return NULL; - if (x[0] == x[1]) { - k = 2; - l = 1; - } else { - k = 1; - l = 2; - } + if (1 != m) { + if (x[0] == x[1]) { + k = 2; + l = 1; + } else { + k = 1; + l = 2; + } - j = 0; - while (j <= n - m) { - if (x[1] != y[j + 1]) { - j += k; - } else { - if (!memcmp(x + 2, y + j + 2, m - 2) && x[0] == y[j]) - return (void *)&y[j]; - j += l; - } + j = 0; + while (j <= n - m) { + if (x[1] != y[j + 1]) { + j += k; + } else { + if (!memcmp(x + 2, y + j + 2, m - 2) + && x[0] == y[j]) + return (void *)&y[j]; + j += l; + } + } + } else { + do { + if (*y == *x) + return (void *)y; + y++; + } while (--n); } return NULL; diff --git a/com32/lib/strspn.c b/com32/lib/strspn.c index abbbf175..7a248205 100644 --- a/com32/lib/strspn.c +++ b/com32/lib/strspn.c @@ -11,12 +11,12 @@ #define LONG_BIT (CHAR_BIT*sizeof(long)) #endif -static inline void set_bit(unsigned long *bitmap, unsigned int bit) +static void set_bit(unsigned long *bitmap, unsigned int bit) { bitmap[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT); } -static inline int test_bit(unsigned long *bitmap, unsigned int bit) +static int test_bit(unsigned long *bitmap, unsigned int bit) { return (int)(bitmap[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1; } diff --git a/com32/lib/sys/open.c b/com32/lib/sys/open.c index a071c61b..3aa211b2 100644 --- a/com32/lib/sys/open.c +++ b/com32/lib/sys/open.c @@ -57,15 +57,17 @@ int open(const char *pathname, int flags, ...) fd = opendev(&__file_dev, NULL, flags); - //printf("enter, file = %s, fd = %d\n", pathname, fd); - if (fd < 0) return -1; fp = &__file_info[fd]; - handle = open_file(pathname, &fp->i.fd); - if (handle < 0) + + handle = __com32.cs_pm->open_file(pathname, &fp->i.fd); + if (handle < 0) { + close(fd); + errno = ENOENT; return -1; + } fp->i.offset = 0; fp->i.nbytes = 0; diff --git a/com32/lib/vsscanf.c b/com32/lib/vsscanf.c index 153dbbdd..d9fec51c 100644 --- a/com32/lib/vsscanf.c +++ b/com32/lib/vsscanf.c @@ -12,6 +12,7 @@ #include <string.h> #include <limits.h> #include <stdio.h> +#include <sys/bitops.h> #ifndef LONG_BIT #define LONG_BIT (CHAR_BIT*sizeof(long)) @@ -46,25 +47,13 @@ enum bail { bail_err /* Conversion mismatch */ }; -static inline const char *skipspace(const char *p) +static const char *skipspace(const char *p) { while (isspace((unsigned char)*p)) p++; return p; } -#undef set_bit -static inline void set_bit(unsigned long *bitmap, unsigned int bit) -{ - bitmap[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT); -} - -#undef test_bit -static inline int test_bit(unsigned long *bitmap, unsigned int bit) -{ - return (int)(bitmap[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1; -} - int vsscanf(const char *buffer, const char *format, va_list ap) { const char *p = format; @@ -323,7 +312,7 @@ set_integer: if (ch == '^' && !(flags & FL_INV)) { matchinv = 1; } else { - set_bit(matchmap, (unsigned char)ch); + set_bit((unsigned char)ch, matchmap); state = st_match; } break; @@ -335,18 +324,18 @@ set_integer: range_start = (unsigned char)ch; state = st_match_range; } else { - set_bit(matchmap, (unsigned char)ch); + set_bit((unsigned char)ch, matchmap); } break; case st_match_range: /* %[ match after - */ if (ch == ']') { - set_bit(matchmap, (unsigned char)'-'); /* - was last character */ + set_bit((unsigned char)'-', matchmap); /* - was last character */ goto match_run; } else { int i; for (i = range_start; i < (unsigned char)ch; i++) - set_bit(matchmap, i); + set_bit(i, matchmap); state = st_match; } break; @@ -354,7 +343,7 @@ set_integer: match_run: /* Match expression finished */ qq = q; while (width && *q - && test_bit(matchmap, (unsigned char)*q) ^ matchinv) { + && test_bit((unsigned char)*q, matchmap) ^ matchinv) { *sarg++ = *q++; } if (q != qq) { diff --git a/com32/modules/chain.c b/com32/modules/chain.c index 6a5b1151..89489d18 100644 --- a/com32/modules/chain.c +++ b/com32/modules/chain.c @@ -76,6 +76,10 @@ * equivalent to seg=0x70 file=<loader> sethidden, * used with DOS' io.sys. * + * drmk=<loader> + * Similar to msdos=<loader> but prepares the special options + * for the Dell Real Mode Kernel. + * * grub=<loader> * same as seg=0x800 file=<loader> & jumping to seg 0x820, * used with GRUB Legacy stage2 files. @@ -266,23 +270,21 @@ static void *read_sectors(uint64_t lba, uint8_t count) if (lba) return NULL; /* Can only read MBR */ - s = 1; - h = 0; - c = 0; + s = h = c = 0; } else { - s = (lba % disk_info.sect) + 1; + s = lba % disk_info.sect; t = lba / disk_info.sect; /* Track = head*cyl */ h = t % disk_info.head; c = t / disk_info.head; } - if (s > 63 || h > 256 || c > 1023) + if (s >= 63 || h >= 256 || c >= 1024) return NULL; inreg.eax.b[0] = count; inreg.eax.b[1] = 0x02; /* Read */ - inreg.ecx.b[1] = c & 0xff; - inreg.ecx.b[0] = s + (c >> 6); + inreg.ecx.b[1] = c; + inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); inreg.edx.b[1] = h; inreg.edx.b[0] = disk_info.disk; inreg.ebx.w[0] = OFFS(buf); @@ -327,22 +329,20 @@ static int write_sector(unsigned int lba, const void *data) if (lba) return -1; /* Can only write MBR */ - s = 1; - h = 0; - c = 0; + s = h = c = 0; } else { - s = (lba % disk_info.sect) + 1; + s = lba % disk_info.sect; t = lba / disk_info.sect; /* Track = head*cyl */ h = t % disk_info.head; c = t / disk_info.head; } - if (s > 63 || h > 256 || c > 1023) + if (s >= 63 || h >= 256 || c >= 1024) return -1; inreg.eax.w[0] = 0x0301; /* Write one sector */ - inreg.ecx.b[1] = c & 0xff; - inreg.ecx.b[0] = s + (c >> 6); + inreg.ecx.b[1] = c; + inreg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); inreg.edx.b[1] = h; inreg.edx.b[0] = disk_info.disk; inreg.ebx.w[0] = OFFS(buf); @@ -1711,16 +1711,31 @@ int main(int argc, char *argv[]) * We only really need 4 new, usable bytes at the end. */ int tsize = (data[ndata].size + 19) & 0xfffffff0; + const union syslinux_derivative_info *sdi; + + sdi = syslinux_derivative_info(); + /* We should lookup the Syslinux partition offset and use it */ + fs_lba = *sdi->disk.partoffset; + /* + * fs_lba should be verified against the disk as some DRMK + * variants will check and fail if it does not match + */ + dprintf(" fs_lba offset is %d\n", fs_lba); + /* DRMK only uses a DWORD */ + if (fs_lba > 0xffffffff) { + error("LBA very large; Only using lower 32 bits; DRMK will probably fail\n"); + } regs.ss = regs.fs = regs.gs = 0; /* Used before initialized */ if (!realloc(data[ndata].data, tsize)) { error("Failed to realloc for DRMK\n"); - goto bail; + goto bail; /* We'll never make it */ } data[ndata].size = tsize; - /* ds:[bp+28] must be 0x0000003f */ + /* ds:bp is assumed by DRMK to be the boot sector */ + /* offset 28 is the FAT HiddenSectors value */ regs.ds = (tsize >> 4) + (opt.seg - 2); /* "Patch" into tail of the new space */ - *(int *)(data[ndata].data + tsize - 4) = 0x0000003f; + *(int *)(data[ndata].data + tsize - 4) = (int)(fs_lba & 0xffffffff); } ndata++; diff --git a/com32/rosh/Makefile b/com32/rosh/Makefile index 7bf5059c..f4b7d866 100644 --- a/com32/rosh/Makefile +++ b/com32/rosh/Makefile @@ -1,6 +1,8 @@ ## ----------------------------------------------------------------------- ## ## Copyright 2001-2008 H. Peter Anvin - All Rights Reserved +## Copyright 2010 Intel Corporation; author: H. Peter Anvin +## Copyright 2008-2010 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 @@ -11,18 +13,34 @@ ## ----------------------------------------------------------------------- ## -## samples for syslinux users +## ROSH Read Only Shell ## topdir = ../.. include MCONFIG +# from com32/sysdump/Makefile +# The DATE is set on the make command line when building binaries for +# official release. Otherwise, substitute a hex string that is pretty much +# guaranteed to be unique to be unique from build to build. +ifndef HEXDATE +HEXDATE := $(shell $(PERL) $(topdir)/now.pl $(SRCS) $(wildcard *.h)) +endif +ifndef DATE +DATE := $(shell sh $(topdir)/gen-id.sh $(VERSION) $(HEXDATE)) +endif + +CFLAGS += -DDATE='"$(DATE)"' +LNXCFLAGS += -DDATE='"$(DATE)"' + rosh.o: rosh.h rosh.lo: rosh.h all: rosh.c32 +allgrc: rosh.c32 rosh.lnx + tidy dist: rm -f *.o *.lo *.a *.lst *.elf .*.d *.tmp diff --git a/com32/rosh/rosh.c b/com32/rosh/rosh.c index bf1176fb..12e09995 100644 --- a/com32/rosh/rosh.c +++ b/com32/rosh/rosh.c @@ -20,7 +20,12 @@ /* * ToDos: - * rosh_ls(): sorted; then multiple columns + * prompt: Allow left/right arrow, home/end and more? + * commands Break into argv/argc-like array + * rosh_cfg: allow -s <file> to change config + * rosh_ls(): sorted; then multiple columns + * prompt: Possibly honor timeout on initial entry for usage as UI + * Also possibly honor totaltimeout */ /*#define DO_DEBUG 1 @@ -32,19 +37,30 @@ * debugging enabled; Comment to remove. */ #include "rosh.h" +#include "../../version.h" #define APP_LONGNAME "Read-Only Shell" #define APP_NAME "rosh" #define APP_AUTHOR "Gene Cumm" #define APP_YEAR "2010" -#define APP_VER "beta-b062" +#define APP_VER "beta-b089" -void rosh_version(void) +/* Print version information to stdout + */ +void rosh_version(int vtype) { - printf("%s v %s; (c) %s %s.\n", APP_LONGNAME, APP_VER, APP_YEAR, - APP_AUTHOR); + char env[256]; + env[0] = 0; + printf("%s v %s; (c) %s %s.\n\tFrom Syslinux %s, %s\n", APP_LONGNAME, APP_VER, APP_YEAR, APP_AUTHOR, VERSION_STR, DATE); + switch (vtype) { + case 1: + rosh_get_env_ver(env, 256); + printf("\tRunning on %s\n", env); + } } +/* Print beta message and if DO_DEBUG/DO_DEBUG2 are active + */ void print_beta(void) { puts(rosh_beta_str); @@ -112,33 +128,157 @@ int rosh_parse_sp_1(char *dest, const char *src, const int ipos) return epos; } +/* + * parse_args1: Try 1 at parsing a string to an argc/argv pair. use free_args1 to free memory malloc'd + * + * Derived from com32/lib/sys/argv.c:__parse_argv() + * Copyright 2004-2009 H. Peter Anvin - All Rights Reserved + * Copyright 2009 Intel Corporation; author: H. Peter Anvin + */ +int parse_args1(char ***iargv, const char *istr) +{ + int argc = 0; + const char *p; + char *q, *r, *args, **arg; + int sp = 1; //, qt = 0; /* Was a space; inside a quote */ + + /* Scan 1: Length */ + /* I could eliminate this if I knew a max length, like strncpy() */ + int len = strlen(istr); + + /* Scan 2: Copy, nullify and make argc */ + if (!(args = malloc(len + 1))) + goto fail_args; + q = args; + for (p = istr;; p++) { + if (*p <= ' ') { + if (!sp) { + sp = 1; + *q++ = '\0'; + } + } else { + if (sp) { + argc++; + sp = 0; + } + *q++ = *p; + } + if (!*p) + break; + } + + q--; /* Point q to final null */ + /* Scan 3: Build array of pointers */ + if (!(*iargv = malloc((argc + 1) * sizeof(char *)))) + goto fail_args_ptr; + arg = *iargv; + arg[argc] = NULL; /* Nullify the last pointer */ + if (*args != '\0') + *arg++ = args; + for (r = args; r < q ; r++) { + if (*r == '\0') { + *arg++ = r + 1; + } + } + +fail_args: + return argc; +fail_args_ptr: + free(args); + return 0; +} + +/* Free argv created by parse_args1() + * argv Argument Values + */ +void free_args1(char ***argv) +{ + char *s; + s = **argv; + free(*argv); + free(s); +} + +/* Convert a string to an argc/argv pair + * str String to parse + * argv Argument Values + * returns Argument Count + */ +int rosh_str2argv(char ***argv, const char *str) +{ + return parse_args1(argv, str); +} + +/* Free an argv created by rosh_str2argv() + * argv Argument Values to free + */ +void rosh_free_argv(char ***argv) +{ + free_args1(argv); +} + +/* Print the contents of an argc/argv pair + * argc Argument Count + * argv Argument Values + */ +void rosh_pr_argv(int argc, char *argv[]) +{ + int i; + for (i = 0; i < argc; i++) { + printf("%s%s", argv[i], (i < argc)? " " : ""); + } + puts(""); +} + +/* Print the contents of an argc/argv pair verbosely + * argc Argument Count + * argv Argument Values + */ +void rosh_pr_argv_v(int argc, char *argv[]) +{ + int i; + for (i = 0; i < argc; i++) { + printf("%4d '%s'\n", i, argv[i]); + } +} + +/* Reset the getopt() environment + */ +void rosh_getopt_reset(void) +{ + optind = 0; + optopt = 0; +} + /* Display help * type Help type - * cmdstr Command string + * cmdstr Command for which help is requested */ void rosh_help(int type, const char *cmdstr) { - const char *istr; - istr = cmdstr; switch (type) { case 2: - istr += rosh_search_nonsp(cmdstr, rosh_search_sp(cmdstr, 0)); - if ((cmdstr == NULL) || (strcmp(istr, "") == 0)) { - rosh_version(); + if ((cmdstr == NULL) || (strcmp(cmdstr, "") == 0)) { + rosh_version(0); puts(rosh_help_str2); } else { - switch (istr[0]) { + switch (cmdstr[0]) { + case 'c': + puts(rosh_help_cd_str); + break; case 'l': puts(rosh_help_ls_str); break; default: - printf(rosh_help_str_adv, istr); + printf(rosh_help_str_adv, cmdstr); } } break; case 1: default: - rosh_version(); + if (cmdstr) + printf("%s: %s: unknown command\n", APP_NAME, cmdstr); + rosh_version(0); puts(rosh_help_str1); } } @@ -187,11 +327,13 @@ void rosh_error(const int ierrno, const char *cmdstr, const char *filestr) /* Concatenate command line arguments into one string * cmdstr Output command string + * cmdlen Length of cmdstr * argc Argument Count * argv Argument Values * barg Beginning Argument */ -int rosh_argcat(char *cmdstr, const int argc, char *argv[], const int barg) +int rosh_argcat(char *cmdstr, const int cmdlen, const int argc, char *argv[], + const int barg) { int i, arglen, curpos; /* index, argument length, current position in cmdstr */ @@ -200,15 +342,15 @@ int rosh_argcat(char *cmdstr, const int argc, char *argv[], const int barg) 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; + if ((curpos + arglen) > (cmdlen - 1)) + arglen = (cmdlen - 1) - curpos; memcpy(cmdstr + curpos, argv[i], arglen); curpos += arglen; - if (curpos >= (ROSH_CMD_SZ - 1)) { + if (curpos >= (cmdlen - 1)) { /* Hopefully, curpos should not be greater than - (ROSH_CMD_SZ - 1) */ + (cmdlen - 1) */ /* Still need a '\0' at the last character */ - cmdstr[(ROSH_CMD_SZ - 1)] = 0; + cmdstr[(cmdlen - 1)] = 0; break; /* Escape out of the for() loop; We can no longer process anything more */ } else { @@ -278,26 +420,19 @@ void rosh_qualify_filestr(char *filestr, const char *ifilstr, } /* Concatenate multiple files to stdout - * cmdstr command string to process + * argc Argument Count + * argv Argument Values */ -void rosh_cat(const char *cmdstr) +void rosh_cat(int argc, char *argv[]) { FILE *f; - char filestr[ROSH_PATH_SZ]; char buf[ROSH_BUF_SZ]; - int numrd; - int cmdpos; + int i, numrd; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); - /* 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"); + for (i = 0; i < argc; i++) { + printf("--File = '%s'\n", argv[i]); + errno = 0; + f = fopen(argv[i], "r"); if (f != NULL) { numrd = fread(buf, 1, ROSH_BUF_SZ, f); while (numrd > 0) { @@ -306,36 +441,37 @@ void rosh_cat(const char *cmdstr) } fclose(f); } else { - rosh_error(errno, "cat", filestr); + rosh_error(errno, "cat", argv[i]); errno = 0; } - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); } } /* rosh_cat */ /* Change PWD (Present Working Directory) - * cmdstr command string to process + * argc Argument count + * argv Argument values * ipwdstr Initial PWD */ -void rosh_cd(const char *cmdstr, const char *ipwdstr) +void rosh_cd(int argc, char *argv[], const char *ipwdstr) { - int rv; + int rv = 0; +#ifdef DO_DEBUG char filestr[ROSH_PATH_SZ]; - int cmdpos; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); - /* 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); - if (strlen(filestr) != 0) - rv = chdir(filestr); - else +#endif /* DO_DEBUG */ + ROSH_DEBUG("CMD: \n"); + ROSH_DEBUG_ARGV_V(argc, argv); + errno = 0; + if (argc == 2) + rv = chdir(argv[1]); + else if (argc == 1) rv = chdir(ipwdstr); + else + rosh_help(2, argv[0]); if (rv != 0) { - rosh_error(errno, "cd", filestr); + if (argc == 2) + rosh_error(errno, "cd", argv[1]); + else + rosh_error(errno, "cd", ipwdstr); errno = 0; } else { #ifdef DO_DEBUG @@ -352,31 +488,61 @@ void rosh_cfg(void) printf("CFG: '%s'\n", syslinux_config_file()); } /* rosh_cfg */ -/* Process optstr to optarr - * optstr option string to process - * optarr option array to populate +/* Echo a string back to the screen + * cmdstr command string to process */ -void rosh_ls_arg_opt(const char *optstr, int *optarr) +void rosh_echo(const char *cmdstr) { - char *cpos; - cpos = strchr(optstr, 'l'); - if (cpos) { - optarr[0] = cpos - optstr; - } else { - optarr[0] = -1; - } - cpos = strchr(optstr, 'F'); - if (cpos) { - optarr[1] = cpos - optstr; + int bpos = 0; + ROSH_DEBUG("CMD: '%s'\n", cmdstr); + bpos = rosh_search_nonsp(cmdstr, rosh_search_sp(cmdstr, 0)); + if (bpos > 1) { + ROSH_DEBUG(" bpos=%d\n", bpos); + printf("'%s'\n", cmdstr + bpos); } else { - optarr[1] = -1; + puts(""); } - cpos = strchr(optstr, 'i'); - if (cpos) { - optarr[2] = cpos - optstr; - } else { - optarr[2] = -1; +} /* rosh_echo */ + +/* Process argc/argv to optarr + * argc Argument count + * argv Argument values + * optarr option array to populate + */ +void rosh_ls_arg_opt(int argc, char *argv[], int optarr[]) +{ + int rv = 0; + + optarr[0] = -1; + optarr[1] = -1; + optarr[2] = -1; + rosh_getopt_reset(); + while (rv != -1) { + ROSH_DEBUG2("getopt optind=%d rv=%d\n", optind, rv); + rv = getopt(argc, argv, rosh_ls_opt_str); + switch (rv) { + case 'l': + case 0: + optarr[0] = 1; + break; + case 'F': + case 1: + optarr[1] = 1; + break; + case 'i': + case 2: + optarr[2] = 1; + break; + case '?': + case -1: + default: + ROSH_DEBUG2("getopt optind=%d rv=%d\n", optind, rv); + break; + } } + ROSH_DEBUG2(" end getopt optind=%d rv=%d\n", optind, rv); + ROSH_DEBUG2("\tIn rosh_ls_arg_opt() opt[0]=%d\topt[1]=%d\topt[2]=%d\n", optarr[0], optarr[1], + optarr[2]); } /* rosh_ls_arg_opt */ /* Retrieve the size of a file argument @@ -428,6 +594,7 @@ int rosh_ls_de_size_mode(struct dirent *de, mode_t * st_mode) filestr2[file2pos] = '/'; } strcpy(filestr2 + file2pos + 1, de->d_name);*/ + errno = 0; status = stat(de->d_name, &fdstat); ROSH_DEBUG2("\t--stat()=%d\terr=%d\n", status, errno); if (errno) { @@ -621,14 +788,17 @@ void rosh_ls_arg_dir(const char *filestr, DIR * d, const int *optarr) int filepos; filepos = 0; + errno = 0; while ((de = readdir(d))) { filepos++; rosh_ls_arg_dir_de(de, optarr); } - if (errno) + if (errno) { rosh_error(errno, "ls:arg_dir", filestr); - else if (filepos == 0) + errno = 0; + } else { if (filepos == 0) ROSH_DEBUG("0 files found"); + } } /* rosh_ls_arg_dir */ /* Simple directory listing for one argument (file/directory) based on @@ -660,9 +830,13 @@ void rosh_ls_arg(const char *filestr, const int *optarr) if (status == 0) { if (S_ISDIR(fdstat.st_mode)) { ROSH_DEBUG("PATH '%s' is a directory\n", filestr); - d = opendir(filestr); - rosh_ls_arg_dir(filestr, d, optarr); - closedir(d); + if ((d = opendir(filestr))) { + rosh_ls_arg_dir(filestr, d, optarr); + closedir(d); + } else { + rosh_error(errno, "ls", filestr); + errno = 0; + } } else { de.d_ino = rosh_ls_d_ino(&fdstat); de.d_type = (IFTODT(fdstat.st_mode)); @@ -705,85 +879,50 @@ int rosh_ls_parse_opt(const char *filestr, char *optstr) return ret; } /* rosh_ls_parse_opt */ -/* List Directory based on cmdstr and pwdstr - * cmdstr command string to process - * pwdstr Present Working Directory string +/* List Directory + * argc Argument count + * argv Argument values */ -void rosh_ls(const char *cmdstr) +void rosh_ls(int argc, char *argv[]) { - char filestr[ROSH_PATH_SZ]; - char optstr[ROSH_OPT_SZ]; /* Options string */ - int cmdpos, tpos; /* Position within cmdstr, temp position */ - int numargs; /* number of non-option arguments */ - int argpos; /* number of non-option arguments processed */ int optarr[3]; + int i; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); - /* Initialization */ - filestr[0] = 0; - optstr[0] = 0; - cmdpos = 0; - numargs = 0; - argpos = 0; - /* skip the first word */ - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - tpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - /* If there are no real arguments, substitute PWD */ - if (strlen(filestr) == 0) { - strcpy(filestr, "."); - cmdpos = tpos; - } else { /* Parse for command line options */ - while (strlen(filestr) > 0) { - numargs += rosh_ls_parse_opt(filestr, optstr); - tpos = rosh_parse_sp_1(filestr, cmdstr, tpos); - } - if (numargs == 0) { - strcpy(filestr, "."); - cmdpos = tpos; - } else { - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - } - } + rosh_ls_arg_opt(argc, argv, optarr); + ROSH_DEBUG2("In ls()\n"); + ROSH_DEBUG2_ARGV_V(argc, argv); #ifdef DO_DEBUG - if (!strchr(optstr, 'l')) - strcat(optstr, "l"); + optarr[0] = 2; #endif /* DO_DEBUG */ - rosh_ls_arg_opt(optstr, optarr); - ROSH_DEBUG("\tfopt: '%s'\n", optstr); - while (strlen(filestr) > 0) { - if (rosh_ls_parse_opt(filestr, NULL)) { - rosh_ls_arg(filestr, optarr); - argpos++; - } - if (argpos < numargs) - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - else - break; + ROSH_DEBUG2(" argc=%d; optind=%d\n", argc, optind); + if (optind >= argc) + rosh_ls_arg(".", optarr); + for (i = optind; i < argc; i++) { + rosh_ls_arg(argv[i], optarr); } } /* rosh_ls */ /* Simple directory listing; calls rosh_ls() - * cmdstr command string to process - * pwdstr Present Working Directory string + * argc Argument count + * argv Argument values */ -void rosh_dir(const char *cmdstr) +void rosh_dir(int argc, char *argv[]) { ROSH_DEBUG(" dir implemented as ls\n"); - rosh_ls(cmdstr); + rosh_ls(argc, argv); } /* rosh_dir */ /* Page through a buffer string * buf Buffer to page through */ -//HERE: minor pagination issue; sometimes prints 1 less than rows -void rosh_more_buf(char *buf, int buflen, int rows, int cols) +void rosh_more_buf(char *buf, int buflen, int rows, int cols, char *scrbuf) { char *bufp, *bufeol, *bufeol2; /* 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 */ + int elpl; /* Extra lines per line read */ (void)cols; @@ -799,10 +938,19 @@ void rosh_more_buf(char *buf, int buflen, int rows, int cols) bufeol = buf + buflen; i = numln; } else { - i += ((bufeol2 - bufeol) / cols); - bufeol = bufeol2 + 1; + elpl = ((bufeol2 - bufeol - 1) / cols); + if (elpl < 0) + elpl = 0; + i += elpl; + ROSH_DEBUG2(" %d/%d ", elpl, i+1); + /* If this will not push too much, use it */ + /* but if it's the first line, use it */ + /* //HERE: We should probably snip the line off */ + if ((i < numln) || (i == elpl)) + bufeol = bufeol2 + 1; } } + ROSH_DEBUG2("\n"); bufcnt = bufeol - bufp; printf("--(%d/%d @%d)\n", bufcnt, buflen, bufpos); memcpy(scrbuf, bufp, bufcnt); @@ -829,7 +977,7 @@ void rosh_more_buf(char *buf, int buflen, int rows, int cols) /* Page through a single file using the open file stream * fd File Descriptor */ -void rosh_more_fd(int fd, int rows, int cols) +void rosh_more_fd(int fd, int rows, int cols, char *scrbuf) { struct stat fdstat; int status; @@ -851,7 +999,7 @@ void rosh_more_fd(int fd, int rows, int cols) ((int)fdstat.st_size - bufpos), f); } fclose(f); - rosh_more_buf(buf, bufpos, rows, cols); + rosh_more_buf(buf, bufpos, rows, cols, scrbuf); } } else { } @@ -859,22 +1007,22 @@ void rosh_more_fd(int fd, int rows, int cols) } /* rosh_more_fd */ /* Page through a file like the more command - * cmdstr command string to process - * ipwdstr Initial PWD + * argc Argument Count + * argv Argument Values */ -void rosh_more(const char *cmdstr) +void rosh_more(int argc, char *argv[]) { - int fd; - char filestr[ROSH_PATH_SZ]; - int cmdpos; + int fd, i; +/* char filestr[ROSH_PATH_SZ]; + int cmdpos;*/ int rows, cols; + char *scrbuf; + int ret; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); - /* Initialization */ - filestr[0] = 0; - cmdpos = 0; - if (getscreensize(1, &rows, &cols)) { - ROSH_DEBUG("getscreensize() fail; fall back\n"); + ROSH_DEBUG_ARGV_V(argc, argv); + ret = getscreensize(1, &rows, &cols); + if (ret) { + ROSH_DEBUG("getscreensize() fail(%d); fall back\n", ret); ROSH_DEBUG("\tROWS='%d'\tCOLS='%d'\n", rows, cols); /* If either fail, go under normal size, just in case */ if (!rows) @@ -883,51 +1031,47 @@ void rosh_more(const char *cmdstr) cols = 75; } ROSH_DEBUG("\tUSE ROWS='%d'\tCOLS='%d'\n", rows, cols); + /* 32 bit align beginning of row and over allocate */ + scrbuf = malloc(rows * ((cols+3)&(INT_MAX - 3))); + if (!scrbuf) + return; - /* skip the first word */ - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); - if (strlen(filestr) > 0) { + if (argc) { /* 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); + for (i = 0; i < argc; i++) { + printf("--File = '%s'\n", argv[i]); + errno = 0; + fd = open(argv[i], O_RDONLY); if (fd != -1) { - rosh_more_fd(fd, rows, cols); + rosh_more_fd(fd, rows, cols, scrbuf); close(fd); } else { - rosh_error(errno, "more", filestr); + rosh_error(errno, "more", argv[i]); errno = 0; } - cmdpos = rosh_parse_sp_1(filestr, cmdstr, cmdpos); } rosh_console_std(); } + free(scrbuf); } /* rosh_more */ /* Page a file with rewind - * cmdstr command string to process - * pwdstr Present Working Directory string - * ipwdstr Initial PWD + * argc Argument Count + * argv Argument Values */ -void rosh_less(const char *cmdstr) +void rosh_less(int argc, char *argv[]) { printf(" less implemented as more (for now)\n"); - rosh_more(cmdstr); + rosh_more(argc, argv); } /* rosh_less */ /* Show PWD - * cmdstr command string to process */ -void rosh_pwd(const char *cmdstr) +void rosh_pwd(void) { - int istr; char pwdstr[ROSH_PATH_SZ]; - if (cmdstr) - istr = 0; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); errno = 0; if (getcwd(pwdstr, ROSH_PATH_SZ)) { printf("%s\n", pwdstr); @@ -935,190 +1079,223 @@ void rosh_pwd(const char *cmdstr) rosh_error(errno, "pwd", ""); errno = 0; } - istr = htonl(*(int *)pwdstr); - ROSH_DEBUG2(" --%08X\n", istr); } /* rosh_pwd */ -/* Reboot +/* Reboot; use warm reboot if one of certain options set + * argc Argument count + * argv Argument values */ -void rosh_reboot(void) +void rosh_reboot(int argc, char *argv[]) { -// char cmdstr[ROSH_CMD_SZ]; -// printf - syslinux_reboot(0); + int rtype = 0; + if (argc) { + /* For now, just use the first */ + switch (argv[0][0]) { + case '1': + case 's': + case 'w': + rtype = 1; + break; + case '-': + switch (argv[0][1]) { + case '1': + case 's': + case 'w': + rtype = 1; + break; + } + break; + } + } + syslinux_reboot(rtype); } /* rosh_reboot */ /* Run a boot string, calling syslinux_run_command - * cmdstr command string to process + * argc Argument count + * argv Argument values */ -void rosh_run(const char *cmdstr) +void rosh_run(int argc, char *argv[]) { - int cmdpos; - char *cmdptr; + char cmdstr[ROSH_CMD_SZ]; + int len; - cmdpos = 0; - ROSH_DEBUG("CMD: '%s'\n", cmdstr); - /* 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); - syslinux_run_command(cmdptr); + len = rosh_argcat(cmdstr, ROSH_CMD_SZ, argc, argv, 0); + if (len) { + printf("--run: '%s'\n", cmdstr); + syslinux_run_command(cmdstr); + } else { + printf(APP_NAME ":run: No arguments\n"); + } } /* rosh_run */ -/* Process a single command string and call handling function - * cmdstr command string to process +/* Process an argc/argv pair and call handling function + * argc Argument count + * argv Argument values * ipwdstr Initial Present Working Directory string * returns Whether to exit prompt */ -char rosh_command(const char *cmdstr, const char *ipwdstr) +char rosh_command(int argc, char *argv[], const char *ipwdstr) { - char do_exit; - char tstr[ROSH_CMD_SZ]; + char do_exit = false; int tlen; - do_exit = false; - ROSH_DEBUG("--cmd:'%s'\n", cmdstr); - tlen = rosh_parse_sp_1(tstr, cmdstr, 0); - switch (cmdstr[0]) { + tlen = strlen(argv[0]); + ROSH_DEBUG_ARGV_V(argc, argv); + switch (argv[0][0]) { case 'e': case 'E': case 'q': case 'Q': - if ((strncasecmp("exit", tstr, tlen) == 0) || - (strncasecmp("quit", tstr, tlen) == 0)) - do_exit = true; - else - rosh_help(1, NULL); + switch (argv[0][1]) { + case 0: + case 'x': + case 'X': + case 'u': + case 'U': + if ((strncasecmp("exit", argv[0], tlen) == 0) || + (strncasecmp("quit", argv[0], tlen) == 0)) + do_exit = true; + else + rosh_help(1, argv[0]); + break; + case 'c': + case 'C': + if (strncasecmp("echo", argv[0], tlen) == 0) + rosh_pr_argv(argc - 1, &argv[1]); + else + rosh_help(1, argv[0]); + break; + default: + rosh_help(1, argv[0]); + } break; case 'c': case 'C': /* run 'cd' 'cat' 'cfg' */ - switch (cmdstr[1]) { + switch (argv[0][1]) { case 'a': case 'A': - if (strncasecmp("cat", tstr, tlen) == 0) - rosh_cat(cmdstr); + if (strncasecmp("cat", argv[0], tlen) == 0) + rosh_cat(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'd': case 'D': - if (strncasecmp("cd", tstr, tlen) == 0) - rosh_cd(cmdstr, ipwdstr); + if (strncasecmp("cd", argv[0], tlen) == 0) + rosh_cd(argc, argv, ipwdstr); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'f': case 'F': - if (strncasecmp("cfg", tstr, tlen) == 0) + if (strncasecmp("cfg", argv[0], tlen) == 0) rosh_cfg(); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; default: - rosh_help(1, NULL); + rosh_help(1, argv[0]); } break; case 'd': case 'D': /* run 'dir' */ - if (strncasecmp("dir", tstr, tlen) == 0) - rosh_dir(cmdstr); + if (strncasecmp("dir", argv[0], tlen) == 0) + rosh_dir(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'h': case 'H': case '?': - if ((strncasecmp("help", tstr, tlen) == 0) || (tlen == 1)) - rosh_help(2, cmdstr); + if ((strncasecmp("help", argv[0], tlen) == 0) || (tlen == 1)) + rosh_help(2, argv[1]); else rosh_help(1, NULL); break; case 'l': case 'L': /* run 'ls' 'less' */ - switch (cmdstr[1]) { + switch (argv[0][1]) { case 0: - case ' ': case 's': case 'S': - if (strncasecmp("ls", tstr, tlen) == 0) - rosh_ls(cmdstr); + if (strncasecmp("ls", argv[0], tlen) == 0) + rosh_ls(argc, argv); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'e': case 'E': - if (strncasecmp("less", tstr, tlen) == 0) - rosh_less(cmdstr); + if (strncasecmp("less", argv[0], tlen) == 0) + rosh_less(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; default: - rosh_help(1, NULL); + rosh_help(1, argv[0]); } break; case 'm': case 'M': - switch (cmdstr[1]) { + switch (argv[0][1]) { case 'a': case 'A': - if (strncasecmp("man", tstr, tlen) == 0) - rosh_help(2, cmdstr); + if (strncasecmp("man", argv[0], tlen) == 0) + rosh_help(2, argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'o': case 'O': - if (strncasecmp("more", tstr, tlen) == 0) - rosh_more(cmdstr); + if (strncasecmp("more", argv[0], tlen) == 0) + rosh_more(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; default: - rosh_help(1, NULL); + rosh_help(1, argv[0]); } break; case 'p': case 'P': /* run 'pwd' */ - if (strncasecmp("pwd", tstr, tlen) == 0) - rosh_pwd(cmdstr); + if (strncasecmp("pwd", argv[0], tlen) == 0) + rosh_pwd(); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'r': case 'R': /* run 'run' */ - switch (cmdstr[1]) { + switch (argv[0][1]) { case 0: - case ' ': case 'e': case 'E': - if (strncasecmp("reboot", tstr, tlen) == 0) - rosh_reboot(); + if (strncasecmp("reboot", argv[0], tlen) == 0) + rosh_reboot(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 'u': case 'U': - if (strncasecmp("run", tstr, tlen) == 0) - rosh_run(cmdstr); + if (strncasecmp("run", argv[0], tlen) == 0) + rosh_run(argc - 1, &argv[1]); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; + default: + rosh_help(1, argv[0]); } break; case 'v': case 'V': - if (strncasecmp("version", tstr, tlen) == 0) - rosh_version(); + if (strncasecmp("version", argv[0], tlen) == 0) + rosh_version(1); else - rosh_help(1, NULL); + rosh_help(1, argv[0]); break; case 0: case '\n': break; default: - rosh_help(1, NULL); - } /* switch(cmdstr[0]) */ + rosh_help(1, argv[0]); + } /* switch(argv[0][0]) */ return do_exit; } /* rosh_command */ @@ -1127,29 +1304,29 @@ char rosh_command(const char *cmdstr, const char *ipwdstr) * icmdstr Initial command line string * returns Exit status */ -int rosh_prompt(const char *icmdstr) +int rosh_prompt(int iargc, char *iargv[]) { int rv; char cmdstr[ROSH_CMD_SZ]; char ipwdstr[ROSH_PATH_SZ]; char do_exit; - char *c; + char **argv; + int argc; rv = 0; do_exit = false; if (!getcwd(ipwdstr, ROSH_PATH_SZ)) strcpy(ipwdstr, "./"); - if (icmdstr[0] != '\0') - do_exit = rosh_command(icmdstr, ipwdstr); + if (iargc > 1) + do_exit = rosh_command(iargc - 1, &iargv[1], ipwdstr); while (!(do_exit)) { /* Extra preceeding newline */ printf("\nrosh: "); /* Read a line from console */ if (fgets(cmdstr, ROSH_CMD_SZ, stdin)) { - /* remove newline from input string */ - c = strchr(cmdstr, '\n'); - *c = 0; - do_exit = rosh_command(cmdstr, ipwdstr); + argc = rosh_str2argv(&argv, cmdstr); + do_exit = rosh_command(argc, argv, ipwdstr); + rosh_free_argv(&argv); } else { do_exit = false; } @@ -1160,19 +1337,21 @@ int rosh_prompt(const char *icmdstr) int main(int argc, char *argv[]) { int rv; - char cmdstr[ROSH_CMD_SZ]; /* Initialization */ rv = 0; rosh_console_std(); - if (argc != 1) { - rv = rosh_argcat(cmdstr, argc, argv, 1); - } else { - rosh_version(); + if (argc == 1) { + rosh_version(0); print_beta(); - cmdstr[0] = '\0'; + } else { +#ifdef DO_DEBUG + char cmdstr[ROSH_CMD_SZ]; + rosh_argcat(cmdstr, ROSH_CMD_SZ, argc, argv, 1); + ROSH_DEBUG("arg='%s'\n", cmdstr); +#endif } - rv = rosh_prompt(cmdstr); - printf("--Exiting '%s'\n", APP_NAME); + rv = rosh_prompt(argc, argv); + printf("--Exiting '" APP_NAME "'\n"); return rv; } diff --git a/com32/rosh/rosh.h b/com32/rosh/rosh.h index a8edda6a..cabf556a 100644 --- a/com32/rosh/rosh.h +++ b/com32/rosh/rosh.h @@ -32,29 +32,36 @@ #include <stdbool.h> /* macro: true false */ #include <string.h> /* strcpy() strlen() memcpy() strchr() */ #include <sys/types.h> +#include <limits.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 <unistd.h> /* getcwd() getopt() */ #include <errno.h> /* errno; error macros */ #include <netinet/in.h> /* For htonl/ntohl/htons/ntohs */ #include <ctype.h> /* isspace() */ #include <getkey.h> -#include <consoles.h> +#include <consoles.h> /* console_ansi_raw() console_ansi_std() */ +// #include <getopt.h> /* getopt_long() */ #ifdef DO_DEBUG # define ROSH_DEBUG printf +# define ROSH_DEBUG_ARGV_V rosh_pr_argv_v /* define ROSH_DEBUG(f, ...) printf (f, ## __VA_ARGS__) */ # ifdef DO_DEBUG2 # define ROSH_DEBUG2 printf +# define ROSH_DEBUG2_ARGV_V rosh_pr_argv_v # else /* DO_DEBUG2 */ /* This forces a format argument into the function call */ # define ROSH_DEBUG2(f, ...) ((void)0) +# define ROSH_DEBUG2_ARGV_V(argc, argv) ((void)0) # endif /* DO_DEBUG2 */ #else /* DO_DEBUG */ # define ROSH_DEBUG(f, ...) ((void)0) +# define ROSH_DEBUG_ARGV_V(argc, argv) ((void)0) # define ROSH_DEBUG2(f, ...) ((void)0) +# define ROSH_DEBUG2_ARGV_V(argc, argv) ((void)0) #endif /* DO_DEBUG */ #ifdef __COM32__ @@ -89,8 +96,17 @@ int stat(const char *pathname, struct stat *buf) return ret; } +int rosh_get_env_ver(char *dest, size_t n) +{ + const struct syslinux_version *slv = syslinux_version(); + strncpy(dest, slv->version_string, n); + return 0; +} + #else # include <termios.h> +# include <sys/ioctl.h> +# include <sys/utsname.h> # define ROSH_IS_COM32 0 static inline char *syslinux_config_file(void) @@ -98,19 +114,43 @@ static inline char *syslinux_config_file(void) return ""; } +int rosh_get_env_ver(char *dest, size_t n) +{ + int ret, len; + struct utsname env; + ret= uname(&env); + if (ret >= 0) { + strncpy(dest, env.sysname, n); + len = strlen(dest); + strncpy(dest + len, " ", (n - len)); + len = strlen(dest); + strncpy(dest + len, env.release, (n - len)); + } + return ret; +} + static inline int getscreensize(int fd, int *rows, int *cols) { char *str; int rv; - *rows = 0; - *cols = 0; + struct winsize ws; + if (rows) + *rows = 0; + if (cols) + *cols = 0; + str = NULL; if (fd == 1) { - if (rows) { + ioctl(0, TIOCGWINSZ, &ws); + if (rows) + *rows = ws.ws_row; + if (cols) + *cols = ws.ws_col; + if (rows && !*rows) { str = getenv("LINES"); if (str) *rows = atoi(str); } - if (cols) { + if (cols && !*cols) { str = getenv("COLUMNS"); if (str) *cols = atoi(str); @@ -201,6 +241,10 @@ const char rosh_beta_str[] = const char rosh_cd_norun_str[] = " -- cd (Change Directory) not implemented for use with run and exit.\n"; +const char rosh_help_cd_str[] = "cd Change directory\n\ + with no argument, return to original directory from entry to rosh\n\ + with one argument, change to that directory"; + const char rosh_help_ls_str[] = "ls List contents of current directory\n\ -l Long format\n\ -i Inode; print Inode of file\n\ @@ -225,4 +269,6 @@ const char rosh_help_str2[] = const char rosh_help_str_adv[] = "No additional help available for '%s'"; +const char rosh_ls_opt_str[] = "lFi"; + #endif /* Not ROSH_H */ diff --git a/core/diskstart.inc b/core/diskstart.inc index 642f37e5..81e983ae 100644 --- a/core/diskstart.inc +++ b/core/diskstart.inc @@ -180,8 +180,11 @@ harddisk: mov dx,[di-76-10] ; Original DS mov si,[di-76-12] ; Original SI shr si,4 + jz .no_partition ; SI == 0 -> assume no partition add dx,si - cmp dx,PartInfo >> 4 + cmp dx,1024 ; DS:SI < 1K (inside the IVT)? + jb .no_partition + cmp dx,PartInfo >> 4 ; DS:SI in overwritten memory? jae .no_partition test byte [di-76],7Fh ; Sanity check: "active flag" should jnz .no_partition ; be 00 or 80 diff --git a/core/fs/diskio.c b/core/fs/diskio.c index 481b59b0..38d3da35 100644 --- a/core/fs/diskio.c +++ b/core/fs/diskio.c @@ -163,8 +163,6 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, memset(&reset, 0, sizeof reset); - ireg.edx.b[0] = disk->disk_number; - lba += disk->part_start; while (count) { chunk = count; diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c index 8f30fed4..7def2f73 100644 --- a/core/fs/iso9660/iso9660.c +++ b/core/fs/iso9660/iso9660.c @@ -63,6 +63,8 @@ static void iso_mangle_name(char *dst, const char *src) if ( (*(dst-1) != '.') && (*(dst-1) != '/') ) break; + if ((dst[-1] == '/') && ((dst - 1) == p)) + break; dst --; i ++; diff --git a/core/fs/lib/mangle.c b/core/fs/lib/mangle.c index 813099fb..8c2077a9 100644 --- a/core/fs/lib/mangle.c +++ b/core/fs/lib/mangle.c @@ -36,6 +36,8 @@ void generic_mangle_name(char *dst, const char *src) break; if (dst[-1] != '/') break; + if ((dst[-1] == '/') && ((dst - 1) == p)) + break; dst--; i++; diff --git a/core/fs/pxe/dnsresolv.c b/core/fs/pxe/dnsresolv.c index 2b263fad..641ea389 100644 --- a/core/fs/pxe/dnsresolv.c +++ b/core/fs/pxe/dnsresolv.c @@ -215,7 +215,7 @@ uint32_t dns_resolv(const char *name) if (!dots) { p--; /* Remove final null */ /* Uncompressed DNS label set so it ends in null */ - strcpy(p, LocalDomain); + p = stpcpy(p, LocalDomain); } /* Fill the DNS query packet */ diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c index 211dd639..40248994 100644 --- a/core/fs/pxe/pxe.c +++ b/core/fs/pxe/pxe.c @@ -642,8 +642,22 @@ static uint32_t pxe_getfssec(struct file *file, char *buf, * @out: the lenght of this file, stores in file->file_len * */ +static void __pxe_searchdir(const char *filename, struct file *file); +extern uint16_t PXERetry; + static void pxe_searchdir(const char *filename, struct file *file) { + int i = PXERetry; + + do { + dprintf("PXE: file = %p, retries left = %d: ", file, i); + __pxe_searchdir(filename, file); + dprintf("%s\n", file->inode ? "ok" : "failed"); + } while (!file->inode && i--); +} + +static void __pxe_searchdir(const char *filename, struct file *file) +{ struct fs_info *fs = file->fs; struct inode *inode; struct pxe_pvt_inode *socket; diff --git a/core/keywords b/core/keywords index c289ae29..7f585b48 100644 --- a/core/keywords +++ b/core/keywords @@ -16,6 +16,7 @@ linux boot bss pxe +pxeretry fdimage comboot com32 diff --git a/core/parseconfig.inc b/core/parseconfig.inc index 00e2163e..ec400a6f 100644 --- a/core/parseconfig.inc +++ b/core/parseconfig.inc @@ -464,6 +464,8 @@ AllowImplicit dw 1 ; Allow implicit kernels AllowOptions dw 1 ; User-specified options allowed IncludeLevel dw 1 ; Nesting level DefaultLevel dw 0 ; The current level of default + global PXERetry +PXERetry dw 0 ; Extra PXE retries VKernel db 0 ; Have we seen any "label" statements? %if IS_PXELINUX diff --git a/core/pxelinux.asm b/core/pxelinux.asm index 95087c80..5341db38 100644 --- a/core/pxelinux.asm +++ b/core/pxelinux.asm @@ -364,6 +364,16 @@ pxenv: pushfd pushad + ; We may be removing ourselves from memory + cmp bx,0073h ; PXENV_RESTART_TFTP + jz .disable_timer + cmp bx,00E5h ; gPXE PXENV_FILE_EXEC + jnz .store_stack + +.disable_timer: + call timer_cleanup + +.store_stack: mov [cs:PXEStack],sp mov [cs:PXEStack+2],ss lss sp,[cs:InitStack] @@ -390,6 +400,17 @@ pxenv: ; This clobbers the AX return, but we already saved it into ; the PXEStatus variable. popad + + ; If the call failed, it could return. + cmp bx,0073h + jz .enable_timer + cmp bx,00E5h + jnz .pop_flags + +.enable_timer: + call timer_init + +.pop_flags: popfd ; Restore flags (incl. IF, DF) ret diff --git a/core/syslinux.ld b/core/syslinux.ld index 466b450e..c390f347 100644 --- a/core/syslinux.ld +++ b/core/syslinux.ld @@ -33,7 +33,7 @@ SECTIONS /* "Early" sections (before the load) */ . = 0x1000; - .earlybss : { + .earlybss (NOLOAD) : { __earlybss_start = .; *(.earlybss) __earlybss_end = .; @@ -42,7 +42,7 @@ SECTIONS __earlybss_dwords = (__earlybss_len + 3) >> 2; . = ALIGN(4); - .bss16 : { + .bss16 (NOLOAD) : { __bss16_start = .; *(.bss16) __bss16_end = .; diff --git a/core/writedec.inc b/core/writedec.inc index bfac0997..19e47968 100644 --- a/core/writedec.inc +++ b/core/writedec.inc @@ -37,6 +37,7 @@ writedec_common: xor cx,cx ; Number of digits .cloop: + mov edx,0 div ebx inc cx push dx @@ -53,5 +54,5 @@ writedec_common: popad ret -writechr: - ret +; writechr: +; ret diff --git a/doc/extlinux.txt b/doc/extlinux.txt index 6974a517..9b267018 100644 --- a/doc/extlinux.txt +++ b/doc/extlinux.txt @@ -24,6 +24,8 @@ slight modifications. 2. The configuration file is called "extlinux.conf", and is expected to be found in the same directory as extlinux is installed in. + Since 4.00 "syslinux.cfg" is also tried if "extlinux.conf" is not + found. 3. Pathnames can be absolute or relative; if absolute (with a leading diff --git a/doc/syslinux.txt b/doc/syslinux.txt index 51d1332c..5b27a6eb 100644 --- a/doc/syslinux.txt +++ b/doc/syslinux.txt @@ -106,24 +106,25 @@ which requires root privilege. ++++ CONFIGURATION FILE ++++ +All options here apply to PXELINUX, ISOLINUX and EXTLINUX as well as +SYSLINUX unless otherwise noted. See the respective .txt files. + All the configurable defaults in SYSLINUX can be changed by putting a file called "syslinux.cfg" in the root directory of the boot disk. -This is a text file in either UNIX or DOS format, containing one or -more of the following items (case is insensitive for keywords; upper -case is used here to indicate that a word should be typed verbatim): - Starting with version 3.35, the configuration file can also be in either the /boot/syslinux or /syslinux directories (searched in that order.) If that is the case, then all filenames are assumed to be relative to that same directory, unless preceded with a slash or backslash. -All options here applies to PXELINUX, ISOLINUX and EXTLINUX as well as -SYSLINUX unless otherwise noted. See the respective .txt files. +The configuration file is a text file in either UNIX or DOS format, +containing one or more of the following items, each on its own line with +optional leading whitespace. Case is insensitive for keywords; upper +case is used here to indicate that a word should be typed verbatim. -# comment - A comment line. The whitespace after the hash mark is mandatory. +#comment + A comment line. INCLUDE filename Inserts the contents of another file at this point in the diff --git a/extlinux/main.c b/extlinux/main.c index 002cecd9..30422c2d 100755 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -100,6 +100,32 @@ struct geometry_table { struct hd_geometry g; }; +static int sysfs_get_offset(int devfd, unsigned long *start) +{ + struct stat st; + char sysfs_name[128]; + FILE *f; + int rv; + + if (fstat(devfd, &st)) + return -1; + + if ((size_t)snprintf(sysfs_name, sizeof sysfs_name, + "/sys/dev/block/%u:%u/start", + major(st.st_dev), minor(st.st_dev)) + >= sizeof sysfs_name) + return -1; + + f = fopen(sysfs_name, "r"); + if (!f) + return -1; + + rv = fscanf(f, "%lu", start); + fclose(f); + + return (rv == 1) ? 0 : -1; +} + /* Standard floppy disk geometries, plus LS-120. Zipdisk geometry (x/64/32) is the final fallback. I don't know what LS-240 has as its geometry, since I don't have one and don't know anyone that does, @@ -123,24 +149,25 @@ int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) struct loop_info li; struct loop_info64 li64; const struct geometry_table *gp; + int rv = 0; memset(geo, 0, sizeof *geo); if (!ioctl(devfd, HDIO_GETGEO, &geo)) { - return 0; + goto ok; } else if (!ioctl(devfd, FDGETPRM, &fd_str)) { geo->heads = fd_str.head; geo->sectors = fd_str.sect; geo->cylinders = fd_str.track; geo->start = 0; - return 0; + goto ok; } /* Didn't work. Let's see if this is one of the standard geometries */ for (gp = standard_geometries; gp->bytes; gp++) { if (gp->bytes == totalbytes) { memcpy(geo, &gp->g, sizeof *geo); - return 0; + goto ok; } } @@ -153,19 +180,25 @@ int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) geo->cylinders = totalbytes / (geo->heads * geo->sectors << SECTOR_SHIFT); geo->start = 0; - if (!opt.sectors && !opt.heads) + if (!opt.sectors && !opt.heads) { fprintf(stderr, "Warning: unable to obtain device geometry (defaulting to %d heads, %d sectors)\n" " (on hard disks, this is usually harmless.)\n", geo->heads, geo->sectors); + rv = 1; /* Suboptimal result */ + } +ok: /* If this is a loopback device, try to set the start */ if (!ioctl(devfd, LOOP_GET_STATUS64, &li64)) geo->start = li64.lo_offset >> SECTOR_SHIFT; else if (!ioctl(devfd, LOOP_GET_STATUS, &li)) geo->start = (unsigned int)li.lo_offset >> SECTOR_SHIFT; + else if (!sysfs_get_offset(devfd, &geo->start)) { + /* OK */ + } - return 1; + return rv; } /* diff --git a/libinstaller/syslxopt.c b/libinstaller/syslxopt.c index 9b42c66f..7ceb3ba2 100644 --- a/libinstaller/syslxopt.c +++ b/libinstaller/syslxopt.c @@ -68,7 +68,7 @@ const struct option long_options[] = { {0, 0, 0, 0} }; -const char short_options[] = "t:fid:UuzS:H:rvho:OM:ma"; +const char short_options[] = "t:fid:UuzsS:H:rvho:OM:ma"; void __attribute__ ((noreturn)) usage(int rv, enum syslinux_mode mode) { diff --git a/man/syslinux.1 b/man/syslinux.1 index 6babfa41..af44979b 100644 --- a/man/syslinux.1 +++ b/man/syslinux.1 @@ -140,11 +140,6 @@ first "label" command.) The default for \fIimage\fP is the same as \fIlabel\fP, and if no "append" is given the default is to use the global entry (if any). Use "append -" to use no options at all. Up to 128 "label" entries are permitted. -.TP -.B Notes: -Labels are mangled as if they were DOS filenames, and must be unique after -mangling. For example, two labels "v2.1.30" and "v2.1.31" will not be -distinguishable. .IP The "image" doesn't have to be a Linux kernel; it can be a boot sector or a COMBOOT file (see below.) diff --git a/memdisk/setup.c b/memdisk/setup.c index 3f69cd35..43151898 100644 --- a/memdisk/setup.c +++ b/memdisk/setup.c @@ -119,7 +119,7 @@ static const char *getcmditem(const char *what) */ #define UNZIP_ALIGN 512 -extern void _end; /* Symbol signalling end of data */ +extern const char _end[]; /* Symbol signalling end of data */ void unzip_if_needed(uint32_t * where_p, uint32_t * size_p) { @@ -171,8 +171,8 @@ void unzip_if_needed(uint32_t * where_p, uint32_t * size_p) ? 0xFFFFFFFF : (uint32_t) ranges[i + 1].start); /* Make sure we don't overwrite ourselves */ - if (startrange < (uint32_t) & _end) - startrange = (uint32_t) & _end; + if (startrange < (uint32_t) _end) + startrange = (uint32_t) _end; /* Allow for alignment */ startrange = diff --git a/modules/Makefile b/modules/Makefile index f3183641..9b50bb23 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -19,7 +19,7 @@ include $(topdir)/MCONFIG.embedded INCLUDES = -I$(com32)/include -BINS = pxechain.com poweroff.com int18.com +BINS = pxechain.com poweroff.com int18.com ver.com all: $(BINS) diff --git a/modules/ver.asm b/modules/ver.asm new file mode 100644 index 00000000..8ef63faf --- /dev/null +++ b/modules/ver.asm @@ -0,0 +1,606 @@ +; **************************************************************************** +; +; ver.asm +; +; A COMBOOT/DOS COM program to display the version of the system +; (Syslinux, DOS, or DRMK) +; +; Copyright (C) 2009-2010 Gene Cumm +; +; 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. +; +; **************************************************************************** + +; %define DEBUG + + section .text + org 0x100 + +_start: + call crlf + mov si,info_str + call writestr + call getdosver + call chkprn_dosver + jnz .end + call chkprn_syslinux + call crlf +.end: +; pop ds + ret + + +; chkprn_syslinux +chkprn_syslinux: +%ifdef DEBUG + mov si,may_sysl_str + call writestr +%endif + cmp eax,59530000h + jne .end + cmp ebx,4C530000h + jne .end + cmp ecx,4E490000h + jne .end + cmp edx,58550000h + jne .end +.is_syslinux: + pushad +%ifdef DEBUG + mov si,is_sysl_str + call writestr +%endif +.get_sysl_ver: + mov ax,0001h + int 22h +; AX=0001h [2.00] Get Version +; +; Input: AX 0001h +; Output: AX number of INT 22h API functions available +; CH Syslinux major version number +; CL Syslinux minor version number +; DL Syslinux derivative ID (e.g. 32h = PXELINUX) +; ES:SI Syslinux version string +; ES:DI Syslinux copyright string +%ifdef DEBUG + push si + push cs + pop ds + mov si,gotver_str + call writestr + pop si +%endif + +.prn_ver_str: + mov si,syslban_str + call writestr + push ds + push es + pop ds + call writestr + call crlf + pop ds +.prn_var: + cmp dl,31h + je .var_sysl + cmp dl,32h + je .var_pxel + cmp dl,33h + je .var_isol + cmp dl,34h + je .var_extl + jmp .var_unk +.var_sysl: + mov si,sysl_str + call writestr + jmp .prn_lnxsp +.var_pxel: + mov si,pxel_str + call writestr + jmp .prn_lnxsp +.var_isol: + mov si,isol_str + call writestr + jmp .prn_lnxsp +.var_extl: + mov si,extl_str + call writestr +; jmp .prn_lnxsp +.prn_lnxsp: + mov si,linsp_str + call writestr + jmp .prn_ver +.var_unk: + mov si,unkvar_str + call writestr +.prn_ver: +%ifdef DEBUG + push si + push cs + pop ds + mov si,prn_ver_str + call writestr + pop si +%endif +.prn_ver_maj: + mov al,ch + call writedecb + mov dl,'.' + call writechr_dl +.prn_ver_min: + mov al,cl +; cmp al,10 +; jae .min_wri +; mov al,'0' +; call writechr +; mov al,cl +; .min_wri: +; call writedecb + call writedecb2 + +.end_prn: + popad +.end: + ret + +; chkprn_dosver Check and print DOS version; +; Input Data from INT21 AH=30h +; AH Major version of DOS or 0 +; AL Minor Version +; BH DOS type +; BL:CX 24-bit OEM serial number +; Return +; ZF Unset if DOS, Set if not DOS (AX=0) +chkprn_dosver: + and ax,ax ; cmp ax,0 + jz .end +.is_dos: + push eax + push edx + push si +%ifdef DEBUG + mov si,is_dos_str + call writestr + call crlf + call prnreg_gp_l + call crlf +%endif +.var_prn: + cmp bh,0 + je .var_pcdos + cmp bh,0FFh + je .var_msdos + cmp bh,0FDh + je .var_freedos + cmp bh,0DEh + je .var_drmk + jmp .var_unk +.var_pcdos: + mov si,pcdos_str + call writestr + jmp .var_end +.var_msdos: + mov si,msdos_str + call writestr + jmp .var_end +.var_freedos: + mov si,freedos_str + call writestr + jmp .var_end +.var_drmk: + mov si,drmk_str + call writestr + jmp .var_end +.var_unk: + mov si,unkdos_str + call writestr + mov si,spparen_str + call writestr + push eax + mov al,bh + call writehex2 + pop eax + mov si,parensp_str + call writestr +; jmp .var_end +.var_end: + call prn_dosver_num + call crlf +.subver: + pop si + pop edx + pop eax + cmp bh,0FFh + je .msdos_ver + cmp bh,0DEh + jne .end_ver +.drmk_ver: + call getprn_drmkver +; jmp .end_ver ; DRMK returns Extended/True DOS +.msdos_ver: + cmp al,5 + jb .end_ver + call getprn_msdosver +.end_ver: + and ax,ax ; Unset ZF +.end: + ret + +; prn_dosver_num Print the numerical DOS version +; Input Data from INT21 AH=30h +; AH Major version of DOS or 0 +; AL Minor Version +; BH DOS type +; BL:CX 24-bit OEM serial number +prn_dosver_num: + push eax + push edx + push si + pushfd +.vmaj_prn: + call writedecb +; call writehex2 + mov dl,'.' + call writechr_dl +.vmin_prn: + mov al,ah + call writedecb +; call writehex2 +.serial: ; Skip if 0 + cmp bl,0 + jne .ser_start + cmp cx,0 + je .end +.ser_start: + mov si,spparen_str + call writestr + mov si,zerox_str + call writestr +.ser_bl: + mov al,bl + call writehex2 +.ser_cx: + mov ax,cx + call writehex4 +.serial_end: + mov si,parensp_str + call writestr +.end: + popfd + pop si + pop edx + pop eax + ret + +; getdosver Get the DOS version +; Return Version or 0 + SYSLINUX message +; EAX Part 1 +; EBX Part 2 +; ECX Part 3 +; EDX Part 4 +getdosver: + mov ecx,0 + mov edx,0 + mov ebx,0 + mov eax,3000h + int 21h + ret + +; getmsdosver Get the Extended MS-DOS version +; Returns Version +; EAX Part 1 +; EBX Part 2 +; ECX Part 3 +; EDX Part 4 +getmsdosver: + mov ecx,0 + mov edx,0 + mov ebx,0 + mov eax,3306h + int 21h + ret + +; getprn_msdosver +getprn_msdosver: + pushad + pushfd + call getmsdosver +%ifdef DEBUG + call prnreg_gp_l + call crlf +%endif + mov si,dosext_str + call writestr + mov eax,ebx + mov ebx,0 + mov ecx,edx + call prn_dosver_num +.end: + popfd + popad + ret + +; getdrmkver: Get the DRMK-specifc OS version +; Returns Version +; AX OS Version +; DX Patch Version +getdrmkver: + mov ax,4452h + int 21h + ret + +; getdrmkver: Get the DRMK-specifc Kernel build info +; Returns Kernel build info +; AX Kernel build date in DOS 16-bit format +; [ES:BX] Kernel private data +getdrmkbld: + mov ax,4458h + int 21h + ret + +; getprn_drmkver: Get/Print DRMK-specific Version info +getprn_drmkver: + pushad + pushfd +.getver: + call getdrmkver +.prnosver: ; "OS Version" + mov si,osver_str + call writestr + mov si,zerox_str + call writestr +; mov ax,0 + call writehex4 + call crlf +.prnpatchver: ; "Patch Version" + mov si,patchver_str + call writestr + mov si,zerox_str + call writestr + mov ax,dx + call writehex4 + call crlf +.getbld: + call getdrmkbld +.prnkernbld: ; "Kernel Build Date" + mov si,kernbld_str + call writestr + call writedate_ax + call crlf +.prnkernprvaddr: + mov si,prvdat_str + call writestr + mov ax,es + call writehex4 + mov dl,':' + call writechr_dl + mov ax,bx + call writehex4 + call crlf +%ifdef DEBUG +.prnkernprv: + mov di,[es:bx] + mov ax,di + call writehex4 + call crlf + mov si,2 + mov cx,8 +.prnkernprv2: + push cx + mov cx,8 +.prnkernprv1: + mov eax,[es:bx+si] + call writehex8 + cmp cx,1 + jbe .prnkern0dash + mov ax,'-' + call writechr +.prnkern0dash: + add si,4 + sub di,4 + cmp di,0 + jbe .prnkernprvend + loop .prnkernprv1 + call crlf + pop cx + loop .prnkernprv2 + jmp .end +.prnkernprvend: + pop cx +%endif +.end: + popfd + popad + ret + +;writedate_ax Write a date in AX in ISO8601 big endian format +; Input +; AX Date in 16-bit DOS format +; 2006-01-11 +; 0011010 0001 01011 +writedate_ax: + pushad + pushfd + mov dx,ax +%ifdef DEBUG + call writehex4 + call crlf +%endif +.year: + shr ax,9 + add ax,1980 + call writedecw + mov al,'-' + call writechr + mov ax,dx +.month: + shr ax,5 + and ax,0Fh +; cmp ax,10 +; jae .month_wri +; mov cx,ax +; mov ax,'0' +; call writechr +; mov ax,cx +; .month_wri: +; call writedecb + call writedecb2 + mov al,'-' + call writechr + mov ax,dx +.day: + and ax,1Fh +; cmp ax,10 +; jae .day_wri +; mov cx,ax +; mov ax,'0' +; call writechr +; mov ax,cx +; .day_wri: +; call writedecb + call writedecb2 +.end: + popfd + popad + ret + +; writechr_dl Write a character to the console saving AX +; Input +; DL character to write +writechr_dl: + push ax + mov ah,02h + int 21h +.end: + pop ax + ret + +; writechr_al Write a character to the console saving AX +; Input +; AL character to write +writechr: +writechr_al: + push dx + mov dl,al + call writechr_dl +.end: pop dx + ret + +; writedecb[23] Print byte as fixed width +; Input +; AL number to write +writedecb3: + pushfd + cmp al,100 + jae .skip + push ax + mov ax,'0' + call writechr + pop ax +.skip: popfd +writedecb2: + pushfd + cmp al,10 + jae .skip + push ax + mov ax,'0' + call writechr + pop ax +.skip: popfd + call writedecb + ret + + +; prnreg_gp_l Dump GP registers (Long) +prnreg_gp_l: + push eax + push si + call crlf + mov si,sp2_str + call writestr + mov si,eax_str + call writestr + call writehex8 + mov si,sp2_str + call writestr + mov si,ecx_str + call writestr + mov eax,ecx + call writehex8 + mov si,sp2_str + call writestr + mov si,edx_str + call writestr + mov eax,edx + call writehex8 + mov si,sp2_str + call writestr + mov si,ebx_str + call writestr + mov eax,ebx + call writehex8 + call crlf + pop si + pop eax +.end: + ret + +; is_zf +is_zf: + push si + jz .true +.false: + mov si,zero_not_str + call writestr + jmp .end +.true: + mov si,zero_is_str + call writestr +.end: + pop si + ret + +%include "../core/macros.inc" ; CR/LF +%include "../core/writestr.inc" ; String output +%include "../core/writehex.inc" ; Hexadecimal output +%include "../core/writedec.inc" ; Decimal output + + section .data +info_str db 'Ver.com b026', CR, LF, 0 +is_dos_str db 'Found DOS', CR, LF, 0 +is_sysl_str db 'Found a Syslinux variant', CR, LF, 0 +is_drmk_str db 'Found DRMK', CR, LF, 0 +may_sysl_str db 'Maybe Syslinux variant', CR, LF, 0 +gotver_str db 'Got the version back', CR, LF, 0 +prn_ver_str db 'Printing version number', CR, LF, 0 +syslban_str db 'Syslinux banner: ',0 +sysl_str db 'SYS', 0 +pxel_str db 'PXE', 0 +isol_str db 'ISO', 0 +extl_str db 'EXT', 0 +linsp_str db 'LINUX ', 0 +unkvar_str db 'Unkown-Variant ', 0 +pcdos_str db 'PC-DOS ', 0 +msdos_str db 'MS-DOS ', 0 +freedos_str db 'FreeDOS ', 0 +unkdos_str db 'Unknown-DOS ', 0 +drmk_str db 'DRMK ', 0 +dosext_str db ' Extended DOS version: ', 0 +osver_str db ' OS Version: ', 0 +patchver_str db ' Patch Version: ', 0 +kernbld_str db ' Kernel Build Date: ', 0 +prvdat_str db ' Private Data Ptr: ', 0 +spparen_str db ' (', 0 +zerox_str db '0x', 0 +parensp_str db ') ', 0 +eax_str db 'EAX=', 0 +ebx_str db 'EBX=', 0 +ecx_str db 'ECX=', 0 +edx_str db 'EDX=', 0 +sp2_str db ' ', 0 +zero_not_str db ' NOT_Zero ',0 +zero_is_str db ' IS_Zero ',0 diff --git a/sample/Makefile b/sample/Makefile index f1006ff9..d7f439ca 100644 --- a/sample/Makefile +++ b/sample/Makefile @@ -15,6 +15,7 @@ ## topdir = .. +include $(topdir)/MCONFIG.embedded PPMTOLSS16 = $(topdir)/utils/ppmtolss16 diff --git a/utils/isohybrid.c b/utils/isohybrid.c index 57c1015e..7ee9a7f0 100644 --- a/utils/isohybrid.c +++ b/utils/isohybrid.c @@ -543,15 +543,11 @@ main(int argc, char *argv[]) if (padding) { - if (!(buf = realloc(buf, padding))) - err(1, "%s: could not re-size buffer", argv[0]); + if (fsync(fileno(fp))) + err(1, "%s: could not synchronise", argv[0]); - if (fseek(fp, isostat.st_size, SEEK_SET)) - err(1, "%s: seek error - 6", argv[0]); - - memset(buf, 0, padding); - if (fwrite(buf, sizeof(char), padding, fp) != (size_t)padding) - err(1, "%s: write error - 2", argv[0]); + if (ftruncate(fileno(fp), isostat.st_size + padding)) + err(1, "%s: could not add padding bytes", argv[0]); } free(buf); diff --git a/utils/memdiskfind.c b/utils/memdiskfind.c index decc788f..815f8bc1 100644 --- a/utils/memdiskfind.c +++ b/utils/memdiskfind.c @@ -94,13 +94,23 @@ static size_t memlimit(void) return maxram; } +static inline size_t get_page_size(void) +{ +#ifdef _SC_PAGESIZE + return sysconf(_SC_PAGESIZE); +#else + /* klibc, for one, doesn't have sysconf() due to excessive multiplex */ + return getpagesize(); +#endif +} + int main(int argc, char *argv[]) { const char *map; int memfd; size_t fbm; const char *ptr, *end; - size_t page = sysconf(_SC_PAGESIZE); + size_t page = get_page_size(); size_t mapbase, maplen; int err = 1; |