; -----------------------------------------------------------------------
;
; 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
; Start of LDLINUX.SYS
; ===========================================================================
+LDLINUX_SYS equ 0x7e00
ldlinux_sys:
syslinux_banner db 0Dh, 0Ah
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
*
* 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;
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);
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);
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);
}
/* 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! */
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");