[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] biosdisk, getroot for Cygwin
From: |
Christian Franke |
Subject: |
Re: [PATCH] biosdisk, getroot for Cygwin |
Date: |
Wed, 07 May 2008 22:42:23 +0200 |
User-agent: |
Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071128 SeaMonkey/1.1.7 |
Updated version of the patch. It adds the functionality necessary for
grub-probe on Cygwin.
It also fixes 2 bugs in strip_extra_slashes() and __GNU__ get_os_disk()
Christian
2008-05-07 Christian Franke <address@hidden>
* util/biosdisk.c: [__CYGWIN__] Add includes.
(grub_util_biosdisk_open): Use Linux code also for Cygwin.
(get_os_disk): Move variable declarations to OS specific
parts to avoid warning.
[__GNU__] (get_os_disk): Fix /dev/sdXsN case.
[__CYGWIN__] (get_os_disk): Add Cygwin /dev/sdXN device names.
(grub_util_biosdisk_get_grub_dev): Use Linux code also for
Cygwin.
* util/getroot.c: [__CYGWIN__] Add includes.
(strip_extra_slashes): Fix "/" case.
[__CYGWIN__] (get_win32_path): New function.
[__CYGWIN__] (grub_get_prefix): Add conversion to win32 path.
[__CYGWIN__] (find_root_device): Disable.
[__CYGWIN__] (get_bootsec_serial): New function.
[__CYGWIN__] (find_cygwin_root_device): Likewise.
[__CYGWIN__] (grub_util_get_grub_dev): Disable /dev/mapper check.
diff --git a/util/biosdisk.c b/util/biosdisk.c
index e6e7f51..1b164a9 100644
--- a/util/biosdisk.c
+++ b/util/biosdisk.c
@@ -77,6 +77,14 @@ struct hd_geometry
# endif /* ! LOOP_MAJOR */
#endif /* __linux__ */
+#ifdef __CYGWIN__
+# include <sys/ioctl.h>
+# include <cygwin/fs.h> /* BLKGETSIZE64 */
+# include <cygwin/hdreg.h> /* HDIO_GETGEO */
+# define MAJOR(dev) ((unsigned) ((dev) >> 16))
+# define FLOPPY_MAJOR 2
+#endif
+
static char *map[256];
#ifdef __linux__
@@ -162,7 +170,7 @@ grub_util_biosdisk_open (const char *name, grub_disk_t disk)
disk->id = drive;
/* Get the size. */
-#ifdef __linux__
+#if defined(__linux__) || defined(__CYGWIN__)
{
unsigned long long nr;
int fd;
@@ -603,16 +611,14 @@ make_device_name (int drive, int dos_part, int bsd_part)
static char *
get_os_disk (const char *os_dev)
{
- char *path, *p;
-
#if defined(__linux__)
- path = xmalloc (PATH_MAX);
+ char *path = xmalloc (PATH_MAX);
if (! realpath (os_dev, path))
return 0;
if (strncmp ("/dev/", path, 5) == 0)
{
- p = path + 5;
+ char *p = path + 5;
/* If this is an IDE disk. */
if (strncmp ("ide/", p, 4) == 0)
@@ -659,15 +665,21 @@ get_os_disk (const char *os_dev)
return path;
#elif defined(__GNU__)
- path = xstrdup (os_dev);
+ char *path = xstrdup (os_dev);
if (strncmp ("/dev/sd", path, 7) == 0 || strncmp ("/dev/hd", path, 7) == 0)
{
- p = strchr (path, 's');
+ char *p = strchr (path + 7, 's');
if (p)
*p = '\0';
}
return path;
+#elif defined(__CYGWIN__)
+ char *path = xstrdup (os_dev);
+ if (strncmp ("/dev/sd", path, 7) == 0 && 'a' <= path[7] && path[7] <= 'z')
+ path[8] = 0;
+ return path;
+
#else
# warning "The function `get_os_disk' might not work on your OS correctly."
return xstrdup (os_dev);
@@ -718,11 +730,15 @@ grub_util_biosdisk_get_grub_dev (const char *os_dev)
if (! S_ISBLK (st.st_mode))
return make_device_name (drive, -1, -1);
-#if defined(__linux__)
+#if defined(__linux__) || defined(__CYGWIN__)
/* Linux counts partitions uniformly, whether a BSD partition or a DOS
partition, so mapping them to GRUB devices is not trivial.
Here, get the start sector of a partition by HDIO_GETGEO, and
- compare it with each partition GRUB recognizes. */
+ compare it with each partition GRUB recognizes.
+
+ Cygwin /dev/sdXN emulation uses Windows partition mapping. It
+ does not count the extended partition and missing primary
+ partitions. Use same method as on Linux here. */
{
char *name;
grub_disk_t disk;
diff --git a/util/getroot.c b/util/getroot.c
index 5a98218..e74ef78 100644
--- a/util/getroot.c
+++ b/util/getroot.c
@@ -22,6 +22,13 @@
#include <string.h>
#include <dirent.h>
+#ifdef __CYGWIN__
+# include <sys/fcntl.h>
+# include <sys/cygwin.h>
+# include <limits.h>
+# define DEV_CYGDRIVE_MAJOR 98
+#endif
+
#include <grub/util/misc.h>
#include <grub/util/biosdisk.h>
#include <grub/util/getroot.h>
@@ -40,7 +47,8 @@ strip_extra_slashes (char *dir)
}
else if (p[1] == '\0')
{
- p[0] = '\0';
+ if (p > dir)
+ p[0] = '\0';
break;
}
@@ -64,6 +72,30 @@ xgetcwd (void)
return path;
}
+#ifdef __CYGWIN__
+/* Convert POSIX path to Win32 path,
+ remove drive letter, replace backslashes. */
+static char *
+get_win32_path (const char *path)
+{
+ char winpath[PATH_MAX];
+ cygwin_conv_to_full_win32_path (path, winpath);
+
+ int len = strlen (winpath);
+ if (len > 2 && winpath[1] == ':')
+ {
+ len -= 2;
+ memmove (winpath, winpath + 2, len + 1);
+ }
+
+ int i;
+ for (i = 0; i < len; i++)
+ if (winpath[i] == '\\')
+ winpath[i] = '/';
+ return xstrdup (winpath);
+}
+#endif
+
char *
grub_get_prefix (const char *dir)
{
@@ -116,6 +148,19 @@ grub_get_prefix (const char *dir)
if (chdir (saved_cwd) < 0)
grub_util_error ("Cannot change directory to `%s'", dir);
+#ifdef __CYGWIN__
+ if (st.st_dev != (DEV_CYGDRIVE_MAJOR << 16))
+ {
+ /* Reached some mount point not below /cygdrive.
+ GRUB does not know Cygwin's emulated mounts,
+ convert to Win32 path. */
+ grub_util_info ("Cygwin prefix = %s", prefix);
+ char * wprefix = get_win32_path (prefix);
+ free (prefix);
+ prefix = wprefix;
+ }
+#endif
+
free (saved_cwd);
free (abs_dir);
free (prev_dir);
@@ -124,6 +169,8 @@ grub_get_prefix (const char *dir)
return prefix;
}
+#ifndef __CYGWIN__
+
static char *
find_root_device (const char *dir, dev_t dev)
{
@@ -216,6 +263,89 @@ find_root_device (const char *dir, dev_t dev)
return 0;
}
+#else /* __CYGWIN__ */
+
+/* Read drive/partition serial number from mbr/boot sector,
+ return 0 on read error, ~0 on unknown serial. */
+static unsigned
+get_bootsec_serial (const char *os_dev, int mbr)
+{
+ /* Read boot sector. */
+ int fd = open (os_dev, O_RDONLY);
+ if (fd < 0)
+ return 0;
+ unsigned char buf[0x200];
+ int n = read (fd, buf, sizeof (buf));
+ close (fd);
+ if (n != sizeof(buf))
+ return 0;
+
+ /* Check signature. */
+ if (!(buf[0x1fe] == 0x55 && buf[0x1ff] == 0xaa))
+ return ~0;
+
+ /* Serial number offset depends on boot sector type. */
+ if (mbr)
+ n = 0x1b8;
+ else if (memcmp (buf + 0x03, "NTFS", 4) == 0)
+ n = 0x048;
+ else if (memcmp (buf + 0x52, "FAT32", 5) == 0)
+ n = 0x043;
+ else if (memcmp (buf + 0x36, "FAT", 3) == 0)
+ n = 0x027;
+ else
+ return ~0;
+ unsigned serial = *(unsigned *)(buf + n);
+ if (serial == 0)
+ return ~0;
+ return serial;
+}
+
+static char *
+find_cygwin_root_device (const char *path, dev_t dev)
+{
+ /* No root device for /cygdrive. */
+ if (dev == (DEV_CYGDRIVE_MAJOR << 16))
+ return 0;
+
+ /* Convert to full POSIX and Win32 path. */
+ char fullpath[PATH_MAX], winpath[PATH_MAX];
+ cygwin_conv_to_full_posix_path (path, fullpath);
+ cygwin_conv_to_full_win32_path (fullpath, winpath);
+
+ /* If identical, this is no real filesystem path. */
+ if (strcmp (fullpath, winpath) == 0)
+ return 0;
+
+ /* Check for floppy drive letter. */
+ if (winpath[0] && winpath[1] == ':' && strchr ("AaBb", winpath[0]))
+ return xstrdup (strchr ("Aa", winpath[0]) ? "/dev/fd0" : "/dev/fd1");
+
+ /* Cygwin returns the partition serial number in stat.st_dev.
+ This is never identical to the device number of the emulated
+ /dev/sdXN device, so above find_root_device () does not work.
+ Search the partion with the same serial in boot sector instead. */
+ char devpath[sizeof ("/dev/sda15") + 13];
+ int d;
+ for (d = 'a'; d <= 'z'; d++) {
+ sprintf (devpath, "/dev/sd%c", d);
+ if (get_bootsec_serial (devpath, 1) == 0)
+ continue;
+ int p;
+ for (p = 1; p <= 15; p++) {
+ sprintf (devpath, "/dev/sd%c%d", d, p);
+ unsigned ser = get_bootsec_serial (devpath, 0);
+ if (ser == 0)
+ break;
+ if (ser != (unsigned)~0 && dev == (dev_t)ser)
+ return xstrdup (devpath);
+ }
+ }
+ return 0;
+}
+
+#endif /* __CYGWIN__ */
+
char *
grub_guess_root_device (const char *dir)
{
@@ -225,6 +355,7 @@ grub_guess_root_device (const char *dir)
if (stat (dir, &st) < 0)
grub_util_error ("Cannot stat `%s'", dir);
+#ifndef __CYGWIN__
#ifdef __linux__
/* We first try to find the device in the /dev/mapper directory. If
we don't do this, we get useless device names like /dev/dm-0 for
@@ -242,12 +373,19 @@ grub_guess_root_device (const char *dir)
os_dev = find_root_device ("/dev", st.st_dev);
}
+#else
+ /* Cygwin specific function. */
+ os_dev = find_cygwin_root_device (dir, st.st_dev);
+
+#endif /* __CYGWIN__ */
+
return os_dev;
}
int
grub_util_get_dev_abstraction (const char *os_dev)
{
+#ifndef __CYGWIN__
/* Check for LVM. */
if (!strncmp (os_dev, "/dev/mapper/", 12))
return GRUB_DEV_ABSTRACTION_LVM;
@@ -255,6 +393,7 @@ grub_util_get_dev_abstraction (const char *os_dev)
/* Check for RAID. */
if (!strncmp (os_dev, "/dev/md", 7))
return GRUB_DEV_ABSTRACTION_RAID;
+#endif /* !__CYGWIN__ */
/* No abstraction found. */
return GRUB_DEV_ABSTRACTION_NONE;
- Re: [PATCH] biosdisk, getroot for Cygwin,
Christian Franke <=
- Re: [PATCH] biosdisk, getroot for Cygwin, Robert Millan, 2008/05/09
- Re: [PATCH] biosdisk, getroot for Cygwin, Christian Franke, 2008/05/09
- Re: [PATCH] biosdisk, getroot for Cygwin, Christian Franke, 2008/05/11
- Re: [PATCH] biosdisk, getroot for Cygwin, Robert Millan, 2008/05/12
- Re: [PATCH] biosdisk, getroot for Cygwin, Christian Franke, 2008/05/13
- Re: [PATCH] biosdisk, getroot for Cygwin, Christian Franke, 2008/05/16