2009-06-11 Felix Zielcke * configure.ac (AC_CHECK_FUNCS): Add realpath. * include/grub/util/hostdisk.c (grub_make_system_path_relative_to_its_root): New function prototype. * util/hostdisk.c: Include . (grub_make_system_path_relative_to_its_root): New function. * util/i386/pc/grub-setup.c (setup): Use grub_make_system_path_relative_to_its_root to make core_path_dev relative to the partition. diff --git a/configure.ac b/configure.ac index e448c2f..9e923a6 100644 --- a/configure.ac +++ b/configure.ac @@ -205,7 +205,7 @@ if test "$target_cpu"-"$platform" = i386-pc; 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/include/grub/util/hostdisk.h b/include/grub/util/hostdisk.h index 21efb0d..a1ecf59 100644 --- a/include/grub/util/hostdisk.h +++ b/include/grub/util/hostdisk.h @@ -23,5 +23,6 @@ void grub_util_biosdisk_init (const char *dev_map); void grub_util_biosdisk_fini (void); char *grub_util_biosdisk_get_grub_dev (const char *os_dev); +char *grub_make_system_path_relative_to_its_root (char *path) #endif /* ! GRUB_BIOSDISK_MACHINE_UTIL_HEADER */ diff --git a/util/hostdisk.c b/util/hostdisk.c index a7262dd..bce1b95 100644 --- a/util/hostdisk.c +++ b/util/hostdisk.c @@ -27,6 +27,7 @@ #include #include +#include #include #include #include @@ -1076,3 +1077,94 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev) return make_device_name (drive, -1, -1); #endif } + +char * +grub_make_system_path_relative_to_its_root (char *path) +{ + struct stat st; + char *buf, *buf2; + uintptr_t offset = 0; + dev_t num; + long path_max; +#ifdef HAVE_REALPATH + char *p; +#endif + + +#ifdef HAVE_REALPATH +# ifdef PATH_MAX + path_max = PATH_MAX +# else + path_max = pathconf (path, _PC_PATH_MAX); + if (path_max <= 0) + /* 1024 is taken from glibc-2.10. */ + path_max = 1024; +# endif + p = xmalloc (path_max); + p = realpath (path, p); + if (p == NULL) + grub_util_error ("failed to get realpath of %s", path); + +#ifdef __CYGWIN__ + if (strncmp (p,"/cygdrive/") == 0) + { + p += sizeof "/cygdrive/c" - 1; + } + else + grub_util_error "path not under /cygdrive/ aborting."; +#endif + buf = xmalloc (path_max); + buf2 = xmalloc (path_max); + strcpy (buf, p); + free (p); +#else /* ! HAVE_REALPATH */ +# warning "The function `grub_make_system_path_relative_to_its_root' might not work on your OS correctly." + path_max = 1024; + buf = xmalloc (path_max); + buf2 = xmalloc (path_max); + memset (buf, 0, sizeof (buf)); + if (*path != '/') + { + size_t len = strlen (path); + + if (getcwd (buf, 1024 - len) == NULL) + grub_util_error ("can not get current working directory"); + + strcat (buf, "/"); + strcat (buf, path); + } + else + { + if (strlen (path) > 1024) + grub_util_error ("path too long"); + strncpy (buf, path, 1024); + } +#endif /* ! HAVE_REALPATH */ + + 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 p"); + 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) + return buf2; + } + return buf2 + offset; +} diff --git a/util/i386/pc/grub-setup.c b/util/i386/pc/grub-setup.c index 997811b..7fb0273 100644 --- a/util/i386/pc/grub-setup.c +++ b/util/i386/pc/grub-setup.c @@ -89,7 +89,7 @@ setup (const char *dir, const char *root, const char *dest, int must_embed, int force) { char *boot_path, *core_path, *core_path_dev; - char *boot_img, *core_img; + char *boot_img, *core_img, *p; size_t boot_size, core_size; grub_uint16_t core_sectors; grub_device_t root_dev, dest_dev; @@ -404,7 +404,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); + p = grub_util_get_path (dir, core_file); + core_path_dev = grub_make_system_path_relative_to_its_root (p); + free (p); /* It is a Good Thing to sync two times. */ sync ();