2009-08-28 Felix Zielcke * conf/common.rmk (bin_UTILITIES): Add grub-mkrelpath. (grub_mkrelpath_SOURCES): New variable. * configure.ac (AC_CHECK_FUNCS): Add realpath. * util/grub-mkconfig_lib.in (make_system_path_relative_to_its_root): Use grub-mkrelpath. * util/grub-mkrelpath.c: New file. diff --git a/conf/common.rmk b/conf/common.rmk index 6d76746..9a2dc4c 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -55,6 +55,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/sh/parser.y $(YACC) -d -p grub_script_yy -b grub_script $(srcdir)/script/sh/parser.y diff --git a/configure.ac b/configure.ac index 549b35c..ee5ebb1 100644 --- a/configure.ac +++ b/configure.ac @@ -172,7 +172,7 @@ if test x$grub_cv_apple_cc = xyes ; then fi # Check for functions. -AC_CHECK_FUNCS(posix_memalign memalign asprintf) +AC_CHECK_FUNCS(posix_memalign memalign asprintf realpath) # # Check for target programs. diff --git a/util/grub-mkconfig_lib.in b/util/grub-mkconfig_lib.in index 2385b08..c8d2736 100644 --- a/util/grub-mkconfig_lib.in +++ b/util/grub-mkconfig_lib.in @@ -32,49 +32,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 index e69de29..7c9c678 100644 --- a/util/grub-mkrelpath.c +++ b/util/grub-mkrelpath.c @@ -0,0 +1,194 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct option options[] = + { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + }; + +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; + +#ifdef HAVE_REALPATH + p = realpath (path, NULL); + + if (buf == 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 = xmalloc (len); + buf2 = xmalloc (len); + strcpy (buf, p); + free (p); +#else /* ! HAVE_REALPATH */ + grub_util_warn ("grub-mkrelpath might not work on your OS correctly."); + if (*path != '/') + { + len = 1024; + buf = xmalloc (len); + do + { + p = getcwd (buf, len); + if (p == NULL) + { + if (errno != ERANGE) + grub_util_error ("can not get current working directory"); + else + len *= 2; + buf = xrealloc (buf, len); + } + } while (p == NULL); + buf = xmalloc (strlen (path) + len + 1); + strcat (buf, "/"); + strcat (buf, path); + } + else + { + buf = xmalloc (strlen (path) + 1); + strcpy (buf, path); + } +#endif /* ! HAVE_REALPATH */ + buf2 = xmalloc (strlen (buf) + 1); + strcpy (buf2, buf); + if (stat (buf, &st) < 0) + grub_util_error ("can not stat %s", p); + + num = st.st_dev; + while (1) + { + p = strrchr (buf, '/'); + if (p == NULL) + grub_util_error ("FIXME no / in buf"); + if (p != buf) + *p = 0; + else + *++p = 0; + + if (stat (buf, &st) < 0) + grub_util_error ("can not stat %s", buf); + + if (st.st_dev != num) + break; + + offset = p - buf; + if (offset == 1) + { + free (buf); + return buf2; + } + } + free (buf); + buf3 = strdup (buf2 + offset); + free (buf2); + return buf3; +} + +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; +}