diff options
-rw-r--r-- | core/comboot.inc | 5 | ||||
-rw-r--r-- | core/diskstart.inc | 19 | ||||
-rw-r--r-- | core/fs/ext2/ext2.c | 6 | ||||
-rw-r--r-- | extlinux/main.c | 54 | ||||
-rw-r--r-- | libinstaller/syslxint.h | 3 | ||||
-rw-r--r-- | libinstaller/syslxmod.c | 1 |
6 files changed, 68 insertions, 20 deletions
diff --git a/core/comboot.inc b/core/comboot.inc index 25409595..03507c89 100644 --- a/core/comboot.inc +++ b/core/comboot.inc @@ -1038,6 +1038,9 @@ err_comlarge db 'COMBOOT image too large.', CR, LF, 0 alignb 4 DOSErrTramp resd 33 ; Error trampolines - global ConfigName, CurrentDirName + global ConfigName ConfigName resb FILENAME_MAX +%ifndef HAVE_CURRENTDIRNAME + global CurrentDirName CurrentDirName resb FILENAME_MAX +%endif diff --git a/core/diskstart.inc b/core/diskstart.inc index 8bb4f78a..3bffc896 100644 --- a/core/diskstart.inc +++ b/core/diskstart.inc @@ -1,7 +1,7 @@ ; ----------------------------------------------------------------------- ; ; Copyright 1994-2009 H. Peter Anvin - All Rights Reserved -; Copyright 2009 Intel Corporation; author: H. Peter Anvin +; Copyright 2009-2010 Intel Corporation; author: H. Peter Anvin ; ; 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 @@ -471,6 +471,7 @@ bootsignature dw kaboom.again-bootsec ; Start of LDLINUX.SYS ; =========================================================================== +LDLINUX_SYS equ 0x7e00 ldlinux_sys: syslinux_banner db 0Dh, 0Ah @@ -491,11 +492,21 @@ ADVSectors dw 0 ; Additional sectors for ADVs LDLDwords dd 0 ; Total dwords starting at ldlinux_sys, CheckSum dd 0 ; Checksum starting at ldlinux_sys ; value = LDLINUX_MAGIC - [sum of dwords] - global CurrentDir -CurrentDir dd 2 ; "Current" directory inode number (EXTLINUX) -SecPtrOffset dw SectorPtrs - ldlinux_sys +CurrentDirPtr dw CurrentDirName-LDLINUX_SYS ; Current directory name string +CurrentDirLen dw FILENAME_MAX +SecPtrOffset dw SectorPtrs - LDLINUX_SYS SecPtrCnt dw (SectorPtrsEnd - SectorPtrs) >> 2 +; +; Installer pokes the base directory here, needs to be in .text16 so the pointer +; address can be calculated by the assembler. +; +%define HAVE_CURRENTDIRNAME + section .data16 + global CurrentDirName +CurrentDirName times FILENAME_MAX db 0 + + section .text16 ldlinux_ent: ; ; Note that some BIOSes are buggy and run the boot sector at 07C0:0000 diff --git a/core/fs/ext2/ext2.c b/core/fs/ext2/ext2.c index 9d4d9ec5..a978677a 100644 --- a/core/fs/ext2/ext2.c +++ b/core/fs/ext2/ext2.c @@ -294,14 +294,14 @@ static struct inode *ext2_iget_by_inr(uint32_t inr) return inode; } -static struct inode *ext2_iget_root() +static struct inode *ext2_iget_root(void) { return ext2_iget_by_inr(EXT2_ROOT_INO); } -static struct inode *ext2_iget_current() +static struct inode *ext2_iget_current(void) { - extern int CurrentDir; + static int CurrentDir = 2; return ext2_iget_by_inr(CurrentDir); } diff --git a/extlinux/main.c b/extlinux/main.c index 7eb59dae..05b390f3 100644 --- a/extlinux/main.c +++ b/extlinux/main.c @@ -354,9 +354,9 @@ int get_geometry(int devfd, uint64_t totalbytes, struct hd_geometry *geo) * * Returns the number of modified bytes in the boot file. */ -int patch_file_and_bootblock(int fd, int dirfd, int devfd) +int patch_file_and_bootblock(int fd, const char *dir, int devfd) { - struct stat dirst; + struct stat dirst, xdst; struct hd_geometry geo; uint32_t *sectp; uint64_t totalbytes, totalsectors; @@ -366,13 +366,38 @@ int patch_file_and_bootblock(int fd, int dirfd, int devfd) struct patch_area *patcharea; int i, dw, nptrs; uint32_t csum; - int secptroffset; + int secptroffset, diroffset, dirlen; + char *dirpath, *subpath; - if (fs_type == EXT2) - if (fstat(dirfd, &dirst)) { - perror("fstat dirfd"); - exit(255); /* This should never happen */ + dirpath = realpath(dir, NULL); + if (!dirpath || stat(dir, &dirst)) { + perror("accessing install directory"); + exit(255); /* This should never happen */ + } + + if (lstat(dirpath, &xdst) || + dirst.st_ino != xdst.st_ino || + dirst.st_dev != xdst.st_dev) { + perror("realpath returned nonsense"); + exit(255); + } + + subpath = strchr(dirpath, '\0'); + while (--subpath > dirpath) { + if (*subpath == '/') { + *subpath = '\0'; + if (lstat(dirpath, &xdst) || dirst.st_dev != xdst.st_dev) { + subpath = strchr(subpath+1, '/'); + if (!subpath) + subpath = "/"; /* It's the root of the filesystem */ + break; + } + *subpath = '/'; } + } + + /* Now subpath should contain the path relative to the fs base */ + dprintf("subpath = %s\n", subpath); totalbytes = get_size(devfd); get_geometry(devfd, totalbytes, &geo); @@ -443,7 +468,6 @@ int patch_file_and_bootblock(int fd, int dirfd, int devfd) set_16(&patcharea->data_sectors, nsect - 2); /* -2 for the ADVs */ set_16(&patcharea->adv_sectors, 2); set_32(&patcharea->dwords, dw); - set_32(&patcharea->currentdir, dirst.st_ino); /* Set the sector pointers */ secptroffset = get_16(&patcharea->secptroffset); @@ -454,6 +478,16 @@ int patch_file_and_bootblock(int fd, int dirfd, int devfd) while (nsect--) set_32(wp++, *sectp++); + /* Poke in the base directory path */ + diroffset = get_16(&patcharea->diroffset); + dirlen = get_16(&patcharea->dirlen); + if (dirlen <= strlen(subpath)) { + fprintf(stderr, "Subdirectory path too long... aborting install!\n"); + exit(1); + } + strncpy((char *)boot_image + diroffset, subpath, dirlen); + free(dirpath); + /* Now produce a checksum */ set_32(&patcharea->checksum, 0); @@ -729,7 +763,7 @@ int ext2_install_file(const char *path, int devfd, struct stat *rst) } /* Map the file, and patch the initial sector accordingly */ - modbytes = patch_file_and_bootblock(fd, dirfd, devfd); + modbytes = patch_file_and_bootblock(fd, path, devfd); /* Write the patch area again - this relies on the file being overwritten in place! */ @@ -771,7 +805,7 @@ bail: since the cow feature of btrfs will move the extlinux.sys every where */ int btrfs_install_file(const char *path, int devfd, struct stat *rst) { - patch_file_and_bootblock(-1, -1, devfd); + patch_file_and_bootblock(-1, path, devfd); if (xpwrite(devfd, boot_image, boot_image_len, BTRFS_EXTLINUX_OFFSET) != boot_image_len) { perror("writing bootblock"); diff --git a/libinstaller/syslxint.h b/libinstaller/syslxint.h index e2a80724..ba3e501e 100644 --- a/libinstaller/syslxint.h +++ b/libinstaller/syslxint.h @@ -87,7 +87,8 @@ struct patch_area { uint16_t adv_sectors; uint32_t dwords; uint32_t checksum; - uint32_t currentdir; + uint16_t diroffset; + uint16_t dirlen; uint16_t secptroffset; uint16_t secptrcnt; }; diff --git a/libinstaller/syslxmod.c b/libinstaller/syslxmod.c index 9e1da440..42160375 100644 --- a/libinstaller/syslxmod.c +++ b/libinstaller/syslxmod.c @@ -255,7 +255,6 @@ int syslinux_patch(const uint32_t * sectors, int nsectors, set_16_sl(&patcharea->data_sectors, nsect); /* Not including ADVs */ set_16_sl(&patcharea->adv_sectors, 0); /* ADVs not supported yet */ set_32_sl(&patcharea->dwords, dw); - set_32_sl(&patcharea->currentdir, 0); /* Set the sector pointers */ wp = (uint32_t *) ((char *)syslinux_ldlinux + |