diff options
author | H. Peter Anvin <hpa@zytor.com> | 2010-01-06 18:40:52 -0800 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-01-06 18:40:52 -0800 |
commit | 44bad3a849a5f30186365eecf69722133775cee8 (patch) | |
tree | b68d2fbff69d386159b95bdbde99da2475ea1fc0 | |
parent | 8739796206f1a69880ed3a223f3a108e050292f8 (diff) | |
download | syslinux-44bad3a849a5f30186365eecf69722133775cee8.tar.gz syslinux-44bad3a849a5f30186365eecf69722133775cee8.tar.xz syslinux-44bad3a849a5f30186365eecf69722133775cee8.zip |
core: initial work on path-based cwd selection
Work on picking the initial cwd by storing a path instead of by
storing an inode number. This should be both more general (in the
sense of supporting filesystems in a generic way) as well as
conceptually cleaner. The code doesn't work yet, but this at least
provides support for the extlinux installer to store its subpath into
the installed image.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-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 + |