* [PATCH] biosdisk, getroot for Cygwin
@ 2007-11-23 20:30 Christian Franke
2008-05-07 20:42 ` Christian Franke
0 siblings, 1 reply; 8+ messages in thread
From: Christian Franke @ 2007-11-23 20:30 UTC (permalink / raw)
To: grub-devel
[-- Attachment #1: Type: text/plain, Size: 986 bytes --]
This patch adds the functionality necessary for grub-probe on Cygwin.
It also fixes 2 bugs in strip_extra_slashes() and __GNU__ get_os_disk().
Christian
2007-11-23 Christian Franke <franke@computer.org>
* 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.
[-- Attachment #2: grub2-biosdisk-getroot.patch --]
[-- Type: text/x-patch, Size: 8036 bytes --]
diff -up grub2.orig/util/biosdisk.c grub2/util/biosdisk.c
--- grub2.orig/util/biosdisk.c 2007-07-22 01:32:31.000000000 +0200
+++ grub2/util/biosdisk.c 2007-11-23 21:00:12.812500000 +0100
@@ -76,6 +76,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__
@@ -161,7 +169,7 @@ grub_util_biosdisk_open (const char *nam
disk->id = drive;
/* Get the size. */
-#ifdef __linux__
+#if defined(__linux__) || defined(__CYGWIN__)
{
unsigned long long nr;
int fd;
@@ -595,16 +603,14 @@ make_device_name (int drive, int dos_par
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 (have_devfs ())
{
@@ -654,15 +660,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 = strrchr (path, '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);
@@ -713,11 +725,15 @@ grub_util_biosdisk_get_grub_dev (const c
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 -up grub2.orig/util/getroot.c grub2/util/getroot.c
--- grub2.orig/util/getroot.c 2007-07-22 01:32:31.000000000 +0200
+++ grub2/util/getroot.c 2007-11-23 20:59:00.671875000 +0100
@@ -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>
@@ -39,7 +46,8 @@ strip_extra_slashes (char *dir)
}
else if (p[1] == '\0')
{
- p[0] = '\0';
+ if (p > dir)
+ p[0] = '\0';
break;
}
@@ -63,6 +71,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)
{
@@ -115,6 +147,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);
@@ -123,6 +168,8 @@ grub_get_prefix (const char *dir)
return prefix;
}
+#ifndef __CYGWIN__
+
static char *
find_root_device (const char *dir, dev_t dev)
{
@@ -215,6 +262,86 @@ find_root_device (const char *dir, dev_t
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;
+ return *(unsigned *)(buf + n);
+}
+
+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)
{
@@ -224,6 +351,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
@@ -236,12 +364,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;
}
char *
grub_util_get_grub_dev (const char *os_dev)
{
+#ifndef __CYGWIN__
/* Check for LVM. */
if (!strncmp (os_dev, "/dev/mapper/", 12))
{
@@ -307,6 +442,7 @@ grub_util_get_grub_dev (const char *os_d
return grub_dev;
}
+#endif /* !__CYGWIN__ */
/* If it's not RAID or LVM, it should be a biosdisk. */
return grub_util_biosdisk_get_grub_dev (os_dev);
^ permalink raw reply [flat|nested] 8+ messages in thread* Re: [PATCH] biosdisk, getroot for Cygwin 2007-11-23 20:30 [PATCH] biosdisk, getroot for Cygwin Christian Franke @ 2008-05-07 20:42 ` Christian Franke 2008-05-09 12:45 ` Robert Millan 0 siblings, 1 reply; 8+ messages in thread From: Christian Franke @ 2008-05-07 20:42 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 1008 bytes --] 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 <franke@computer.org> * 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. [-- Attachment #2: grub2-biosdisk-getroot-2.patch --] [-- Type: text/x-patch, Size: 8177 bytes --] 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; ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] biosdisk, getroot for Cygwin 2008-05-07 20:42 ` Christian Franke @ 2008-05-09 12:45 ` Robert Millan 2008-05-09 17:32 ` Christian Franke 0 siblings, 1 reply; 8+ messages in thread From: Robert Millan @ 2008-05-09 12:45 UTC (permalink / raw) To: The development of GRUB 2 On Wed, May 07, 2008 at 10:42:23PM +0200, Christian Franke wrote: > + > + /* 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; Did you consider using a struct here? > + /* 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]; Where does this 13 come from? Would be nice to make it explicit (e.g. sizeof(something) or so). > +#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__ */ The logic here seems a bit over-complicated. Surely whenever you have __linux__ you don't have __CYGWIN__. Are you sure it can't be simplified? > +#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__ */ I think what we're missing here is "ifdef __linux__" since both LVM and dmRAID are Linux-specific. -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] biosdisk, getroot for Cygwin 2008-05-09 12:45 ` Robert Millan @ 2008-05-09 17:32 ` Christian Franke 2008-05-11 21:04 ` Christian Franke 2008-05-12 15:25 ` Robert Millan 0 siblings, 2 replies; 8+ messages in thread From: Christian Franke @ 2008-05-09 17:32 UTC (permalink / raw) To: The development of GRUB 2 Robert Millan wrote: > On Wed, May 07, 2008 at 10:42:23PM +0200, Christian Franke wrote: > >> + >> + /* 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; >> > > Did you consider using a struct here? > > There are 4 boot sector types, a clean declaration would require a union of 4 structs. IMO not worth the effort. >> + /* 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]; >> > > Where does this 13 come from? Would be nice to make it explicit (e.g. > sizeof(something) or so). > > 13 "paranoia" bytes added to the required size :-) >> +#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__ */ >> > > The logic here seems a bit over-complicated. Surely whenever you have __linux__ > you don't have __CYGWIN__. Are you sure it can't be simplified? > > An alternative would be to move the #ifndef __CYGWIN__ behind the #ifdef __linux__ block: #ifdef __linux__ ... os_dev = find_root_device ("/dev/mapper", st.st_dev); ... if (! os_dev) #endif #ifndef __CYGWIN__ { /* This might be truly slow, but is there any better way? */ os_dev = find_root_device ("/dev", st.st_dev); } #else /* __CYGWIN__ */ /* Cygwin specific function. */ os_dev = find_cygwin_root_device (dir, st.st_dev); #endif /* __CYGWIN__ */ I'm not sure whether this would be more readable. >> +#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__ */ >> > > I think what we're missing here is "ifdef __linux__" since both LVM and > dmRAID are Linux-specific. > > Yes. Christian ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] biosdisk, getroot for Cygwin 2008-05-09 17:32 ` Christian Franke @ 2008-05-11 21:04 ` Christian Franke 2008-05-12 15:25 ` Robert Millan 1 sibling, 0 replies; 8+ messages in thread From: Christian Franke @ 2008-05-11 21:04 UTC (permalink / raw) To: The development of GRUB 2 Christian Franke wrote: > Robert Millan wrote: >> On Wed, May 07, 2008 at 10:42:23PM +0200, Christian Franke wrote: >>> +#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__ */ >>> >> >> The logic here seems a bit over-complicated. Surely whenever you >> have __linux__ >> you don't have __CYGWIN__. Are you sure it can't be simplified? >> >> > > An alternative would be to move the #ifndef __CYGWIN__ behind the > #ifdef __linux__ block: > > #ifdef __linux__ > ... > os_dev = find_root_device ("/dev/mapper", st.st_dev); > ... > if (! os_dev) > #endif > #ifndef __CYGWIN__ > { > /* This might be truly slow, but is there any better way? */ > os_dev = find_root_device ("/dev", st.st_dev); > } > > #else /* __CYGWIN__ */ > /* Cygwin specific function. */ > os_dev = find_cygwin_root_device (dir, st.st_dev); > > #endif /* __CYGWIN__ */ > > > I'm not sure whether this would be more readable. > Probably more readable and extensible - Use early returns: #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 LVM. */ os_dev = find_root_device ("/dev/mapper", st.st_dev); if (os_dev) return os_dev; /* The same applies to /dev/evms directory (for EVMS volumes). */ os_dev = find_root_device ("/dev/evms", st.st_dev); if (os_dev) return os_dev; #endif /* __linux__ */ #ifndef __CYGWIN__ /* This might be truly slow, but is there any better way? */ os_dev = find_root_device ("/dev", st.st_dev); #else /* __CYGWIN__ */ /* Cygwin specific function. */ os_dev = find_cygwin_root_device (dir, st.st_dev); #endif /* __CYGWIN__ */ return os_dev; } Christian ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] biosdisk, getroot for Cygwin 2008-05-09 17:32 ` Christian Franke 2008-05-11 21:04 ` Christian Franke @ 2008-05-12 15:25 ` Robert Millan 2008-05-13 21:17 ` Christian Franke 1 sibling, 1 reply; 8+ messages in thread From: Robert Millan @ 2008-05-12 15:25 UTC (permalink / raw) To: The development of GRUB 2 On Fri, May 09, 2008 at 07:32:42PM +0200, Christian Franke wrote: > >>+ char devpath[sizeof ("/dev/sda15") + 13]; > >> > > > >Where does this 13 come from? Would be nice to make it explicit (e.g. > >sizeof(something) or so). > > 13 "paranoia" bytes added to the required size :-) A comment saying that would be nice. On Sun, May 11, 2008 at 11:04:39PM +0200, Christian Franke wrote: > > Probably more readable and extensible - Use early returns: Yeah I like that better too. > #ifndef __CYGWIN__ > /* This might be truly slow, but is there any better way? */ > os_dev = find_root_device ("/dev", st.st_dev); > > #else /* __CYGWIN__ */ > /* Cygwin specific function. */ > os_dev = find_cygwin_root_device (dir, st.st_dev); > > #endif /* __CYGWIN__ */ I'd suggest removing the double-negation here; it looks more readable with "#ifdef / #else" IMHO (and is easier to add more OS-specific checks like "#if defined(__CYGWIN__) / #elif defined(...) / #else". -- Robert Millan <GPLv2> I know my rights; I want my phone call! <DRM> What use is a phone call… if you are unable to speak? (as seen on /.) ^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [PATCH] biosdisk, getroot for Cygwin 2008-05-12 15:25 ` Robert Millan @ 2008-05-13 21:17 ` Christian Franke 2008-05-16 21:43 ` Christian Franke 0 siblings, 1 reply; 8+ messages in thread From: Christian Franke @ 2008-05-13 21:17 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 2210 bytes --] Robert Millan wrote: > On Fri, May 09, 2008 at 07:32:42PM +0200, Christian Franke wrote: > >>>> + char devpath[sizeof ("/dev/sda15") + 13]; >>>> >>>> >>> Where does this 13 come from? Would be nice to make it explicit (e.g. >>> sizeof(something) or so). >>> >> 13 "paranoia" bytes added to the required size :-) >> > > A comment saying that would be nice. > > Done. > On Sun, May 11, 2008 at 11:04:39PM +0200, Christian Franke wrote: > >> Probably more readable and extensible - Use early returns: >> > > Yeah I like that better too. > > >> #ifndef __CYGWIN__ >> /* This might be truly slow, but is there any better way? */ >> os_dev = find_root_device ("/dev", st.st_dev); >> >> #else /* __CYGWIN__ */ >> /* Cygwin specific function. */ >> os_dev = find_cygwin_root_device (dir, st.st_dev); >> >> #endif /* __CYGWIN__ */ >> > > I'd suggest removing the double-negation here; it looks more readable > with "#ifdef / #else" IMHO (and is easier to add more OS-specific checks > like "#if defined(__CYGWIN__) / #elif defined(...) / #else". > > Done, new patch below. If there are no further comments, I will commit it in a few days. Christian 2008-05-13 Christian Franke <franke@computer.org> * 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. [__linux__] (grub_guess_root_device): Add early returns to simplify structure. [__CYGWIN__] (grub_guess_root_device): Call find_cygwin_root_device. [__linux__] (grub_util_get_dev_abstraction): Enable LVM and RAID check for Linux only. [-- Attachment #2: grub2-biosdisk-getroot-3.patch --] [-- Type: text/x-patch, Size: 8552 bytes --] diff --git a/util/biosdisk.c b/util/biosdisk.c index fcf01a4..ddb3718 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; @@ -616,16 +624,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) @@ -692,15 +698,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); @@ -751,11 +763,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..1202a5c 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,92 @@ 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]; /* Size + Paranoia. */ + 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) { @@ -230,17 +363,24 @@ grub_guess_root_device (const char *dir) we don't do this, we get useless device names like /dev/dm-0 for LVM. */ os_dev = find_root_device ("/dev/mapper", st.st_dev); + if (os_dev) + return os_dev; /* The same applies to /dev/evms directory (for EVMS volumes). */ - if (! os_dev) - os_dev = find_root_device ("/dev/evms", st.st_dev); + os_dev = find_root_device ("/dev/evms", st.st_dev); + if (os_dev) + return os_dev; +#endif - if (! os_dev) +#ifdef __CYGWIN__ + /* Cygwin specific function. */ + os_dev = find_cygwin_root_device (dir, st.st_dev); + +#else + + /* This might be truly slow, but is there any better way? */ + os_dev = find_root_device ("/dev", st.st_dev); #endif - { - /* This might be truly slow, but is there any better way? */ - os_dev = find_root_device ("/dev", st.st_dev); - } return os_dev; } @@ -248,6 +388,7 @@ grub_guess_root_device (const char *dir) int grub_util_get_dev_abstraction (const char *os_dev) { +#ifdef __linux__ /* Check for LVM. */ if (!strncmp (os_dev, "/dev/mapper/", 12)) return GRUB_DEV_ABSTRACTION_LVM; @@ -255,6 +396,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 /* No abstraction found. */ return GRUB_DEV_ABSTRACTION_NONE; ^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH] biosdisk, getroot for Cygwin 2008-05-13 21:17 ` Christian Franke @ 2008-05-16 21:43 ` Christian Franke 0 siblings, 0 replies; 8+ messages in thread From: Christian Franke @ 2008-05-16 21:43 UTC (permalink / raw) To: The development of GRUB 2 > > Done, new patch below. If there are no further comments, I will commit > it in a few days. > Committed. Christian ^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2008-05-16 21:43 UTC | newest] Thread overview: 8+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-11-23 20:30 [PATCH] biosdisk, getroot for Cygwin Christian Franke 2008-05-07 20:42 ` Christian Franke 2008-05-09 12:45 ` Robert Millan 2008-05-09 17:32 ` Christian Franke 2008-05-11 21:04 ` Christian Franke 2008-05-12 15:25 ` Robert Millan 2008-05-13 21:17 ` Christian Franke 2008-05-16 21:43 ` Christian Franke
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.