diff --git a/ChangeLog b/ChangeLog index 186ce7184..59e14a0c0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,22 @@ +2009-11-24 Felix Zielcke + + * util/grub-mkrelpath.c: New file. + * conf/common.rmk (bin_UTILITIES): Add grub-mkrelpath. + (grub_mkrelpath_SOURCES): New variable. + * include/grub/util/misc.h: New function prototype. + * util/misc.c (make_system_path_relative_to_its_root): New function. + + * util/grub-mkconfig_lib.in (bindir): New variable. + (grub_mkrelpath): Likewise. + (make_system_path_relative_to_its_root): Use grub-mkrelpath. + + * util/probe.c (probe): Make the file path relative to its root. + Change a info message to use the GRUB path. Enable again the + check if we can read the file with GRUB facilities. + + * util/i386/pc/grub-setup.c (setup): Make core.img path relative + to its root. + 2009-11-24 Felix Zielcke * Makefile.in: Don't include GRUB_CONTRIB makefiles with emu diff --git a/conf/common.rmk b/conf/common.rmk index 532a72f67..216098b51 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -71,6 +71,10 @@ grub_mkfont_CFLAGS = $(freetype_cflags) grub_mkfont_LDFLAGS = $(freetype_libs) endif +# For grub-mkrelpath. +bin_UTILITIES += grub-mkrelpath +grub_mkrelpath_SOURCES = util/grub-mkrelpath.c util/misc.c + # For the parser. grub_script.tab.c grub_script.tab.h: script/parser.y $(YACC) -d -p grub_script_yy -b grub_script $(srcdir)/script/parser.y diff --git a/include/grub/util/misc.h b/include/grub/util/misc.h index 6a93ab044..d0184d416 100644 --- a/include/grub/util/misc.h +++ b/include/grub/util/misc.h @@ -1,6 +1,6 @@ /* * GRUB -- GRand Unified Bootloader - * Copyright (C) 2002,2003,2005,2006,2007,2008 Free Software Foundation, Inc. + * Copyright (C) 2002,2003,2005,2006,2007,2008,2009 Free Software Foundation, Inc. * * GRUB is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -76,4 +76,7 @@ grub_int64_t grub_util_get_disk_size (char *name); #endif + +char *make_system_path_relative_to_its_root (const char *path); + #endif /* ! GRUB_UTIL_MISC_HEADER */ diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in index bb30cc475..5b5dfd42a 100644 --- a/util/grub-mkconfig_lib.in +++ b/util/grub-mkconfig_lib.in @@ -20,10 +20,12 @@ prefix=@prefix@ exec_prefix=@exec_prefix@ datarootdir=@datarootdir@ datadir=@datadir@ +bindir=@bindir@ sbindir=@sbindir@ pkgdatadir=${datadir}/`echo @PACKAGE_TARNAME@ | sed "${transform}"` grub_probe=${sbindir}/`echo grub-probe | sed ${transform}` +grub_mkrelpath=${bindir}/`echo grub-mkrelpath | sed ${transform}` grub_warn () { @@ -32,49 +34,7 @@ grub_warn () make_system_path_relative_to_its_root () { - path=$1 - # abort if file doesn't exist - if test -e $path ; then : ;else - return 1 - fi - - # canonicalize - if path=`readlink -f $path` ; then : ; else - return 1 - fi - - # if not a directory, climb up to the directory containing it - if test -d $path ; then - dir=$path - else - dir=`echo $path | sed -e "s,/[^/]*$,,g"` - fi - - num=`stat -c %d $dir` - - # this loop sets $dir to the root directory of the filesystem we're inspecting - while : ; do - parent=`readlink -f $dir/..` - if [ "x`stat -c %d $parent`" = "x$num" ] ; then : ; else - # $parent is another filesystem; we found it. - break - fi - if [ "x$dir" = "x/" ] ; then - # / is our root. - break - fi - dir=$parent - done - - # This function never prints trailing slashes (so that its output can be - # appended a slash unconditionally). Each slash in $dir is considered a - # preceding slash, and therefore the root directory is an empty string. - if [ "$dir" = "/" ] ; then - dir="" - fi - - # XXX: This fails if $dir contains ','. - path=`echo "$path" | sed -e "s,^$dir,,g"` || return 1 + path="`${grub_mkrelpath} $1`" case "`uname 2>/dev/null`" in CYGWIN*) diff --git a/util/grub-mkrelpath.c b/util/grub-mkrelpath.c new file mode 100644 index 000000000..3deb4c412 --- /dev/null +++ b/util/grub-mkrelpath.c @@ -0,0 +1,99 @@ +/* grub-mkrelpath.c - make a system path relative to its root */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see . + */ + +#include +#include + +static struct option options[] = + { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + }; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try ``grub-mkrelpath --help'' for more information.\n"); + else + printf ("\ +Usage: grub-mkrelpath [OPTIONS] PATH\n\ +\n\ +Make a system path relative to it's root.\n\ +\n\ +Options:\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ +\n\ +Report bugs to <%s>.\n", PACKAGE_BUGREPORT); + + exit (status); +} + +int +main (int argc, char *argv[]) +{ + char *argument, *relpath; + + progname = "grub-mkrelpath"; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "hV", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + default: + usage (1); + break; + } + } + + if (optind >= argc) + { + fprintf (stderr, "No path is specified.\n"); + usage (1); + } + + if (optind + 1 != argc) + { + fprintf (stderr, "Unknown extra argument `%s'.\n", argv[optind + 1]); + usage (1); + } + + argument = argv[optind]; + + relpath = make_system_path_relative_to_its_root (argument); + printf ("%s\n", relpath); + free (relpath); + + return 0; +} diff --git a/util/grub-probe.c b/util/grub-probe.c index 4e3f96451..1594d0dcb 100644 --- a/util/grub-probe.c +++ b/util/grub-probe.c @@ -235,9 +235,6 @@ probe (const char *path, char *device_name) if (print == PRINT_FS) { - /* FIXME: `path' can't be used to read a file via GRUB facilities, - because it's not relative to its root. */ -#if 0 struct stat st; stat (path, &st); @@ -247,12 +244,17 @@ probe (const char *path, char *device_name) /* Regular file. Verify that we can read it properly. */ grub_file_t file; + char *rel_path; grub_util_info ("reading %s via OS facilities", path); filebuf_via_sys = grub_util_read_image (path); - grub_util_info ("reading %s via GRUB facilities", path); - asprintf (&grub_path, "(%s)%s", drive_name, path); + rel_path = make_system_path_relative_to_its_root (path); + asprintf (&grub_path, "(%s)%s", drive_name, rel_path); + free (rel_path); + grub_util_info ("reading %s via GRUB facilities", grub_path); file = grub_file_open (grub_path); + if (! file) + grub_util_error ("can not open %s via GRUB facilities", grub_path); filebuf_via_grub = xmalloc (file->size); grub_file_read (file, filebuf_via_grub, file->size); @@ -261,7 +263,6 @@ probe (const char *path, char *device_name) if (memcmp (filebuf_via_grub, filebuf_via_sys, file->size)) grub_util_error ("files differ"); } -#endif printf ("%s\n", fs->name); } diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index f20db1e9a..1c7e8452f 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -90,7 +90,7 @@ setup (const char *dir, const char *boot_file, const char *core_file, const char *root, const char *dest, int must_embed, int force, int fs_probe) { - char *boot_path, *core_path, *core_path_dev; + char *boot_path, *core_path, *core_path_dev, *core_path_dev_full; char *boot_img, *core_img; size_t boot_size, core_size; grub_uint16_t core_sectors; @@ -426,7 +426,9 @@ unable_to_embed: /* Make sure that GRUB reads the identical image as the OS. */ tmp_img = xmalloc (core_size); - core_path_dev = grub_util_get_path (dir, core_file); + core_path_dev_full = grub_util_get_path (dir, core_file); + core_path_dev = make_system_path_relative_to_its_root (core_path_dev_full); + free (core_path_dev_full); /* It is a Good Thing to sync two times. */ sync (); diff --git a/util/misc.c b/util/misc.c index 799ffbf85..765adf58b 100644 --- a/util/misc.c +++ b/util/misc.c @@ -18,10 +18,12 @@ #include +#include #include #include #include #include +#include #include #include #include @@ -447,3 +449,82 @@ fail: } #endif /* __MINGW32__ */ + +/* This function never prints trailing slashes (so that its output + can be appended a slash unconditionally). */ +char * +make_system_path_relative_to_its_root (const char *path) +{ + struct stat st; + char *p, *buf, *buf2, *buf3; + uintptr_t offset = 0; + dev_t num; + size_t len; + + /* canonicalize. */ + p = realpath (path, NULL); + + if (p == NULL) + { + if (errno != EINVAL) + grub_util_error ("failed to get realpath of %s", path); + else + grub_util_error ("realpath not supporting (path, NULL)"); + } + len = strlen (p) + 1; + buf = strdup (p); + free (p); + + if (stat (buf, &st) < 0) + grub_util_error ("can not stat %s: %s", buf, strerror (errno)); + + buf2 = strdup (buf); + num = st.st_dev; + + /* This loop sets offset to the number of chars of the root + directory we're inspecting. */ + while (1) + { + p = strrchr (buf, '/'); + if (p == NULL) + /* This should never happen. */ + grub_util_error ("FIXME: no / in buf. (make_system_path_relative_to_its_root)"); + if (p != buf) + *p = 0; + else + *++p = 0; + + if (stat (buf, &st) < 0) + grub_util_error ("can not stat %s: %s", buf, strerror (errno)); + + /* buf is another filesystem; we found it. */ + if (st.st_dev != num) + break; + + offset = p - buf; + /* offset == 1 means root directory. */ + if (offset == 1) + { + free (buf); + len = strlen (buf2); + while (buf2[len - 1] == '/' && len > 1) + { + buf2[len - 1] = '\0'; + len--; + } + return buf2; + } + } + free (buf); + buf3 = strdup (buf2 + offset); + free (buf2); + + len = strlen (buf3); + while (buf3[len - 1] == '/' && len > 1) + { + buf3[len - 1] = '\0'; + len--; + } + + return buf3; +}