aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/comboot.inc5
-rw-r--r--core/diskstart.inc19
-rw-r--r--core/fs/ext2/ext2.c6
-rw-r--r--extlinux/main.c54
-rw-r--r--libinstaller/syslxint.h3
-rw-r--r--libinstaller/syslxmod.c1
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 +