diff options
-rw-r--r-- | core/cmdline.inc | 4 | ||||
-rw-r--r-- | core/comboot.inc | 4 | ||||
-rw-r--r-- | core/fs/btrfs/btrfs.c | 68 | ||||
-rw-r--r-- | core/fs/chdir.c | 59 | ||||
-rw-r--r-- | core/fs/diskio.c | 156 | ||||
-rw-r--r-- | core/fs/fat/fat.c | 81 | ||||
-rw-r--r-- | core/fs/fs.c | 68 | ||||
-rw-r--r-- | core/fs/getcwd.c | 13 | ||||
-rw-r--r-- | core/fs/getfssec.c | 4 | ||||
-rw-r--r-- | core/fs/iso9660/iso9660.c | 29 | ||||
-rw-r--r-- | core/fs/lib/loadconfig.c | 30 | ||||
-rw-r--r-- | core/fs/lib/searchconfig.c | 40 | ||||
-rw-r--r-- | core/fs/pxe/dhcp_option.c | 193 | ||||
-rw-r--r-- | core/fs/pxe/dnsresolv.c | 95 | ||||
-rw-r--r-- | core/fs/pxe/idle.c | 2 | ||||
-rw-r--r-- | core/fs/pxe/pxe.c | 241 | ||||
-rw-r--r-- | core/fs/pxe/pxe.h | 34 | ||||
-rw-r--r-- | core/fs/readdir.c | 11 | ||||
-rw-r--r-- | core/include/fs.h | 12 | ||||
-rw-r--r-- | core/pxelinux.asm | 16 |
20 files changed, 675 insertions, 485 deletions
diff --git a/core/cmdline.inc b/core/cmdline.inc index 7fa53816..3e63f9ab 100644 --- a/core/cmdline.inc +++ b/core/cmdline.inc @@ -48,12 +48,14 @@ make_plain_cmdline: ; Actual IPAppend strings... ; %if IS_PXELINUX - extern IPOption, BOOTIFStr + extern IPOption, BOOTIFStr, SYSUUIDStr + global IPAppends, numIPAppends section .data16 alignz 2 IPAppends dw IPOption dw BOOTIFStr + dw SYSUUIDStr numIPAppends equ ($-IPAppends)/2 %else IPAppends equ 0 diff --git a/core/comboot.inc b/core/comboot.inc index 45b770f3..0c9956a0 100644 --- a/core/comboot.inc +++ b/core/comboot.inc @@ -580,8 +580,10 @@ comapi_derinfo: mov P_SI,ax mov ax,[InitStack+2] mov P_FS,ax - mov eax,[MyIP] + mov eax,[IPInfo.MyIP] mov P_ECX,eax + mov P_GS,0 + mov P_DI,IPInfo %else ; Physical medium... diff --git a/core/fs/btrfs/btrfs.c b/core/fs/btrfs/btrfs.c index 72dcbe92..b6a14e3b 100644 --- a/core/fs/btrfs/btrfs.c +++ b/core/fs/btrfs/btrfs.c @@ -11,6 +11,7 @@ * */ +#include <dprintf.h> #include <stdio.h> #include <string.h> #include <cache.h> @@ -54,12 +55,9 @@ static int bin_search(void *ptr, int item_size, void *cmp_item, cmp_func func, return 1; } -static int cache_ready; +/* XXX: these should go into the filesystem instance structure */ static struct btrfs_chunk_map chunk_map; static struct btrfs_super_block sb; -/* used for small chunk read for btrfs_read */ -#define RAW_BUF_SIZE 4096 -static u8 raw_buf[RAW_BUF_SIZE]; static u64 fs_tree; static int btrfs_comp_chunk_map(struct btrfs_chunk_map_item *m1, @@ -127,36 +125,8 @@ static u64 logical_physical(u64 logical) chunk_map.map[slot-1].logical; } -/* raw read from disk, offset and count are bytes */ -static int raw_read(struct fs_info *fs, char *buf, u64 offset, u64 count) -{ - struct disk *disk = fs->fs_dev->disk; - size_t max = RAW_BUF_SIZE >> disk->sector_shift; - size_t off, cnt, done, total; - sector_t sec; - - total = count; - while (count > 0) { - sec = offset >> disk->sector_shift; - off = offset - (sec << disk->sector_shift); - done = disk->rdwr_sectors(disk, raw_buf, sec, max, 0); - if (done == 0)/* no data */ - break; - cnt = (done << disk->sector_shift) - off; - if (cnt > count) - cnt = count; - memcpy(buf, raw_buf + off, cnt); - count -= cnt; - buf += cnt; - offset += cnt; - if (done != max)/* no enough sectors */ - break; - } - return total - count; -} - /* cache read from disk, offset and count are bytes */ -static int cache_read(struct fs_info *fs, char *buf, u64 offset, u64 count) +static int btrfs_read(struct fs_info *fs, char *buf, u64 offset, u64 count) { const char *cd; size_t block_size = fs->fs_dev->cache_block_size; @@ -181,13 +151,6 @@ static int cache_read(struct fs_info *fs, char *buf, u64 offset, u64 count) return total - count; } -static int btrfs_read(struct fs_info *fs, char *buf, u64 offset, u64 count) -{ - if (cache_ready) - return cache_read(fs, buf, offset, count); - return raw_read(fs, buf, offset, count); -} - /* btrfs has several super block mirrors, need to calculate their location */ static inline u64 btrfs_sb_offset(int mirror) { @@ -207,9 +170,16 @@ static void btrfs_read_super_block(struct fs_info *fs) u64 transid = 0; struct btrfs_super_block buf; + sb.total_bytes = ~0; /* Unknown as of yet */ + /* find most recent super block */ for (i = 0; i < BTRFS_SUPER_MIRROR_MAX; i++) { offset = btrfs_sb_offset(i); + dprintf("btrfs super: %llu max %llu\n", + offset, sb.total_bytes); + if (offset >= sb.total_bytes) + break; + ret = btrfs_read(fs, (char *)&buf, offset, sizeof(buf)); if (ret < sizeof(buf)) break; @@ -560,10 +530,19 @@ static int btrfs_next_extent(struct inode *inode, uint32_t lstart) ret = search_tree(fs, fs_tree, &search_key, &path); if (ret) { /* impossible */ printf("btrfs: search extent data error!\n"); - return 0; + return -1; } extent_item = *(struct btrfs_file_extent_item *)path.data; + if (extent_item.encryption) { + printf("btrfs: found encrypted data, cannot continue!\n"); + return -1; + } + if (extent_item.compression) { + printf("btrfs: found compressed data, cannot continue!\n"); + return -1; + } + if (extent_item.type == BTRFS_FILE_EXTENT_INLINE) {/* inline file */ /* we fake a extent here, and PVT of inode will tell us */ offset = path.offsets[0] + sizeof(struct btrfs_header) @@ -666,16 +645,15 @@ static int btrfs_fs_init(struct fs_info *fs) fs->block_shift = BTRFS_BLOCK_SHIFT; fs->block_size = 1 << fs->block_shift; + /* Initialize the block cache */ + cache_init(fs->fs_dev, fs->block_shift); + btrfs_read_super_block(fs); if (strncmp((char *)(&sb.magic), BTRFS_MAGIC, sizeof(sb.magic))) return -1; btrfs_read_sys_chunk_array(); btrfs_read_chunk_tree(fs); btrfs_get_fs_tree(fs); - cache_ready = 1; - - /* Initialize the block cache */ - cache_init(fs->fs_dev, fs->block_shift); return fs->block_shift; } diff --git a/core/fs/chdir.c b/core/fs/chdir.c index bfce9bce..9e8dfd2e 100644 --- a/core/fs/chdir.c +++ b/core/fs/chdir.c @@ -16,15 +16,56 @@ void pm_realpath(com32sys_t *regs) realpath(dst, src, FILENAME_MAX); } +#define EMIT(x) \ +do { \ + if (++n < bufsize) \ + *q++ = (x); \ +} while (0) + +static size_t join_paths(char *dst, size_t bufsize, + const char *s1, const char *s2) +{ + const char *list[2]; + int i; + char c; + const char *p; + char *q = dst; + size_t n = 0; + bool slash = false; + + list[0] = s1; + list[1] = s2; + + for (i = 0; i < 2; i++) { + p = list[i]; + + while ((c = *p++)) { + if (c == '/') { + if (!slash) + EMIT(c); + slash = true; + } else { + EMIT(c); + slash = false; + } + } + } + + if (bufsize) + *q = '\0'; + + return n; +} + size_t realpath(char *dst, const char *src, size_t bufsize) { if (this_fs->fs_ops->realpath) { return this_fs->fs_ops->realpath(this_fs, dst, src, bufsize); } else { /* Filesystems with "common" pathname resolution */ - return snprintf(dst, bufsize, "%s%s", - src[0] == '/' ? "" : this_fs->cwd_name, - src); + return join_paths(dst, bufsize, + src[0] == '/' ? "" : this_fs->cwd_name, + src); } } @@ -32,7 +73,7 @@ int chdir(const char *src) { int rv; struct file *file; - char *p; + char cwd_buf[CURRENTDIR_MAX]; if (this_fs->fs_ops->chdir) return this_fs->fs_ops->chdir(this_fs, src); @@ -53,14 +94,10 @@ int chdir(const char *src) _close_file(file); /* Save the current working directory */ - realpath(this_fs->cwd_name, src, CURRENTDIR_MAX); - p = strchr(this_fs->cwd_name, '\0'); + realpath(cwd_buf, src, CURRENTDIR_MAX); /* Make sure the cwd_name ends in a slash, it's supposed to be a prefix */ - if (p < this_fs->cwd_name + CURRENTDIR_MAX - 1 && - (p == this_fs->cwd_name || p[1] != '/')) { - p[0] = '/'; - p[1] = '\0'; - } + join_paths(this_fs->cwd_name, CURRENTDIR_MAX, cwd_buf, "/"); + return 0; } diff --git a/core/fs/diskio.c b/core/fs/diskio.c index 464cca6d..d4901c3d 100644 --- a/core/fs/diskio.c +++ b/core/fs/diskio.c @@ -56,7 +56,7 @@ static int chs_rdwr_sectors(struct disk *disk, void *buf, t = xlba / disk->s; h = t % disk->h; c = t / disk->h; - + ireg.eax.b[0] = chunk; ireg.ecx.b[1] = c; ireg.ecx.b[0] = ((c & 0x300) >> 2) | (s+1); @@ -65,11 +65,20 @@ static int chs_rdwr_sectors(struct disk *disk, void *buf, ireg.es = SEG(tptr); retry = RETRY_COUNT; - + for (;;) { + dprintf("CHS[%02x]: %u @ %llu (%u/%u/%u) %04x:%04x %s %p\n", + ireg.edx.b[0], chunk, xlba, c, h, s+1, + ireg.es, ireg.ebx.w[0], + (ireg.eax.b[1] & 1) ? "<-" : "->", + ptr); + __intcall(0x13, &ireg, &oreg); if (!(oreg.eflags.l & EFLAGS_CF)) break; + + dprintf("CHS: error AX = %04x\n", oreg.eax.w[0]); + if (retry--) continue; @@ -80,6 +89,11 @@ static int chs_rdwr_sectors(struct disk *disk, void *buf, retry = RETRY_COUNT; ireg.eax.b[0] = chunk; continue; + } else { + printf("CHS: Error %04x %s sector %llu (%u/%u/%u)\n", + oreg.eax.w[0], + is_write ? "writing" : "reading", + lba, c, h, s+1); } return done; /* Failure */ } @@ -113,18 +127,22 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, char *tptr; size_t chunk, freeseg; int sector_shift = disk->sector_shift; - com32sys_t ireg, oreg; + com32sys_t ireg, oreg, reset; size_t done = 0; size_t bytes; int retry; memset(&ireg, 0, sizeof ireg); - + ireg.eax.b[1] = 0x42 + is_write; ireg.edx.b[0] = disk->disk_number; ireg.ds = SEG(&pkt); ireg.esi.w[0] = OFFS(&pkt); + memset(&reset, 0, sizeof reset); + + ireg.edx.b[0] = disk->disk_number; + lba += disk->part_start; while (count) { chunk = count; @@ -157,12 +175,29 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, pkt.buf = FAR_PTR(tptr); pkt.lba = lba; + dprintf("EDD[%02x]: %u @ %llu %04x:%04x %s %p\n", + ireg.edx.b[0], pkt.blocks, pkt.lba, + pkt.buf.seg, pkt.buf.offs, + (ireg.eax.b[1] & 1) ? "<-" : "->", + ptr); + __intcall(0x13, &ireg, &oreg); if (!(oreg.eflags.l & EFLAGS_CF)) break; + + dprintf("EDD: error AX = %04x\n", oreg.eax.w[0]); + if (retry--) continue; + /* + * Some systems seem to get "stuck" in an error state when + * using EBIOS. Doesn't happen when using CBIOS, which is + * good, since some other systems get timeout failures + * waiting for the floppy disk to spin up. + */ + __intcall(0x13, &reset, NULL); + /* For any starting value, this will always end with ..., 1, 0 */ chunk >>= 1; if (chunk) { @@ -172,7 +207,10 @@ static int edd_rdwr_sectors(struct disk *disk, void *buf, } /*** XXX: Consider falling back to CHS here?! ***/ - printf("reading sectors error(EDD)\n"); + printf("EDD: Error %04x %s sector %llu\n", + oreg.eax.w[0], + is_write ? "writing" : "reading", + lba); return done; /* Failure */ } @@ -216,7 +254,7 @@ static inline bool is_power_of_2(uint32_t x) static int ilog2(uint32_t num) { int i = 0; - + if (!is_power_of_2(num)) { printf("ERROR: the num must be power of 2 when conveting to log2\n"); return 0; @@ -241,57 +279,73 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start, static struct disk disk; static __lowmem struct edd_disk_params edd_params; com32sys_t ireg, oreg; - bool ebios = cdrom; - int sector_size = cdrom ? 2048 : 512; - unsigned int hard_max_transfer = ebios ? 127 : 63; + bool ebios; + int sector_size; + unsigned int hard_max_transfer; memset(&ireg, 0, sizeof ireg); - - /* Get EBIOS support */ - ireg.eax.b[1] = 0x41; - ireg.ebx.w[0] = 0x55aa; ireg.edx.b[0] = devno; - ireg.eflags.b[0] = 0x3; /* CF set */ - __intcall(0x13, &ireg, &oreg); - - if (cdrom || (!(oreg.eflags.l & EFLAGS_CF) && - oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1))) { + if (cdrom) { + /* + * The query functions don't work right on some CD-ROM stacks. + * Known affected systems: ThinkPad T22, T23. + */ + sector_size = 2048; ebios = true; - hard_max_transfer = 127; - - /* Query EBIOS parameters */ - edd_params.len = sizeof edd_params; - - ireg.eax.b[1] = 0x48; - ireg.ds = SEG(&edd_params); - ireg.esi.w[0] = OFFS(&edd_params); - __intcall(0x13, &ireg, &oreg); - - if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) { - if (edd_params.len < sizeof edd_params) - memset((char *)&edd_params + edd_params.len, 0, - sizeof edd_params - edd_params.len); - if (edd_params.sector_size >= 512 && - is_power_of_2(edd_params.sector_size)) - sector_size = edd_params.sector_size; + hard_max_transfer = 32; + } else { + sector_size = 512; + ebios = false; + hard_max_transfer = 63; + + /* CBIOS parameters */ + disk.h = bsHeads; + disk.s = bsSecPerTrack; + + if ((int8_t)devno < 0) { + /* Get hard disk geometry from BIOS */ + + ireg.eax.b[1] = 0x08; + __intcall(0x13, &ireg, &oreg); + + if (!(oreg.eflags.l & EFLAGS_CF)) { + disk.h = oreg.edx.b[1] + 1; + disk.s = oreg.ecx.b[0] & 63; + } } - } - /* CBIOS parameters */ - disk.h = bsHeads; - disk.s = bsSecPerTrack; + /* Get EBIOS support */ + ireg.eax.b[1] = 0x41; + ireg.ebx.w[0] = 0x55aa; + ireg.eflags.b[0] = 0x3; /* CF set */ - if ((int8_t)devno < 0) { - /* Get hard disk geometry from BIOS */ - - ireg.eax.b[1] = 0x08; __intcall(0x13, &ireg, &oreg); + + if (!(oreg.eflags.l & EFLAGS_CF) && + oreg.ebx.w[0] == 0xaa55 && (oreg.ecx.b[0] & 1)) { + ebios = true; + hard_max_transfer = 127; + + /* Query EBIOS parameters */ + edd_params.len = sizeof edd_params; + + ireg.eax.b[1] = 0x48; + ireg.ds = SEG(&edd_params); + ireg.esi.w[0] = OFFS(&edd_params); + __intcall(0x13, &ireg, &oreg); - if (!(oreg.eflags.l & EFLAGS_CF)) { - disk.h = oreg.edx.b[1] + 1; - disk.s = oreg.ecx.b[0] & 63; + if (!(oreg.eflags.l & EFLAGS_CF) && oreg.eax.b[1] == 0) { + if (edd_params.len < sizeof edd_params) + memset((char *)&edd_params + edd_params.len, 0, + sizeof edd_params - edd_params.len); + + if (edd_params.sector_size >= 512 && + is_power_of_2(edd_params.sector_size)) + sector_size = edd_params.sector_size; + } } + } disk.disk_number = devno; @@ -306,11 +360,15 @@ struct disk *disk_init(uint8_t devno, bool cdrom, sector_t part_start, disk.maxtransfer = MaxTransfer; + dprintf("disk %02x cdrom %d type %d sector %u/%u offset %llu limit %u\n", + devno, cdrom, ebios, sector_size, disk.sector_shift, + part_start, disk.maxtransfer); + return &disk; } -/* +/* * Initialize the device structure. * * NOTE: the disk cache needs to be revamped to support multiple devices... @@ -324,9 +382,9 @@ struct device * device_init(uint8_t devno, bool cdrom, sector_t part_start, dev.disk = disk_init(devno, cdrom, part_start, bsHeads, bsSecPerTrack, MaxTransfer); - + dev.cache_data = diskcache; dev.cache_size = sizeof diskcache; - + return &dev; } diff --git a/core/fs/fat/fat.c b/core/fs/fat/fat.c index a21f4312..5902f481 100644 --- a/core/fs/fat/fat.c +++ b/core/fs/fat/fat.c @@ -6,6 +6,7 @@ #include <core.h> #include <disk.h> #include <fs.h> +#include <ilog2.h> #include <klibc/compiler.h> #include "codepage.h" #include "fat_fs.h" @@ -19,7 +20,6 @@ static struct inode * new_fat_inode(struct fs_info *fs) return inode; } - /* * Check for a particular sector in the FAT cache */ @@ -276,26 +276,32 @@ static void mangle_dos_name(char *mangle_buf, const char *src) int i; unsigned char c; - i = 0; - while (i < 11) { - c = *src++; - + if (src[0] == '.' && (!src[1] || (src[1] == '.' && !src[2]))) { + /* . and .. mangle to their respective zero-padded version */ + i = stpcpy(mangle_buf, src) - mangle_buf; + } else { + i = 0; + while (i < 11) { + c = *src++; + if ((c <= ' ') || (c == '/')) break; - + if (c == '.') { while (i < 8) mangle_buf[i++] = ' '; i = 8; continue; } - + c = codepage.upper[c]; if (i == 0 && c == 0xe5) c = 0x05; /* Special hack for the first byte only! */ - + mangle_buf[i++] = c; + } } + while (i < 11) mangle_buf[i++] = ' '; @@ -408,7 +414,10 @@ static inline sector_t first_sector(struct fs_info *fs, sector_t sector; first_clust = (dir->first_cluster_high << 16) + dir->first_cluster_low; - sector = ((first_clust - 2) << sbi->clust_shift) + sbi->data; + if (first_clust == 0) + sector = sbi->root; /* first_clust == 0 means root directory */ + else + sector = ((first_clust - 2) << sbi->clust_shift) + sbi->data; return sector; } @@ -533,7 +542,16 @@ found: inode->size = de->file_size; PVT(inode)->start_cluster = (de->first_cluster_high << 16) + de->first_cluster_low; - PVT(inode)->start = PVT(inode)->here = first_sector(fs, de); + if (PVT(inode)->start_cluster == 0) { + /* Root directory */ + int root_size = FAT_SB(fs)->root_size; + + PVT(inode)->start_cluster = FAT_SB(fs)->root_cluster; + inode->size = root_size ? root_size << fs->sector_shift : ~0; + PVT(inode)->start = PVT(inode)->here = FAT_SB(fs)->root; + } else { + PVT(inode)->start = PVT(inode)->here = first_sector(fs, de); + } inode->mode = get_inode_mode(de->attr); return inode; @@ -696,45 +714,6 @@ got: return 0; } -/* Load the config file, return 1 if failed, or 0 */ -static int vfat_load_config(void) -{ - const char *search_directories[] = { - "/boot/syslinux", - "/syslinux", - "/", - NULL - }; - com32sys_t regs; - int i; - - /* If installed by extlinux, try the extlinux filename */ - if (*CurrentDirName && !generic_load_config()) - return 0; - - for (i = 0; search_directories[i]; i++) { - memset(®s, 0, sizeof regs); - snprintf(ConfigName, FILENAME_MAX, "%s/syslinux.cfg", - search_directories[i]); - regs.edi.w[0] = OFFS_WRT(ConfigName, 0); - call16(core_open, ®s, ®s); - if (!(regs.eflags.l & EFLAGS_ZF)) - break; - } - if (!search_directories[i]) - return -1; - - /* Set the current working directory */ - chdir(search_directories[i]); - return 0; -} - -static inline __constfunc uint32_t bsr(uint32_t num) -{ - asm("bsrl %1,%0" : "=r" (num) : "rm" (num)); - return num; -} - /* init. the fs meta data, return the block size in bits */ static int vfat_fs_init(struct fs_info *fs) { @@ -767,7 +746,7 @@ static int vfat_fs_init(struct fs_info *fs) sbi->root_size = root_dir_size(fs, &fat); sbi->data = sbi->root + sbi->root_size; - sbi->clust_shift = bsr(fat.bxSecPerClust); + sbi->clust_shift = ilog2(fat.bxSecPerClust); sbi->clust_byte_shift = sbi->clust_shift + fs->sector_shift; sbi->clust_mask = fat.bxSecPerClust - 1; sbi->clust_size = fat.bxSecPerClust << fs->sector_shift; @@ -808,7 +787,7 @@ const struct fs_ops vfat_fs_ops = { .getfssec = generic_getfssec, .close_file = generic_close_file, .mangle_name = vfat_mangle_name, - .load_config = vfat_load_config, + .load_config = generic_load_config, .readdir = vfat_readdir, .iget_root = vfat_iget_root, .iget = vfat_iget, diff --git a/core/fs/fs.c b/core/fs/fs.c index 9b8e30f0..48856c9e 100644 --- a/core/fs/fs.c +++ b/core/fs/fs.c @@ -30,6 +30,18 @@ struct inode *alloc_inode(struct fs_info *fs, uint32_t ino, size_t data) } /* + * Free a refcounted inode + */ +void put_inode(struct inode *inode) +{ + while (inode && --inode->refcnt == 0) { + struct inode *dead = inode; + inode = inode->parent; + free(dead); + } +} + +/* * Get an empty file structure */ static struct file *alloc_file(void) @@ -193,19 +205,14 @@ int searchdir(const char *name) char *part, *p, echar; int symlink_count = MAX_SYMLINK_CNT; -// mp("enter: name = %s", name); - if (!(file = alloc_file())) goto err_no_close; -// mp("111"); file->fs = this_fs; /* if we have ->searchdir method, call it */ if (file->fs->fs_ops->searchdir) { file->fs->fs_ops->searchdir(name, file); -// mp("this fs has searchdir(), inode = %d",file->inode); - if (file->inode) return file_to_handle(file); else @@ -215,13 +222,10 @@ int searchdir(const char *name) /* else, try the generic-path-lookup method */ parent = get_inode(this_fs->cwd); -// mp("222"); p = pathbuf = strdup(name); if (!pathbuf) goto err; - //mp("parent->ino = %d", parent->ino); - do { got_link: if (*p == '/') { @@ -243,7 +247,20 @@ int searchdir(const char *name) p++; *p++ = '\0'; - if (part[0] != '.' || part[1] != '\0') { + if (part[0] == '.' && part[1] == '.' && part[2] == '\0') { + if (inode->parent) { + put_inode(parent); + parent = get_inode(inode->parent); + put_inode(inode); + inode = NULL; + if (!echar) { + /* Terminal double dots */ + inode = parent; + parent = inode->parent ? + get_inode(inode->parent) : NULL; + } + } + } else if (part[0] != '.' || part[1] != '\0') { inode = this_fs->fs_ops->iget(part, parent); if (!inode) goto err; @@ -286,7 +303,7 @@ int searchdir(const char *name) goto got_link; } - put_inode(parent); + inode->parent = parent; parent = NULL; if (!echar) @@ -312,16 +329,11 @@ int searchdir(const char *name) file->inode = inode; file->offset = 0; - dprintf("File %s -> %p (inode %p) len %u\n", name, file, - inode, inode->size); - return file_to_handle(file); err: - if (inode) - put_inode(inode); - if (parent) - put_inode(parent); + put_inode(inode); + put_inode(parent); if (pathbuf) free(pathbuf); _close_file(file); @@ -338,14 +350,20 @@ int open_file(const char *name, struct com32_filedata *filedata) mangle_name(mangled_name, name); rv = searchdir(mangled_name); - //mp("name = %s, rv = %d", name, rv); + if (rv < 0) + return rv; - if (rv >= 0) { - file = handle_to_file(rv); - filedata->size = file->inode->size; - filedata->blocklg2 = SECTOR_SHIFT(file->fs); - filedata->handle = rv; + file = handle_to_file(rv); + + if (file->inode->mode != DT_REG) { + _close_file(file); + return -1; } + + filedata->size = file->inode->size; + filedata->blocklg2 = SECTOR_SHIFT(file->fs); + filedata->handle = rv; + return rv; } @@ -409,10 +427,8 @@ void fs_init(com32sys_t *regs) /* ops is a ptr list for several fs_ops */ const struct fs_ops **ops = (const struct fs_ops **)regs->eax.l; - mp("enter"); - /* Initialize malloc() */ - //mem_init(); + mem_init(); /* Default name for the root directory */ fs.cwd_name[0] = '/'; diff --git a/core/fs/getcwd.c b/core/fs/getcwd.c new file mode 100644 index 00000000..a7b6c7a9 --- /dev/null +++ b/core/fs/getcwd.c @@ -0,0 +1,13 @@ +#include <string.h> +#include "fs.h" + +char *getcwd(char *buf, size_t size) +{ + char *ret = NULL; + + if((buf != NULL) && (strlen(this_fs->cwd_name) < size)) { + strcpy(buf, this_fs->cwd_name); + ret = buf; + } + return ret; +} diff --git a/core/fs/getfssec.c b/core/fs/getfssec.c index 3d62d4e6..e099b64e 100644 --- a/core/fs/getfssec.c +++ b/core/fs/getfssec.c @@ -144,6 +144,10 @@ uint32_t generic_getfssec(struct file *file, char *buf, if (!inode->this_extent.len) { /* Doesn't matter if it's contiguous... */ inode->this_extent = inode->next_extent; + if (!inode->next_extent.len) { + sectors = 0; /* Failed to get anything... we're dead */ + break; + } } else if (inode->next_extent.len && inode->next_extent.pstart == next_pstart(&inode->this_extent)) { /* Coalesce extents and loop */ diff --git a/core/fs/iso9660/iso9660.c b/core/fs/iso9660/iso9660.c index d695e439..62137d0d 100644 --- a/core/fs/iso9660/iso9660.c +++ b/core/fs/iso9660/iso9660.c @@ -273,30 +273,21 @@ static int iso_readdir(struct file *file, struct dirent *dirent) /* Load the config file, return 1 if failed, or 0 */ static int iso_load_config(void) { - const char *search_directories[] = { + static const char *search_directories[] = { "/boot/isolinux", "/isolinux", + "/boot/syslinux", + "/syslinux", "/", NULL }; - com32sys_t regs; - int i; - - for (i = 0; search_directories[i]; i++) { - memset(®s, 0, sizeof regs); - snprintf(ConfigName, FILENAME_MAX, "%s/isolinux.cfg", - search_directories[i]); - regs.edi.w[0] = OFFS_WRT(ConfigName, 0); - call16(core_open, ®s, ®s); - if (!(regs.eflags.l & EFLAGS_ZF)) - break; - } - if (!search_directories[i]) - return -1; - - /* Set the current working directory */ - chdir(search_directories[i]); - return 0; + static const char *filenames[] = { + "isolinux.cfg", + "syslinux.cfg", + NULL + }; + + return search_config(search_directories, filenames); } static int iso_fs_init(struct fs_info *fs) diff --git a/core/fs/lib/loadconfig.c b/core/fs/lib/loadconfig.c index 9318c1c3..c9652b6c 100644 --- a/core/fs/lib/loadconfig.c +++ b/core/fs/lib/loadconfig.c @@ -5,20 +5,30 @@ #include <fs.h> /* - * Standard version of load_config for extlinux-installed filesystems + * Standard version of load_config for extlinux/syslinux filesystems. + * + * This searches for extlinux.conf and syslinux.cfg in the install + * directory, followed by a set of fallback directories. If found, + * set the current working directory to match. */ int generic_load_config(void) { - com32sys_t regs; + static const char *search_directories[] = { + NULL, /* CurrentDirName */ + "/boot/syslinux", + "/syslinux", + "/", + NULL + }; + static const char *filenames[] = { + "extlinux.conf", + "syslinux.cfg", + NULL + }; - chdir(CurrentDirName); - realpath(ConfigName, "extlinux.conf", FILENAME_MAX); + search_directories[0] = CurrentDirName; - dprintf("Config = %s\n", ConfigName); + dprintf("CurrentDirName: \"%s\"\n", CurrentDirName); - memset(®s, 0, sizeof regs); - regs.edi.w[0] = OFFS_WRT(ConfigName, 0); - call16(core_open, ®s, ®s); - - return (regs.eflags.l & EFLAGS_ZF) ? -1 : 0; + return search_config(search_directories, filenames); } diff --git a/core/fs/lib/searchconfig.c b/core/fs/lib/searchconfig.c new file mode 100644 index 00000000..24bfde31 --- /dev/null +++ b/core/fs/lib/searchconfig.c @@ -0,0 +1,40 @@ +#include <dprintf.h> +#include <stdio.h> +#include <string.h> +#include <core.h> +#include <fs.h> + +/* + * Common implementation of load_config + * + * This searches for a specified set of filenames in a specified set + * of directories. If found, set the current working directory to + * match. + */ +int search_config(const char *search_directories[], const char *filenames[]) +{ + char confignamebuf[FILENAME_MAX]; + com32sys_t regs; + const char *sd, **sdp; + const char *sf, **sfp; + + for (sdp = search_directories; (sd = *sdp); sdp++) { + for (sfp = filenames; (sf = *sfp); sfp++) { + memset(®s, 0, sizeof regs); + snprintf(confignamebuf, sizeof confignamebuf, + "%s%s%s", + sd, (*sd && sd[strlen(sd)-1] == '/') ? "" : "/", + sf); + realpath(ConfigName, confignamebuf, FILENAME_MAX); + regs.edi.w[0] = OFFS_WRT(ConfigName, 0); + dprintf("Config search: %s\n", ConfigName); + call16(core_open, ®s, ®s); + if (!(regs.eflags.l & EFLAGS_ZF)) { + chdir(sd); + return 0; /* Got it */ + } + } + } + + return -1; +} diff --git a/core/fs/pxe/dhcp_option.c b/core/fs/pxe/dhcp_option.c index e18b605d..50f2de04 100644 --- a/core/fs/pxe/dhcp_option.c +++ b/core/fs/pxe/dhcp_option.c @@ -8,93 +8,87 @@ char LocalDomain[256]; int over_load; uint8_t uuid_type; -char uuid[17]; +uint8_t uuid[16]; -static void parse_dhcp_options(void *, int, uint8_t); +static void parse_dhcp_options(const void *, int, uint8_t); -static void subnet_mask(void *data, int opt_len) +static void subnet_mask(const void *data, int opt_len) { if (opt_len != 4) return; - net_mask = *(uint32_t *)data; + IPInfo.netmask = *(const uint32_t *)data; } -static void router(void *data, int opt_len) +static void router(const void *data, int opt_len) { if (opt_len != 4) return; - gate_way = *(uint32_t *)data; + IPInfo.gateway = *(const uint32_t *)data; } -static void dns_servers(void *data, int opt_len) +static void dns_servers(const void *data, int opt_len) { - int num = opt_len >> 2; - int i; + const uint32_t *dp = data; + int num = 0; - if (num > DNS_MAX_SERVERS) - num = DNS_MAX_SERVERS; + while (num < DNS_MAX_SERVERS) { + uint32_t ip; - for (i = 0; i < num; i++) { - dns_server[i] = *(uint32_t *)data; - data += 4; - } + if (opt_len < 4) + break; -#if 0 - /* - * if you find you got no corret DNS server, you can add - * it here manually. BUT be carefull the DNS_MAX_SERVERS - */ - if (i < DNS_MAX_SERVERS ) { - dns_server[i++] = your_master_dns_server; - dns_server[i++] = your_second_dns_server; + opt_len -= 4; + ip = *dp++; + if (ip_ok(ip)) + dns_server[num++] = ip; } -#endif + while (num < DNS_MAX_SERVERS) + dns_server[num++] = 0; } -static void local_domain(void *data, int opt_len) +static void local_domain(const void *data, int opt_len) { - char *p = (char *)data + opt_len; + char buffer[256]; char *ld = LocalDomain; - char end = *p; - - *p = '\0'; /* Zero-terminate option */ - dns_mangle(&ld, data); - *p = end; /* Restore ending byte */ + + memcpy(buffer, data, opt_len); + buffer[opt_len] = 0; + + dns_mangle(&ld, buffer); } -static void vendor_encaps(void *data, int opt_len) +static void vendor_encaps(const void *data, int opt_len) { - /* Only recongnize PXELINUX options */ + /* Only recognize PXELINUX options */ parse_dhcp_options(data, opt_len, 208); } -static void option_overload(void *data, int opt_len) +static void option_overload(const void *data, int opt_len) { if (opt_len != 1) return; over_load = *(uint8_t *)data; } - -static void server(void *data, int opt_len) +static void server(const void *data, int opt_len) { uint32_t ip; if (opt_len != 4) return; - - if (server_ip) + + if (IPInfo.serverip) return; - + ip = *(uint32_t *)data; if (ip_ok(ip)) - server_ip = ip; + IPInfo.serverip = ip; } -static void client_identifier(void *data, int opt_len) +static void client_identifier(const void *data, int opt_len) { if (opt_len > MAC_MAX || opt_len < 2 || - MAC_len != (opt_len >> 8) || + MAC_len != (opt_len >> 8) || *(uint8_t *)data != MAC_type) return; @@ -104,54 +98,53 @@ static void client_identifier(void *data, int opt_len) MAC[opt_len] = 0; } -static void bootfile_name(void *data, int opt_len) +static void bootfile_name(const void *data, int opt_len) { - strncpy(boot_file, data, opt_len); + memcpy(boot_file, data, opt_len); boot_file[opt_len] = 0; } - -static void uuid_client_identifier(void *data, int opt_len) + +static void uuid_client_identifier(const void *data, int opt_len) { - int type = *(uint8_t *)data; + int type = *(const uint8_t *)data; if (opt_len != 17 || type != 0 || have_uuid) return; have_uuid = true; uuid_type = type; memcpy(uuid, data+1, 16); - uuid[16] = 0; } -static void pxelinux_configfile(void *data, int opt_len) +static void pxelinux_configfile(const void *data, int opt_len) { DHCPMagic |= 2; - strncpy(ConfigName, data, opt_len); + memcpy(ConfigName, data, opt_len); ConfigName[opt_len] = 0; } -static void pxelinux_pathprefix(void *data, int opt_len) +static void pxelinux_pathprefix(const void *data, int opt_len) { DHCPMagic |= 4; - strncpy(path_prefix, data, opt_len); + memcpy(path_prefix, data, opt_len); path_prefix[opt_len] = 0; } -static void pxelinux_reboottime(void *data, int opt_len) +static void pxelinux_reboottime(const void *data, int opt_len) { - if ((opt_len && 0xff) != 4) - return ; - - RebootTime = ntohl(*(uint32_t *)data); + if (opt_len != 4) + return; + + RebootTime = ntohl(*(const uint32_t *)data); DHCPMagic |= 8; /* Got reboot time */ } struct dhcp_options { int opt_num; - void (*fun) (void *, int); + void (*fun)(const void *, int); }; -static struct dhcp_options dhcp_opts[] = { +static const struct dhcp_options dhcp_opts[] = { {1, subnet_mask}, {3, router}, {6, dns_servers}, @@ -168,56 +161,54 @@ static struct dhcp_options dhcp_opts[] = { }; /* - * Parse a sequence of DHCP options, pointed to by _option_; + * Parse a sequence of DHCP options, pointed to by _option_; * -- some DHCP servers leave option fields unterminated * in violation of the spec. * * filter contains the minimum value for the option to recognize * -- this is used to restrict parsing to PXELINUX-specific options only. - */ -static void parse_dhcp_options(void *option, int size, uint8_t opt_filter) + */ +static void parse_dhcp_options(const void *option, int size, uint8_t opt_filter) { - uint8_t opt_num; - uint8_t opt_len; - int opt_entries = sizeof(dhcp_opts) / sizeof(dhcp_opts[0]); + int opt_num; + int opt_len; + const int opt_entries = sizeof(dhcp_opts) / sizeof(dhcp_opts[0]); int i = 0; - char *p = option; - struct dhcp_options *opt; - - while (size--) { + const uint8_t *p = option; + const struct dhcp_options *opt; + + /* The only 1-byte options are 00 and FF, neither of which matter */ + while (size >= 2) { opt_num = *p++; + size--; - if (!size) - break; if (opt_num == 0) continue; if (opt_num == 0xff) break; - - /* Anything else will have a lenght filed */ + + /* Anything else will have a length field */ opt_len = *p++; /* c <- option lenght */ - size = size - opt_len - 1; + size -= opt_len + 1; if (size < 0) break; - if (opt_num < opt_filter) { /* Is the option value valid */ - option += opt_len; /* Try next */ - continue; - } - - opt = dhcp_opts; - for (i = 0; i < opt_entries; i++) { - if (opt_num == opt->opt_num) { - opt->fun(p, opt_len); - break; - } - opt ++; - } - + + if (opt_num >= opt_filter) { + opt = dhcp_opts; + for (i = 0; i < opt_entries; i++) { + if (opt_num == opt->opt_num) { + opt->fun(p, opt_len); + break; + } + opt++; + } + } + /* parse next */ p += opt_len; } } - + /* * parse_dhcp * @@ -244,22 +235,24 @@ void parse_dhcp(int pkt_len) struct bootp_t *dhcp = (struct bootp_t *)trackbuf; int opt_len; + IPInfo.ipv4 = 4; /* This is IPv4 only for now... */ + over_load = 0; if (ip_ok(dhcp->yip)) - MyIP = dhcp->yip; - + IPInfo.myip = dhcp->yip; + if (ip_ok(dhcp->sip)) - server_ip = dhcp->sip; - + IPInfo.serverip = dhcp->sip; + opt_len = (char *)dhcp + pkt_len - (char *)&dhcp->options; - if (opt_len && (dhcp->option_magic == BOOTP_OPTION_MAGIC)) + if (opt_len && (dhcp->option_magic == BOOTP_OPTION_MAGIC)) parse_dhcp_options(&dhcp->options, opt_len, 0); - if (over_load & 1) + if (over_load & 1) parse_dhcp_options(&dhcp->bootfile, 128, 0); - else if (dhcp->bootfile[0]) - strcpy(boot_file, dhcp->bootfile); - - if (over_load & 2) + else if (dhcp->bootfile[0]) + strcpy(boot_file, dhcp->bootfile); + + if (over_load & 2) parse_dhcp_options(dhcp->sname, 64, 0); -} +} diff --git a/core/fs/pxe/dnsresolv.c b/core/fs/pxe/dnsresolv.c index df7f33c1..2b263fad 100644 --- a/core/fs/pxe/dnsresolv.c +++ b/core/fs/pxe/dnsresolv.c @@ -35,7 +35,7 @@ struct dnsquery { } __attribute__ ((packed)); /* - * The DNS Resource recodes structure + * The DNS Resource recodes structure */ struct dnsrr { uint16_t type; @@ -50,7 +50,7 @@ uint32_t dns_server[DNS_MAX_SERVERS] = {0, }; /* - * Turn a string in _src_ into a DNS "label set" in _dst_; returns the + * Turn a string in _src_ into a DNS "label set" in _dst_; returns the * number of dots encountered. On return, *dst is updated. */ int dns_mangle(char **dst, const char *p) @@ -58,14 +58,14 @@ int dns_mangle(char **dst, const char *p) char *q = *dst; char *count_ptr; char c; - int dots = 0; + int dots = 0; count_ptr = q; *q++ = 0; while (1) { c = *p++; - if (c == 0 || c == ':') + if (c == 0 || c == ':' || c == '/') break; if (c == '.') { dots++; @@ -73,7 +73,7 @@ int dns_mangle(char **dst, const char *p) *q++ = 0; continue; } - + *count_ptr += 1; *q++ = c; } @@ -85,7 +85,7 @@ int dns_mangle(char **dst, const char *p) *dst = q; return dots; } - + /* * Compare two sets of DNS labels, in _s1_ and _s2_; the one in _s2_ @@ -126,7 +126,7 @@ static void *dns_copylabel(void *dst, const void *src, const void *buf) uint8_t *q = dst; const uint8_t *p = src; unsigned int c0, c1; - + while (1) { c0 = p[0]; if (c0 >= 0xc0) { @@ -151,7 +151,7 @@ static void *dns_copylabel(void *dst, const void *src, const void *buf) static char *dns_skiplabel(char *label) { uint8_t c; - + while (1) { c = *label++; if (c >= 0xc0) @@ -184,16 +184,20 @@ uint32_t dns_resolv(const char *name) const uint8_t *timeout_ptr = TimeoutTable; uint32_t oldtime; uint32_t srv; - uint32_t *srv_ptr = dns_server; + uint32_t *srv_ptr; struct dnshdr *hd1 = (struct dnshdr *)DNSSendBuf; - struct dnshdr *hd2 = (struct dnshdr *)DNSRecvBuf; + struct dnshdr *hd2 = (struct dnshdr *)DNSRecvBuf; struct dnsquery *query; struct dnsrr *rr; static __lowmem struct s_PXENV_UDP_WRITE udp_write; - static __lowmem struct s_PXENV_UDP_READ udp_read; + static __lowmem struct s_PXENV_UDP_READ udp_read; uint16_t local_port; uint32_t result = 0; + /* Make sure we have at least one valid DNS server */ + if (!dns_server[0]) + return 0; + /* Get a local port number */ local_port = get_port(); @@ -204,68 +208,61 @@ uint32_t dns_resolv(const char *name) hd1->ancount = 0; /* No answers */ hd1->nscount = 0; /* No NS */ hd1->arcount = 0; /* No AR */ - + p = DNSSendBuf + sizeof(struct dnshdr); dots = dns_mangle(&p, name); /* store the CNAME */ - + if (!dots) { p--; /* Remove final null */ /* Uncompressed DNS label set so it ends in null */ - strcpy(p, LocalDomain); + strcpy(p, LocalDomain); } - + /* Fill the DNS query packet */ query = (struct dnsquery *)p; query->qtype = htons(TYPE_A); query->qclass = htons(CLASS_IN); p += sizeof(struct dnsquery); - + /* Now send it to name server */ timeout_ptr = TimeoutTable; timeout = *timeout_ptr++; - while (srv_ptr < dns_server + DNS_MAX_SERVERS) { - srv = *srv_ptr++; - if (!srv) - continue; /* just move on before runing the time out */ + srv_ptr = dns_server; + while (timeout) { + srv = *srv_ptr++; + if (!srv) { + srv_ptr = dns_server; + srv = *srv_ptr++; + } + udp_write.status = 0; udp_write.ip = srv; - udp_write.gw = ((srv ^ MyIP) & net_mask) ? gate_way : 0; + udp_write.gw = gateway(srv); udp_write.src_port = local_port; udp_write.dst_port = DNS_PORT; udp_write.buffer_size = p - DNSSendBuf; udp_write.buffer = FAR_PTR(DNSSendBuf); err = pxe_call(PXENV_UDP_WRITE, &udp_write); - if (err || udp_write.status != 0) + if (err || udp_write.status) continue; - + oldtime = jiffies(); - while (1) { + do { + if (jiffies() - oldtime >= timeout) + goto again; + udp_read.status = 0; udp_read.src_ip = srv; - udp_read.dest_ip = MyIP; + udp_read.dest_ip = IPInfo.myip; udp_read.s_port = DNS_PORT; udp_read.d_port = local_port; - udp_read.buffer_size = DNS_MAX_PACKET; + udp_read.buffer_size = PKTBUF_SIZE; udp_read.buffer = FAR_PTR(DNSRecvBuf); err = pxe_call(PXENV_UDP_READ, &udp_read); - if (err || udp_read.status) - continue; - - /* Got a packet, deal with it... */ - if (hd2->id == hd1->id) - break; - - if (jiffies()-oldtime >= timeout) { - /* time out */ - timeout = *timeout_ptr++; - if (!timeout) - goto done; /* All time ticks run out */ - else - goto again; - } - } + } while (err || udp_read.status || hd2->id != hd1->id); + if ((hd2->flags ^ 0x80) & htons(0xf80f)) - goto badness; + goto badness; ques = htons(hd2->qdcount); /* Questions */ reps = htons(hd2->ancount); /* Replies */ @@ -302,7 +299,7 @@ uint32_t dns_resolv(const char *name) default: break; } - } + } /* not the one we want, try next */ p += sizeof(struct dnsrr) + rd_len; @@ -319,13 +316,13 @@ uint32_t dns_resolv(const char *name) ; domain doesn't exist. If this turns out to be a ; problem, we may want to add code to go through all ; the servers before giving up. - + ; If the DNS server wasn't capable of recursion, and ; isn't capable of giving us an authoritative reply ; (i.e. neither AA or RA set), then at least try a ; different setver... */ - if (hd2->flags == htons(0x480)) + if (hd2->flags == htons(0x480)) continue; break; /* failed */ @@ -339,10 +336,10 @@ done: return result; } - - + + /* - * the one should be called from ASM file + * the one should be called from ASM file */ void pxe_dns_resolv(com32sys_t *regs) { diff --git a/core/fs/pxe/idle.c b/core/fs/pxe/idle.c index 0538b163..52a87c34 100644 --- a/core/fs/pxe/idle.c +++ b/core/fs/pxe/idle.c @@ -27,7 +27,7 @@ static int pxe_idle_poll(void) memset(&read_buf, 0, sizeof read_buf); read_buf.src_ip = 0; /* Any destination */ - read_buf.dest_ip = MyIP; + read_buf.dest_ip = IPInfo.myip; read_buf.s_port = 0; /* Any source port */ read_buf.d_port = htons(9); /* Discard port (not used...) */ read_buf.buffer_size = sizeof junk_pkt; diff --git a/core/fs/pxe/pxe.c b/core/fs/pxe/pxe.c index 011ef293..25bd094d 100644 --- a/core/fs/pxe/pxe.c +++ b/core/fs/pxe/pxe.c @@ -9,17 +9,16 @@ #define GPXE 1 -uint32_t server_ip = 0; /* IP address of boot server */ -uint32_t net_mask = 0; /* net_mask of this subnet */ -uint32_t gate_way = 0; /* Default router */ -uint16_t real_base_mem; /* Amount of DOS memory after freeing */ +static uint16_t real_base_mem; /* Amount of DOS memory after freeing */ uint8_t MAC[MAC_MAX]; /* Actual MAC address */ uint8_t MAC_len; /* MAC address len */ uint8_t MAC_type; /* MAC address type */ char __bss16 BOOTIFStr[7+3*(MAC_MAX+1)]; -#define MAC_str (BOOTIFStr+7) +#define MAC_str (BOOTIFStr+7) /* The actual hardware address */ +char __bss16 SYSUUIDStr[8+32+5]; +#define UUID_str (SYSUUIDStr+8) /* The actual UUID */ char boot_file[256]; /* From DHCP */ char path_prefix[256]; /* From DHCP */ @@ -27,7 +26,6 @@ char dot_quad_buf[16]; static bool has_gpxe; static uint32_t gpxe_funcs; -static uint8_t uuid_dashes[] = {4, 2, 2, 2, 6, 0}; bool have_uuid = false; /* Common receive buffer */ @@ -70,6 +68,7 @@ static struct inode *allocate_socket(struct fs_info *fs) } else { struct pxe_pvt_inode *socket = PVT(inode); socket->tftp_localport = get_port(); + inode->mode = DT_REG; /* No other types relevant for PXE */ } return inode; @@ -175,15 +174,17 @@ static int hexbyte(const char *p) * assignable unicast addresses in the near future. * */ -int ip_ok(uint32_t ip) +bool ip_ok(uint32_t ip) { - if (ip == -1 || /* Refuse the all-one address */ - (ip & 0xff) == 0 || /* Refuse network zero */ - (ip & 0xff) == 0xff || /* Refuse loopback */ - (ip & 0xf0) == 0xe0 ) /* Refuse class D */ - return 0; + uint8_t ip_hi = (uint8_t)ip; /* First octet of the ip address */ + + if (ip == 0xffffffff || /* Refuse the all-ones address */ + ip_hi == 0 || /* Refuse network zero */ + ip_hi == 127 || /* Refuse the loopback network */ + (ip_hi & 240) == 224) /* Refuse class D */ + return false; - return 1; + return true; } @@ -297,7 +298,7 @@ static void tftp_error(struct inode *inode, uint16_t errnum, udp_write.src_port = socket->tftp_localport; udp_write.dst_port = socket->tftp_remoteport; udp_write.ip = socket->tftp_remoteip; - udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0; + udp_write.gw = gateway(udp_write.ip); udp_write.buffer = FAR_PTR(&err_buf); udp_write.buffer_size = 4 + len + 1; @@ -326,7 +327,7 @@ static void ack_packet(struct inode *inode, uint16_t ack_num) udp_write.src_port = socket->tftp_localport; udp_write.dst_port = socket->tftp_remoteport; udp_write.ip = socket->tftp_remoteip; - udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0; + udp_write.gw = gateway(udp_write.ip); udp_write.buffer = FAR_PTR(ack_packet_buf); udp_write.buffer_size = 4; @@ -390,7 +391,7 @@ static enum pxe_path_type pxe_path_type(const char *str) else return PXE_TFTP; } else if (p > str && p[1] == '/' && p[2] == '/') { - if (strncasecmp(str, "tftp://", 7)) + if (!strncasecmp(str, "tftp://", 7)) return PXE_URL_TFTP; else return PXE_URL; @@ -480,7 +481,7 @@ static void fill_buffer(struct inode *inode) { int err; int last_pkt; - const uint8_t *timeout_ptr = TimeoutTable; + const uint8_t *timeout_ptr; uint8_t timeout; uint16_t buffersize; uint32_t oldtime; @@ -513,7 +514,7 @@ static void fill_buffer(struct inode *inode) udp_read.buffer = FAR_PTR(packet_buf); udp_read.buffer_size = PKTBUF_SIZE; udp_read.src_ip = socket->tftp_remoteip; - udp_read.dest_ip = MyIP; + udp_read.dest_ip = IPInfo.myip; udp_read.s_port = socket->tftp_remoteport; udp_read.d_port = socket->tftp_localport; err = pxe_call(PXENV_UDP_READ, &udp_read); @@ -638,7 +639,7 @@ static uint32_t pxe_getfssec(struct file *file, char *buf, * @param:filename, the file we wanna open * * @out: open_file_t structure, stores in file->open_file - * @ouT: the lenght of this file, stores in file->file_len + * @out: the lenght of this file, stores in file->file_len * */ static void pxe_searchdir(const char *filename, struct file *file) @@ -660,6 +661,7 @@ static void pxe_searchdir(const char *filename, struct file *file) int i = 0; int err; int buffersize; + int rrq_len; const uint8_t *timeout_ptr; uint32_t timeout; uint32_t oldtime; @@ -688,12 +690,12 @@ static void pxe_searchdir(const char *filename, struct file *file) case PXE_RELATIVE: /* Really shouldn't happen... */ case PXE_URL: buf = stpcpy(buf, filename); - ip = server_ip; /* Default server */ + ip = IPInfo.serverip; /* Default server */ break; case PXE_HOMESERVER: buf = stpcpy(buf, filename+2); - ip = server_ip; + ip = IPInfo.serverip; break; case PXE_TFTP: @@ -708,8 +710,8 @@ static void pxe_searchdir(const char *filename, struct file *file) while (*np && *np != '/' && *np != ':') np++; if (np > filename + 7) { - if (parse_dotquad(filename, &ip) != np) - ip = dns_resolv(filename); + if (parse_dotquad(filename + 7, &ip) != np) + ip = dns_resolv(filename + 7); } if (*np == ':') { np++; @@ -733,6 +735,7 @@ static void pxe_searchdir(const char *filename, struct file *file) *buf++ = *np++; } } + *buf = '\0'; break; } @@ -743,16 +746,13 @@ static void pxe_searchdir(const char *filename, struct file *file) memcpy(buf, rrq_tail, sizeof rrq_tail); buf += sizeof rrq_tail; + rrq_len = buf - rrq_packet_buf; + inode = allocate_socket(fs); if (!inode) return; /* Allocation failure */ socket = PVT(inode); - timeout_ptr = TimeoutTable; /* Reset timeout */ - timeout = *timeout_ptr; - oldtime = jiffies(); - -sendreq: #if GPXE if (path_type == PXE_URL) { if (has_gpxe) { @@ -777,36 +777,44 @@ sendreq: } #endif /* GPXE */ + timeout_ptr = TimeoutTable; /* Reset timeout */ + +sendreq: + timeout = *timeout_ptr++; + if (!timeout) + return; /* No file available... */ + oldtime = jiffies(); + socket->tftp_remoteip = ip; tid = socket->tftp_localport; /* TID(local port No) */ udp_write.buffer = FAR_PTR(rrq_packet_buf); udp_write.ip = ip; - udp_write.gw = ((udp_write.ip ^ MyIP) & net_mask) ? gate_way : 0; + udp_write.gw = gateway(udp_write.ip); udp_write.src_port = tid; udp_write.dst_port = server_port; - udp_write.buffer_size = buf - rrq_packet_buf; - err = pxe_call(PXENV_UDP_WRITE, &udp_write); + udp_write.buffer_size = rrq_len; + pxe_call(PXENV_UDP_WRITE, &udp_write); /* If the WRITE call fails, we let the timeout take care of it... */ wait_pkt: for (;;) { buf = packet_buf; + udp_read.status = 0; udp_read.buffer = FAR_PTR(buf); udp_read.buffer_size = PKTBUF_SIZE; - udp_read.dest_ip = MyIP; + udp_read.dest_ip = IPInfo.myip; udp_read.d_port = tid; err = pxe_call(PXENV_UDP_READ, &udp_read); - if (err) { + if (err || udp_read.status) { uint32_t now = jiffies(); - if (now-oldtime >= timeout) - goto failure; - continue; - } - - /* Make sure the packet actually came from the server */ - if (udp_read.src_ip == socket->tftp_remoteip) - break; + if (now - oldtime >= timeout) + goto sendreq; + } else { + /* Make sure the packet actually came from the server */ + if (udp_read.src_ip == socket->tftp_remoteip) + break; + } } socket->tftp_remoteport = udp_read.s_port; @@ -817,7 +825,7 @@ wait_pkt: socket->tftp_blksize = TFTP_BLOCKSIZE; buffersize = udp_read.buffer_size - 2; /* bytes after opcode */ if (buffersize < 0) - goto failure; /* Garbled reply */ + goto wait_pkt; /* Garbled reply */ /* * Get the opcode type, and parse it @@ -841,12 +849,12 @@ wait_pkt: */ buffersize -= 2; if (buffersize < 0) - goto failure; + goto wait_pkt; data = packet_buf + 2; blk_num = *(uint16_t *)data; data += 2; if (blk_num != htons(1)) - goto failure; + goto wait_pkt; socket->tftp_lastpkt = blk_num; if (buffersize > TFTP_BLOCKSIZE) goto err_reply; /* Corrupt */ @@ -955,15 +963,6 @@ err_reply: tftp_error(inode, TFTP_EOPTNEG, "TFTP protocol error"); printf("TFTP server sent an incomprehesible reply\n"); kaboom(); - -failure: - if (jiffies() - oldtime < timeout) - goto wait_pkt; - - /* Otherwise, we need to try again */ - timeout_ptr++; - if (*timeout_ptr) - goto sendreq; /* Try again */ } @@ -1048,6 +1047,7 @@ static int try_load(char *config_name) regs.edi.w[0] = OFFS_WRT(KernelName, 0); call16(core_open, ®s, ®s); if (regs.eflags.l & EFLAGS_ZF) { + strcpy(ConfigName, KernelName); printf("\r"); return 0; } else { @@ -1064,39 +1064,23 @@ static int pxe_load_config(void) const char *default_str = "default"; char *config_file; char *last; - char *p; - uint8_t *uuid_ptr; int tries = 8; get_prefix(); if (DHCPMagic & 0x02) { /* We got a DHCP option, try it first */ - if (try_load(boot_file)) + if (try_load(ConfigName)) return 0; } /* * Have to guess config file name ... */ - memcpy(ConfigName, cfgprefix, strlen(cfgprefix)); - config_file = ConfigName + strlen(cfgprefix); + config_file = stpcpy(ConfigName, cfgprefix); /* Try loading by UUID */ if (have_uuid) { - uuid_ptr = uuid_dashes; - p = config_file; - while (*uuid_ptr) { - int len = *uuid_ptr; - char *src = uuid; - - lchexbytes(p, src, len); - p += len * 2; - src += len; - uuid_ptr++; - *p++ = '-'; - } - /* Remove last dash and zero-terminate */ - *--p = '\0'; + strcpy(config_file, UUID_str); if (try_load(ConfigName)) return 0; } @@ -1107,7 +1091,7 @@ static int pxe_load_config(void) return 0; /* Nope, try hexadecimal IP prefixes... */ - uchexbytes(config_file, (uint8_t *)&MyIP, 4); /* Convet to hex string */ + uchexbytes(config_file, (uint8_t *)&IPInfo.myip, 4); last = &config_file[8]; while (tries) { *last = '\0'; /* Zero-terminate string */ @@ -1127,7 +1111,7 @@ static int pxe_load_config(void) } /* - * Generate the botif string, and the hardware-based config string + * Generate the bootif string. */ static void make_bootif_string(void) { @@ -1140,6 +1124,35 @@ static void make_bootif_string(void) for (i = MAC_len; i; i--) dst += sprintf(dst, "-%02x", *src++); } +/* + * Generate the SYSUUID string, if we have one... + */ +static void make_sysuuid_string(void) +{ + static const uint8_t uuid_dashes[] = {4, 2, 2, 2, 6, 0}; + const uint8_t *src = uuid; + const uint8_t *uuid_ptr = uuid_dashes; + char *dst; + + SYSUUIDStr[0] = '\0'; /* If nothing there... */ + + /* Try loading by UUID */ + if (have_uuid) { + dst = stpcpy(SYSUUIDStr, "SYSUUID="); + + while (*uuid_ptr) { + int len = *uuid_ptr; + + lchexbytes(dst, src, len); + dst += len * 2; + src += len; + uuid_ptr++; + *dst++ = '-'; + } + /* Remove last dash and zero-terminate */ + *--dst = '\0'; + } +} /* * Generate an ip=<client-ip>:<boot-server-ip>:<gw-ip>:<netmask> @@ -1151,33 +1164,46 @@ char __bss16 IPOption[3+4*16]; static void genipopt(void) { char *p = IPOption; + const uint32_t *v = &IPInfo.myip; + int i; p = stpcpy(p, "ip="); - p += gendotquad(p, MyIP); - *p++ = ':'; - - p += gendotquad(p, server_ip); - *p++ = ':'; - - p += gendotquad(p, gate_way); - *p++ = ':'; - - gendotquad(p, net_mask); + for (i = 0; i < 4; i++) { + p += gendotquad(p, *v++); + *p++ = ':'; + } + *--p = '\0'; } /* Generate ip= option and print the ip adress */ static void ip_init(void) { - uint32_t ip = MyIP; + uint32_t ip = IPInfo.myip; genipopt(); gendotquad(dot_quad_buf, ip); ip = ntohl(ip); printf("My IP address seems to be %08X %s\n", ip, dot_quad_buf); - printf("%s\n", IPOption); +} + +/* + * Print the IPAPPEND strings, in order + */ +extern const uint16_t IPAppends[]; +extern const char numIPAppends[]; + +static void print_ipappend(void) +{ + size_t i; + + for (i = 0; i < (size_t)numIPAppends; i++) { + const char *p = (const char *)(size_t)IPAppends[i]; + if (*p) + printf("%s\n", p); + } } /* @@ -1412,7 +1438,7 @@ static void udp_init(void) { int err; static __lowmem struct s_PXENV_UDP_OPEN udp_open; - udp_open.src_ip = MyIP; + udp_open.src_ip = IPInfo.myip; err = pxe_call(PXENV_UDP_OPEN, &udp_open); if (err || udp_open.status) { printf("Failed to initialize UDP stack "); @@ -1473,7 +1499,9 @@ static void network_init(void) printf("\n"); make_bootif_string(); + make_sysuuid_string(); ip_init(); + print_ipappend(); /* * Check to see if we got any PXELINUX-specific DHCP options; in particular, @@ -1627,12 +1655,17 @@ void unload_pxe(void) PXENV_UNDI_SHUTDOWN, PXENV_UNLOAD_STACK, PXENV_UNDI_CLEANUP, 0 }; - uint8_t api; + unsigned int api; const uint8_t *api_ptr; - uint16_t flag = 0; int err; size_t int_addr; - static __lowmem struct s_PXENV_UNLOAD_STACK unload_stack; + static __lowmem union { + struct s_PXENV_UNDI_SHUTDOWN undi_shutdown; + struct s_PXENV_UNLOAD_STACK unload_stack; + struct s_PXENV_STOP_UNDI stop_undi; + struct s_PXENV_UNDI_CLEANUP undi_cleanup; + uint16_t Status; /* All calls have this as the first member */ + } unload_call; dprintf("FBM before unload = %d\n", BIOS_fbm); @@ -1644,22 +1677,25 @@ void unload_pxe(void) if (KeepPXE || err) return; - api_ptr = major_ver(APIVer) >= 2 ? new_api_unload : old_api_unload; + dprintf("APIVer = %04x\n", APIVer); + + api_ptr = APIVer >= 0x0200 ? new_api_unload : old_api_unload; while((api = *api_ptr++)) { - memset(&unload_stack, 0, sizeof unload_stack); - err = pxe_call(api, &unload_stack); - if (err || unload_stack.Status != PXENV_STATUS_SUCCESS) { + dprintf("PXE call %04x\n", api); + memset(&unload_call, 0, sizeof unload_call); + err = pxe_call(api, &unload_call); + if (err || unload_call.Status != PXENV_STATUS_SUCCESS) { dprintf("PXE unload API call %04x failed\n", api); goto cant_free; } } - flag = 0xff00; - if (real_base_mem <= BIOS_fbm) { /* Santiy check */ + api = 0xff00; + if (real_base_mem <= BIOS_fbm) { /* Sanity check */ dprintf("FBM %d < real_base_mem %d\n", BIOS_fbm, real_base_mem); goto cant_free; } - flag++; + api++; /* Check that PXE actually unhooked the INT 0x1A chain */ int_addr = (size_t)GET_PTR(*(far_ptr_t *)(4 * 0x1a)); @@ -1670,13 +1706,14 @@ void unload_pxe(void) return; } - dprintf("Can't free FBM, real_base_mem = %d, FBM = %d, INT 1A = %08x (%d)\n", - real_base_mem, BIOS_fbm, *(uint32_t *)(4 * 0x1a), int_addr); + dprintf("Can't free FBM, real_base_mem = %d, " + "FBM = %d, INT 1A = %08x (%d)\n", + real_base_mem, BIOS_fbm, + *(uint32_t *)(4 * 0x1a), int_addr); cant_free: - - printf("Failed to free base memory error %04x-%08x\n", - flag, *(uint32_t *)(4 * 0x1a)); + printf("Failed to free base memory error %04x-%08x (%d/%dK)\n", + api, *(uint32_t *)(4 * 0x1a), BIOS_fbm, real_base_mem); return; } diff --git a/core/fs/pxe/pxe.h b/core/fs/pxe/pxe.h index e801aea5..1e6fa76a 100644 --- a/core/fs/pxe/pxe.h +++ b/core/fs/pxe/pxe.h @@ -32,7 +32,6 @@ #define PKTBUF_SIZE 2048 /* */ #define is_digit(c) (((c) >= '0') && ((c) <= '9')) -#define major_ver(v) (((v) >> 8) && 0xff) static inline bool is_hex(char c) { @@ -170,13 +169,20 @@ struct pxe_pvt_inode { #define PVT(i) ((struct pxe_pvt_inode *)((i)->pvt)) /* + * Network boot information + */ +struct ip_info { + uint32_t ipv4; + uint32_t myip; + uint32_t serverip; + uint32_t gateway; + uint32_t netmask; +}; + +/* * Variable externs */ -extern uint32_t server_ip; -extern uint32_t MyIP; -extern uint32_t net_mask; -extern uint32_t gate_way; -extern uint16_t server_port; +extern struct ip_info IPInfo; extern uint8_t MAC[]; extern char BOOTIFStr[]; @@ -195,7 +201,6 @@ extern char dot_quad_buf[]; extern uint32_t dns_server[]; -extern uint16_t real_base_mem; extern uint16_t APIVer; extern far_ptr_t PXEEntry; extern uint8_t KeepPXE; @@ -204,18 +209,29 @@ extern far_ptr_t InitStack; extern bool have_uuid; extern uint8_t uuid_type; -extern char uuid[]; +extern uint8_t uuid[]; extern uint16_t BIOS_fbm; extern const uint8_t TimeoutTable[]; +/* + * Compute the suitable gateway for a specific route -- too many + * vendor PXE stacks don't do this correctly... + */ +static inline uint32_t gateway(uint32_t ip) +{ + if ((ip ^ IPInfo.myip) & IPInfo.netmask) + return IPInfo.gateway; + else + return 0; +} /* * functions */ /* pxe.c */ -int ip_ok(uint32_t); +bool ip_ok(uint32_t); int pxe_call(int, void *); /* dhcp_options.c */ diff --git a/core/fs/readdir.c b/core/fs/readdir.c index d20fc33b..d071affd 100644 --- a/core/fs/readdir.c +++ b/core/fs/readdir.c @@ -10,13 +10,20 @@ DIR *opendir(const char *path) { int rv; + struct file *file; rv = searchdir(path); if (rv < 0) return NULL; - /* XXX: check for a directory handle here */ - return (DIR *)handle_to_file(rv); + file = handle_to_file(rv); + + if (file->inode->mode != DT_DIR) { + _close_file(file); + return NULL; + } + + return (DIR *)file; } /* diff --git a/core/include/fs.h b/core/include/fs.h index f1d35bbb..da247a98 100644 --- a/core/include/fs.h +++ b/core/include/fs.h @@ -94,6 +94,7 @@ struct extent { */ struct inode { struct fs_info *fs; /* The filesystem this inode is associated with */ + struct inode *parent; /* Parent directory, if any */ int refcnt; int mode; /* FILE , DIR or SYMLINK */ uint32_t size; @@ -157,11 +158,8 @@ static inline struct inode *get_inode(struct inode *inode) inode->refcnt++; return inode; } -static inline void put_inode(struct inode *inode) -{ - if (! --inode->refcnt) - free(inode); -} + +void put_inode(struct inode *inode); static inline void malloc_error(char *obj) { @@ -204,6 +202,9 @@ DIR *opendir(const char *pathname); struct dirent *readdir(DIR *dir); int closedir(DIR *dir); +/* getcwd.c */ +char *getcwd(char *buf, size_t size); + /* * Generic functions that filesystem drivers may choose to use */ @@ -212,6 +213,7 @@ int closedir(DIR *dir); void generic_mangle_name(char *, const char *); /* loadconfig.c */ +int search_config(const char *search_directores[], const char *filenames[]); int generic_load_config(void); /* close.c */ diff --git a/core/pxelinux.asm b/core/pxelinux.asm index 0b87e735..8084ac9a 100644 --- a/core/pxelinux.asm +++ b/core/pxelinux.asm @@ -530,7 +530,15 @@ exten_table_end: KeepPXE db 0 ; Should PXE be kept around? ; -; IP information (initialized to "unknown" values) - alignz 4 - global MyIP -MyIP dd 0 ; My IP address +; IP information. Note that the field are in the same order as the +; Linux kernel expects in the ip= option. +; + section .bss16 + alignb 4 + global IPInfo +IPInfo: +.IPv4 resd 1 ; IPv4 information +.MyIP resd 1 ; My IP address +.ServerIP resd 1 +.GatewayIP resd 1 +.Netmask resd 1 |