From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with archive (Exim 4.43) id 1Jw1so-0004h4-QG for mharc-grub-devel@gnu.org; Tue, 13 May 2008 17:18:02 -0400 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1Jw1sm-0004gz-2G for grub-devel@gnu.org; Tue, 13 May 2008 17:18:00 -0400 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1Jw1sl-0004gZ-6N for grub-devel@gnu.org; Tue, 13 May 2008 17:17:59 -0400 Received: from [199.232.76.173] (port=34913 helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1Jw1sl-0004gM-2j for grub-devel@gnu.org; Tue, 13 May 2008 17:17:59 -0400 Received: from mailout03.t-online.de ([194.25.134.81]:42433) by monty-python.gnu.org with esmtp (Exim 4.60) (envelope-from ) id 1Jw1sk-0002uQ-3g for grub-devel@gnu.org; Tue, 13 May 2008 17:17:58 -0400 Received: from fwd30.aul.t-online.de by mailout03.sul.t-online.de with smtp id 1Jw1se-0004X4-02; Tue, 13 May 2008 23:17:52 +0200 Received: from [10.3.2.2] (Z4wU0eZ68h09RssdvmQkggaLptnlgGkp6pfiGo7z+ti2mhi14THhWV+ICCkP6vpQFZ@[217.235.249.115]) by fwd30.aul.t-online.de with esmtp id 1Jw1sT-22UUq00; Tue, 13 May 2008 23:17:41 +0200 Message-ID: <482A0577.5030402@t-online.de> Date: Tue, 13 May 2008 23:17:43 +0200 From: Christian Franke User-Agent: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.11) Gecko/20071128 SeaMonkey/1.1.7 MIME-Version: 1.0 To: The development of GRUB 2 References: <47473879.1020004@t-online.de> <4822142F.1040505@t-online.de> <20080509124506.GA3705@thorin> <48248ABA.5010704@t-online.de> <20080512152527.GA1841@thorin> In-Reply-To: <20080512152527.GA1841@thorin> Content-Type: multipart/mixed; boundary="------------080507040907010900010304" X-ID: Z4wU0eZ68h09RssdvmQkggaLptnlgGkp6pfiGo7z+ti2mhi14THhWV+ICCkP6vpQFZ X-TOI-MSGID: ac28c8b7-6c74-4c90-9fe9-cd783fd55ba4 X-detected-kernel: by monty-python.gnu.org: Linux 2.6 (newer, 3) Subject: Re: [PATCH] biosdisk, getroot for Cygwin X-BeenThere: grub-devel@gnu.org X-Mailman-Version: 2.1.5 Precedence: list Reply-To: The development of GRUB 2 List-Id: The development of GRUB 2 List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Tue, 13 May 2008 21:18:00 -0000 This is a multi-part message in MIME format. --------------080507040907010900010304 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit 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 * 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. --------------080507040907010900010304 Content-Type: text/x-patch; name="grub2-biosdisk-getroot-3.patch" Content-Transfer-Encoding: 7bit Content-Disposition: inline; filename="grub2-biosdisk-getroot-3.patch" 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 +# include /* BLKGETSIZE64 */ +# include /* 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 #include +#ifdef __CYGWIN__ +# include +# include +# include +# define DEV_CYGDRIVE_MAJOR 98 +#endif + #include #include #include @@ -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; --------------080507040907010900010304--