core: initial work on path-based cwd selection
authorH. Peter Anvin <hpa@zytor.com>
Thu, 7 Jan 2010 02:40:52 +0000 (18:40 -0800)
committerH. Peter Anvin <hpa@zytor.com>
Thu, 7 Jan 2010 02:40:52 +0000 (18:40 -0800)
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>
core/comboot.inc
core/diskstart.inc
core/fs/ext2/ext2.c
extlinux/main.c
libinstaller/syslxint.h
libinstaller/syslxmod.c

index 2540959..03507c8 100644 (file)
@@ -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
index 8bb4f78..3bffc89 100644 (file)
@@ -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
index 9d4d9ec..a978677 100644 (file)
@@ -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);
 }
index 7eb59da..05b390f 100644 (file)
@@ -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");
index e2a8072..ba3e501 100644 (file)
@@ -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;
 };
index 9e1da44..4216037 100644 (file)
@@ -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 +