All of lore.kernel.org
 help / color / mirror / Atom feed
From: Christian Franke <Christian.Franke@t-online.de>
To: The development of GRUB 2 <grub-devel@gnu.org>
Subject: Re: [PATCH] biosdisk, getroot for Cygwin
Date: Tue, 13 May 2008 23:17:43 +0200	[thread overview]
Message-ID: <482A0577.5030402@t-online.de> (raw)
In-Reply-To: <20080512152527.GA1841@thorin>

[-- 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;

  reply	other threads:[~2008-05-13 21:18 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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=482A0577.5030402@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.