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 /extlinux/main.c | |
parent | 8739796206f1a69880ed3a223f3a108e050292f8 (diff) | |
download | syslinux-44bad3a849a5f30186365eecf69722133775cee8.tar.gz |
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>
Diffstat (limited to 'extlinux/main.c')
-rw-r--r-- | extlinux/main.c | 54 |
1 files changed, 44 insertions, 10 deletions
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"); |