From: Christian Franke <Christian.Franke@t-online.de>
To: grub-devel@gnu.org
Subject: [PATCH] biosdisk, getroot for Cygwin
Date: Fri, 23 Nov 2007 21:30:49 +0100 [thread overview]
Message-ID: <47473879.1020004@t-online.de> (raw)
[-- 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);
next reply other threads:[~2007-11-23 20:30 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2007-11-23 20:30 Christian Franke [this message]
2008-05-07 20:42 ` [PATCH] biosdisk, getroot for Cygwin 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
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=47473879.1020004@t-online.de \
--to=christian.franke@t-online.de \
--cc=grub-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.