summaryrefslogtreecommitdiffstats
path: root/grub-core/osdep
diff options
context:
space:
mode:
Diffstat (limited to 'grub-core/osdep')
-rw-r--r--grub-core/osdep/apple/getroot.c109
-rw-r--r--grub-core/osdep/apple/hostdisk.c95
-rw-r--r--grub-core/osdep/aros/config.c94
-rw-r--r--grub-core/osdep/aros/getroot.c228
-rw-r--r--grub-core/osdep/aros/hostdisk.c617
-rw-r--r--grub-core/osdep/aros/relpath.c75
-rw-r--r--grub-core/osdep/basic/compress.c21
-rw-r--r--grub-core/osdep/basic/emunet.c50
-rw-r--r--grub-core/osdep/basic/getroot.c82
-rw-r--r--grub-core/osdep/basic/hostdisk.c58
-rw-r--r--grub-core/osdep/basic/init.c38
-rw-r--r--grub-core/osdep/basic/no_platform.c46
-rw-r--r--grub-core/osdep/basic/ofpath.c29
-rw-r--r--grub-core/osdep/basic/platform.c32
-rw-r--r--grub-core/osdep/basic/random.c43
-rw-r--r--grub-core/osdep/blocklist.c7
-rw-r--r--grub-core/osdep/bsd/getroot.c204
-rw-r--r--grub-core/osdep/bsd/hostdisk.c130
-rw-r--r--grub-core/osdep/compress.c5
-rw-r--r--grub-core/osdep/config.c7
-rw-r--r--grub-core/osdep/cputime.c5
-rw-r--r--grub-core/osdep/devmapper/getroot.c347
-rw-r--r--grub-core/osdep/devmapper/hostdisk.c230
-rw-r--r--grub-core/osdep/dl.c5
-rw-r--r--grub-core/osdep/emuconsole.c5
-rw-r--r--grub-core/osdep/emunet.c5
-rw-r--r--grub-core/osdep/exec.c3
-rw-r--r--grub-core/osdep/freebsd/getroot.c364
-rw-r--r--grub-core/osdep/freebsd/hostdisk.c128
-rw-r--r--grub-core/osdep/generic/blocklist.c132
-rw-r--r--grub-core/osdep/getroot.c22
-rw-r--r--grub-core/osdep/haiku/getroot.c105
-rw-r--r--grub-core/osdep/haiku/hostdisk.c69
-rw-r--r--grub-core/osdep/hostdisk.c22
-rw-r--r--grub-core/osdep/hurd/getroot.c247
-rw-r--r--grub-core/osdep/hurd/hostdisk.c146
-rw-r--r--grub-core/osdep/init.c5
-rw-r--r--grub-core/osdep/linux/blocklist.c136
-rw-r--r--grub-core/osdep/linux/emunet.c74
-rw-r--r--grub-core/osdep/linux/getroot.c1164
-rw-r--r--grub-core/osdep/linux/hostdisk.c465
-rw-r--r--grub-core/osdep/linux/ofpath.c769
-rw-r--r--grub-core/osdep/linux/platform.c156
-rw-r--r--grub-core/osdep/ofpath.c5
-rw-r--r--grub-core/osdep/password.c5
-rw-r--r--grub-core/osdep/platform.c9
-rw-r--r--grub-core/osdep/platform_unix.c3
-rw-r--r--grub-core/osdep/random.c10
-rw-r--r--grub-core/osdep/relpath.c7
-rw-r--r--grub-core/osdep/sleep.c5
-rw-r--r--grub-core/osdep/sun/getroot.c126
-rw-r--r--grub-core/osdep/sun/hostdisk.c73
-rw-r--r--grub-core/osdep/unix/compress.c41
-rw-r--r--grub-core/osdep/unix/config.c139
-rw-r--r--grub-core/osdep/unix/cputime.c22
-rw-r--r--grub-core/osdep/unix/dl.c61
-rw-r--r--grub-core/osdep/unix/emuconsole.c184
-rw-r--r--grub-core/osdep/unix/exec.c245
-rw-r--r--grub-core/osdep/unix/getroot.c787
-rw-r--r--grub-core/osdep/unix/hostdisk.c319
-rw-r--r--grub-core/osdep/unix/password.c75
-rw-r--r--grub-core/osdep/unix/platform.c241
-rw-r--r--grub-core/osdep/unix/random.c48
-rw-r--r--grub-core/osdep/unix/relpath.c151
-rw-r--r--grub-core/osdep/unix/sleep.c30
-rw-r--r--grub-core/osdep/windows/blocklist.c118
-rw-r--r--grub-core/osdep/windows/config.c57
-rw-r--r--grub-core/osdep/windows/cputime.c19
-rw-r--r--grub-core/osdep/windows/dl.c59
-rw-r--r--grub-core/osdep/windows/emuconsole.c308
-rw-r--r--grub-core/osdep/windows/getroot.c355
-rw-r--r--grub-core/osdep/windows/hostdisk.c689
-rw-r--r--grub-core/osdep/windows/init.c190
-rw-r--r--grub-core/osdep/windows/password.c51
-rw-r--r--grub-core/osdep/windows/platform.c426
-rw-r--r--grub-core/osdep/windows/random.c55
-rw-r--r--grub-core/osdep/windows/relpath.c96
-rw-r--r--grub-core/osdep/windows/sleep.c31
78 files changed, 11614 insertions, 0 deletions
diff --git a/grub-core/osdep/apple/getroot.c b/grub-core/osdep/apple/getroot.c
new file mode 100644
index 0000000..2091ded
--- /dev/null
+++ b/grub-core/osdep/apple/getroot.c
@@ -0,0 +1,109 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <grub/types.h>
+
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+
+#include <sys/wait.h>
+
+# include <sys/disk.h>
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <sys/mount.h>
+
+char *
+grub_util_part_to_disk (const char *os_dev, struct stat *st,
+ int *is_part)
+{
+ char *path = xstrdup (os_dev);
+
+ if (! S_ISCHR (st->st_mode))
+ {
+ *is_part = 0;
+ return path;
+ }
+
+ if (strncmp ("/dev/", path, 5) == 0)
+ {
+ char *p;
+ for (p = path + 5; *p; ++p)
+ if (grub_isdigit(*p))
+ {
+ p = strpbrk (p, "sp");
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+ break;
+ }
+ }
+ return path;
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
+{
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
+ enum grub_dev_abstraction_types ab __attribute__ ((unused)))
+{
+ return 0;
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *dev __attribute__ ((unused)))
+{
+ return 0;
+}
diff --git a/grub-core/osdep/apple/hostdisk.c b/grub-core/osdep/apple/hostdisk.c
new file mode 100644
index 0000000..8d9b4b4
--- /dev/null
+++ b/grub-core/osdep/apple/hostdisk.c
@@ -0,0 +1,95 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+# include <sys/disk.h>
+
+grub_int64_t
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
+{
+ unsigned long long nr;
+ unsigned sector_size, log_sector_size;
+
+ if (ioctl (fd, DKIOCGETBLOCKCOUNT, &nr))
+ return -1;
+
+ if (ioctl (fd, DKIOCGETBLOCKSIZE, &sector_size))
+ return -1;
+
+ if (sector_size & (sector_size - 1) || !sector_size)
+ return -1;
+ for (log_sector_size = 0;
+ (1 << log_sector_size) < sector_size;
+ log_sector_size++);
+
+ if (log_secsize)
+ *log_secsize = log_sector_size;
+
+ return nr << log_sector_size;
+}
+
+grub_util_fd_t
+grub_util_fd_open (const char *os_dev, int flags)
+{
+ grub_util_fd_t ret;
+
+#ifdef O_LARGEFILE
+ flags |= O_LARGEFILE;
+#endif
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+
+ ret = open (os_dev, flags, S_IROTH | S_IRGRP | S_IRUSR | S_IWUSR);
+
+ /* If we can't have exclusive access, try shared access */
+ if (ret < 0)
+ ret = open (os_dev, flags | O_SHLOCK, S_IROTH | S_IRGRP | S_IRUSR | S_IWUSR);
+
+ return ret;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
diff --git a/grub-core/osdep/aros/config.c b/grub-core/osdep/aros/config.c
new file mode 100644
index 0000000..c82d0ea
--- /dev/null
+++ b/grub-core/osdep/aros/config.c
@@ -0,0 +1,94 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/exec.h>
+#include <grub/emu/config.h>
+#include <grub/util/install.h>
+#include <grub/util/misc.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <stdlib.h>
+
+const char *
+grub_util_get_config_filename (void)
+{
+ static char *value = NULL;
+ if (!value)
+ value = grub_util_path_concat (3, GRUB_SYSCONFDIR,
+ "default", "grub");
+ return value;
+}
+
+const char *
+grub_util_get_pkgdatadir (void)
+{
+ const char *ret = getenv ("pkgdatadir");
+ if (ret)
+ return ret;
+ return GRUB_DATADIR "/" PACKAGE;
+}
+
+const char *
+grub_util_get_pkglibdir (void)
+{
+ return GRUB_LIBDIR "/" PACKAGE;
+}
+
+const char *
+grub_util_get_localedir (void)
+{
+ return LOCALEDIR;
+}
+
+void
+grub_util_load_config (struct grub_util_config *cfg)
+{
+ const char *cfgfile;
+ FILE *f = NULL;
+ const char *v;
+
+ memset (cfg, 0, sizeof (*cfg));
+
+ v = getenv ("GRUB_ENABLE_CRYPTODISK");
+ if (v && v[0] == 'y' && v[1] == '\0')
+ cfg->is_cryptodisk_enabled = 1;
+
+ v = getenv ("GRUB_DISTRIBUTOR");
+ if (v)
+ cfg->grub_distributor = xstrdup (v);
+
+ cfgfile = grub_util_get_config_filename ();
+ if (!grub_util_is_regular (cfgfile))
+ return;
+
+ f = grub_util_fopen (cfgfile, "r");
+ if (f)
+ {
+ grub_util_parse_config (f, cfg, 0);
+ fclose (f);
+ }
+ else
+ grub_util_warn (_("cannot open configuration file `%s': %s"),
+ cfgfile, strerror (errno));
+}
diff --git a/grub-core/osdep/aros/getroot.c b/grub-core/osdep/aros/getroot.c
new file mode 100644
index 0000000..a27df9e
--- /dev/null
+++ b/grub-core/osdep/aros/getroot.c
@@ -0,0 +1,228 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+
+#include <string.h>
+#include <dos/dos.h>
+#include <dos/filesystem.h>
+#include <dos/exall.h>
+#include <proto/dos.h>
+#include <proto/exec.h>
+#include <devices/trackdisk.h>
+
+char *
+grub_util_part_to_disk (const char *dev,
+ struct stat *st __attribute__ ((unused)),
+ int *is_part)
+{
+ const char *dname;
+ char *ret;
+ struct DosList *dl;
+ struct DeviceNode *dn;
+ struct FileSysStartupMsg *fm;
+ struct DosEnvec *envec;
+
+ if (dev[0] != '/' || dev[1] != '/' || dev[2] != ':')
+ return xstrdup (dev);
+
+ dname = dev + 3;
+ dl = LockDosList(LDF_READ);
+
+ if (!dl)
+ {
+ return xstrdup (dev);
+ }
+
+ dn = (struct DeviceNode *) FindDosEntry (dl, (unsigned char *) dname,
+ LDF_DEVICES);
+ UnLockDosList (LDF_READ);
+ if (!dn)
+ return xstrdup (dev);
+
+ fm = (struct FileSysStartupMsg *) BADDR(dn->dn_Startup);
+ envec = (struct DosEnvec *) fm->fssm_Environ;
+
+ if (envec->de_LowCyl == 0)
+ return xstrdup (dev);
+
+ *is_part = 1;
+
+ ret = xasprintf ("//:%s/%lx/%lx", fm->fssm_Device, fm->fssm_Unit, (unsigned long) fm->fssm_Flags);
+
+ return ret;
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
+{
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
+ enum grub_dev_abstraction_types ab __attribute__ ((unused)))
+{
+ return 0;
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *dev)
+{
+ const char *dname;
+ struct DosList *dl;
+ struct DeviceNode *dn;
+ struct FileSysStartupMsg *fm;
+ struct DosEnvec *envec;
+
+ if (dev[0] != '/' || dev[1] != '/' || dev[2] != ':')
+ return 0;
+
+ dname = dev + 3;
+ dl = LockDosList(LDF_READ);
+ if (!dl)
+ {
+ return 0;
+ }
+ dn = (struct DeviceNode *) FindDosEntry (dl, (unsigned char *) dname,
+ LDF_DEVICES);
+ UnLockDosList (LDF_READ);
+ if (!dn)
+ return 0;
+
+ fm = (struct FileSysStartupMsg *) BADDR(dn->dn_Startup);
+ envec = (struct DosEnvec *) fm->fssm_Environ;
+
+ return (((grub_uint64_t) envec->de_Surfaces
+ * (grub_uint64_t) envec->de_BlocksPerTrack
+ * (grub_uint64_t) envec->de_LowCyl)
+ * (grub_uint64_t) envec->de_SizeBlock) >> 7;
+}
+
+char **
+grub_guess_root_devices (const char *path)
+{
+ char **os_dev = NULL;
+ struct InfoData id;
+ BPTR lck;
+ struct DeviceList *dl;
+ struct DosList *dl2;
+ size_t sz;
+ const char *nm;
+
+ lck = Lock ((const unsigned char *) path, SHARED_LOCK);
+ if (!lck)
+ grub_util_info ("Lock(%s) failed", path);
+ if (!lck || !Info (lck, &id))
+ {
+ char *p;
+ if (lck)
+ UnLock (lck);
+ grub_util_info ("Info(%s) failed", path);
+ os_dev = xmalloc (2 * sizeof (os_dev[0]));
+ sz = strlen (path);
+ os_dev[0] = xmalloc (sz + 5);
+ os_dev[0][0] = '/';
+ os_dev[0][1] = '/';
+ os_dev[0][2] = ':';
+ memcpy (os_dev[0] + 3, path, sz);
+ os_dev[0][sz + 3] = ':';
+ os_dev[0][sz + 4] = '\0';
+ p = strchr (os_dev[0] + 3, ':');
+ *p = '\0';
+ os_dev[1] = NULL;
+ return os_dev;
+ }
+ dl = BADDR (id.id_VolumeNode);
+
+ if (!dl->dl_Task)
+ grub_util_error ("unsupported device %s", dl->dl_Name);
+
+ grub_util_info ("dl=%p, dl->dl_Name=%s, dl->dl_Task=%p",
+ dl, dl->dl_Name,
+ dl->dl_Task);
+
+ for (dl2 = LockDosList(LDF_READ | LDF_DEVICES);
+ dl2;
+ dl2 = NextDosEntry (dl2, LDF_DEVICES))
+ {
+ if (dl2->dol_Task == dl->dl_Task)
+ break;
+ }
+
+ if (lck)
+ UnLock (lck);
+
+ if (dl2)
+ nm = (char *) dl2->dol_Name;
+ else
+ nm = (char *) dl->dl_Name;
+
+ grub_util_info ("dl2=%p, nm=%s", dl2, nm);
+
+ os_dev = xmalloc (2 * sizeof (os_dev[0]));
+ sz = strlen (nm);
+
+ os_dev[0] = xmalloc (sz + 4);
+ os_dev[0][0] = '/';
+ os_dev[0][1] = '/';
+ os_dev[0][2] = ':';
+ memcpy (os_dev[0] + 3, nm, sz);
+ os_dev[0][sz+3] = '\0';
+ os_dev[1] = NULL;
+
+ UnLockDosList (LDF_READ | LDF_DEVICES);
+
+ return os_dev;
+}
+
+int
+grub_util_biosdisk_is_floppy (grub_disk_t disk)
+{
+ const char *dname;
+
+ dname = grub_util_biosdisk_get_osdev (disk);
+
+ if (dname[0] != '/' || dname[1] != '/' || dname[2] != ':')
+ return 0;
+
+ dname += 3;
+
+ if (strncmp (dname, TD_NAME, sizeof (TD_NAME) - 1) == 0
+ && (TD_NAME[sizeof (TD_NAME) - 1] == '/'
+ || TD_NAME[sizeof (TD_NAME) - 1] == '\0'))
+ return 1;
+ return 0;
+}
+
diff --git a/grub-core/osdep/aros/hostdisk.c b/grub-core/osdep/aros/hostdisk.c
new file mode 100644
index 0000000..3b2c9de
--- /dev/null
+++ b/grub-core/osdep/aros/hostdisk.c
@@ -0,0 +1,617 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <time.h>
+
+#include <string.h>
+#include <dos/dos.h>
+#include <dos/filesystem.h>
+#include <dos/exall.h>
+#include <proto/dos.h>
+#include <devices/hardblocks.h>
+#include <devices/newstyle.h>
+#include <proto/exec.h>
+#include <proto/utility.h>
+#include <proto/partition.h>
+#include <devices/trackdisk.h>
+#include <exec/errors.h>
+
+#define BOUNCE_SIZE 1048576
+
+static ULONG *bounce;
+
+char *
+grub_canonicalize_file_name (const char *path)
+{
+ char *ret;
+ BPTR lck;
+
+ if (path[0] == '/' && path[1] == '/' && path[2] == ':')
+ return xstrdup (path);
+
+ ret = xmalloc (2048);
+ lck = Lock ((const unsigned char *) path, SHARED_LOCK);
+
+ if (!lck || !NameFromLock (lck, (unsigned char *) ret, 2040))
+ {
+ free (ret);
+ ret = xstrdup (path);
+ }
+ if (lck)
+ UnLock (lck);
+
+ return ret;
+}
+
+static grub_uint64_t
+grub_util_get_fd_size_volume (grub_util_fd_t fd __attribute__ ((unused)),
+ const char *dev,
+ unsigned *log_secsize)
+{
+ struct DriveGeometry *geo;
+ LONG err;
+ unsigned sector_size, log_sector_size;
+
+ if (!bounce)
+ bounce = AllocVec (BOUNCE_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
+ if (!bounce)
+ grub_util_error ("out of memory");
+
+ fd->ioreq->iotd_Req.io_Command = TD_GETGEOMETRY;
+ fd->ioreq->iotd_Req.io_Length = sizeof (*geo);
+ fd->ioreq->iotd_Req.io_Data = bounce;
+ fd->ioreq->iotd_Req.io_Offset = 0;
+ fd->ioreq->iotd_Req.io_Actual = 0;
+ err = DoIO ((struct IORequest *) fd->ioreq);
+ if (err)
+ {
+ grub_util_info ("I/O failed with error %d, IoErr=%d", (int)err, (int) IoErr ());
+ return -1;
+ }
+
+ geo = (struct DriveGeometry *) bounce;
+
+ sector_size = geo->dg_SectorSize;
+
+ if (sector_size & (sector_size - 1) || !sector_size)
+ return -1;
+
+ for (log_sector_size = 0;
+ (1 << log_sector_size) < sector_size;
+ log_sector_size++);
+
+ if (log_secsize)
+ *log_secsize = log_sector_size;
+
+ return (grub_uint64_t) geo->dg_TotalSectors * (grub_uint64_t) geo->dg_SectorSize;
+}
+
+static grub_uint64_t
+grub_util_get_fd_size_file (grub_util_fd_t fd,
+ const char *dev __attribute__ ((unused)),
+ unsigned *log_secsize)
+{
+ off_t oo, ro;
+ *log_secsize = 9;
+ /* FIXME: support 64-bit offsets. */
+ oo = lseek (fd->fd, 0, SEEK_CUR);
+ ro = lseek (fd->fd, 0, SEEK_END);
+ lseek (fd->fd, oo, SEEK_SET);
+ return ro;
+}
+
+int
+grub_util_fd_seek (grub_util_fd_t fd, grub_uint64_t off)
+{
+ switch (fd->type)
+ {
+ case GRUB_UTIL_FD_FILE:
+ if (lseek (fd->fd, 0, SEEK_SET) == (off_t) -1)
+ return -1;
+ fd->off = off;
+ return 0;
+ case GRUB_UTIL_FD_DISK:
+ fd->off = off;
+ return 0;
+ }
+
+ return -1;
+}
+
+grub_util_fd_t
+grub_util_fd_open (const char *dev, int flg)
+{
+ grub_util_fd_t ret = xmalloc (sizeof (*ret));
+ const char *p1, *p2;
+ const char *dname;
+ char *tmp;
+ IPTR unit = 0;
+ ULONG flags = 0;
+
+#ifdef O_LARGEFILE
+ flg |= O_LARGEFILE;
+#endif
+#ifdef O_BINARY
+ flg |= O_BINARY;
+#endif
+
+ ret->off = 0;
+
+ if (dev[0] != '/' || dev[1] != '/' || dev[2] != ':')
+ {
+ ret->type = GRUB_UTIL_FD_FILE;
+ ret->fd = open (dev, flg, S_IROTH | S_IRGRP | S_IRUSR | S_IWUSR);
+ if (ret->fd < 0)
+ {
+ free (ret);
+ return NULL;
+ }
+ return ret;
+ }
+
+ p1 = strchr (dev + 3, '/');
+ if (!p1)
+ p1 = dev + strlen (dev);
+ else
+ {
+ unit = grub_strtoul (p1 + 1, &p2, 16);
+ if (p2 && *p2 == '/')
+ flags = grub_strtoul (p2 + 1, 0, 16);
+ }
+
+ ret->mp = CreateMsgPort();
+ if (!ret->mp)
+ {
+ free (ret);
+ return NULL;
+ }
+ ret->ioreq = (struct IOExtTD *) CreateIORequest(ret->mp,
+ sizeof(struct IOExtTD));
+ if (!ret->ioreq)
+ {
+ free (ret);
+ DeleteMsgPort (ret->mp);
+ return NULL;
+ }
+
+ dname = dev + 3;
+ ret->type = GRUB_UTIL_FD_DISK;
+
+ tmp = xmalloc (p1 - dname + 1);
+ memcpy (tmp, dname, p1 - dname);
+ tmp[p1 - dname] = '\0';
+
+ ret->is_floppy = (strcmp (tmp, TD_NAME) == 0);
+ ret->is_64 = 1;
+
+ if (OpenDevice ((unsigned char *) tmp, unit,
+ (struct IORequest *) ret->ioreq, flags))
+ {
+ free (tmp);
+ free (ret);
+ DeleteMsgPort (ret->mp);
+ return NULL;
+ }
+ free (tmp);
+ return ret;
+}
+
+static ssize_t
+grub_util_fd_read_file (grub_util_fd_t fd, char *buf, size_t len)
+{
+ ssize_t size = len;
+
+ while (len)
+ {
+ ssize_t ret = read (fd->fd, buf, len);
+
+ if (ret <= 0)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ return ret;
+ }
+
+ fd->off += ret;
+ len -= ret;
+ buf += ret;
+ }
+
+ return size;
+}
+
+/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
+ error occurs, otherwise return LEN. */
+static ssize_t
+grub_util_fd_write_file (grub_util_fd_t fd, const char *buf, size_t len)
+{
+ ssize_t size = len;
+
+ while (len)
+ {
+ ssize_t ret = write (fd->fd, buf, len);
+
+ if (ret <= 0)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ return ret;
+ }
+
+ fd->off += ret;
+ len -= ret;
+ buf += ret;
+ }
+
+ return size;
+}
+
+static void
+stop_motor (grub_util_fd_t fd)
+{
+ if (!fd->is_floppy)
+ return;
+ fd->ioreq->iotd_Req.io_Command = TD_MOTOR;
+ fd->ioreq->iotd_Req.io_Length = 0;
+ fd->ioreq->iotd_Req.io_Data = 0;
+ fd->ioreq->iotd_Req.io_Offset = 0;
+ fd->ioreq->iotd_Req.io_Actual = 0;
+ DoIO ((struct IORequest *) fd->ioreq);
+}
+
+static ssize_t
+grub_util_fd_read_volume (grub_util_fd_t fd, char *buf, size_t len)
+{
+ grub_uint64_t adj = 0;
+
+ if (!bounce)
+ bounce = AllocVec (BOUNCE_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
+ if (!bounce)
+ grub_util_error ("out of memory");
+
+ while (len)
+ {
+ size_t cr = len;
+ LONG err;
+ if (cr > BOUNCE_SIZE)
+ cr = BOUNCE_SIZE;
+ retry:
+ if (fd->is_64)
+ fd->ioreq->iotd_Req.io_Command = NSCMD_TD_READ64;
+ else
+ fd->ioreq->iotd_Req.io_Command = CMD_READ;
+ fd->ioreq->iotd_Req.io_Length = cr;
+ fd->ioreq->iotd_Req.io_Data = bounce;
+ fd->ioreq->iotd_Req.io_Offset = fd->off & 0xFFFFFFFF;
+ fd->ioreq->iotd_Req.io_Actual = fd->off >> 32;
+ err = DoIO ((struct IORequest *) fd->ioreq);
+ if (err == IOERR_NOCMD && fd->is_64)
+ {
+ fd->is_64 = 0;
+ goto retry;
+ }
+ if (err)
+ {
+ grub_util_info ("I/O failed with error %d, IoErr=%d", (int)err, (int) IoErr ());
+ stop_motor (fd);
+ return -1;
+ }
+ memcpy (buf, bounce, cr);
+ adj += cr;
+ len -= cr;
+ buf += cr;
+ }
+
+ fd->off += adj;
+ stop_motor (fd);
+ return adj;
+}
+
+static ssize_t
+grub_util_fd_write_volume (grub_util_fd_t fd, const char *buf, size_t len)
+{
+ grub_uint64_t adj = 0;
+ if (!bounce)
+ bounce = AllocVec (BOUNCE_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
+ if (!bounce)
+ grub_util_error ("out of memory");
+
+ while (len)
+ {
+ size_t cr = len;
+ LONG err;
+ if (cr > BOUNCE_SIZE)
+ cr = BOUNCE_SIZE;
+ retry:
+ if (fd->is_64)
+ fd->ioreq->iotd_Req.io_Command = NSCMD_TD_WRITE64;
+ else
+ fd->ioreq->iotd_Req.io_Command = CMD_WRITE;
+ fd->ioreq->iotd_Req.io_Length = cr;
+ fd->ioreq->iotd_Req.io_Data = bounce;
+ fd->ioreq->iotd_Req.io_Offset = fd->off & 0xFFFFFFFF;
+ fd->ioreq->iotd_Req.io_Actual = fd->off >> 32;
+ memcpy (bounce, buf, cr);
+ err = DoIO ((struct IORequest *) fd->ioreq);
+ if (err == IOERR_NOCMD && fd->is_64)
+ {
+ fd->is_64 = 0;
+ goto retry;
+ }
+ if (err)
+ {
+ grub_util_info ("I/O failed with error %d", err);
+ stop_motor (fd);
+ return -1;
+ }
+
+ adj += cr;
+ len -= cr;
+ buf += cr;
+ }
+
+ fd->off += adj;
+ stop_motor (fd);
+ return adj;
+}
+
+ssize_t
+grub_util_fd_read (grub_util_fd_t fd, char *buf, size_t len)
+{
+ switch (fd->type)
+ {
+ case GRUB_UTIL_FD_FILE:
+ return grub_util_fd_read_file (fd, buf, len);
+ case GRUB_UTIL_FD_DISK:
+ return grub_util_fd_read_volume (fd, buf, len);
+ }
+ return -1;
+}
+
+ssize_t
+grub_util_fd_write (grub_util_fd_t fd, const char *buf, size_t len)
+{
+ switch (fd->type)
+ {
+ case GRUB_UTIL_FD_FILE:
+ return grub_util_fd_write_file (fd, buf, len);
+ case GRUB_UTIL_FD_DISK:
+ return grub_util_fd_write_volume (fd, buf, len);
+ }
+ return -1;
+}
+
+grub_uint64_t
+grub_util_get_fd_size (grub_util_fd_t fd,
+ const char *dev,
+ unsigned *log_secsize)
+{
+ switch (fd->type)
+ {
+ case GRUB_UTIL_FD_FILE:
+ return grub_util_get_fd_size_file (fd, dev, log_secsize);
+
+ case GRUB_UTIL_FD_DISK:
+ return grub_util_get_fd_size_volume (fd, dev, log_secsize);
+ }
+ return -1;
+}
+
+int
+grub_util_fd_close (grub_util_fd_t fd)
+{
+ switch (fd->type)
+ {
+ case GRUB_UTIL_FD_FILE:
+ return close (fd->fd);
+ case GRUB_UTIL_FD_DISK:
+ CloseDevice ((struct IORequest *) fd->ioreq);
+ DeleteIORequest((struct IORequest *) fd->ioreq);
+ DeleteMsgPort (fd->mp);
+ return 0;
+ }
+ return 0;
+}
+
+static int allow_fd_syncs = 1;
+
+static int
+grub_util_fd_sync_volume (grub_util_fd_t fd)
+{
+ LONG err;
+
+ fd->ioreq->iotd_Req.io_Command = CMD_UPDATE;
+ fd->ioreq->iotd_Req.io_Length = 0;
+ fd->ioreq->iotd_Req.io_Data = 0;
+ fd->ioreq->iotd_Req.io_Offset = 0;
+ fd->ioreq->iotd_Req.io_Actual = 0;
+ err = DoIO ((struct IORequest *) fd->ioreq);
+ if (err)
+ {
+ grub_util_info ("I/O failed with error %d, IoErr=%d", (int)err, (int) IoErr ());
+ return -1;
+ }
+ return 0;
+}
+
+int
+grub_util_fd_sync (grub_util_fd_t fd)
+{
+ if (allow_fd_syncs)
+ {
+ switch (fd->type)
+ {
+ case GRUB_UTIL_FD_FILE:
+ return fsync (fd->fd);
+ case GRUB_UTIL_FD_DISK:
+ return grub_util_fd_sync_volume (fd);
+ }
+ }
+ return 0;
+}
+
+int
+grub_util_file_sync (FILE *f)
+{
+ if (fflush (f) != 0)
+ return -1;
+ if (!allow_fd_syncs)
+ return 0;
+ return fsync (fileno (f));
+}
+
+void
+grub_util_disable_fd_syncs (void)
+{
+ allow_fd_syncs = 0;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
+
+
+const char *
+grub_util_fd_strerror (void)
+{
+ static char buf[201];
+ LONG err = IoErr ();
+ if (!err)
+ return _("Success");
+ memset (buf, '\0', sizeof (buf));
+ Fault (err, (const unsigned char *) "", (STRPTR) buf, sizeof (buf));
+ if (buf[0] == ':')
+ return buf + 1;
+ return buf;
+}
+
+FILE *
+grub_util_fopen (const char *path, const char *mode)
+{
+ return fopen (path, mode);
+}
+
+int
+grub_util_is_directory (const char *path)
+{
+ struct stat st;
+
+ if (stat (path, &st) == -1)
+ return 0;
+
+ return S_ISDIR (st.st_mode);
+}
+
+int
+grub_util_is_regular (const char *path)
+{
+ struct stat st;
+
+ if (stat (path, &st) == -1)
+ return 0;
+
+ return S_ISREG (st.st_mode);
+}
+
+int
+grub_util_is_special_file (const char *path)
+{
+ struct stat st;
+
+ if (lstat (path, &st) == -1)
+ return 1;
+ return (!S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode));
+}
+
+static char *
+get_temp_name (void)
+{
+ static int ctr = 0;
+ char *t;
+ struct stat st;
+
+ while (1)
+ {
+ t = xasprintf ("T:grub.%d.%d.%d.%d", (int) getpid (), (int) getppid (),
+ ctr++, time (0));
+ if (stat (t, &st) == -1)
+ return t;
+ free (t);
+ }
+}
+
+char *
+grub_util_make_temporary_file (void)
+{
+ char *ret = get_temp_name ();
+ FILE *f;
+
+ f = grub_util_fopen (ret, "wb");
+ if (f)
+ fclose (f);
+ return ret;
+}
+
+char *
+grub_util_make_temporary_dir (void)
+{
+ char *ret = get_temp_name ();
+
+ grub_util_mkdir (ret);
+
+ return ret;
+}
+
+grub_uint32_t
+grub_util_get_mtime (const char *path)
+{
+ struct stat st;
+
+ if (stat (path, &st) == -1)
+ return 0;
+
+ return st.st_mtime;
+}
diff --git a/grub-core/osdep/aros/relpath.c b/grub-core/osdep/aros/relpath.c
new file mode 100644
index 0000000..9c2328d
--- /dev/null
+++ b/grub-core/osdep/aros/relpath.c
@@ -0,0 +1,75 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+
+#include <string.h>
+#include <dos/dos.h>
+#include <dos/filesystem.h>
+#include <dos/exall.h>
+#include <proto/dos.h>
+#include <proto/exec.h>
+#include <devices/trackdisk.h>
+
+char *
+grub_make_system_path_relative_to_its_root (const char *path)
+{
+ char *p;
+ unsigned char *tmp;
+ char *ret;
+ BPTR lck;
+
+ if (path[0] == '/' && path[1] == '/' && path[2] == ':')
+ return xstrdup (path);
+
+ tmp = xmalloc (2048);
+
+ lck = Lock ((const unsigned char *) path, SHARED_LOCK);
+ if (!lck || !NameFromLock (lck, tmp, 2040))
+ {
+ free (tmp);
+ tmp = (unsigned char *) xstrdup (path);
+ }
+ if (lck)
+ UnLock (lck);
+ p = strchr ((char *) tmp, ':');
+ if (!p)
+ return (char *) tmp;
+ if (p[1] == '/' || p[1] == '\0')
+ {
+ ret = xstrdup (p + 1);
+ }
+ else
+ {
+ ret = xmalloc (strlen (p + 1) + 2);
+ ret[0] = '/';
+ strcpy (ret + 1, p + 1);
+ }
+
+ free (tmp);
+ return ret;
+}
diff --git a/grub-core/osdep/basic/compress.c b/grub-core/osdep/basic/compress.c
new file mode 100644
index 0000000..9794640
--- /dev/null
+++ b/grub-core/osdep/basic/compress.c
@@ -0,0 +1,21 @@
+#include <config.h>
+#include <grub/util/install.h>
+#include <grub/util/misc.h>
+
+int
+grub_install_compress_gzip (const char *src, const char *dest)
+{
+ grub_util_error (_("no compression is available for your platform"));
+}
+
+int
+grub_install_compress_xz (const char *src, const char *dest)
+{
+ grub_util_error (_("no compression is available for your platform"));
+}
+
+int
+grub_install_compress_lzop (const char *src, const char *dest)
+{
+ grub_util_error (_("no compression is available for your platform"));
+}
diff --git a/grub-core/osdep/basic/emunet.c b/grub-core/osdep/basic/emunet.c
new file mode 100644
index 0000000..6362e5c
--- /dev/null
+++ b/grub-core/osdep/basic/emunet.c
@@ -0,0 +1,50 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <grub/i18n.h>
+#include <grub/emu/net.h>
+
+grub_ssize_t
+grub_emunet_send (const void *packet __attribute__ ((unused)),
+ grub_size_t sz __attribute__ ((unused)))
+{
+ return -1;
+}
+
+grub_ssize_t
+grub_emunet_receive (void *packet __attribute__ ((unused)),
+ grub_size_t sz __attribute__ ((unused)))
+{
+ return -1;
+}
+
+int
+grub_emunet_create (grub_size_t *mtu)
+{
+ *mtu = 1500;
+ return -1;
+}
+
+void
+grub_emunet_close (void)
+{
+ return;
+}
diff --git a/grub-core/osdep/basic/getroot.c b/grub-core/osdep/basic/getroot.c
new file mode 100644
index 0000000..8831eb3
--- /dev/null
+++ b/grub-core/osdep/basic/getroot.c
@@ -0,0 +1,82 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <grub/types.h>
+
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+
+
+char *
+grub_util_part_to_disk (const char *os_dev,
+ struct stat *st __attribute__ ((unused)),
+ int *is_part)
+{
+ *is_part = 0;
+ return xstrdup (os_dev);
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
+{
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
+ enum grub_dev_abstraction_types ab __attribute__ ((unused)))
+{
+ return 0;
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *dev __attribute__ ((unused)))
+{
+ return 0;
+}
diff --git a/grub-core/osdep/basic/hostdisk.c b/grub-core/osdep/basic/hostdisk.c
new file mode 100644
index 0000000..529bf29
--- /dev/null
+++ b/grub-core/osdep/basic/hostdisk.c
@@ -0,0 +1,58 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+grub_int64_t
+grub_util_get_fd_size_os (grub_util_fd_t fd __attribute__ ((unused)),
+ const char *name __attribute__ ((unused)),
+ unsigned *log_secsize __attribute__ ((unused)))
+{
+# warning "No special routine to get the size of a block device is implemented for your OS. This is not possibly fatal."
+
+ return -1;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
diff --git a/grub-core/osdep/basic/init.c b/grub-core/osdep/basic/init.c
new file mode 100644
index 0000000..c54c710
--- /dev/null
+++ b/grub-core/osdep/basic/init.c
@@ -0,0 +1,38 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <grub/util/misc.h>
+#include <grub/i18n.h>
+
+#include "progname.h"
+
+void
+grub_util_host_init (int *argc __attribute__ ((unused)),
+ char ***argv)
+{
+ set_program_name ((*argv)[0]);
+
+#if (defined (GRUB_UTIL) && defined(ENABLE_NLS) && ENABLE_NLS)
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, LOCALEDIR);
+ textdomain (PACKAGE);
+#endif /* (defined(ENABLE_NLS) && ENABLE_NLS) */
+}
diff --git a/grub-core/osdep/basic/no_platform.c b/grub-core/osdep/basic/no_platform.c
new file mode 100644
index 0000000..d76c34c
--- /dev/null
+++ b/grub-core/osdep/basic/no_platform.c
@@ -0,0 +1,46 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/types.h>
+#include <grub/emu/misc.h>
+#include <grub/util/install.h>
+#include <grub/util/misc.h>
+
+#include "platform.c"
+
+void
+grub_install_register_ieee1275 (int is_prep, const char *install_device,
+ int partno, const char *relpath)
+{
+ grub_util_error ("%s", _("no IEEE1275 routines are available for your platform"));
+}
+
+void
+grub_install_register_efi (grub_device_t efidir_grub_dev,
+ const char *efifile_path,
+ const char *efi_distributor)
+{
+ grub_util_error ("%s", _("no EFI routines are available for your platform"));
+}
+
+void
+grub_install_sgi_setup (const char *install_device,
+ const char *imgfile, const char *destname)
+{
+ grub_util_error ("%s", _("no SGI routines are available for your platform"));
+}
diff --git a/grub-core/osdep/basic/ofpath.c b/grub-core/osdep/basic/ofpath.c
new file mode 100644
index 0000000..c3fe06f
--- /dev/null
+++ b/grub-core/osdep/basic/ofpath.c
@@ -0,0 +1,29 @@
+/* ofpath.c - calculate OpenFirmware path names given an OS device */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009, 2011,2012, 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/util/ofpath.h>
+#include <grub/mm.h>
+
+char *
+grub_util_devname_to_ofpath (const char *sys_devname __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+
diff --git a/grub-core/osdep/basic/platform.c b/grub-core/osdep/basic/platform.c
new file mode 100644
index 0000000..a7dafd8
--- /dev/null
+++ b/grub-core/osdep/basic/platform.c
@@ -0,0 +1,32 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/util/install.h>
+
+const char *
+grub_install_get_default_arm_platform (void)
+{
+ return "arm-uboot";
+}
+
+const char *
+grub_install_get_default_x86_platform (void)
+{
+ return "i386-pc";
+}
+
diff --git a/grub-core/osdep/basic/random.c b/grub-core/osdep/basic/random.c
new file mode 100644
index 0000000..b5ccad4
--- /dev/null
+++ b/grub-core/osdep/basic/random.c
@@ -0,0 +1,43 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1992-1999,2001,2003,2004,2005,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <grub/types.h>
+#include <grub/crypto.h>
+#include <grub/auth.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/i18n.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+grub_get_random (void *out, grub_size_t len)
+{
+#warning "No random number generator is available for your OS. \
+Some functions like grub-mkpaswd and installing on UUID-less disks will be \
+disabled."
+ grub_util_error ("%s",
+ /* TRANSLATORS: The OS itself may very well have a random
+ number generator but GRUB doesn't know how to access it. */
+ _("no random number generator is available for your OS"));
+}
diff --git a/grub-core/osdep/blocklist.c b/grub-core/osdep/blocklist.c
new file mode 100644
index 0000000..1f58b0f
--- /dev/null
+++ b/grub-core/osdep/blocklist.c
@@ -0,0 +1,7 @@
+#ifdef __linux__
+#include "linux/blocklist.c"
+#elif defined (__MINGW32__) || defined (__CYGWIN__)
+#include "windows/blocklist.c"
+#else
+#include "generic/blocklist.c"
+#endif
diff --git a/grub-core/osdep/bsd/getroot.c b/grub-core/osdep/bsd/getroot.c
new file mode 100644
index 0000000..dbc6a2f
--- /dev/null
+++ b/grub-core/osdep/bsd/getroot.c
@@ -0,0 +1,204 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <grub/types.h>
+
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+
+#include <sys/wait.h>
+
+# include <sys/ioctl.h>
+# include <sys/disklabel.h> /* struct disklabel */
+# include <sys/disk.h> /* struct dkwedge_info */
+# ifdef HAVE_GETRAWPARTITION
+# include <util.h> /* getrawpartition */
+# endif /* HAVE_GETRAWPARTITION */
+#if defined(__NetBSD__)
+# include <sys/fdio.h>
+#endif
+#if defined(__OpenBSD__)
+# include <sys/dkio.h>
+#endif
+
+char *
+grub_util_part_to_disk (const char *os_dev, struct stat *st,
+ int *is_part)
+{
+ int rawpart = -1;
+
+ if (! S_ISCHR (st->st_mode))
+ {
+ *is_part = 0;
+ return xstrdup (os_dev);
+ }
+
+# ifdef HAVE_GETRAWPARTITION
+ rawpart = getrawpartition();
+# endif /* HAVE_GETRAWPARTITION */
+ if (rawpart < 0)
+ return xstrdup (os_dev);
+
+#if defined(__NetBSD__)
+ /* NetBSD disk wedges are of the form "/dev/rdk.*". */
+ if (strncmp ("/dev/rdk", os_dev, sizeof("/dev/rdk") - 1) == 0)
+ {
+ struct dkwedge_info dkw;
+ int fd;
+
+ fd = open (os_dev, O_RDONLY);
+ if (fd == -1)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ N_("cannot open `%s': %s"), os_dev,
+ strerror (errno));
+ return xstrdup (os_dev);
+ }
+ if (ioctl (fd, DIOCGWEDGEINFO, &dkw) == -1)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "cannot get disk wedge info of `%s'", os_dev);
+ close (fd);
+ return xstrdup (os_dev);
+ }
+ *is_part = (dkw.dkw_offset != 0);
+ close (fd);
+ return xasprintf ("/dev/r%s%c", dkw.dkw_parent, 'a' + rawpart);
+ }
+#endif
+
+ /* NetBSD (disk label) partitions are of the form "/dev/r[a-z]+[0-9][a-z]". */
+ if (strncmp ("/dev/r", os_dev, sizeof("/dev/r") - 1) == 0 &&
+ (os_dev[sizeof("/dev/r") - 1] >= 'a' && os_dev[sizeof("/dev/r") - 1] <= 'z') &&
+ strncmp ("fd", os_dev + sizeof("/dev/r") - 1, sizeof("fd") - 1) != 0) /* not a floppy device name */
+ {
+ char *path = xstrdup (os_dev);
+ char *p;
+ for (p = path + sizeof("/dev/r"); *p >= 'a' && *p <= 'z'; p++);
+ if (grub_isdigit(*p))
+ {
+ p++;
+ if ((*p >= 'a' && *p <= 'z') && (*(p+1) == '\0'))
+ {
+ if (*p != 'a' + rawpart)
+ *is_part = 1;
+ /* path matches the required regular expression and
+ p points to its last character. */
+ *p = 'a' + rawpart;
+ }
+ }
+ return path;
+ }
+
+ return xstrdup (os_dev);
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
+{
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
+ enum grub_dev_abstraction_types ab __attribute__ ((unused)))
+{
+ return 0;
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *dev)
+{
+ int fd;
+# if defined(__NetBSD__)
+ struct dkwedge_info dkw;
+# endif /* defined(__NetBSD__) */
+ struct disklabel label;
+ int p_index;
+
+ fd = grub_util_fd_open (dev, O_RDONLY);
+ if (fd == -1)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
+ dev, strerror (errno));
+ return 0;
+ }
+
+# if defined(__NetBSD__)
+ /* First handle the case of disk wedges. */
+ if (ioctl (fd, DIOCGWEDGEINFO, &dkw) == 0)
+ {
+ close (fd);
+ return (grub_disk_addr_t) dkw.dkw_offset;
+ }
+# endif /* defined(__NetBSD__) */
+
+ if (ioctl (fd, DIOCGDINFO, &label) == -1)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "cannot get disk label of `%s'", dev);
+ close (fd);
+ return 0;
+ }
+
+ close (fd);
+
+ if (dev[0])
+ p_index = dev[strlen(dev) - 1] - 'a';
+ else
+ p_index = -1;
+
+ if (p_index >= label.d_npartitions || p_index < 0)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "no disk label entry for `%s'", dev);
+ return 0;
+ }
+ return (grub_disk_addr_t) label.d_partitions[p_index].p_offset;
+}
diff --git a/grub-core/osdep/bsd/hostdisk.c b/grub-core/osdep/bsd/hostdisk.c
new file mode 100644
index 0000000..5912d14
--- /dev/null
+++ b/grub-core/osdep/bsd/hostdisk.c
@@ -0,0 +1,130 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+# include <sys/ioctl.h>
+# include <sys/disklabel.h> /* struct disklabel */
+# include <sys/disk.h> /* struct dkwedge_info */
+# ifdef HAVE_GETRAWPARTITION
+# include <util.h> /* getrawpartition */
+# endif /* HAVE_GETRAWPARTITION */
+# if defined(__NetBSD__)
+# include <sys/fdio.h>
+# endif
+# if defined(__OpenBSD__)
+# include <sys/dkio.h>
+# endif
+
+#if defined(__NetBSD__)
+/* Adjust device driver parameters. This function should be called just
+ after successfully opening the device. For now, it simply prevents the
+ floppy driver from retrying operations on failure, as otherwise the
+ driver takes a while to abort when there is no floppy in the drive. */
+static void
+configure_device_driver (grub_util_fd_t fd)
+{
+ struct stat st;
+
+ if (fstat (fd, &st) < 0 || ! S_ISCHR (st.st_mode))
+ return;
+ if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
+ {
+ int floppy_opts;
+
+ if (ioctl (fd, FDIOCGETOPTS, &floppy_opts) == -1)
+ return;
+ floppy_opts |= FDOPT_NORETRY;
+ if (ioctl (fd, FDIOCSETOPTS, &floppy_opts) == -1)
+ return;
+ }
+}
+grub_util_fd_t
+grub_util_fd_open (const char *os_dev, int flags)
+{
+ grub_util_fd_t ret;
+
+#ifdef O_LARGEFILE
+ flags |= O_LARGEFILE;
+#endif
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+
+ ret = open (os_dev, flags, S_IROTH | S_IRGRP | S_IRUSR | S_IWUSR);
+ if (ret >= 0)
+ configure_device_driver (fd);
+ return ret;
+}
+
+#endif
+
+grub_int64_t
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
+{
+ struct disklabel label;
+ unsigned sector_size, log_sector_size;
+
+#if defined(__NetBSD__)
+ grub_hostdisk_configure_device_driver (fd);
+#endif
+
+ if (ioctl (fd, DIOCGDINFO, &label) == -1)
+ return -1;
+
+ sector_size = label.d_secsize;
+ if (sector_size & (sector_size - 1) || !sector_size)
+ return -1;
+ for (log_sector_size = 0;
+ (1 << log_sector_size) < sector_size;
+ log_sector_size++);
+
+ if (log_secsize)
+ *log_secsize = log_sector_size;
+
+ return (grub_uint64_t) label.d_secperunit << log_sector_size;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
diff --git a/grub-core/osdep/compress.c b/grub-core/osdep/compress.c
new file mode 100644
index 0000000..cc808d0
--- /dev/null
+++ b/grub-core/osdep/compress.c
@@ -0,0 +1,5 @@
+#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__AROS__)
+#include "unix/compress.c"
+#else
+#include "basic/compress.c"
+#endif
diff --git a/grub-core/osdep/config.c b/grub-core/osdep/config.c
new file mode 100644
index 0000000..b9f7819
--- /dev/null
+++ b/grub-core/osdep/config.c
@@ -0,0 +1,7 @@
+#if defined (__MINGW32__) && !defined (__CYGWIN__)
+#include "windows/config.c"
+#elif defined (__AROS__)
+#include "aros/config.c"
+#else
+#include "unix/config.c"
+#endif
diff --git a/grub-core/osdep/cputime.c b/grub-core/osdep/cputime.c
new file mode 100644
index 0000000..d3ee4c8
--- /dev/null
+++ b/grub-core/osdep/cputime.c
@@ -0,0 +1,5 @@
+#ifdef __MINGW32__
+#include "windows/cputime.c"
+#else
+#include "unix/cputime.c"
+#endif
diff --git a/grub-core/osdep/devmapper/getroot.c b/grub-core/osdep/devmapper/getroot.c
new file mode 100644
index 0000000..a13a39c
--- /dev/null
+++ b/grub-core/osdep/devmapper/getroot.c
@@ -0,0 +1,347 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <grub/emu/getroot.h>
+#include <grub/mm.h>
+
+#ifdef HAVE_DEVICE_MAPPER
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#if defined(MAJOR_IN_MKDEV)
+#include <sys/mkdev.h>
+#elif defined(MAJOR_IN_SYSMACROS)
+#include <sys/sysmacros.h>
+#endif
+
+#include <libdevmapper.h>
+
+#include <grub/types.h>
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+
+static int
+grub_util_open_dm (const char *os_dev, struct dm_tree **tree,
+ struct dm_tree_node **node)
+{
+ uint32_t maj, min;
+ struct stat st;
+
+ *node = NULL;
+ *tree = NULL;
+
+ if (stat (os_dev, &st) < 0)
+ return 0;
+
+ maj = major (st.st_rdev);
+ min = minor (st.st_rdev);
+
+ if (!dm_is_dm_major (maj))
+ return 0;
+
+ *tree = dm_tree_create ();
+ if (! *tree)
+ {
+ grub_puts_ (N_("Failed to create `device-mapper' tree"));
+ grub_dprintf ("hostdisk", "dm_tree_create failed\n");
+ return 0;
+ }
+
+ if (! dm_tree_add_dev (*tree, maj, min))
+ {
+ grub_dprintf ("hostdisk", "dm_tree_add_dev failed\n");
+ dm_tree_free (*tree);
+ *tree = NULL;
+ return 0;
+ }
+
+ *node = dm_tree_find_node (*tree, maj, min);
+ if (! *node)
+ {
+ grub_dprintf ("hostdisk", "dm_tree_find_node failed\n");
+ dm_tree_free (*tree);
+ *tree = NULL;
+ return 0;
+ }
+ return 1;
+}
+
+static char *
+get_dm_uuid (const char *os_dev)
+{
+ struct dm_tree *tree;
+ struct dm_tree_node *node;
+ const char *node_uuid;
+ char *ret;
+
+ if (!grub_util_open_dm (os_dev, &tree, &node))
+ return NULL;
+
+ node_uuid = dm_tree_node_get_uuid (node);
+ if (! node_uuid)
+ {
+ grub_dprintf ("hostdisk", "%s has no DM uuid\n", os_dev);
+ dm_tree_free (tree);
+ return NULL;
+ }
+
+ ret = grub_strdup (node_uuid);
+
+ dm_tree_free (tree);
+
+ return ret;
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dm_abstraction (const char *os_dev)
+{
+ char *uuid;
+
+ uuid = get_dm_uuid (os_dev);
+
+ if (uuid == NULL)
+ return GRUB_DEV_ABSTRACTION_NONE;
+
+ if (strncmp (uuid, "LVM-", 4) == 0)
+ {
+ grub_free (uuid);
+ return GRUB_DEV_ABSTRACTION_LVM;
+ }
+ if (strncmp (uuid, "CRYPT-LUKS1-", 12) == 0)
+ {
+ grub_free (uuid);
+ return GRUB_DEV_ABSTRACTION_LUKS;
+ }
+
+ grub_free (uuid);
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+void
+grub_util_pull_devmapper (const char *os_dev)
+{
+ struct dm_tree *tree;
+ struct dm_tree_node *node;
+ struct dm_tree_node *child;
+ void *handle = NULL;
+ char *lastsubdev = NULL;
+ char *uuid;
+
+ uuid = get_dm_uuid (os_dev);
+
+ if (!grub_util_open_dm (os_dev, &tree, &node))
+ {
+ grub_free (uuid);
+ return;
+ }
+
+ while ((child = dm_tree_next_child (&handle, node, 0)))
+ {
+ const struct dm_info *dm = dm_tree_node_get_info (child);
+ char *subdev;
+ if (!dm)
+ continue;
+ subdev = grub_find_device ("/dev", makedev (dm->major, dm->minor));
+ if (subdev)
+ {
+ lastsubdev = subdev;
+ grub_util_pull_device (subdev);
+ }
+ }
+ if (uuid && strncmp (uuid, "CRYPT-LUKS1-", sizeof ("CRYPT-LUKS1-") - 1) == 0
+ && lastsubdev)
+ {
+ char *grdev = grub_util_get_grub_dev (lastsubdev);
+ dm_tree_free (tree);
+ if (grdev)
+ {
+ grub_err_t err;
+ err = grub_cryptodisk_cheat_mount (grdev, os_dev);
+ if (err)
+ grub_util_error (_("can't mount encrypted volume `%s': %s"),
+ lastsubdev, grub_errmsg);
+ }
+ grub_free (grdev);
+ }
+ else
+ dm_tree_free (tree);
+ grub_free (uuid);
+}
+
+char *
+grub_util_devmapper_part_to_disk (struct stat *st,
+ int *is_part, const char *path)
+{
+ int major, minor;
+
+ if (grub_util_get_dm_node_linear_info (st->st_rdev,
+ &major, &minor, 0))
+ {
+ *is_part = 1;
+ return grub_find_device ("/dev", makedev (major, minor));
+ }
+ *is_part = 0;
+ return xstrdup (path);
+}
+
+char *
+grub_util_get_devmapper_grub_dev (const char *os_dev)
+{
+ char *uuid, *optr;
+ char *grub_dev;
+
+ uuid = get_dm_uuid (os_dev);
+ if (!uuid)
+ return NULL;
+
+ switch (grub_util_get_dev_abstraction (os_dev))
+ {
+ case GRUB_DEV_ABSTRACTION_LVM:
+ {
+ unsigned i;
+ int dashes[] = { 0, 6, 10, 14, 18, 22, 26, 32, 38, 42, 46, 50, 54, 58};
+
+ grub_dev = xmalloc (grub_strlen (uuid) + 40);
+ optr = grub_stpcpy (grub_dev, "lvmid/");
+ for (i = 0; i < ARRAY_SIZE (dashes) - 1; i++)
+ {
+ memcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i],
+ dashes[i+1] - dashes[i]);
+ optr += dashes[i+1] - dashes[i];
+ *optr++ = '-';
+ }
+ optr = stpcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i]);
+ *optr = '\0';
+ grub_dev[sizeof("lvmid/xxxxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxxxx") - 1]
+ = '/';
+ free (uuid);
+ return grub_dev;
+ }
+
+ case GRUB_DEV_ABSTRACTION_LUKS:
+ {
+ char *dash;
+
+ dash = grub_strchr (uuid + sizeof ("CRYPT-LUKS1-") - 1, '-');
+ if (dash)
+ *dash = 0;
+ grub_dev = grub_xasprintf ("cryptouuid/%s",
+ uuid + sizeof ("CRYPT-LUKS1-") - 1);
+ grub_free (uuid);
+ return grub_dev;
+ }
+
+ default:
+ grub_free (uuid);
+ return NULL;
+ }
+}
+
+char *
+grub_util_get_vg_uuid (const char *os_dev)
+{
+ char *uuid, *vgid;
+ int dashes[] = { 0, 6, 10, 14, 18, 22, 26, 32};
+ unsigned i;
+ char *optr;
+
+ uuid = get_dm_uuid (os_dev);
+ if (!uuid)
+ return NULL;
+
+ vgid = xmalloc (grub_strlen (uuid));
+ optr = vgid;
+ for (i = 0; i < ARRAY_SIZE (dashes) - 1; i++)
+ {
+ memcpy (optr, uuid + sizeof ("LVM-") - 1 + dashes[i],
+ dashes[i+1] - dashes[i]);
+ optr += dashes[i+1] - dashes[i];
+ *optr++ = '-';
+ }
+ optr--;
+ *optr = '\0';
+ grub_free (uuid);
+ return vgid;
+}
+
+void
+grub_util_devmapper_cleanup (void)
+{
+ dm_lib_release ();
+}
+
+#else
+void
+grub_util_pull_devmapper (const char *os_dev __attribute__ ((unused)))
+{
+ return;
+}
+
+void
+grub_util_devmapper_cleanup (void)
+{
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dm_abstraction (const char *os_dev __attribute__ ((unused)))
+{
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+char *
+grub_util_get_vg_uuid (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+char *
+grub_util_devmapper_part_to_disk (struct stat *st __attribute__ ((unused)),
+ int *is_part __attribute__ ((unused)),
+ const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+char *
+grub_util_get_devmapper_grub_dev (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+#endif
diff --git a/grub-core/osdep/devmapper/hostdisk.c b/grub-core/osdep/devmapper/hostdisk.c
new file mode 100644
index 0000000..a8afc0c
--- /dev/null
+++ b/grub-core/osdep/devmapper/hostdisk.c
@@ -0,0 +1,230 @@
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+#if defined(MAJOR_IN_MKDEV)
+#include <sys/mkdev.h>
+#elif defined(MAJOR_IN_SYSMACROS)
+#include <sys/sysmacros.h>
+#endif
+
+#ifdef HAVE_DEVICE_MAPPER
+# include <libdevmapper.h>
+
+static void device_mapper_null_log (int level __attribute__ ((unused)),
+ const char *file __attribute__ ((unused)),
+ int line __attribute__ ((unused)),
+ int dm_errno __attribute__ ((unused)),
+ const char *f __attribute__ ((unused)),
+ ...)
+{
+}
+
+int
+grub_device_mapper_supported (void)
+{
+ static int supported = -1;
+
+ if (supported == -1)
+ {
+ struct dm_task *dmt;
+
+ /* Suppress annoying log messages. */
+ dm_log_with_errno_init (&device_mapper_null_log);
+
+ dmt = dm_task_create (DM_DEVICE_VERSION);
+ supported = (dmt != NULL);
+ if (dmt)
+ dm_task_destroy (dmt);
+
+ /* Restore the original logger. */
+ dm_log_with_errno_init (NULL);
+ }
+
+ return supported;
+}
+
+int
+grub_util_device_is_mapped (const char *dev)
+{
+ struct stat st;
+
+ if (!grub_device_mapper_supported ())
+ return 0;
+
+ if (stat (dev, &st) < 0)
+ return 0;
+
+#if GRUB_DISK_DEVS_ARE_CHAR
+ if (! S_ISCHR (st.st_mode))
+#else
+ if (! S_ISBLK (st.st_mode))
+#endif
+ return 0;
+
+ return dm_is_dm_major (major (st.st_rdev));
+}
+
+int
+grub_util_device_is_mapped_stat (struct stat *st)
+{
+#if GRUB_DISK_DEVS_ARE_CHAR
+ if (! S_ISCHR (st->st_mode))
+#else
+ if (! S_ISBLK (st->st_mode))
+#endif
+ return 0;
+
+ if (!grub_device_mapper_supported ())
+ return 0;
+
+ return dm_is_dm_major (major (st->st_rdev));
+}
+
+
+int
+grub_util_get_dm_node_linear_info (dev_t dev,
+ int *maj, int *min,
+ grub_disk_addr_t *st)
+{
+ struct dm_task *dmt;
+ void *next = NULL;
+ uint64_t length, start;
+ char *target, *params;
+ const char *ptr;
+ int major = 0, minor = 0;
+ int first = 1;
+ grub_disk_addr_t partstart = 0;
+ const char *node_uuid;
+
+ major = major (dev);
+ minor = minor (dev);
+
+ while (1)
+ {
+ dmt = dm_task_create(DM_DEVICE_TABLE);
+ if (!dmt)
+ break;
+
+ if (! (dm_task_set_major_minor (dmt, major, minor, 0)))
+ {
+ dm_task_destroy (dmt);
+ break;
+ }
+ dm_task_no_open_count(dmt);
+ if (!dm_task_run(dmt))
+ {
+ dm_task_destroy (dmt);
+ break;
+ }
+ node_uuid = dm_task_get_uuid (dmt);
+ if (node_uuid && (strncmp (node_uuid, "LVM-", 4) == 0
+ || strncmp (node_uuid, "mpath-", 6) == 0))
+ {
+ dm_task_destroy (dmt);
+ break;
+ }
+
+ next = dm_get_next_target(dmt, next, &start, &length,
+ &target, &params);
+ if (grub_strcmp (target, "linear") != 0)
+ {
+ dm_task_destroy (dmt);
+ break;
+ }
+ major = grub_strtoul (params, &ptr, 10);
+ if (grub_errno)
+ {
+ dm_task_destroy (dmt);
+ grub_errno = GRUB_ERR_NONE;
+ return 0;
+ }
+ if (*ptr != ':')
+ {
+ dm_task_destroy (dmt);
+ return 0;
+ }
+ ptr++;
+ minor = grub_strtoul (ptr, &ptr, 10);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ dm_task_destroy (dmt);
+ return 0;
+ }
+
+ if (*ptr != ' ')
+ {
+ dm_task_destroy (dmt);
+ return 0;
+ }
+ ptr++;
+ partstart += grub_strtoull (ptr, &ptr, 10);
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ dm_task_destroy (dmt);
+ return 0;
+ }
+
+ dm_task_destroy (dmt);
+ first = 0;
+ if (!dm_is_dm_major (major))
+ break;
+ }
+ if (first)
+ return 0;
+ if (maj)
+ *maj = major;
+ if (min)
+ *min = minor;
+ if (st)
+ *st = partstart;
+ return 1;
+}
+#else
+
+int
+grub_util_device_is_mapped (const char *dev __attribute__ ((unused)))
+{
+ return 0;
+}
+
+int
+grub_util_get_dm_node_linear_info (dev_t dev __attribute__ ((unused)),
+ int *maj __attribute__ ((unused)),
+ int *min __attribute__ ((unused)),
+ grub_disk_addr_t *st __attribute__ ((unused)))
+{
+ return 0;
+}
+
+int
+grub_util_device_is_mapped_stat (struct stat *st __attribute__ ((unused)))
+{
+ return 0;
+}
+
+#endif
diff --git a/grub-core/osdep/dl.c b/grub-core/osdep/dl.c
new file mode 100644
index 0000000..c511747
--- /dev/null
+++ b/grub-core/osdep/dl.c
@@ -0,0 +1,5 @@
+#if defined (__MINGW32__) || defined (__CYGWIN__)
+#include "windows/dl.c"
+#else
+#include "unix/dl.c"
+#endif
diff --git a/grub-core/osdep/emuconsole.c b/grub-core/osdep/emuconsole.c
new file mode 100644
index 0000000..13ede31
--- /dev/null
+++ b/grub-core/osdep/emuconsole.c
@@ -0,0 +1,5 @@
+#if defined (__MINGW32__) && !defined (__CYGWIN__)
+#include "windows/emuconsole.c"
+#else
+#include "unix/emuconsole.c"
+#endif
diff --git a/grub-core/osdep/emunet.c b/grub-core/osdep/emunet.c
new file mode 100644
index 0000000..4b0bac4
--- /dev/null
+++ b/grub-core/osdep/emunet.c
@@ -0,0 +1,5 @@
+#if defined (__linux__)
+#include "linux/emunet.c"
+#else
+#include "basic/emunet.c"
+#endif
diff --git a/grub-core/osdep/exec.c b/grub-core/osdep/exec.c
new file mode 100644
index 0000000..9dcd926
--- /dev/null
+++ b/grub-core/osdep/exec.c
@@ -0,0 +1,3 @@
+#if (!defined (__MINGW32__) || defined (__CYGWIN__)) && !defined (__AROS__)
+#include "unix/exec.c"
+#endif
diff --git a/grub-core/osdep/freebsd/getroot.c b/grub-core/osdep/freebsd/getroot.c
new file mode 100644
index 0000000..b1e8244
--- /dev/null
+++ b/grub-core/osdep/freebsd/getroot.c
@@ -0,0 +1,364 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <grub/types.h>
+# include <sys/param.h>
+# include <sys/mount.h>
+# include <sys/disk.h> /* DIOCGMEDIASIZE */
+# include <sys/param.h>
+# include <sys/sysctl.h>
+#include <libgeom.h>
+
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/cryptodisk.h>
+
+#include <sys/wait.h>
+
+#include <libgeom.h>
+
+#define LVM_DEV_MAPPER_STRING "/dev/linux_lvm/"
+
+static const char *
+grub_util_get_geom_abstraction (const char *dev)
+{
+ char *whole;
+ struct gmesh mesh;
+ struct gclass *class;
+ const char *name;
+ int err;
+
+ if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return 0;
+ name = dev + sizeof ("/dev/") - 1;
+ grub_util_follow_gpart_up (name, NULL, &whole);
+
+ grub_util_info ("following geom '%s'", name);
+
+ err = geom_gettree (&mesh);
+ if (err != 0)
+ /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
+ Usually left untranslated.
+ */
+ grub_util_error ("%s", _("couldn't open geom"));
+
+ LIST_FOREACH (class, &mesh.lg_class, lg_class)
+ {
+ struct ggeom *geom;
+ LIST_FOREACH (geom, &class->lg_geom, lg_geom)
+ {
+ struct gprovider *provider;
+ LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
+ if (strcmp (provider->lg_name, name) == 0)
+ return class->lg_name;
+ }
+ }
+ return NULL;
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev)
+{
+ const char *abstrac;
+ abstrac = grub_util_get_geom_abstraction (os_dev);
+ grub_util_info ("abstraction of %s is %s", os_dev, abstrac);
+ if (abstrac && grub_strcasecmp (abstrac, "eli") == 0)
+ return GRUB_DEV_ABSTRACTION_GELI;
+
+ /* Check for LVM. */
+ if (!strncmp (os_dev, LVM_DEV_MAPPER_STRING, sizeof(LVM_DEV_MAPPER_STRING)-1))
+ return GRUB_DEV_ABSTRACTION_LVM;
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+char *
+grub_util_part_to_disk (const char *os_dev, struct stat *st,
+ int *is_part)
+{
+ char *out, *out2;
+
+ if (! S_ISCHR (st->st_mode))
+ {
+ *is_part = 0;
+ return xstrdup (os_dev);
+ }
+
+ if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return xstrdup (os_dev);
+ grub_util_follow_gpart_up (os_dev + sizeof ("/dev/") - 1, NULL, &out);
+
+ if (grub_strcmp (os_dev + sizeof ("/dev/") - 1, out) != 0)
+ *is_part = 1;
+ out2 = xasprintf ("/dev/%s", out);
+ free (out);
+
+ return out2;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev,
+ enum grub_dev_abstraction_types ab)
+{
+ switch (ab)
+ {
+ case GRUB_DEV_ABSTRACTION_GELI:
+ {
+ char *whole;
+ struct gmesh mesh;
+ struct gclass *class;
+ const char *name;
+ int err;
+ char *lastsubdev = NULL;
+
+ if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return 1;
+ name = os_dev + sizeof ("/dev/") - 1;
+ grub_util_follow_gpart_up (name, NULL, &whole);
+
+ grub_util_info ("following geom '%s'", name);
+
+ err = geom_gettree (&mesh);
+ if (err != 0)
+ /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
+ Usually left untranslated.
+ */
+ grub_util_error ("%s", _("couldn't open geom"));
+
+ LIST_FOREACH (class, &mesh.lg_class, lg_class)
+ {
+ struct ggeom *geom;
+ LIST_FOREACH (geom, &class->lg_geom, lg_geom)
+ {
+ struct gprovider *provider;
+ LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
+ if (strcmp (provider->lg_name, name) == 0)
+ {
+ struct gconsumer *consumer;
+ char *fname;
+
+ LIST_FOREACH (consumer, &geom->lg_consumer, lg_consumer)
+ break;
+ if (!consumer)
+ grub_util_error ("%s",
+ _("couldn't find geli consumer"));
+ fname = xasprintf ("/dev/%s", consumer->lg_provider->lg_name);
+ grub_util_info ("consumer %s", consumer->lg_provider->lg_name);
+ lastsubdev = consumer->lg_provider->lg_name;
+ grub_util_pull_device (fname);
+ free (fname);
+ }
+ }
+ }
+ if (ab == GRUB_DEV_ABSTRACTION_GELI && lastsubdev)
+ {
+ char *fname = xasprintf ("/dev/%s", lastsubdev);
+ char *grdev = grub_util_get_grub_dev (fname);
+ free (fname);
+
+ if (grdev)
+ {
+ grub_err_t gr_err;
+ gr_err = grub_cryptodisk_cheat_mount (grdev, os_dev);
+ if (gr_err)
+ grub_util_error (_("can't mount encrypted volume `%s': %s"),
+ lastsubdev, grub_errmsg);
+ }
+
+ grub_free (grdev);
+ }
+ }
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev)
+{
+ char *grub_dev = NULL;
+
+ switch (grub_util_get_dev_abstraction (os_dev))
+ {
+ /* Fallback for non-devmapper build. In devmapper-builds LVM is handled
+ in rub_util_get_devmapper_grub_dev and this point isn't reached.
+ */
+ case GRUB_DEV_ABSTRACTION_LVM:
+ {
+ unsigned short len;
+ grub_size_t offset = sizeof (LVM_DEV_MAPPER_STRING) - 1;
+
+ len = strlen (os_dev) - offset + 1;
+ grub_dev = xmalloc (len + sizeof ("lvm/"));
+
+ grub_memcpy (grub_dev, "lvm/", sizeof ("lvm/") - 1);
+ grub_memcpy (grub_dev + sizeof ("lvm/") - 1, os_dev + offset, len);
+ }
+ break;
+
+ case GRUB_DEV_ABSTRACTION_GELI:
+ {
+ char *whole;
+ struct gmesh mesh;
+ struct gclass *class;
+ const char *name;
+ int err;
+
+ if (strncmp (os_dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return 0;
+ name = os_dev + sizeof ("/dev/") - 1;
+ grub_util_follow_gpart_up (name, NULL, &whole);
+
+ grub_util_info ("following geom '%s'", name);
+
+ err = geom_gettree (&mesh);
+ if (err != 0)
+ /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
+ Usually left untranslated.
+ */
+ grub_util_error ("%s", _("couldn't open geom"));
+
+ LIST_FOREACH (class, &mesh.lg_class, lg_class)
+ {
+ struct ggeom *geom;
+ LIST_FOREACH (geom, &class->lg_geom, lg_geom)
+ {
+ struct gprovider *provider;
+ LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
+ if (strcmp (provider->lg_name, name) == 0)
+ {
+ struct gconsumer *consumer;
+ char *fname;
+ char *uuid;
+
+ LIST_FOREACH (consumer, &geom->lg_consumer, lg_consumer)
+ break;
+ if (!consumer)
+ grub_util_error ("%s",
+ _("couldn't find geli consumer"));
+ fname = xasprintf ("/dev/%s", consumer->lg_provider->lg_name);
+ uuid = grub_util_get_geli_uuid (fname);
+ if (!uuid)
+ grub_util_error ("%s",
+ _("couldn't retrieve geli UUID"));
+ grub_dev = xasprintf ("cryptouuid/%s", uuid);
+ free (fname);
+ free (uuid);
+ }
+ }
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ return grub_dev;
+}
+
+/* FIXME: geom actually gives us the whole container hierarchy.
+ It can be used more efficiently than this. */
+void
+grub_util_follow_gpart_up (const char *name, grub_disk_addr_t *off_out, char **name_out)
+{
+ struct gmesh mesh;
+ struct gclass *class;
+ int err;
+ struct ggeom *geom;
+
+ grub_util_info ("following geom '%s'", name);
+
+ err = geom_gettree (&mesh);
+ if (err != 0)
+ /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
+ Usually left untranslated.
+ */
+ grub_util_error ("%s", _("couldn't open geom"));
+
+ LIST_FOREACH (class, &mesh.lg_class, lg_class)
+ if (strcasecmp (class->lg_name, "part") == 0)
+ break;
+ if (!class)
+ /* TRANSLATORS: geom is the name of (k)FreeBSD device framework.
+ Usually left untranslated. "part" is the identifier of one of its
+ classes. */
+ grub_util_error ("%s", _("couldn't find geom `part' class"));
+
+ LIST_FOREACH (geom, &class->lg_geom, lg_geom)
+ {
+ struct gprovider *provider;
+ LIST_FOREACH (provider, &geom->lg_provider, lg_provider)
+ if (strcmp (provider->lg_name, name) == 0)
+ {
+ char *name_tmp = xstrdup (geom->lg_name);
+ grub_disk_addr_t off = 0;
+ struct gconfig *config;
+ grub_util_info ("geom '%s' has parent '%s'", name, geom->lg_name);
+
+ grub_util_follow_gpart_up (name_tmp, &off, name_out);
+ free (name_tmp);
+ LIST_FOREACH (config, &provider->lg_config, lg_config)
+ if (strcasecmp (config->lg_name, "offset") == 0)
+ off += strtoull (config->lg_val, 0, 10) / provider->lg_sectorsize;
+ if (off_out)
+ *off_out = off;
+ return;
+ }
+ }
+ grub_util_info ("geom '%s' has no parent", name);
+ if (name_out)
+ *name_out = xstrdup (name);
+ if (off_out)
+ *off_out = 0;
+}
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *dev)
+{
+ grub_disk_addr_t out;
+ if (strncmp (dev, "/dev/", sizeof ("/dev/") - 1) != 0)
+ return 0;
+ grub_util_follow_gpart_up (dev + sizeof ("/dev/") - 1, &out, NULL);
+
+ return out;
+}
diff --git a/grub-core/osdep/freebsd/hostdisk.c b/grub-core/osdep/freebsd/hostdisk.c
new file mode 100644
index 0000000..6145d07
--- /dev/null
+++ b/grub-core/osdep/freebsd/hostdisk.c
@@ -0,0 +1,128 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+# include <sys/disk.h> /* DIOCGMEDIASIZE */
+# include <sys/param.h>
+# include <sys/sysctl.h>
+# include <sys/mount.h>
+# include <libgeom.h>
+
+grub_int64_t
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
+{
+ unsigned long long nr;
+ unsigned sector_size, log_sector_size;
+
+ if (ioctl (fd, DIOCGMEDIASIZE, &nr))
+ return -1;
+
+ if (ioctl (fd, DIOCGSECTORSIZE, &sector_size))
+ return -1;
+ if (sector_size & (sector_size - 1) || !sector_size)
+ return -1;
+ for (log_sector_size = 0;
+ (1 << log_sector_size) < sector_size;
+ log_sector_size++);
+
+ if (log_secsize)
+ *log_secsize = log_sector_size;
+
+ if (nr & (sector_size - 1))
+ grub_util_error ("%s", _("unaligned device size"));
+
+ return nr;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
+
+grub_util_fd_t
+grub_util_fd_open (const char *os_dev, int flags)
+{
+ grub_util_fd_t ret;
+ int sysctl_flags, sysctl_oldflags;
+ size_t sysctl_size = sizeof (sysctl_flags);
+
+#ifdef O_LARGEFILE
+ flags |= O_LARGEFILE;
+#endif
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+
+ if (sysctlbyname ("kern.geom.debugflags", &sysctl_oldflags, &sysctl_size, NULL, 0))
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, "cannot get current flags of sysctl kern.geom.debugflags");
+ return GRUB_UTIL_FD_INVALID;
+ }
+ sysctl_flags = sysctl_oldflags | 0x10;
+ if (! (sysctl_oldflags & 0x10)
+ && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_flags, sysctl_size))
+ {
+ if (errno == EPERM)
+ /* Running as an unprivileged user; don't worry about restoring
+ flags, although if we try to write to anything interesting such
+ as the MBR then we may fail later. */
+ sysctl_oldflags = 0x10;
+ else
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags of sysctl kern.geom.debugflags");
+ return GRUB_UTIL_FD_INVALID;
+ }
+ }
+
+ ret = open (os_dev, flags, S_IROTH | S_IRGRP | S_IRUSR | S_IWUSR);
+
+ if (! (sysctl_oldflags & 0x10)
+ && sysctlbyname ("kern.geom.debugflags", NULL , 0, &sysctl_oldflags, sysctl_size))
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, "cannot set flags back to the old value for sysctl kern.geom.debugflags");
+ close (ret);
+ return GRUB_UTIL_FD_INVALID;
+ }
+
+ return ret;
+}
diff --git a/grub-core/osdep/generic/blocklist.c b/grub-core/osdep/generic/blocklist.c
new file mode 100644
index 0000000..2d90403
--- /dev/null
+++ b/grub-core/osdep/generic/blocklist.c
@@ -0,0 +1,132 @@
+/* grub-setup.c - make GRUB usable */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <grub/disk.h>
+#include <grub/file.h>
+#include <grub/partition.h>
+#include <grub/util/misc.h>
+#include <grub/util/install.h>
+#include <grub/emu/hostdisk.h>
+
+#include <string.h>
+
+#define MAX_TRIES 5
+
+void
+grub_install_get_blocklist (grub_device_t root_dev,
+ const char *core_path, const char *core_img,
+ size_t core_size,
+ void (*callback) (grub_disk_addr_t sector,
+ unsigned offset,
+ unsigned length,
+ void *data),
+ void *hook_data)
+{
+ int i;
+ char *tmp_img;
+ char *core_path_dev;
+
+ core_path_dev = grub_make_system_path_relative_to_its_root (core_path);
+
+ /* Make sure that GRUB reads the identical image as the OS. */
+ tmp_img = xmalloc (core_size);
+
+ for (i = 0; i < MAX_TRIES; i++)
+ {
+ grub_file_t file;
+
+ grub_util_info ((i == 0) ? _("attempting to read the core image `%s' from GRUB")
+ : _("attempting to read the core image `%s' from GRUB again"),
+ core_path_dev);
+
+ grub_disk_cache_invalidate_all ();
+
+ file = grub_file_open (core_path_dev, GRUB_FILE_TYPE_NONE | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (file)
+ {
+ if (grub_file_size (file) != core_size)
+ grub_util_info ("succeeded in opening the core image but the size is different (%d != %d)",
+ (int) grub_file_size (file), (int) core_size);
+ else if (grub_file_read (file, tmp_img, core_size)
+ != (grub_ssize_t) core_size)
+ grub_util_info ("succeeded in opening the core image but cannot read %d bytes",
+ (int) core_size);
+ else if (memcmp (core_img, tmp_img, core_size) != 0)
+ {
+#if 0
+ FILE *dump;
+ FILE *dump2;
+
+ dump = fopen ("dump.img", "wb");
+ if (dump)
+ {
+ fwrite (tmp_img, 1, core_size, dump);
+ fclose (dump);
+ }
+
+ dump2 = fopen ("dump2.img", "wb");
+ if (dump2)
+ {
+ fwrite (core_img, 1, core_size, dump2);
+ fclose (dump2);
+ }
+
+#endif
+ grub_util_info ("succeeded in opening the core image but the data is different");
+ }
+ else
+ {
+ grub_file_close (file);
+ break;
+ }
+
+ grub_file_close (file);
+ }
+ else
+ grub_util_info ("couldn't open the core image");
+
+ if (grub_errno)
+ grub_util_info ("error message = %s", grub_errmsg);
+
+ grub_errno = GRUB_ERR_NONE;
+ grub_util_biosdisk_flush (root_dev->disk);
+ sleep (1);
+ }
+
+ if (i == MAX_TRIES)
+ grub_util_error (_("cannot read `%s' correctly"), core_path_dev);
+
+ grub_file_t file;
+ /* Now read the core image to determine where the sectors are. */
+ file = grub_file_open (core_path_dev, GRUB_FILE_TYPE_NONE | GRUB_FILE_TYPE_NO_DECOMPRESS);
+ if (! file)
+ grub_util_error ("%s", grub_errmsg);
+
+ file->read_hook = callback;
+ file->read_hook_data = hook_data;
+ if (grub_file_read (file, tmp_img, core_size) != (grub_ssize_t) core_size)
+ grub_util_error ("%s", _("failed to read the sectors of the core image"));
+
+ grub_file_close (file);
+ free (tmp_img);
+
+ free (core_path_dev);
+}
diff --git a/grub-core/osdep/getroot.c b/grub-core/osdep/getroot.c
new file mode 100644
index 0000000..69a80e9
--- /dev/null
+++ b/grub-core/osdep/getroot.c
@@ -0,0 +1,22 @@
+#ifdef __linux__
+#include "linux/getroot.c"
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include "freebsd/getroot.c"
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#include "bsd/getroot.c"
+#elif defined(__APPLE__)
+#include "apple/getroot.c"
+#elif defined(__sun__)
+#include "sun/getroot.c"
+#elif defined(__GNU__)
+#include "hurd/getroot.c"
+#elif defined(__CYGWIN__) || defined (__MINGW32__)
+#include "windows/getroot.c"
+#elif defined(__AROS__)
+#include "aros/getroot.c"
+#elif defined (__HAIKU__)
+#include "haiku/getroot.c"
+#else
+# warning "No getroot OS-specific functions is available for your system. Device detection may not work properly."
+#include "basic/getroot.c"
+#endif
diff --git a/grub-core/osdep/haiku/getroot.c b/grub-core/osdep/haiku/getroot.c
new file mode 100644
index 0000000..4e123c0
--- /dev/null
+++ b/grub-core/osdep/haiku/getroot.c
@@ -0,0 +1,105 @@
+#include <config.h>
+#include <config-util.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <stdint.h>
+#include <grub/util/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <fs_info.h>
+#include <Drivers.h>
+#include <StorageDefs.h>
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
+{
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
+ enum grub_dev_abstraction_types ab __attribute__ ((unused)))
+{
+ return 0;
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+char **
+grub_guess_root_devices (const char *dir_in)
+{
+ dev_t dv = dev_for_path (dir_in);
+ fs_info inf;
+ char **ret;
+ if (fs_stat_dev (dv, &inf) != B_OK)
+ return NULL;
+ ret = xmalloc (2 * sizeof (ret[0]));
+ ret[0] = xstrdup (inf.device_name);
+ ret[1] = NULL;
+ return ret;
+}
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *dev)
+{
+ partition_info part;
+ grub_disk_addr_t ret;
+ int fd = open (dev, O_RDONLY);
+ if (fd < 0)
+ return 0;
+ if (ioctl (fd, B_GET_PARTITION_INFO, &part, sizeof (part)) < 0)
+ {
+ close (fd);
+ return 0;
+ }
+ ret = part.offset;
+ close (fd);
+ fd = open (part.device, O_RDONLY);
+
+ device_geometry geo;
+ if (ioctl (fd, B_GET_GEOMETRY, &geo, sizeof (geo)) < 0)
+ return 0;
+ ret /= geo.bytes_per_sector ? : 512;
+ close (fd);
+ return ret;
+}
+
+char *
+grub_util_part_to_disk (const char *os_dev,
+ struct stat *st __attribute__ ((unused)),
+ int *is_part)
+{
+ char *ret;
+ partition_info part;
+ int fd = open (os_dev, O_RDONLY);
+ *is_part = 0;
+
+ if (fd < 0)
+ return xstrdup (os_dev);
+ if (ioctl (fd, B_GET_PARTITION_INFO, &part, sizeof (part)) < 0)
+ {
+ close (fd);
+ return xstrdup (os_dev);
+ }
+ ret = xstrdup (part.device);
+ close (fd);
+ *is_part=1;
+ return ret;
+}
+
+int
+grub_util_biosdisk_is_floppy (grub_disk_t disk)
+{
+ const char *dname;
+
+ dname = grub_util_biosdisk_get_osdev (disk);
+
+ return (strncmp (dname, "/dev/disk/floppy/", sizeof ("/dev/disk/floppy/") - 1)
+ == 0);
+}
diff --git a/grub-core/osdep/haiku/hostdisk.c b/grub-core/osdep/haiku/hostdisk.c
new file mode 100644
index 0000000..5623539
--- /dev/null
+++ b/grub-core/osdep/haiku/hostdisk.c
@@ -0,0 +1,69 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+#include <sys/ioctl.h>
+#include <Drivers.h>
+#include <StorageDefs.h>
+
+grub_int64_t
+grub_util_get_fd_size_os (grub_util_fd_t fd,
+ const char *name __attribute__ ((unused)),
+ unsigned *log_secsize)
+{
+ device_geometry part;
+ unsigned lg;
+ if (ioctl (fd, B_GET_GEOMETRY, &part, sizeof (part)) < 0)
+ return -1;
+ for (lg = 0; (1 << lg) < part.bytes_per_sector; lg++);
+ if (log_secsize)
+ *log_secsize= lg;
+ return ((grub_uint64_t) part.cylinder_count
+ * (grub_uint64_t) part.head_count
+ * (grub_uint64_t) part.sectors_per_track
+ * (grub_uint64_t) part.bytes_per_sector);
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
diff --git a/grub-core/osdep/hostdisk.c b/grub-core/osdep/hostdisk.c
new file mode 100644
index 0000000..1853979
--- /dev/null
+++ b/grub-core/osdep/hostdisk.c
@@ -0,0 +1,22 @@
+#ifdef __linux__
+#include "linux/hostdisk.c"
+#elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include "freebsd/hostdisk.c"
+#elif defined(__NetBSD__) || defined(__OpenBSD__)
+#include "bsd/hostdisk.c"
+#elif defined(__APPLE__)
+#include "apple/hostdisk.c"
+#elif defined(__sun__)
+#include "sun/hostdisk.c"
+#elif defined(__GNU__)
+#include "hurd/hostdisk.c"
+#elif defined(__CYGWIN__) || defined(__MINGW32__)
+#include "windows/hostdisk.c"
+#elif defined(__AROS__)
+#include "aros/hostdisk.c"
+#elif defined (__HAIKU__)
+#include "haiku/hostdisk.c"
+#else
+# warning "No hostdisk OS-specific functions is available for your system. Device detection may not work properly."
+#include "basic/hostdisk.c"
+#endif
diff --git a/grub-core/osdep/hurd/getroot.c b/grub-core/osdep/hurd/getroot.c
new file mode 100644
index 0000000..c66b206
--- /dev/null
+++ b/grub-core/osdep/hurd/getroot.c
@@ -0,0 +1,247 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <grub/types.h>
+
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+
+#include <sys/wait.h>
+
+#include <hurd.h>
+#include <hurd/lookup.h>
+#include <hurd/fs.h>
+#include <sys/mman.h>
+
+static char *
+grub_util_find_hurd_root_device (const char *path)
+{
+ file_t file;
+ error_t err;
+ char *argz = NULL, *name = NULL, *ret;
+ size_t argz_len = 0;
+ int i;
+
+ file = file_name_lookup (path, 0, 0);
+ if (file == MACH_PORT_NULL)
+ /* TRANSLATORS: The first %s is the file being looked at, the second %s is
+ the error message. */
+ grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
+
+ /* This returns catenated 0-terminated strings. */
+ err = file_get_fs_options (file, &argz, &argz_len);
+ if (err)
+ /* TRANSLATORS: On GNU/Hurd, a "translator" is similar to a filesystem
+ mount, but handled by a userland daemon, whose invocation command line
+ is being fetched here. First %s is the file being looked at (for which
+ we are fetching the "translator" command line), second %s is the error
+ message.
+ */
+ grub_util_error (_("cannot get translator command line "
+ "for path `%s': %s"), path, strerror(err));
+ if (argz_len == 0)
+ grub_util_error (_("translator command line is empty for path `%s'"), path);
+
+ /* Make sure the string is terminated. */
+ argz[argz_len-1] = 0;
+
+ /* Skip first word (translator path) and options. */
+ for (i = strlen (argz) + 1; i < argz_len; i += strlen (argz + i) + 1)
+ {
+ if (argz[i] != '-')
+ {
+ /* Non-option. Only accept one, assumed to be the FS path. */
+ /* XXX: this should be replaced by an RPC to the translator. */
+ if (name)
+ /* TRANSLATORS: we expect to get something like
+ /hurd/foobar --option1 --option2=baz /dev/something
+ */
+ grub_util_error (_("translator `%s' for path `%s' has several "
+ "non-option words, at least `%s' and `%s'"),
+ argz, path, name, argz + i);
+ name = argz + i;
+ }
+ }
+
+ if (!name)
+ /* TRANSLATORS: we expect to get something like
+ /hurd/foobar --option1 --option2=baz /dev/something
+ */
+ grub_util_error (_("translator `%s' for path `%s' is given only options, "
+ "cannot find device part"), argz, path);
+
+ if (strncmp (name, "device:", sizeof ("device:") - 1) == 0)
+ {
+ char *dev_name = name + sizeof ("device:") - 1;
+ size_t size = sizeof ("/dev/") - 1 + strlen (dev_name) + 1;
+ char *next;
+ ret = malloc (size);
+ next = stpncpy (ret, "/dev/", size);
+ stpncpy (next, dev_name, size - (next - ret));
+ }
+ else if (!strncmp (name, "file:", sizeof ("file:") - 1))
+ ret = strdup (name + sizeof ("file:") - 1);
+ else
+ ret = strdup (name);
+
+ munmap (argz, argz_len);
+ return ret;
+}
+
+static int
+is_fulldisk (const char *child, const char *parent)
+{
+ if (strcmp (parent, child) == 0)
+ return 1;
+ if (strncmp (parent, "/dev/", sizeof ("/dev/") - 1) == 0
+ && child[0] !=0 && strcmp (parent + sizeof ("/dev/") - 1, child) == 0)
+ return 1;
+ if (strncmp (child, "/dev/", sizeof ("/dev/") - 1) == 0
+ && parent[0] != 0 && strcmp (child + sizeof ("/dev/") - 1, parent) == 0)
+ return 1;
+ return 0;
+}
+
+char *
+grub_util_part_to_disk (const char *os_dev,
+ struct stat *st,
+ int *is_part)
+{
+ char *path;
+ grub_disk_addr_t offset;
+ char *p;
+
+ if (! S_ISBLK (st->st_mode))
+ {
+ *is_part = 0;
+ return xstrdup (os_dev);
+ }
+
+ if (!grub_util_hurd_get_disk_info (os_dev, NULL, &offset, NULL, &path))
+ return xstrdup (os_dev);
+
+ /* Some versions of Hurd use badly glued Linux code to handle partitions
+ resulting in partitions being promoted to disks. */
+ if (path && !(offset == 0 && is_fulldisk (path, os_dev)
+ && (strncmp ("/dev/sd", os_dev, 7) == 0
+ || strncmp ("/dev/hd", os_dev, 7) == 0)))
+ {
+ *is_part = !is_fulldisk (path, os_dev);
+ if (path[0] != '/')
+ {
+ char *n = xasprintf ("/dev/%s", path);
+ free (path);
+ path = n;
+ }
+ return path;
+ }
+ free (path);
+
+ path = xstrdup (os_dev);
+
+ p = strchr (path + 7, 's');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+ return path;
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
+{
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
+ enum grub_dev_abstraction_types ab __attribute__ ((unused)))
+{
+ return 0;
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *dev)
+{
+ grub_uint32_t secsize;
+ grub_disk_addr_t offset;
+ char *path;
+ if (!grub_util_hurd_get_disk_info (dev, &secsize, &offset, NULL, &path))
+ return 0;
+ if (path && !(offset == 0 && is_fulldisk (path, dev)
+ && (strncmp ("/dev/sd", dev, 7) == 0
+ || strncmp ("/dev/hd", dev, 7) == 0)))
+ {
+ free (path);
+ return (secsize / 512) * offset;
+ }
+ free (path);
+ return -1;
+}
+
+char **
+grub_guess_root_devices (const char *dir)
+{
+ char **os_dev = NULL;
+
+ os_dev = xmalloc (2 * sizeof (os_dev[0]));
+
+ /* GNU/Hurd specific function. */
+ os_dev[0] = grub_util_find_hurd_root_device (dir);
+
+ if (!os_dev[0])
+ {
+ free (os_dev);
+ return 0;
+ }
+
+ os_dev[1] = 0;
+
+ return os_dev;
+}
diff --git a/grub-core/osdep/hurd/hostdisk.c b/grub-core/osdep/hurd/hostdisk.c
new file mode 100644
index 0000000..c47b5a5
--- /dev/null
+++ b/grub-core/osdep/hurd/hostdisk.c
@@ -0,0 +1,146 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <hurd.h>
+#include <hurd/lookup.h>
+#include <hurd/fs.h>
+#include <sys/mman.h>
+
+int
+grub_util_hurd_get_disk_info (const char *dev, grub_uint32_t *secsize, grub_disk_addr_t *offset,
+ grub_disk_addr_t *size, char **parent)
+{
+ file_t file;
+ mach_port_t *ports;
+ int *ints;
+ loff_t *offsets;
+ char *data;
+ error_t err;
+ mach_msg_type_number_t num_ports = 0, num_ints = 0, num_offsets = 0, data_len = 0;
+
+ file = file_name_lookup (dev, 0, 0);
+ if (file == MACH_PORT_NULL)
+ return 0;
+
+ err = file_get_storage_info (file,
+ &ports, &num_ports,
+ &ints, &num_ints,
+ &offsets, &num_offsets,
+ &data, &data_len);
+
+ if (num_ints < 1)
+ grub_util_error (_("Storage information for `%s' does not include type"), dev);
+ if (ints[0] != STORAGE_DEVICE)
+ grub_util_error (_("`%s' is not a local disk"), dev);
+
+ if (num_offsets != 2)
+ grub_util_error (_("Storage information for `%s' indicates neither a plain partition nor a plain disk"), dev);
+ if (parent)
+ {
+ *parent = NULL;
+ if (num_ints >= 5)
+ {
+ size_t len = ints[4];
+ if (len > data_len)
+ len = data_len;
+ *parent = xmalloc (len+1);
+ memcpy (*parent, data, len);
+ (*parent)[len] = '\0';
+ }
+ }
+ if (offset)
+ *offset = offsets[0];
+ if (size)
+ *size = offsets[1];
+ if (secsize)
+ *secsize = ints[2];
+ if (ports && num_ports > 0)
+ {
+ mach_msg_type_number_t i;
+ for (i = 0; i < num_ports; i++)
+ {
+ mach_port_t port = ports[i];
+ if (port != MACH_PORT_NULL)
+ mach_port_deallocate (mach_task_self(), port);
+ }
+ munmap ((caddr_t) ports, num_ports * sizeof (*ports));
+ }
+
+ if (ints && num_ints > 0)
+ munmap ((caddr_t) ints, num_ints * sizeof (*ints));
+ if (offsets && num_offsets > 0)
+ munmap ((caddr_t) offsets, num_offsets * sizeof (*offsets));
+ if (data && data_len > 0)
+ munmap (data, data_len);
+ mach_port_deallocate (mach_task_self (), file);
+
+ return 1;
+}
+
+grub_int64_t
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
+{
+ grub_uint32_t sector_size;
+ grub_disk_addr_t size;
+ unsigned log_sector_size;
+
+ if (!grub_util_hurd_get_disk_info (name, &sector_size, NULL, &size, NULL))
+ return -1;
+
+ if (sector_size & (sector_size - 1) || !sector_size)
+ return -1;
+ for (log_sector_size = 0;
+ (1 << log_sector_size) < sector_size;
+ log_sector_size++);
+
+ if (log_secsize)
+ *log_secsize = log_sector_size;
+
+ return size << log_sector_size;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
diff --git a/grub-core/osdep/init.c b/grub-core/osdep/init.c
new file mode 100644
index 0000000..207f670
--- /dev/null
+++ b/grub-core/osdep/init.c
@@ -0,0 +1,5 @@
+#if defined (__MINGW32__)
+#include "windows/init.c"
+#else
+#include "basic/init.c"
+#endif
diff --git a/grub-core/osdep/linux/blocklist.c b/grub-core/osdep/linux/blocklist.c
new file mode 100644
index 0000000..c77d608
--- /dev/null
+++ b/grub-core/osdep/linux/blocklist.c
@@ -0,0 +1,136 @@
+/* grub-setup.c - make GRUB usable */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2005,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <dirent.h>
+#include <assert.h>
+#include <sys/ioctl.h>
+#include <linux/types.h>
+#include <linux/fs.h>
+#include <linux/fiemap.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/util/misc.h>
+#include <grub/util/install.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+void
+grub_install_get_blocklist (grub_device_t root_dev,
+ const char *core_path,
+ const char *core_img __attribute__ ((unused)),
+ size_t core_size,
+ void (*callback) (grub_disk_addr_t sector,
+ unsigned offset,
+ unsigned length,
+ void *data),
+ void *hook_data)
+{
+ grub_partition_t container = root_dev->disk->partition;
+ grub_uint64_t container_start = grub_partition_get_start (container);
+ struct fiemap fie1;
+ int fd;
+
+ /* Write the first two sectors of the core image onto the disk. */
+ grub_util_info ("opening the core image `%s'", core_path);
+ fd = open (core_path, O_RDONLY);
+ if (fd < 0)
+ grub_util_error (_("cannot open `%s': %s"), core_path,
+ strerror (errno));
+
+ grub_memset (&fie1, 0, sizeof (fie1));
+ fie1.fm_length = core_size;
+ fie1.fm_flags = FIEMAP_FLAG_SYNC;
+
+ if (ioctl (fd, FS_IOC_FIEMAP, &fie1) < 0)
+ {
+ int nblocks, i;
+ int bsize;
+ int mul;
+
+ grub_util_info ("FIEMAP failed. Reverting to FIBMAP");
+
+ if (ioctl (fd, FIGETBSZ, &bsize) < 0)
+ grub_util_error (_("can't retrieve blocklists: %s"),
+ strerror (errno));
+ if (bsize & (GRUB_DISK_SECTOR_SIZE - 1))
+ grub_util_error ("%s", _("blocksize is not divisible by 512"));
+ if (!bsize)
+ grub_util_error ("%s", _("invalid zero blocksize"));
+ mul = bsize >> GRUB_DISK_SECTOR_BITS;
+ nblocks = (core_size + bsize - 1) / bsize;
+ if (mul == 0 || nblocks == 0)
+ grub_util_error ("%s", _("can't retrieve blocklists"));
+ for (i = 0; i < nblocks; i++)
+ {
+ unsigned blk = i;
+ int rest;
+ if (ioctl (fd, FIBMAP, &blk) < 0)
+ grub_util_error (_("can't retrieve blocklists: %s"),
+ strerror (errno));
+
+ rest = core_size - ((i * mul) << GRUB_DISK_SECTOR_BITS);
+ if (rest <= 0)
+ break;
+ if (rest > GRUB_DISK_SECTOR_SIZE * mul)
+ rest = GRUB_DISK_SECTOR_SIZE * mul;
+ callback (((grub_uint64_t) blk) * mul
+ + container_start,
+ 0, rest, hook_data);
+ }
+ }
+ else
+ {
+ struct fiemap *fie2;
+ int i;
+ fie2 = xmalloc (sizeof (*fie2)
+ + fie1.fm_mapped_extents
+ * sizeof (fie1.fm_extents[1]));
+ memset (fie2, 0, sizeof (*fie2)
+ + fie1.fm_mapped_extents * sizeof (fie2->fm_extents[1]));
+ fie2->fm_length = core_size;
+ fie2->fm_flags = FIEMAP_FLAG_SYNC;
+ fie2->fm_extent_count = fie1.fm_mapped_extents;
+ if (ioctl (fd, FS_IOC_FIEMAP, fie2) < 0)
+ grub_util_error (_("can't retrieve blocklists: %s"),
+ strerror (errno));
+ for (i = 0; i < fie2->fm_mapped_extents; i++)
+ {
+ callback ((fie2->fm_extents[i].fe_physical
+ >> GRUB_DISK_SECTOR_BITS)
+ + container_start,
+ fie2->fm_extents[i].fe_physical
+ & (GRUB_DISK_SECTOR_SIZE - 1),
+ fie2->fm_extents[i].fe_length, hook_data);
+ }
+ free (fie2);
+ }
+ close (fd);
+}
diff --git a/grub-core/osdep/linux/emunet.c b/grub-core/osdep/linux/emunet.c
new file mode 100644
index 0000000..19b188f
--- /dev/null
+++ b/grub-core/osdep/linux/emunet.c
@@ -0,0 +1,74 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <linux/if.h>
+#include <linux/if_tun.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <string.h>
+
+#include <grub/emu/net.h>
+
+static int fd;
+
+grub_ssize_t
+grub_emunet_send (const void *packet, grub_size_t sz)
+{
+ return write (fd, packet, sz);
+}
+
+grub_ssize_t
+grub_emunet_receive (void *packet, grub_size_t sz)
+{
+ return read (fd, packet, sz);
+}
+
+int
+grub_emunet_create (grub_size_t *mtu)
+{
+ struct ifreq ifr;
+ *mtu = 1500;
+ fd = open ("/dev/net/tun", O_RDWR | O_NONBLOCK);
+ if (fd < 0)
+ return -1;
+ memset (&ifr, 0, sizeof (ifr));
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ if (ioctl (fd, TUNSETIFF, &ifr) < 0)
+ {
+ close (fd);
+ fd = -1;
+ return -1;
+ }
+ return 0;
+}
+
+void
+grub_emunet_close (void)
+{
+ if (fd < 0)
+ return;
+
+ close (fd);
+ fd = -1;
+}
diff --git a/grub-core/osdep/linux/getroot.c b/grub-core/osdep/linux/getroot.c
new file mode 100644
index 0000000..001b818
--- /dev/null
+++ b/grub-core/osdep/linux/getroot.c
@@ -0,0 +1,1164 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#if defined(MAJOR_IN_MKDEV)
+#include <sys/mkdev.h>
+#elif defined(MAJOR_IN_SYSMACROS)
+#include <sys/sysmacros.h>
+#endif
+
+#include <grub/types.h>
+#include <sys/ioctl.h> /* ioctl */
+#include <sys/mount.h>
+
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+
+#include <sys/wait.h>
+
+#include <linux/types.h>
+#include <linux/major.h>
+#include <linux/raid/md_p.h>
+#include <linux/raid/md_u.h>
+#include <grub/i18n.h>
+#include <grub/emu/exec.h>
+#include <grub/btrfs.h>
+
+#define LVM_DEV_MAPPER_STRING "/dev/mapper/"
+
+/* Defines taken from btrfs/ioctl.h. */
+
+struct btrfs_ioctl_dev_info_args
+{
+ grub_uint64_t devid;
+ grub_uint8_t uuid[16];
+ grub_uint64_t bytes_used;
+ grub_uint64_t total_bytes;
+ grub_uint64_t unused[379];
+ grub_uint8_t path[1024];
+};
+
+struct btrfs_ioctl_fs_info_args
+{
+ grub_uint64_t max_id;
+ grub_uint64_t num_devices;
+ grub_uint8_t fsid[16];
+ grub_uint64_t reserved[124];
+};
+
+struct btrfs_ioctl_ino_lookup_args
+{
+ grub_uint64_t treeid;
+ grub_uint64_t objectid;
+ char name[4080];
+};
+
+struct btrfs_ioctl_search_key
+{
+ grub_uint64_t tree_id;
+ grub_uint64_t min_objectid;
+ grub_uint64_t max_objectid;
+ grub_uint64_t min_offset;
+ grub_uint64_t max_offset;
+ grub_uint64_t min_transid;
+ grub_uint64_t max_transid;
+ grub_uint32_t min_type;
+ grub_uint32_t max_type;
+ grub_uint32_t nr_items;
+ grub_uint32_t unused[9];
+};
+
+struct btrfs_ioctl_search_args {
+ struct btrfs_ioctl_search_key key;
+ grub_uint64_t buf[(4096 - sizeof(struct btrfs_ioctl_search_key))
+ / sizeof (grub_uint64_t)];
+};
+
+#define BTRFS_IOC_TREE_SEARCH _IOWR(0x94, 17, \
+ struct btrfs_ioctl_search_args)
+#define BTRFS_IOC_INO_LOOKUP _IOWR(0x94, 18, \
+ struct btrfs_ioctl_ino_lookup_args)
+#define BTRFS_IOC_DEV_INFO _IOWR(0x94, 30, \
+ struct btrfs_ioctl_dev_info_args)
+#define BTRFS_IOC_FS_INFO _IOR(0x94, 31, \
+ struct btrfs_ioctl_fs_info_args)
+
+static int
+grub_util_is_imsm (const char *os_dev);
+
+
+#define ESCAPED_PATH_MAX (4 * PATH_MAX)
+struct mountinfo_entry
+{
+ int id;
+ int major, minor;
+ char enc_root[ESCAPED_PATH_MAX + 1], enc_path[ESCAPED_PATH_MAX + 1];
+ char fstype[ESCAPED_PATH_MAX + 1], device[ESCAPED_PATH_MAX + 1];
+};
+
+static char **
+grub_util_raid_getmembers (const char *name, int bootable)
+{
+ int fd, ret, i, j;
+ char **devicelist;
+ mdu_version_t version;
+ mdu_array_info_t info;
+ mdu_disk_info_t disk;
+
+ fd = open (name, O_RDONLY);
+
+ if (fd == -1)
+ grub_util_error (_("cannot open `%s': %s"), name, strerror (errno));
+
+ ret = ioctl (fd, RAID_VERSION, &version);
+ if (ret != 0)
+ grub_util_error (_("ioctl RAID_VERSION error: %s"), strerror (errno));
+
+ if ((version.major != 0 || version.minor != 90)
+ && (version.major != 1 || version.minor != 0)
+ && (version.major != 1 || version.minor != 1)
+ && (version.major != 1 || version.minor != 2))
+ grub_util_error (_("unsupported RAID version: %d.%d"),
+ version.major, version.minor);
+
+ if (bootable && (version.major != 0 || version.minor != 90))
+ grub_util_error (_("unsupported RAID version: %d.%d"),
+ version.major, version.minor);
+
+ ret = ioctl (fd, GET_ARRAY_INFO, &info);
+ if (ret != 0)
+ grub_util_error (_("ioctl GET_ARRAY_INFO error: %s"), strerror (errno));
+
+ devicelist = xcalloc (info.nr_disks + 1, sizeof (char *));
+
+ for (i = 0, j = 0; j < info.nr_disks; i++)
+ {
+ disk.number = i;
+ ret = ioctl (fd, GET_DISK_INFO, &disk);
+ if (ret != 0)
+ grub_util_error (_("ioctl GET_DISK_INFO error: %s"), strerror (errno));
+
+ if (disk.state & (1 << MD_DISK_REMOVED))
+ continue;
+
+ if (disk.state & (1 << MD_DISK_ACTIVE))
+ devicelist[j] = grub_find_device (NULL,
+ makedev (disk.major, disk.minor));
+ else
+ devicelist[j] = NULL;
+ j++;
+ }
+
+ devicelist[j] = NULL;
+
+ close (fd);
+
+ return devicelist;
+}
+
+/* Statting something on a btrfs filesystem always returns a virtual device
+ major/minor pair rather than the real underlying device, because btrfs
+ can span multiple underlying devices (and even if it's currently only
+ using a single device it can be dynamically extended onto another). We
+ can't deal with the multiple-device case yet, but in the meantime, we can
+ at least cope with the single-device case by scanning
+ /proc/self/mountinfo. */
+static void
+unescape (char *str)
+{
+ char *optr;
+ const char *iptr;
+ for (iptr = optr = str; *iptr; optr++)
+ {
+ if (iptr[0] == '\\' && iptr[1] >= '0' && iptr[1] < '8'
+ && iptr[2] >= '0' && iptr[2] < '8'
+ && iptr[3] >= '0' && iptr[3] < '8')
+ {
+ *optr = (((iptr[1] - '0') << 6) | ((iptr[2] - '0') << 3)
+ | (iptr[3] - '0'));
+ iptr += 4;
+ }
+ else
+ *optr = *iptr++;
+ }
+ *optr = 0;
+}
+
+static char **
+grub_find_root_devices_from_btrfs (const char *dir)
+{
+ int fd;
+ struct btrfs_ioctl_fs_info_args fsi;
+ int i, j = 0;
+ char **ret;
+
+ fd = open (dir, 0);
+ if (fd < 0)
+ return NULL;
+
+ if (ioctl (fd, BTRFS_IOC_FS_INFO, &fsi) < 0)
+ {
+ close (fd);
+ return NULL;
+ }
+
+ ret = xcalloc (fsi.num_devices + 1, sizeof (ret[0]));
+
+ for (i = 1; i <= fsi.max_id && j < fsi.num_devices; i++)
+ {
+ struct btrfs_ioctl_dev_info_args devi;
+ memset (&devi, 0, sizeof (devi));
+ devi.devid = i;
+ if (ioctl (fd, BTRFS_IOC_DEV_INFO, &devi) < 0)
+ {
+ close (fd);
+ free (ret);
+ return NULL;
+ }
+ ret[j++] = xstrdup ((char *) devi.path);
+ if (j >= fsi.num_devices)
+ break;
+ }
+ close (fd);
+ ret[j] = 0;
+ return ret;
+}
+
+static char *
+get_btrfs_fs_prefix (const char *mount_path)
+{
+ struct btrfs_ioctl_ino_lookup_args args;
+ struct stat st;
+ int fd;
+ grub_uint64_t tree_id, inode_id;
+ char *ret = NULL;
+
+ fd = open (mount_path, O_RDONLY);
+
+ if (fd < 0)
+ return NULL;
+ memset (&args, 0, sizeof(args));
+ args.objectid = GRUB_BTRFS_TREE_ROOT_OBJECTID;
+
+ if (ioctl (fd, BTRFS_IOC_INO_LOOKUP, &args) < 0)
+ goto fail;
+ tree_id = args.treeid;
+
+ if (fstat (fd, &st) < 0)
+ goto fail;
+ inode_id = st.st_ino;
+
+ while (tree_id != GRUB_BTRFS_ROOT_VOL_OBJECTID
+ || inode_id != GRUB_BTRFS_TREE_ROOT_OBJECTID)
+ {
+ const char *name;
+ size_t namelen;
+ struct btrfs_ioctl_search_args sargs;
+ char *old;
+
+ memset (&sargs, 0, sizeof(sargs));
+
+ if (inode_id == GRUB_BTRFS_TREE_ROOT_OBJECTID)
+ {
+ struct grub_btrfs_root_backref *br;
+
+ sargs.key.tree_id = 1;
+ sargs.key.min_objectid = tree_id;
+ sargs.key.max_objectid = tree_id;
+
+ sargs.key.min_offset = 0;
+ sargs.key.max_offset = ~0ULL;
+ sargs.key.min_transid = 0;
+ sargs.key.max_transid = ~0ULL;
+ sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
+ sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_ROOT_BACKREF;
+
+ sargs.key.nr_items = 1;
+
+ if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0)
+ goto fail;
+
+ if (sargs.key.nr_items == 0)
+ goto fail;
+
+ tree_id = sargs.buf[2];
+ br = (struct grub_btrfs_root_backref *) (sargs.buf + 4);
+ inode_id = grub_le_to_cpu64 (br->inode_id);
+ name = br->name;
+ namelen = grub_le_to_cpu16 (br->n);
+ }
+ else
+ {
+ struct grub_btrfs_inode_ref *ir;
+
+ sargs.key.tree_id = tree_id;
+ sargs.key.min_objectid = inode_id;
+ sargs.key.max_objectid = inode_id;
+
+ sargs.key.min_offset = 0;
+ sargs.key.max_offset = ~0ULL;
+ sargs.key.min_transid = 0;
+ sargs.key.max_transid = ~0ULL;
+ sargs.key.min_type = GRUB_BTRFS_ITEM_TYPE_INODE_REF;
+ sargs.key.max_type = GRUB_BTRFS_ITEM_TYPE_INODE_REF;
+
+ if (ioctl (fd, BTRFS_IOC_TREE_SEARCH, &sargs) < 0)
+ goto fail;
+
+ if (sargs.key.nr_items == 0)
+ goto fail;
+
+ inode_id = sargs.buf[2];
+
+ ir = (struct grub_btrfs_inode_ref *) (sargs.buf + 4);
+ name = ir->name;
+ namelen = grub_le_to_cpu16 (ir->n);
+ }
+ old = ret;
+ ret = xmalloc (namelen + (old ? strlen (old) : 0) + 2);
+ ret[0] = '/';
+ memcpy (ret + 1, name, namelen);
+ if (old)
+ {
+ strcpy (ret + 1 + namelen, old);
+ free (old);
+ }
+ else
+ ret[1+namelen] = '\0';
+ }
+ if (!ret)
+ ret = xstrdup ("/");
+ close (fd);
+ return ret;
+
+ fail:
+ free (ret);
+ close (fd);
+ return NULL;
+}
+
+
+char **
+grub_find_root_devices_from_mountinfo (const char *dir, char **relroot)
+{
+ FILE *fp = NULL;
+ char *buf = NULL;
+ size_t len = 0;
+ grub_size_t entry_len, entry_max = 4;
+ struct mountinfo_entry *entries;
+ struct mountinfo_entry parent_entry = { 0, 0, 0, "", "", "", "" };
+ int i;
+ int retry = 0;
+ int dir_fd = -1;
+ char **ret = NULL;
+
+ if (! *dir)
+ dir = "/";
+ if (relroot)
+ *relroot = NULL;
+
+ entries = xcalloc (entry_max, sizeof (*entries));
+
+again:
+ fp = grub_util_fopen ("/proc/self/mountinfo", "r");
+ if (! fp)
+ goto out; /* fall through to other methods */
+
+ entry_len = 0;
+
+ /* First, build a list of relevant visible mounts. */
+ while (getline (&buf, &len, fp) > 0)
+ {
+ struct mountinfo_entry entry;
+ int count;
+ size_t enc_path_len;
+ const char *sep;
+
+ if (sscanf (buf, "%d %d %u:%u %s %s%n",
+ &entry.id, &parent_entry.id, &entry.major, &entry.minor,
+ entry.enc_root, entry.enc_path, &count) < 6)
+ continue;
+
+ unescape (entry.enc_root);
+ unescape (entry.enc_path);
+
+ enc_path_len = strlen (entry.enc_path);
+ /* Check that enc_path is a prefix of dir. The prefix must either be
+ the entire string, or end with a slash, or be immediately followed
+ by a slash. */
+ if (strncmp (dir, entry.enc_path, enc_path_len) != 0 ||
+ (enc_path_len && dir[enc_path_len - 1] != '/' &&
+ dir[enc_path_len] && dir[enc_path_len] != '/'))
+ continue;
+
+ sep = strstr (buf + count, " - ");
+ if (!sep)
+ continue;
+
+ sep += sizeof (" - ") - 1;
+ if (sscanf (sep, "%s %s", entry.fstype, entry.device) != 2)
+ continue;
+
+ unescape (entry.device);
+
+ /* Using the mount IDs, find out where this fits in the list of
+ visible mount entries we've seen so far. There are three
+ interesting cases. Firstly, it may be inserted at the end: this is
+ the usual case of /foo/bar being mounted after /foo. Secondly, it
+ may be inserted at the start: for example, this can happen for
+ filesystems that are mounted before / and later moved under it.
+ Thirdly, it may occlude part or all of the existing filesystem
+ tree, in which case the end of the list needs to be pruned and this
+ new entry will be inserted at the end. */
+ if (entry_len >= entry_max)
+ {
+ entry_max <<= 1;
+ entries = xrealloc (entries, entry_max * sizeof (*entries));
+ }
+
+ if (!entry_len)
+ {
+ /* Initialise list. */
+ entry_len = 2;
+ entries[0] = parent_entry;
+ entries[1] = entry;
+ }
+ else
+ {
+ for (i = entry_len - 1; i >= 0; i--)
+ {
+ if (entries[i].id == parent_entry.id)
+ {
+ /* Insert at end, pruning anything previously above this. */
+ entry_len = i + 2;
+ entries[i + 1] = entry;
+ break;
+ }
+ else if (i == 0 && entries[i].id == entry.id)
+ {
+ /* Insert at start. */
+ entry_len++;
+ memmove (entries + 1, entries,
+ (entry_len - 1) * sizeof (*entries));
+ entries[0] = parent_entry;
+ entries[1] = entry;
+ break;
+ }
+ }
+ }
+ }
+
+ /* Now scan visible mounts for the ones we're interested in. */
+ for (i = entry_len - 1; i >= 0; i--)
+ {
+ char *fs_prefix = NULL;
+ if (!*entries[i].device)
+ continue;
+
+ if (grub_strcmp (entries[i].fstype, "fuse.zfs") == 0
+ || grub_strcmp (entries[i].fstype, "zfs") == 0)
+ {
+ char *slash;
+ slash = strchr (entries[i].device, '/');
+ if (slash)
+ *slash = 0;
+ ret = grub_util_find_root_devices_from_poolname (entries[i].device);
+ if (slash)
+ *slash = '/';
+ if (relroot)
+ {
+ if (!slash)
+ fs_prefix = xasprintf ("/@%s", entries[i].enc_root);
+ else if (strchr (slash + 1, '@'))
+ fs_prefix = xasprintf ("/%s%s", slash + 1, entries[i].enc_root);
+ else
+ fs_prefix = xasprintf ("/%s@%s", slash + 1,
+ entries[i].enc_root);
+ }
+ }
+ else if (grub_strcmp (entries[i].fstype, "btrfs") == 0)
+ {
+ ret = grub_find_root_devices_from_btrfs (dir);
+ fs_prefix = get_btrfs_fs_prefix (entries[i].enc_path);
+ }
+ else if (!retry && grub_strcmp (entries[i].fstype, "autofs") == 0)
+ {
+ /* If the best match is automounted, try to trigger mount. We cannot
+ simply return here because stat() on automounted directory does not
+ trigger mount and returns bogus (pseudo)device number instead.
+ We keep mountpoint open until end of scan to prevent timeout. */
+
+ int flags = O_RDONLY|O_DIRECTORY;
+
+ fclose (fp);
+#ifdef O_LARGEFILE
+ flags |= O_LARGEFILE;
+#endif
+ dir_fd = open (entries[i].enc_path, flags);
+ retry = 1;
+ goto again;
+ }
+ if (!ret)
+ {
+ ret = xmalloc (2 * sizeof (ret[0]));
+ ret[0] = strdup (entries[i].device);
+ ret[1] = 0;
+ }
+ if (!fs_prefix)
+ fs_prefix = entries[i].enc_root;
+ if (relroot)
+ {
+ char *ptr;
+ grub_size_t enc_root_len = strlen (fs_prefix);
+ grub_size_t enc_path_len = strlen (entries[i].enc_path);
+ grub_size_t dir_strlen = strlen (dir);
+ *relroot = xmalloc (enc_root_len +
+ 2 + dir_strlen);
+ ptr = grub_stpcpy (*relroot, fs_prefix);
+ if (dir_strlen > enc_path_len)
+ {
+ while (ptr > *relroot && *(ptr - 1) == '/')
+ ptr--;
+ if (dir[enc_path_len] != '/')
+ *ptr++ = '/';
+ ptr = grub_stpcpy (ptr, dir + enc_path_len);
+ }
+ *ptr = 0;
+ }
+ if (fs_prefix != entries[i].enc_root)
+ free (fs_prefix);
+ break;
+ }
+
+out:
+ free (buf);
+ free (entries);
+ if (fp)
+ fclose (fp);
+ if (dir_fd != -1)
+ close (dir_fd);
+ return ret;
+}
+
+static char *
+get_mdadm_uuid (const char *os_dev)
+{
+ const char *argv[5];
+ int fd;
+ pid_t pid;
+ FILE *mdadm;
+ char *buf = NULL;
+ size_t len = 0;
+ char *name = NULL;
+
+ argv[0] = "mdadm";
+ argv[1] = "--detail";
+ argv[2] = "--export";
+ argv[3] = os_dev;
+ argv[4] = NULL;
+
+ pid = grub_util_exec_pipe (argv, &fd);
+
+ if (!pid)
+ return NULL;
+
+ /* Parent. Read mdadm's output. */
+ mdadm = fdopen (fd, "r");
+ if (! mdadm)
+ {
+ grub_util_warn (_("Unable to open stream from %s: %s"),
+ "mdadm", strerror (errno));
+ goto out;
+ }
+
+ while (getline (&buf, &len, mdadm) > 0)
+ {
+ if (strncmp (buf, "MD_UUID=", sizeof ("MD_UUID=") - 1) == 0)
+ {
+ char *name_start, *ptri, *ptro;
+
+ free (name);
+ name_start = buf + sizeof ("MD_UUID=") - 1;
+ ptro = name = xmalloc (strlen (name_start) + 1);
+ for (ptri = name_start; *ptri && *ptri != '\n' && *ptri != '\r';
+ ptri++)
+ if ((*ptri >= '0' && *ptri <= '9')
+ || (*ptri >= 'a' && *ptri <= 'f')
+ || (*ptri >= 'A' && *ptri <= 'F'))
+ *ptro++ = *ptri;
+ *ptro = 0;
+ }
+ }
+
+out:
+ close (fd);
+ waitpid (pid, NULL, 0);
+ free (buf);
+
+ return name;
+}
+
+static int
+grub_util_is_imsm (const char *os_dev)
+{
+ int retry;
+ int is_imsm = 0;
+ int container_seen = 0;
+ const char *dev = os_dev;
+
+ do
+ {
+ const char *argv[5];
+ int fd;
+ pid_t pid;
+ FILE *mdadm;
+ char *buf = NULL;
+ size_t len = 0;
+
+ retry = 0; /* We'll do one more pass if device is part of container */
+
+ argv[0] = "mdadm";
+ argv[1] = "--detail";
+ argv[2] = "--export";
+ argv[3] = dev;
+ argv[4] = NULL;
+
+ pid = grub_util_exec_pipe (argv, &fd);
+
+ if (!pid)
+ {
+ if (dev != os_dev)
+ free ((void *) dev);
+ return 0;
+ }
+
+ /* Parent. Read mdadm's output. */
+ mdadm = fdopen (fd, "r");
+ if (! mdadm)
+ {
+ grub_util_warn (_("Unable to open stream from %s: %s"),
+ "mdadm", strerror (errno));
+ close (fd);
+ waitpid (pid, NULL, 0);
+ if (dev != os_dev)
+ free ((void *) dev);
+ return 0;
+ }
+
+ while (getline (&buf, &len, mdadm) > 0)
+ {
+ if (strncmp (buf, "MD_CONTAINER=", sizeof ("MD_CONTAINER=") - 1) == 0
+ && !container_seen)
+ {
+ char *newdev, *ptr;
+ newdev = xstrdup (buf + sizeof ("MD_CONTAINER=") - 1);
+ ptr = newdev + strlen (newdev) - 1;
+ for (; ptr >= newdev && (*ptr == '\n' || *ptr == '\r'); ptr--);
+ ptr[1] = 0;
+ grub_util_info ("Container of %s is %s", dev, newdev);
+ dev = newdev;
+ container_seen = retry = 1;
+ break;
+ }
+ if (strncmp (buf, "MD_METADATA=imsm",
+ sizeof ("MD_METADATA=imsm") - 1) == 0)
+ {
+ is_imsm = 1;
+ grub_util_info ("%s is imsm", dev);
+ break;
+ }
+ }
+
+ free (buf);
+ close (fd);
+ waitpid (pid, NULL, 0);
+ }
+ while (retry);
+
+ if (dev != os_dev)
+ free ((void *) dev);
+ return is_imsm;
+}
+
+char *
+grub_util_part_to_disk (const char *os_dev, struct stat *st,
+ int *is_part)
+{
+ char *path;
+
+ if (! S_ISBLK (st->st_mode))
+ {
+ *is_part = 0;
+ return xstrdup (os_dev);
+ }
+
+ path = xmalloc (PATH_MAX);
+
+ if (! realpath (os_dev, path))
+ return NULL;
+
+ if (strncmp ("/dev/", path, 5) == 0)
+ {
+ char *p = path + 5;
+
+ /* If this is an IDE disk. */
+ if (strncmp ("ide/", p, 4) == 0)
+ {
+ p = strstr (p, "part");
+ if (p)
+ {
+ *is_part = 1;
+ strcpy (p, "disc");
+ }
+
+ return path;
+ }
+
+ /* If this is a SCSI disk. */
+ if (strncmp ("scsi/", p, 5) == 0)
+ {
+ p = strstr (p, "part");
+ if (p)
+ {
+ *is_part = 1;
+ strcpy (p, "disc");
+ }
+
+ return path;
+ }
+
+ /* If this is a DAC960 disk. */
+ if (strncmp ("rd/c", p, 4) == 0)
+ {
+ /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+
+ /* If this is a Mylex AcceleRAID Array. */
+ if (strncmp ("rs/c", p, 4) == 0)
+ {
+ /* /dev/rd/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+ /* If this is a CCISS disk. */
+ if (strncmp ("cciss/c", p, sizeof ("cciss/c") - 1) == 0)
+ {
+ /* /dev/cciss/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+
+ /* If this is an AOE disk. */
+ if (strncmp ("etherd/e", p, sizeof ("etherd/e") - 1) == 0)
+ {
+ /* /dev/etherd/e[0-9]+\.[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+
+ /* If this is a Compaq Intelligent Drive Array. */
+ if (strncmp ("ida/c", p, sizeof ("ida/c") - 1) == 0)
+ {
+ /* /dev/ida/c[0-9]+d[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+
+ /* If this is an I2O disk. */
+ if (strncmp ("i2o/hd", p, sizeof ("i2o/hd") - 1) == 0)
+ {
+ /* /dev/i2o/hd[a-z]([0-9]+)? */
+ if (p[sizeof ("i2o/hda") - 1])
+ *is_part = 1;
+ p[sizeof ("i2o/hda") - 1] = '\0';
+ return path;
+ }
+
+ /* If this is a MultiMediaCard (MMC). */
+ if (strncmp ("mmcblk", p, sizeof ("mmcblk") - 1) == 0)
+ {
+ /* /dev/mmcblk[0-9]+(p[0-9]+)? */
+ p = strchr (p, 'p');
+ if (p)
+ {
+ *is_part = 1;
+ *p = '\0';
+ }
+
+ return path;
+ }
+
+ if (strncmp ("md", p, 2) == 0
+ && p[2] >= '0' && p[2] <= '9')
+ {
+ char *ptr = p + 2;
+ while (*ptr >= '0' && *ptr <= '9')
+ ptr++;
+ if (*ptr)
+ *is_part = 1;
+ *ptr = 0;
+ return path;
+ }
+
+ if (strncmp ("nbd", p, 3) == 0
+ && p[3] >= '0' && p[3] <= '9')
+ {
+ char *ptr = p + 3;
+ while (*ptr >= '0' && *ptr <= '9')
+ ptr++;
+ if (*ptr)
+ *is_part = 1;
+ *ptr = 0;
+ return path;
+ }
+
+ /* If this is an IDE, SCSI or Virtio disk. */
+ if (strncmp ("vdisk", p, 5) == 0
+ && p[5] >= 'a' && p[5] <= 'z')
+ {
+ /* /dev/vdisk[a-z][0-9]* */
+ if (p[6])
+ *is_part = 1;
+ p[6] = '\0';
+ return path;
+ }
+ if ((strncmp ("hd", p, 2) == 0
+ || strncmp ("vd", p, 2) == 0
+ || strncmp ("sd", p, 2) == 0)
+ && p[2] >= 'a' && p[2] <= 'z')
+ {
+ char *pp = p + 2;
+ while (*pp >= 'a' && *pp <= 'z')
+ pp++;
+ if (*pp)
+ *is_part = 1;
+ /* /dev/[hsv]d[a-z]+[0-9]* */
+ *pp = '\0';
+ return path;
+ }
+
+ /* If this is a Xen virtual block device. */
+ if ((strncmp ("xvd", p, 3) == 0) && p[3] >= 'a' && p[3] <= 'z')
+ {
+ char *pp = p + 3;
+ while (*pp >= 'a' && *pp <= 'z')
+ pp++;
+ if (*pp)
+ *is_part = 1;
+ /* /dev/xvd[a-z]+[0-9]* */
+ *pp = '\0';
+ return path;
+ }
+
+ /* If this is an rssd device. */
+ if ((strncmp ("rssd", p, 4) == 0) && p[4] >= 'a' && p[4] <= 'z')
+ {
+ char *pp = p + 4;
+ while (*pp >= 'a' && *pp <= 'z')
+ pp++;
+ if (*pp)
+ *is_part = 1;
+ /* /dev/rssd[a-z]+[0-9]* */
+ *pp = '\0';
+ return path;
+ }
+
+ /* If this is a loop device */
+ if ((strncmp ("loop", p, 4) == 0) && p[4] >= '0' && p[4] <= '9')
+ {
+ char *pp = p + 4;
+ while (*pp >= '0' && *pp <= '9')
+ pp++;
+ if (*pp == 'p')
+ *is_part = 1;
+ /* /dev/loop[0-9]+p[0-9]* */
+ *pp = '\0';
+ return path;
+ }
+
+ /* If this is a NVMe device */
+ if ((strncmp ("nvme", p, 4) == 0) && p[4] >= '0' && p[4] <= '9')
+ {
+ char *pp = p + 4;
+ while (*pp >= '0' && *pp <= '9')
+ pp++;
+ if (*pp == 'n')
+ pp++;
+ while (*pp >= '0' && *pp <= '9')
+ pp++;
+ if (*pp == 'p')
+ *is_part = 1;
+ /* /dev/nvme[0-9]+n[0-9]+p[0-9]* */
+ *pp = '\0';
+ return path;
+ }
+ }
+
+ return path;
+}
+
+static char *
+grub_util_get_raid_grub_dev (const char *os_dev)
+{
+ char *grub_dev = NULL;
+ if (os_dev[7] == '_' && os_dev[8] == 'd')
+ {
+ /* This a partitionable RAID device of the form /dev/md_dNNpMM. */
+
+ char *p, *q;
+
+ p = strdup (os_dev + sizeof ("/dev/md_d") - 1);
+
+ q = strchr (p, 'p');
+ if (q)
+ *q = ',';
+
+ grub_dev = xasprintf ("md%s", p);
+ free (p);
+ }
+ else if (os_dev[7] == '/' && os_dev[8] == 'd')
+ {
+ /* This a partitionable RAID device of the form /dev/md/dNNpMM. */
+
+ char *p, *q;
+
+ p = strdup (os_dev + sizeof ("/dev/md/d") - 1);
+
+ q = strchr (p, 'p');
+ if (q)
+ *q = ',';
+
+ grub_dev = xasprintf ("md%s", p);
+ free (p);
+ }
+ else if (os_dev[7] >= '0' && os_dev[7] <= '9')
+ {
+ char *p , *q;
+
+ p = strdup (os_dev + sizeof ("/dev/md") - 1);
+
+ q = strchr (p, 'p');
+ if (q)
+ *q = ',';
+
+ grub_dev = xasprintf ("md%s", p);
+ free (p);
+ }
+ else if (os_dev[7] == '/' && os_dev[8] >= '0' && os_dev[8] <= '9')
+ {
+ char *p , *q;
+
+ p = strdup (os_dev + sizeof ("/dev/md/") - 1);
+
+ q = strchr (p, 'p');
+ if (q)
+ *q = ',';
+
+ grub_dev = xasprintf ("md%s", p);
+ free (p);
+ }
+ else if (os_dev[7] == '/')
+ {
+ /* mdraid 1.x with a free name. */
+ char *p , *q;
+
+ p = strdup (os_dev + sizeof ("/dev/md/") - 1);
+
+ q = strchr (p, 'p');
+ if (q)
+ *q = ',';
+
+ grub_dev = xasprintf ("md/%s", p);
+ free (p);
+ }
+ else
+ grub_util_error (_("unknown kind of RAID device `%s'"), os_dev);
+
+ {
+ char *mdadm_name = get_mdadm_uuid (os_dev);
+
+ if (mdadm_name)
+ {
+ const char *q;
+
+ for (q = os_dev + strlen (os_dev) - 1; q >= os_dev
+ && grub_isdigit (*q); q--);
+
+ if (q >= os_dev && *q == 'p')
+ {
+ free (grub_dev);
+ grub_dev = xasprintf ("mduuid/%s,%s", mdadm_name, q + 1);
+ goto done;
+ }
+ free (grub_dev);
+ grub_dev = xasprintf ("mduuid/%s", mdadm_name);
+
+ done:
+ free (mdadm_name);
+ }
+ }
+ return grub_dev;
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev)
+{
+#ifndef HAVE_DEVICE_MAPPER
+ if ((strncmp ("/dev/mapper/", os_dev, 12) == 0))
+ return GRUB_DEV_ABSTRACTION_LVM;
+#endif
+
+ /* Check for RAID. */
+ if (!strncmp (os_dev, "/dev/md", 7) && ! grub_util_device_is_mapped (os_dev)
+ && !grub_util_is_imsm (os_dev))
+ return GRUB_DEV_ABSTRACTION_RAID;
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev,
+ enum grub_dev_abstraction_types ab)
+{
+ switch (ab)
+ {
+ case GRUB_DEV_ABSTRACTION_RAID:
+ {
+ char **devicelist = grub_util_raid_getmembers (os_dev, 0);
+ int i;
+ for (i = 0; devicelist[i];i++)
+ {
+ grub_util_pull_device (devicelist[i]);
+ free (devicelist[i]);
+ }
+ free (devicelist);
+ }
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev)
+{
+ char *grub_dev = NULL;
+
+ switch (grub_util_get_dev_abstraction (os_dev))
+ {
+ /* Fallback for non-devmapper build. In devmapper-builds LVM is handled
+ in grub_util_get_devmapper_grub_dev and this point isn't reached.
+ */
+ case GRUB_DEV_ABSTRACTION_LVM:
+ {
+ unsigned short len;
+ grub_size_t offset = sizeof (LVM_DEV_MAPPER_STRING) - 1;
+
+ len = strlen (os_dev) - offset + 1;
+ grub_dev = xmalloc (len + sizeof ("lvm/"));
+
+ grub_memcpy (grub_dev, "lvm/", sizeof ("lvm/") - 1);
+ grub_memcpy (grub_dev + sizeof ("lvm/") - 1, os_dev + offset, len);
+ }
+ break;
+
+ case GRUB_DEV_ABSTRACTION_RAID:
+ grub_dev = grub_util_get_raid_grub_dev (os_dev);
+ break;
+
+ default: /* GRUB_DEV_ABSTRACTION_NONE */
+ break;
+ }
+
+ return grub_dev;
+}
+
+char *
+grub_make_system_path_relative_to_its_root_os (const char *path)
+{
+ char *bind = NULL;
+ grub_size_t len;
+ grub_free (grub_find_root_devices_from_mountinfo (path, &bind));
+ if (bind && bind[0])
+ {
+ len = strlen (bind);
+ while (len > 0 && bind[len - 1] == '/')
+ {
+ bind[len - 1] = '\0';
+ len--;
+ }
+ return bind;
+ }
+ grub_free (bind);
+ return NULL;
+}
diff --git a/grub-core/osdep/linux/hostdisk.c b/grub-core/osdep/linux/hostdisk.c
new file mode 100644
index 0000000..da62f92
--- /dev/null
+++ b/grub-core/osdep/linux/hostdisk.c
@@ -0,0 +1,465 @@
+/* hostdisk.c - emulate biosdisk */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/emu/exec.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+# include <sys/ioctl.h> /* ioctl */
+# include <sys/mount.h>
+# ifndef BLKFLSBUF
+# define BLKFLSBUF _IO (0x12,97) /* flush buffer cache */
+# endif /* ! BLKFLSBUF */
+# include <sys/ioctl.h> /* ioctl */
+# ifndef HDIO_GETGEO
+# define HDIO_GETGEO 0x0301 /* get device geometry */
+/* If HDIO_GETGEO is not defined, it is unlikely that hd_geometry is
+ defined. */
+struct hd_geometry
+{
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned short cylinders;
+ unsigned long start;
+};
+# endif /* ! HDIO_GETGEO */
+# ifndef BLKGETSIZE64
+# define BLKGETSIZE64 _IOR(0x12,114,size_t) /* return device size */
+# endif /* ! BLKGETSIZE64 */
+
+
+grub_int64_t
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
+{
+ unsigned long long nr;
+ unsigned sector_size, log_sector_size;
+
+ if (ioctl (fd, BLKGETSIZE64, &nr))
+ return -1;
+
+ if (ioctl (fd, BLKSSZGET, &sector_size))
+ return -1;
+
+ if (sector_size & (sector_size - 1) || !sector_size)
+ return -1;
+ for (log_sector_size = 0;
+ (1 << log_sector_size) < sector_size;
+ log_sector_size++);
+
+ if (log_secsize)
+ *log_secsize = log_sector_size;
+
+ if (nr & ((1 << log_sector_size) - 1))
+ grub_util_error ("%s", _("unaligned device size"));
+
+ return nr;
+}
+
+static char *
+sysfs_partition_path (const char *dev, const char *entry)
+{
+ const char *argv[7];
+ int fd;
+ pid_t pid;
+ FILE *udevadm;
+ char *buf = NULL;
+ size_t len = 0;
+ char *path = NULL;
+
+ argv[0] = "udevadm";
+ argv[1] = "info";
+ argv[2] = "--query";
+ argv[3] = "path";
+ argv[4] = "--name";
+ argv[5] = dev;
+ argv[6] = NULL;
+
+ pid = grub_util_exec_pipe (argv, &fd);
+
+ if (!pid)
+ return NULL;
+
+ /* Parent. Read udevadm's output. */
+ udevadm = fdopen (fd, "r");
+ if (!udevadm)
+ {
+ grub_util_warn (_("Unable to open stream from %s: %s"),
+ "udevadm", strerror (errno));
+ close (fd);
+ goto out;
+ }
+
+ if (getline (&buf, &len, udevadm) > 0)
+ {
+ char *newline;
+
+ newline = strchr (buf, '\n');
+ if (newline)
+ *newline = '\0';
+ path = xasprintf ("/sys%s/%s", buf, entry);
+ }
+
+out:
+ if (udevadm)
+ fclose (udevadm);
+ waitpid (pid, NULL, 0);
+ free (buf);
+
+ return path;
+}
+
+static int
+sysfs_partition_start (const char *dev, grub_disk_addr_t *start)
+{
+ char *path;
+ FILE *fp;
+ unsigned long long val;
+ int ret = 0;
+
+ path = sysfs_partition_path (dev, "start");
+ if (!path)
+ return 0;
+
+ fp = grub_util_fopen (path, "r");
+ if (!fp)
+ goto out;
+
+ if (fscanf (fp, "%llu", &val) == 1)
+ {
+ *start = (grub_disk_addr_t) val;
+ ret = 1;
+ }
+
+out:
+ free (path);
+ if (fp)
+ fclose (fp);
+
+ return ret;
+}
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *dev)
+{
+ grub_disk_addr_t start = 0;
+ grub_util_fd_t fd;
+ struct hd_geometry hdg;
+
+ if (sysfs_partition_start (dev, &start))
+ return start;
+
+ fd = open (dev, O_RDONLY);
+ if (fd == -1)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
+ dev, strerror (errno));
+ return 0;
+ }
+
+ if (ioctl (fd, HDIO_GETGEO, &hdg))
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "cannot get disk geometry of `%s'", dev);
+ close (fd);
+ return 0;
+ }
+
+ close (fd);
+
+ return hdg.start;
+}
+
+/* Cache of partition start sectors for each disk. */
+struct linux_partition_cache
+{
+ struct linux_partition_cache *next;
+ struct linux_partition_cache **prev;
+ char *dev;
+ unsigned long start;
+ int partno;
+};
+
+struct linux_partition_cache *linux_partition_cache_list;
+
+/* Check if we have devfs support. */
+static int
+have_devfs (void)
+{
+ static int dev_devfsd_exists = -1;
+
+ if (dev_devfsd_exists < 0)
+ {
+ struct stat st;
+
+ dev_devfsd_exists = stat ("/dev/.devfsd", &st) == 0;
+ }
+
+ return dev_devfsd_exists;
+}
+
+#pragma GCC diagnostic ignored "-Wformat-nonliteral"
+
+static int
+grub_hostdisk_linux_find_partition (char *dev, grub_disk_addr_t sector)
+{
+ size_t len = strlen (dev);
+ const char *format;
+ char *p;
+ int i;
+ char real_dev[PATH_MAX];
+ struct linux_partition_cache *cache;
+ int missing = 0;
+
+ strcpy(real_dev, dev);
+
+ if (have_devfs () && strcmp (real_dev + len - 5, "/disc") == 0)
+ {
+ p = real_dev + len - 4;
+ format = "part%d";
+ }
+ else if (strncmp (real_dev, "/dev/disk/by-id/",
+ sizeof ("/dev/disk/by-id/") - 1) == 0)
+ {
+ p = real_dev + len;
+ format = "-part%d";
+ }
+ else if (real_dev[len - 1] >= '0' && real_dev[len - 1] <= '9')
+ {
+ p = real_dev + len;
+ format = "p%d";
+ }
+ else
+ {
+ p = real_dev + len;
+ format = "%d";
+ }
+
+ for (cache = linux_partition_cache_list; cache; cache = cache->next)
+ {
+ if (strcmp (cache->dev, dev) == 0 && cache->start == sector)
+ {
+ sprintf (p, format, cache->partno);
+ strcpy (dev, real_dev);
+ return 1;
+ }
+ }
+
+ for (i = 1; i < 10000; i++)
+ {
+ grub_util_fd_t fd;
+ grub_disk_addr_t start;
+ struct stat st;
+
+ sprintf (p, format, i);
+
+ fd = open (real_dev, O_RDONLY);
+ if (fd == -1)
+ {
+ if (missing++ < 10)
+ continue;
+ else
+ return 0;
+ }
+ missing = 0;
+
+ if (fstat (fd, &st) < 0
+ || !grub_util_device_is_mapped_stat (&st)
+ || !grub_util_get_dm_node_linear_info (st.st_rdev, 0, 0, &start))
+ start = grub_util_find_partition_start_os (real_dev);
+ /* We don't care about errors here. */
+ grub_errno = GRUB_ERR_NONE;
+
+ close (fd);
+
+ if (start == sector)
+ {
+ struct linux_partition_cache *new_cache_item;
+
+ new_cache_item = xmalloc (sizeof *new_cache_item);
+ new_cache_item->dev = xstrdup (dev);
+ new_cache_item->start = start;
+ new_cache_item->partno = i;
+ grub_list_push (GRUB_AS_LIST_P (&linux_partition_cache_list),
+ GRUB_AS_LIST (new_cache_item));
+
+ strcpy (dev, real_dev);
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+#pragma GCC diagnostic error "-Wformat-nonliteral"
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev)
+{
+ grub_util_fd_t fd;
+ struct stat st;
+
+ fd = open (os_dev, O_RDONLY);
+ if (fd >= 0 && fstat (fd, &st) >= 0 && S_ISBLK (st.st_mode))
+ ioctl (fd, BLKFLSBUF, 0);
+ if (fd >= 0)
+ close (fd);
+}
+
+int
+grub_util_fd_open_device (const grub_disk_t disk, grub_disk_addr_t sector, int flags,
+ grub_disk_addr_t *max)
+{
+ grub_util_fd_t fd;
+ struct grub_util_hostdisk_data *data = disk->data;
+
+ *max = ~0ULL;
+
+#ifdef O_LARGEFILE
+ flags |= O_LARGEFILE;
+#endif
+#ifdef O_SYNC
+ flags |= O_SYNC;
+#endif
+#ifdef O_FSYNC
+ flags |= O_FSYNC;
+#endif
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+#ifdef O_CLOEXEC
+ flags |= O_CLOEXEC;
+#endif
+
+ /* Linux has a bug that the disk cache for a whole disk is not consistent
+ with the one for a partition of the disk. */
+ {
+ int is_partition = 0;
+ char dev[PATH_MAX];
+ grub_disk_addr_t part_start = 0;
+
+ part_start = grub_partition_get_start (disk->partition)
+ >> (disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
+
+ strncpy (dev, grub_util_biosdisk_get_osdev (disk), sizeof (dev) - 1);
+ dev[sizeof(dev) - 1] = '\0';
+ if (disk->partition
+ && strncmp (dev, "/dev/", 5) == 0)
+ {
+ if (sector >= part_start)
+ is_partition = grub_hostdisk_linux_find_partition (dev, part_start);
+ else
+ *max = part_start - sector;
+ }
+
+ reopen:
+
+ if (data->dev && strcmp (data->dev, dev) == 0 &&
+ data->access_mode == (flags & O_ACCMODE))
+ {
+ grub_dprintf ("hostdisk", "reusing open device `%s'\n", dev);
+ fd = data->fd;
+ }
+ else
+ {
+ free (data->dev);
+ data->dev = 0;
+ if (data->fd != -1)
+ {
+ if (data->access_mode == O_RDWR || data->access_mode == O_WRONLY)
+ {
+ fsync (data->fd);
+ if (data->is_disk)
+ ioctl (data->fd, BLKFLSBUF, 0);
+ }
+
+ close (data->fd);
+ data->fd = -1;
+ }
+
+ /* Open the partition. */
+ grub_dprintf ("hostdisk", "opening the device `%s' in open_device()\n", dev);
+ fd = open (dev, flags);
+ if (fd < 0)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
+ dev, strerror (errno));
+ return -1;
+ }
+
+ data->dev = xstrdup (dev);
+ data->access_mode = (flags & O_ACCMODE);
+ data->fd = fd;
+
+ if (data->is_disk)
+ ioctl (data->fd, BLKFLSBUF, 0);
+ }
+
+ if (is_partition)
+ {
+ *max = grub_util_get_fd_size (fd, dev, 0);
+ *max >>= disk->log_sector_size;
+ if (sector - part_start >= *max)
+ {
+ *max = disk->partition->len - (sector - part_start);
+ if (*max == 0)
+ *max = ~0ULL;
+ is_partition = 0;
+ strncpy (dev, grub_util_biosdisk_get_osdev (disk), sizeof (dev) - 1);
+ dev[sizeof(dev) - 1] = '\0';
+ goto reopen;
+ }
+ sector -= part_start;
+ *max -= sector;
+ }
+ }
+
+ if (grub_util_fd_seek (fd, sector << disk->log_sector_size))
+ {
+ close (fd);
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot seek `%s': %s"),
+ grub_util_biosdisk_get_osdev (disk), strerror (errno));
+ return -1;
+ }
+
+ return fd;
+}
diff --git a/grub-core/osdep/linux/ofpath.c b/grub-core/osdep/linux/ofpath.c
new file mode 100644
index 0000000..a6153d3
--- /dev/null
+++ b/grub-core/osdep/linux/ofpath.c
@@ -0,0 +1,769 @@
+/* ofpath.c - calculate OpenFirmware path names given an OS device */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009, 2011,2012, 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#undef OFPATH_STANDALONE
+
+#ifndef OFPATH_STANDALONE
+#include <grub/types.h>
+#include <grub/util/misc.h>
+#include <grub/util/ofpath.h>
+#include <grub/i18n.h>
+#endif
+
+#include <limits.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+
+#ifdef __sparc__
+typedef enum
+ {
+ GRUB_OFPATH_SPARC_WWN_ADDR = 1,
+ GRUB_OFPATH_SPARC_TGT_LUN,
+ } ofpath_sparc_addressing;
+
+struct ofpath_sparc_hba
+{
+ grub_uint32_t device_id;
+ ofpath_sparc_addressing addressing;
+};
+
+static struct ofpath_sparc_hba sparc_lsi_hba[] = {
+ /* Rhea, Jasper 320, LSI53C1020/1030. */
+ {0x30, GRUB_OFPATH_SPARC_TGT_LUN},
+ /* SAS-1068E. */
+ {0x50, GRUB_OFPATH_SPARC_TGT_LUN},
+ /* SAS-1064E. */
+ {0x56, GRUB_OFPATH_SPARC_TGT_LUN},
+ /* Pandora SAS-1068E. */
+ {0x58, GRUB_OFPATH_SPARC_TGT_LUN},
+ /* Aspen, Invader, LSI SAS-3108. */
+ {0x5d, GRUB_OFPATH_SPARC_TGT_LUN},
+ /* Niwot, SAS 2108. */
+ {0x79, GRUB_OFPATH_SPARC_TGT_LUN},
+ /* Erie, Falcon, LSI SAS 2008. */
+ {0x72, GRUB_OFPATH_SPARC_WWN_ADDR},
+ /* LSI WarpDrive 6203. */
+ {0x7e, GRUB_OFPATH_SPARC_WWN_ADDR},
+ /* LSI SAS 2308. */
+ {0x87, GRUB_OFPATH_SPARC_WWN_ADDR},
+ /* LSI SAS 3008. */
+ {0x97, GRUB_OFPATH_SPARC_WWN_ADDR},
+ {0, 0}
+};
+
+static const int LSI_VENDOR_ID = 0x1000;
+#endif
+
+#ifdef OFPATH_STANDALONE
+#define xmalloc malloc
+void
+grub_util_error (const char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf (stderr, "ofpath: error: ");
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+ fputc ('\n', stderr);
+ exit (1);
+}
+
+void
+grub_util_info (const char *fmt, ...)
+{
+ va_list ap;
+
+ fprintf (stderr, "ofpath: info: ");
+ va_start (ap, fmt);
+ vfprintf (stderr, fmt, ap);
+ va_end (ap);
+ fputc ('\n', stderr);
+}
+
+#define grub_util_warn grub_util_info
+#define _(x) x
+#define xstrdup strdup
+#endif
+
+static void
+kill_trailing_dir(char *path)
+{
+ char *end = path + strlen(path) - 1;
+
+ while (end >= path)
+ {
+ if (*end != '/')
+ {
+ end--;
+ continue;
+ }
+ *end = '\0';
+ break;
+ }
+}
+
+static void
+trim_newline (char *path)
+{
+ char *end = path + strlen(path) - 1;
+
+ while (*end == '\n')
+ *end-- = '\0';
+}
+
+#define MAX_DISK_CAT 64
+
+static char *
+find_obppath (const char *sysfs_path_orig)
+{
+ char *sysfs_path, *path;
+ size_t path_size = strlen (sysfs_path_orig) + sizeof ("/obppath");
+
+ sysfs_path = xstrdup (sysfs_path_orig);
+ path = xmalloc (path_size);
+
+ while (1)
+ {
+ int fd;
+ char *of_path;
+ struct stat st;
+ size_t size;
+
+ snprintf(path, path_size, "%s/obppath", sysfs_path);
+#if 0
+ printf("Trying %s\n", path);
+#endif
+
+ fd = open(path, O_RDONLY);
+
+#ifndef __sparc__
+ if (fd < 0 || fstat (fd, &st) < 0)
+ {
+ if (fd >= 0)
+ close (fd);
+ snprintf(path, path_size, "%s/devspec", sysfs_path);
+ fd = open(path, O_RDONLY);
+ }
+#endif
+
+ if (fd < 0 || fstat (fd, &st) < 0)
+ {
+ if (fd >= 0)
+ close (fd);
+ kill_trailing_dir(sysfs_path);
+ if (!strcmp(sysfs_path, "/sys"))
+ {
+ grub_util_info (_("`obppath' not found in parent dirs of `%s',"
+ " no IEEE1275 name discovery"),
+ sysfs_path_orig);
+ free (path);
+ free (sysfs_path);
+ return NULL;
+ }
+ continue;
+ }
+ size = st.st_size;
+ of_path = xmalloc (size + MAX_DISK_CAT + 1);
+ memset(of_path, 0, size + MAX_DISK_CAT + 1);
+ if (read(fd, of_path, size) < 0)
+ {
+ grub_util_info (_("cannot read `%s': %s"), path, strerror (errno));
+ close(fd);
+ free (path);
+ free (of_path);
+ free (sysfs_path);
+ return NULL;
+ }
+ close(fd);
+
+ trim_newline(of_path);
+ free (path);
+ free (sysfs_path);
+ return of_path;
+ }
+}
+
+static char *
+xrealpath (const char *in)
+{
+ char *out;
+#ifdef PATH_MAX
+ out = xmalloc (PATH_MAX);
+ out = realpath (in, out);
+#else
+ out = realpath (in, NULL);
+#endif
+ if (!out)
+ grub_util_error (_("failed to get canonical path of `%s'"), in);
+ return out;
+}
+
+static char *
+block_device_get_sysfs_path_and_link(const char *devicenode)
+{
+ char *rpath;
+ char *rpath2;
+ char *ret;
+ size_t tmp_size = strlen (devicenode) + sizeof ("/sys/block/");
+ char *tmp = xmalloc (tmp_size);
+
+ memcpy (tmp, "/sys/block/", sizeof ("/sys/block/"));
+ strcat (tmp, devicenode);
+
+ rpath = xrealpath (tmp);
+ rpath2 = xmalloc (strlen (rpath) + sizeof ("/device"));
+ strcpy (rpath2, rpath);
+ strcat (rpath2, "/device");
+
+ ret = xrealpath (rpath2);
+
+ free (tmp);
+ free (rpath);
+ free (rpath2);
+ return ret;
+}
+
+static inline int
+my_isdigit (int c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+static const char *
+trailing_digits (const char *p)
+{
+ const char *end;
+
+ end = p + strlen(p) - 1;
+ while (end >= p)
+ {
+ if (! my_isdigit(*end))
+ break;
+ end--;
+ }
+
+ return end + 1;
+}
+
+static char *
+__of_path_common(char *sysfs_path,
+ const char *device, int devno)
+{
+ const char *digit_string;
+ char disk[MAX_DISK_CAT];
+ char *of_path = find_obppath(sysfs_path);
+
+ if (!of_path)
+ return NULL;
+
+ digit_string = trailing_digits (device);
+ if (*digit_string == '\0')
+ {
+ snprintf(disk, sizeof (disk), "/disk@%d", devno);
+ }
+ else
+ {
+ int part;
+
+ sscanf(digit_string, "%d", &part);
+ snprintf(disk, sizeof (disk), "/disk@%d:%c", devno, 'a' + (part - 1));
+ }
+ strcat(of_path, disk);
+ return of_path;
+}
+
+static char *
+get_basename(char *p)
+{
+ char *ret = p;
+
+ while (*p)
+ {
+ if (*p == '/')
+ ret = p + 1;
+ p++;
+ }
+
+ return ret;
+}
+
+static char *
+of_path_of_vdisk(const char *sys_devname __attribute__((unused)),
+ const char *device,
+ const char *devnode __attribute__((unused)),
+ const char *devicenode)
+{
+ char *sysfs_path, *p;
+ int devno, junk;
+ char *ret;
+
+ sysfs_path = block_device_get_sysfs_path_and_link(devicenode);
+ p = get_basename (sysfs_path);
+ sscanf(p, "vdc-port-%d-%d", &devno, &junk);
+ ret = __of_path_common (sysfs_path, device, devno);
+
+ free (sysfs_path);
+ return ret;
+}
+
+static char *
+of_path_of_ide(const char *sys_devname __attribute__((unused)), const char *device,
+ const char *devnode __attribute__((unused)),
+ const char *devicenode)
+{
+ char *sysfs_path, *p;
+ int chan, devno;
+ char *ret;
+
+ sysfs_path = block_device_get_sysfs_path_and_link(devicenode);
+ p = get_basename (sysfs_path);
+ sscanf(p, "%d.%d", &chan, &devno);
+
+ ret = __of_path_common(sysfs_path, device, 2 * chan + devno);
+
+ free (sysfs_path);
+ return ret;
+}
+
+#ifdef __sparc__
+static char *
+of_path_of_nvme(const char *sys_devname __attribute__((unused)),
+ const char *device,
+ const char *devnode __attribute__((unused)),
+ const char *devicenode)
+{
+ char *sysfs_path, *of_path, disk[MAX_DISK_CAT];
+ const char *digit_string, *part_end;
+
+ digit_string = trailing_digits (device);
+ part_end = devicenode + strlen (devicenode) - 1;
+
+ if ((*digit_string != '\0') && (*part_end == 'p'))
+ {
+ /* We have a partition number, strip it off. */
+ int part;
+ char *nvmedev, *end;
+
+ nvmedev = strdup (devicenode);
+
+ if (!nvmedev)
+ return NULL;
+
+ end = nvmedev + strlen (nvmedev) - 1;
+ /* Remove the p. */
+ *end = '\0';
+ sscanf (digit_string, "%d", &part);
+ snprintf (disk, sizeof (disk), "/disk@1:%c", 'a' + (part - 1));
+ sysfs_path = block_device_get_sysfs_path_and_link (nvmedev);
+ free (nvmedev);
+ }
+ else
+ {
+ /* We do not have the parition. */
+ snprintf (disk, sizeof (disk), "/disk@1");
+ sysfs_path = block_device_get_sysfs_path_and_link (device);
+ }
+
+ of_path = find_obppath (sysfs_path);
+
+ if (of_path)
+ strcat (of_path, disk);
+
+ free (sysfs_path);
+ return of_path;
+}
+#endif
+
+static int
+vendor_is_ATA(const char *path)
+{
+ int fd, err;
+ char *bufname;
+ char bufcont[3];
+ size_t path_size;
+
+ path_size = strlen (path) + sizeof ("/vendor");
+
+ bufname = xmalloc (path_size);
+
+ snprintf (bufname, path_size, "%s/vendor", path);
+ fd = open (bufname, O_RDONLY);
+ if (fd < 0)
+ grub_util_error (_("cannot open `%s': %s"), bufname, strerror (errno));
+
+ memset(bufcont, 0, sizeof (bufcont));
+ err = read(fd, bufcont, sizeof (bufcont));
+ if (err < 0)
+ grub_util_error (_("cannot open `%s': %s"), bufname, strerror (errno));
+
+ close(fd);
+ free (bufname);
+
+ return (memcmp(bufcont, "ATA", 3) == 0);
+}
+
+#ifdef __sparc__
+static void
+check_hba_identifiers (const char *sysfs_path, int *vendor, int *device_id)
+{
+ char *ed = strstr (sysfs_path, "host");
+ size_t path_size;
+ char *p, *path;
+ char buf[8];
+ int fd;
+
+ if (!ed)
+ return;
+
+ p = xstrdup (sysfs_path);
+ ed = strstr (p, "host");
+
+ *ed = '\0';
+
+ path_size = (strlen (p) + sizeof ("vendor"));
+ path = xmalloc (path_size);
+
+ if (!path)
+ goto out;
+
+ snprintf (path, path_size, "%svendor", p);
+ fd = open (path, O_RDONLY);
+
+ if (fd < 0)
+ goto out;
+
+ memset (buf, 0, sizeof (buf));
+
+ if (read (fd, buf, sizeof (buf) - 1) < 0)
+ goto out;
+
+ close (fd);
+ sscanf (buf, "%x", vendor);
+
+ snprintf (path, path_size, "%sdevice", p);
+ fd = open (path, O_RDONLY);
+
+ if (fd < 0)
+ goto out;
+
+ memset (buf, 0, sizeof (buf));
+
+ if (read (fd, buf, sizeof (buf) - 1) < 0)
+ goto out;
+
+ close (fd);
+ sscanf (buf, "%x", device_id);
+
+ out:
+ free (path);
+ free (p);
+}
+#endif
+
+static void
+check_sas (const char *sysfs_path, int *tgt, unsigned long int *sas_address)
+{
+ char *ed = strstr (sysfs_path, "end_device");
+ char *p, *q, *path;
+ char phy[21];
+ int fd;
+ size_t path_size;
+
+ if (!ed)
+ return;
+
+ /* SAS devices are identified using disk@$PHY_ID */
+ p = xstrdup (sysfs_path);
+ ed = strstr(p, "end_device");
+ if (!ed)
+ return;
+
+ q = ed;
+ while (*q && *q != '/')
+ q++;
+ *q = '\0';
+
+ path_size = (strlen (p) + strlen (ed)
+ + sizeof ("%s/sas_device/%s/phy_identifier"));
+ path = xmalloc (path_size);
+ snprintf (path, path_size, "%s/sas_device/%s/phy_identifier", p, ed);
+ fd = open (path, O_RDONLY);
+ if (fd < 0)
+ grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
+
+ memset (phy, 0, sizeof (phy));
+ if (read (fd, phy, sizeof (phy) - 1) < 0)
+ grub_util_error (_("cannot read `%s': %s"), path, strerror (errno));
+
+ close (fd);
+
+ sscanf (phy, "%d", tgt);
+
+ snprintf (path, path_size, "%s/sas_device/%s/sas_address", p, ed);
+ fd = open (path, O_RDONLY);
+ if (fd < 0)
+ grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
+
+ memset (phy, 0, sizeof (phy));
+ if (read (fd, phy, sizeof (phy) - 1) < 0)
+ grub_util_error (_("cannot read `%s': %s"), path, strerror (errno));
+ sscanf (phy, "%lx", sas_address);
+
+ free (path);
+ free (p);
+ close (fd);
+}
+
+static char *
+of_path_of_scsi(const char *sys_devname __attribute__((unused)), const char *device,
+ const char *devnode __attribute__((unused)),
+ const char *devicenode)
+{
+ const char *p, *digit_string, *disk_name;
+ int host, bus, tgt, lun;
+ unsigned long int sas_address = 0;
+ char *sysfs_path, disk[MAX_DISK_CAT - sizeof ("/fp@0,0")];
+ char *of_path;
+
+ sysfs_path = block_device_get_sysfs_path_and_link(devicenode);
+ p = get_basename (sysfs_path);
+ sscanf(p, "%d:%d:%d:%d", &host, &bus, &tgt, &lun);
+ check_sas (sysfs_path, &tgt, &sas_address);
+
+ if (vendor_is_ATA(sysfs_path))
+ {
+ of_path = __of_path_common(sysfs_path, device, tgt);
+ free (sysfs_path);
+ return of_path;
+ }
+
+ of_path = find_obppath(sysfs_path);
+ if (!of_path)
+ goto out;
+
+ if (strstr (of_path, "qlc"))
+ strcat (of_path, "/fp@0,0");
+
+ if (strstr (of_path, "sbus"))
+ disk_name = "sd";
+ else
+ disk_name = "disk";
+
+ digit_string = trailing_digits (device);
+ if (strncmp (of_path, "/vdevice/", sizeof ("/vdevice/") - 1) == 0)
+ {
+ unsigned long id = 0x8000 | (tgt << 8) | (bus << 5) | lun;
+ if (*digit_string == '\0')
+ {
+ snprintf(disk, sizeof (disk), "/%s@%04lx000000000000", disk_name, id);
+ }
+ else
+ {
+ int part;
+
+ sscanf(digit_string, "%d", &part);
+ snprintf(disk, sizeof (disk),
+ "/%s@%04lx000000000000:%c", disk_name, id, 'a' + (part - 1));
+ }
+ }
+ else
+ {
+#ifdef __sparc__
+ ofpath_sparc_addressing addressing = GRUB_OFPATH_SPARC_TGT_LUN;
+ int vendor = 0, device_id = 0;
+ char *optr = disk;
+
+ check_hba_identifiers (sysfs_path, &vendor, &device_id);
+
+ if (vendor == LSI_VENDOR_ID)
+ {
+ struct ofpath_sparc_hba *lsi_hba;
+
+ /*
+ * Over time different OF addressing schemes have been supported.
+ * There is no generic addressing scheme that works across
+ * every HBA.
+ */
+ for (lsi_hba = sparc_lsi_hba; lsi_hba->device_id; lsi_hba++)
+ if (lsi_hba->device_id == device_id)
+ {
+ addressing = lsi_hba->addressing;
+ break;
+ }
+ }
+
+ if (addressing == GRUB_OFPATH_SPARC_WWN_ADDR)
+ optr += snprintf (disk, sizeof (disk), "/%s@w%lx,%x", disk_name,
+ sas_address, lun);
+ else
+ optr += snprintf (disk, sizeof (disk), "/%s@%x,%x", disk_name, tgt,
+ lun);
+
+ if (*digit_string != '\0')
+ {
+ int part;
+
+ sscanf (digit_string, "%d", &part);
+ snprintf (optr, sizeof (disk) - (optr - disk - 1), ":%c", 'a'
+ + (part - 1));
+ }
+#else
+ if (lun == 0)
+ {
+ int sas_id = 0;
+ sas_id = bus << 16 | tgt << 8 | lun;
+
+ if (*digit_string == '\0')
+ {
+ snprintf(disk, sizeof (disk), "/sas/%s@%x", disk_name, sas_id);
+ }
+ else
+ {
+ int part;
+
+ sscanf(digit_string, "%d", &part);
+ snprintf(disk, sizeof (disk),
+ "/sas/%s@%x:%c", disk_name, sas_id, 'a' + (part - 1));
+ }
+ }
+ else
+ {
+ char *lunstr;
+ int lunpart[4];
+
+ lunstr = xmalloc (20);
+
+ lunpart[0] = (lun >> 8) & 0xff;
+ lunpart[1] = lun & 0xff;
+ lunpart[2] = (lun >> 24) & 0xff;
+ lunpart[3] = (lun >> 16) & 0xff;
+
+ sprintf(lunstr, "%02x%02x%02x%02x00000000", lunpart[0], lunpart[1], lunpart[2], lunpart[3]);
+ long int longlun = atol(lunstr);
+
+ if (*digit_string == '\0')
+ {
+ snprintf(disk, sizeof (disk), "/sas/%s@%lx,%lu", disk_name, sas_address, longlun);
+ }
+ else
+ {
+ int part;
+
+ sscanf(digit_string, "%d", &part);
+ snprintf(disk, sizeof (disk),
+ "/sas/%s@%lx,%lu:%c", disk_name, sas_address, longlun, 'a' + (part - 1));
+ }
+ free (lunstr);
+ }
+#endif
+ }
+ strcat(of_path, disk);
+
+ out:
+ free (sysfs_path);
+ return of_path;
+}
+
+static char *
+strip_trailing_digits (const char *p)
+{
+ char *new, *end;
+
+ new = strdup (p);
+ end = new + strlen(new) - 1;
+ while (end >= new)
+ {
+ if (! my_isdigit(*end))
+ break;
+ *end-- = '\0';
+ }
+
+ return new;
+}
+
+char *
+grub_util_devname_to_ofpath (const char *sys_devname)
+{
+ char *name_buf, *device, *devnode, *devicenode, *ofpath;
+
+ name_buf = xrealpath (sys_devname);
+
+ device = get_basename (name_buf);
+ devnode = strip_trailing_digits (name_buf);
+ devicenode = strip_trailing_digits (device);
+
+ if (device[0] == 'h' && device[1] == 'd')
+ ofpath = of_path_of_ide(name_buf, device, devnode, devicenode);
+ else if (device[0] == 's'
+ && (device[1] == 'd' || device[1] == 'r'))
+ ofpath = of_path_of_scsi(name_buf, device, devnode, devicenode);
+ else if (device[0] == 'v' && device[1] == 'd' && device[2] == 'i'
+ && device[3] == 's' && device[4] == 'k')
+ ofpath = of_path_of_vdisk(name_buf, device, devnode, devicenode);
+ else if (device[0] == 'f' && device[1] == 'd'
+ && device[2] == '0' && device[3] == '\0')
+ /* All the models I've seen have a devalias "floppy".
+ New models have no floppy at all. */
+ ofpath = xstrdup ("floppy");
+#ifdef __sparc__
+ else if (device[0] == 'n' && device[1] == 'v' && device[2] == 'm'
+ && device[3] == 'e')
+ ofpath = of_path_of_nvme (name_buf, device, devnode, devicenode);
+#endif
+ else
+ {
+ grub_util_warn (_("unknown device type %s"), device);
+ ofpath = NULL;
+ }
+
+ free (devnode);
+ free (devicenode);
+ free (name_buf);
+
+ return ofpath;
+}
+
+#ifdef OFPATH_STANDALONE
+int main(int argc, char **argv)
+{
+ char *of_path;
+
+ if (argc != 2)
+ {
+ printf(_("Usage: %s DEVICE\n"), argv[0]);
+ return 1;
+ }
+
+ of_path = grub_util_devname_to_ofpath (argv[1]);
+ if (of_path)
+ printf("%s\n", of_path);
+ free (of_path);
+
+ return 0;
+}
+#endif
diff --git a/grub-core/osdep/linux/platform.c b/grub-core/osdep/linux/platform.c
new file mode 100644
index 0000000..e28a79d
--- /dev/null
+++ b/grub-core/osdep/linux/platform.c
@@ -0,0 +1,156 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <grub/util/install.h>
+#include <grub/emu/exec.h>
+#include <grub/emu/misc.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+
+#include <sys/utsname.h>
+
+static int
+is_not_empty_directory (const char *dir)
+{
+ DIR *d;
+ struct dirent *de;
+
+ d = opendir (dir);
+ if (!d)
+ return 0;
+ while ((de = readdir (d)))
+ {
+ if (strcmp (de->d_name, ".") == 0
+ || strcmp (de->d_name, "..") == 0)
+ continue;
+ closedir (d);
+ return 1;
+ }
+
+ closedir (d);
+ return 0;
+}
+
+static int
+is_64_kernel (void)
+{
+ struct utsname un;
+
+ if (uname (&un) < 0)
+ return 0;
+
+ return strcmp (un.machine, "x86_64") == 0;
+}
+
+static int
+read_platform_size (void)
+{
+ FILE *fp;
+ char *buf = NULL;
+ size_t len = 0;
+ int ret = 0;
+
+ /* Newer kernels can tell us directly about the size of the
+ * underlying firmware - let's see if that interface is there. */
+ fp = grub_util_fopen ("/sys/firmware/efi/fw_platform_size", "r");
+ if (fp != NULL)
+ {
+ if (getline (&buf, &len, fp) >= 3) /* 2 digits plus newline */
+ {
+ if (strncmp (buf, "32", 2) == 0)
+ ret = 32;
+ else if (strncmp (buf, "64", 2) == 0)
+ ret = 64;
+ }
+ free (buf);
+ fclose (fp);
+ }
+
+ if (ret == 0)
+ {
+ /* Unrecognised - fall back to matching the kernel size
+ * instead */
+ if (is_64_kernel ())
+ ret = 64;
+ else
+ ret = 32;
+ }
+
+ return ret;
+}
+
+/* Are we running on an EFI-based system? */
+static int
+is_efi_system (void)
+{
+ /*
+ * Linux uses efivarfs (mounted on /sys/firmware/efi/efivars) to access the
+ * EFI variable store. Some legacy systems may still use the deprecated
+ * efivars interface (accessed through /sys/firmware/efi/vars). Where both
+ * are present, libefivar will use the former in preference, so attempting
+ * to load efivars will not interfere with later operations.
+ */
+ grub_util_exec_redirect_all ((const char * []){ "modprobe", "efivars", NULL },
+ NULL, NULL, "/dev/null");
+
+ grub_util_info ("Looking for /sys/firmware/efi ..");
+ if (is_not_empty_directory ("/sys/firmware/efi"))
+ {
+ grub_util_info ("...found");
+ return 1;
+ }
+ else
+ {
+ grub_util_info ("... not found");
+ return 0;
+ }
+}
+
+const char *
+grub_install_get_default_arm_platform (void)
+{
+ if (is_efi_system())
+ return "arm-efi";
+ else
+ return "arm-uboot";
+}
+
+const char *
+grub_install_get_default_x86_platform (void)
+{
+ if (is_efi_system())
+ {
+ if (read_platform_size() == 64)
+ return "x86_64-efi";
+ else
+ return "i386-efi";
+ }
+
+ grub_util_info ("Looking for /proc/device-tree ..");
+ if (is_not_empty_directory ("/proc/device-tree"))
+ {
+ grub_util_info ("...found");
+ return "i386-ieee1275";
+ }
+
+ grub_util_info ("... not found");
+ return "i386-pc";
+}
diff --git a/grub-core/osdep/ofpath.c b/grub-core/osdep/ofpath.c
new file mode 100644
index 0000000..1389b1d
--- /dev/null
+++ b/grub-core/osdep/ofpath.c
@@ -0,0 +1,5 @@
+#if defined (__linux__)
+#include "linux/ofpath.c"
+#else
+#include "basic/ofpath.c"
+#endif
diff --git a/grub-core/osdep/password.c b/grub-core/osdep/password.c
new file mode 100644
index 0000000..1a7615e
--- /dev/null
+++ b/grub-core/osdep/password.c
@@ -0,0 +1,5 @@
+#if defined (__MINGW32__) && !defined (__CYGWIN__)
+#include "windows/password.c"
+#else
+#include "unix/password.c"
+#endif
diff --git a/grub-core/osdep/platform.c b/grub-core/osdep/platform.c
new file mode 100644
index 0000000..441d152
--- /dev/null
+++ b/grub-core/osdep/platform.c
@@ -0,0 +1,9 @@
+#ifdef __linux__
+#include "linux/platform.c"
+#elif defined (__MINGW32__) || defined (__CYGWIN__)
+#include "windows/platform.c"
+#elif defined (__MINGW32__) || defined (__CYGWIN__) || defined (__AROS__)
+#include "basic/no_platform.c"
+#else
+#include "basic/platform.c"
+#endif
diff --git a/grub-core/osdep/platform_unix.c b/grub-core/osdep/platform_unix.c
new file mode 100644
index 0000000..db6a02d
--- /dev/null
+++ b/grub-core/osdep/platform_unix.c
@@ -0,0 +1,3 @@
+#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__AROS__)
+#include "unix/platform.c"
+#endif
diff --git a/grub-core/osdep/random.c b/grub-core/osdep/random.c
new file mode 100644
index 0000000..c6f9bc5
--- /dev/null
+++ b/grub-core/osdep/random.c
@@ -0,0 +1,10 @@
+#if defined (_WIN32) || defined (__CYGWIN__)
+#include "windows/random.c"
+#elif defined (__linux__) || defined (__FreeBSD__) \
+ || defined (__FreeBSD_kernel__) || defined (__OpenBSD__) \
+ || defined (__GNU__) || defined (__NetBSD__) \
+ || defined (__APPLE__) || defined(__sun__) || defined (__HAIKU__)
+#include "unix/random.c"
+#else
+#include "basic/random.c"
+#endif
diff --git a/grub-core/osdep/relpath.c b/grub-core/osdep/relpath.c
new file mode 100644
index 0000000..4e10d8a
--- /dev/null
+++ b/grub-core/osdep/relpath.c
@@ -0,0 +1,7 @@
+#if defined (__MINGW32__) || defined (__CYGWIN__)
+#include "windows/relpath.c"
+#elif defined (__AROS__)
+#include "aros/relpath.c"
+#else
+#include "unix/relpath.c"
+#endif
diff --git a/grub-core/osdep/sleep.c b/grub-core/osdep/sleep.c
new file mode 100644
index 0000000..c4ff172
--- /dev/null
+++ b/grub-core/osdep/sleep.c
@@ -0,0 +1,5 @@
+#if defined (__MINGW32__) || defined (__CYGWIN__)
+#include "windows/sleep.c"
+#else
+#include "unix/sleep.c"
+#endif
diff --git a/grub-core/osdep/sun/getroot.c b/grub-core/osdep/sun/getroot.c
new file mode 100644
index 0000000..6116037
--- /dev/null
+++ b/grub-core/osdep/sun/getroot.c
@@ -0,0 +1,126 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <grub/types.h>
+
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+
+#include <sys/wait.h>
+
+# include <sys/types.h>
+# include <sys/mkdev.h>
+# include <sys/dkio.h>
+
+
+char *
+grub_util_part_to_disk (const char *os_dev,
+ struct stat *st,
+ int *is_part)
+{
+ char *colon = grub_strrchr (os_dev, ':');
+
+ if (! S_ISCHR (st->st_mode))
+ {
+ *is_part = 0;
+ return xstrdup (os_dev);
+ }
+
+ if (grub_memcmp (os_dev, "/devices", sizeof ("/devices") - 1) == 0
+ && colon)
+ {
+ char *ret = xmalloc (colon - os_dev + sizeof (":q,raw"));
+ if (grub_strcmp (colon, ":q,raw") != 0)
+ *is_part = 1;
+ grub_memcpy (ret, os_dev, colon - os_dev);
+ grub_memcpy (ret + (colon - os_dev), ":q,raw", sizeof (":q,raw"));
+ return ret;
+ }
+ else
+ return xstrdup (os_dev);
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
+{
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
+ enum grub_dev_abstraction_types ab __attribute__ ((unused)))
+{
+ return 0;
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *dev)
+{
+ int fd;
+ struct extpart_info pinfo;
+
+ fd = open (dev, O_RDONLY);
+ if (fd == -1)
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE, N_("cannot open `%s': %s"),
+ dev, strerror (errno));
+ return 0;
+ }
+
+ if (ioctl (fd, DKIOCEXTPARTINFO, &pinfo))
+ {
+ grub_error (GRUB_ERR_BAD_DEVICE,
+ "cannot get disk geometry of `%s'", dev);
+ close (fd);
+ return 0;
+ }
+
+ close (fd);
+
+ return pinfo.p_start;
+}
diff --git a/grub-core/osdep/sun/hostdisk.c b/grub-core/osdep/sun/hostdisk.c
new file mode 100644
index 0000000..dab96dc
--- /dev/null
+++ b/grub-core/osdep/sun/hostdisk.c
@@ -0,0 +1,73 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+# include <sys/dkio.h>
+
+grub_int64_t
+grub_util_get_fd_size_os (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
+{
+ struct dk_minfo minfo;
+ unsigned sector_size, log_sector_size;
+
+ if (!ioctl (fd, DKIOCGMEDIAINFO, &minfo))
+ return -1;
+
+ sector_size = minfo.dki_lbsize;
+
+ if (sector_size & (sector_size - 1) || !sector_size)
+ return -1;
+ for (log_sector_size = 0;
+ (1 << log_sector_size) < sector_size;
+ log_sector_size++);
+
+ if (log_secsize)
+ *log_secsize = log_sector_size;
+
+ return minfo.dki_capacity << log_sector_size;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
diff --git a/grub-core/osdep/unix/compress.c b/grub-core/osdep/unix/compress.c
new file mode 100644
index 0000000..dee5620
--- /dev/null
+++ b/grub-core/osdep/unix/compress.c
@@ -0,0 +1,41 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/emu/exec.h>
+#include <grub/util/install.h>
+
+int
+grub_install_compress_gzip (const char *src, const char *dest)
+{
+ return grub_util_exec_redirect ((const char * []) { "gzip", "--best",
+ "--stdout", NULL }, src, dest);
+}
+
+int
+grub_install_compress_xz (const char *src, const char *dest)
+{
+ return grub_util_exec_redirect ((const char * []) { "xz",
+ "--lzma2=dict=128KiB", "--check=none", "--stdout", NULL }, src, dest);
+}
+
+int
+grub_install_compress_lzop (const char *src, const char *dest)
+{
+ return grub_util_exec_redirect ((const char * []) { "lzop", "-9", "-c",
+ NULL }, src, dest);
+}
diff --git a/grub-core/osdep/unix/config.c b/grub-core/osdep/unix/config.c
new file mode 100644
index 0000000..7d63251
--- /dev/null
+++ b/grub-core/osdep/unix/config.c
@@ -0,0 +1,139 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/exec.h>
+#include <grub/emu/config.h>
+#include <grub/util/install.h>
+#include <grub/util/misc.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <stdlib.h>
+
+const char *
+grub_util_get_config_filename (void)
+{
+ static char *value = NULL;
+ if (!value)
+ value = grub_util_path_concat (3, GRUB_SYSCONFDIR,
+ "default", "grub");
+ return value;
+}
+
+const char *
+grub_util_get_pkgdatadir (void)
+{
+ const char *ret = getenv ("pkgdatadir");
+ if (ret)
+ return ret;
+ return GRUB_DATADIR "/" PACKAGE;
+}
+
+const char *
+grub_util_get_pkglibdir (void)
+{
+ return GRUB_LIBDIR "/" PACKAGE;
+}
+
+const char *
+grub_util_get_localedir (void)
+{
+ return LOCALEDIR;
+}
+
+void
+grub_util_load_config (struct grub_util_config *cfg)
+{
+ pid_t pid;
+ const char *argv[4];
+ char *script, *ptr;
+ const char *cfgfile, *iptr;
+ FILE *f = NULL;
+ int fd;
+ const char *v;
+
+ memset (cfg, 0, sizeof (*cfg));
+
+ v = getenv ("GRUB_ENABLE_CRYPTODISK");
+ if (v && v[0] == 'y' && v[1] == '\0')
+ cfg->is_cryptodisk_enabled = 1;
+
+ v = getenv ("GRUB_DISTRIBUTOR");
+ if (v)
+ cfg->grub_distributor = xstrdup (v);
+
+ cfgfile = grub_util_get_config_filename ();
+ if (!grub_util_is_regular (cfgfile))
+ return;
+
+ argv[0] = "sh";
+ argv[1] = "-c";
+
+ script = xcalloc (4, strlen (cfgfile) + 300);
+
+ ptr = script;
+ memcpy (ptr, ". '", 3);
+ ptr += 3;
+ for (iptr = cfgfile; *iptr; iptr++)
+ {
+ if (*iptr == '\\')
+ {
+ memcpy (ptr, "'\\''", 4);
+ ptr += 4;
+ continue;
+ }
+ *ptr++ = *iptr;
+ }
+
+ strcpy (ptr, "'; printf \"GRUB_ENABLE_CRYPTODISK=%s\\nGRUB_DISTRIBUTOR=%s\\n\" "
+ "\"$GRUB_ENABLE_CRYPTODISK\" \"$GRUB_DISTRIBUTOR\"");
+
+ argv[2] = script;
+ argv[3] = '\0';
+
+ pid = grub_util_exec_pipe (argv, &fd);
+ if (pid)
+ f = fdopen (fd, "r");
+ if (f)
+ {
+ grub_util_parse_config (f, cfg, 1);
+ fclose (f);
+ }
+ if (pid)
+ {
+ close (fd);
+ waitpid (pid, NULL, 0);
+ }
+ if (f)
+ return;
+
+ f = grub_util_fopen (cfgfile, "r");
+ if (f)
+ {
+ grub_util_parse_config (f, cfg, 0);
+ fclose (f);
+ }
+ else
+ grub_util_warn (_("cannot open configuration file `%s': %s"),
+ cfgfile, strerror (errno));
+}
diff --git a/grub-core/osdep/unix/cputime.c b/grub-core/osdep/unix/cputime.c
new file mode 100644
index 0000000..cff359a
--- /dev/null
+++ b/grub-core/osdep/unix/cputime.c
@@ -0,0 +1,22 @@
+#include <config.h>
+#include <config-util.h>
+
+#include <sys/times.h>
+#include <unistd.h>
+#include <grub/emu/misc.h>
+
+grub_uint64_t
+grub_util_get_cpu_time_ms (void)
+{
+ struct tms tm;
+ static long sc_clk_tck;
+ if (!sc_clk_tck)
+ {
+ sc_clk_tck = sysconf(_SC_CLK_TCK);
+ if (sc_clk_tck <= 0)
+ sc_clk_tck = 1000;
+ }
+
+ times (&tm);
+ return (tm.tms_utime * 1000ULL) / sc_clk_tck;
+}
diff --git a/grub-core/osdep/unix/dl.c b/grub-core/osdep/unix/dl.c
new file mode 100644
index 0000000..562b101
--- /dev/null
+++ b/grub-core/osdep/unix/dl.c
@@ -0,0 +1,61 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <sys/mman.h>
+#include <stdlib.h>
+#include <string.h>
+
+void *
+grub_osdep_dl_memalign (grub_size_t align, grub_size_t size)
+{
+ void *ret;
+ if (align < 8192 * 16)
+ align = 8192 * 16;
+ size = ALIGN_UP (size, 8192 * 16);
+
+#if defined(HAVE_POSIX_MEMALIGN)
+ if (posix_memalign (&ret, align, size) != 0)
+ ret = 0;
+#elif defined(HAVE_MEMALIGN)
+ ret = memalign (align, size);
+#else
+#error "Complete this"
+#endif
+
+ if (!ret)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ return NULL;
+ }
+
+ mprotect (ret, size, PROT_READ | PROT_WRITE | PROT_EXEC);
+ return ret;
+}
+
+void
+grub_dl_osdep_dl_free (void *ptr)
+{
+ if (ptr)
+ free (ptr);
+}
diff --git a/grub-core/osdep/unix/emuconsole.c b/grub-core/osdep/unix/emuconsole.c
new file mode 100644
index 0000000..7308798
--- /dev/null
+++ b/grub-core/osdep/unix/emuconsole.c
@@ -0,0 +1,184 @@
+/* console.c -- console for GRUB. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <grub/term.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/time.h>
+#include <grub/terminfo.h>
+#include <grub/dl.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <termios.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <langinfo.h>
+
+#include <grub/emu/console.h>
+
+extern struct grub_terminfo_output_state grub_console_terminfo_output;
+static int original_fl;
+static int saved_orig;
+static struct termios orig_tty;
+static struct termios new_tty;
+
+static void
+put (struct grub_term_output *term __attribute__ ((unused)), const int c)
+{
+ char chr = c;
+ ssize_t actual;
+
+ actual = write (STDOUT_FILENO, &chr, 1);
+ if (actual < 1)
+ {
+ /* We cannot do anything about this, but some systems require us to at
+ least pretend to check the result. */
+ }
+}
+
+static int
+readkey (struct grub_term_input *term __attribute__ ((unused)))
+{
+ grub_uint8_t c;
+ ssize_t actual;
+
+ actual = read (STDIN_FILENO, &c, 1);
+ if (actual > 0)
+ return c;
+ return -1;
+}
+
+static grub_err_t
+grub_console_init_input (struct grub_term_input *term)
+{
+ if (!saved_orig)
+ {
+ original_fl = fcntl (STDIN_FILENO, F_GETFL);
+ fcntl (STDIN_FILENO, F_SETFL, original_fl | O_NONBLOCK);
+ }
+
+ saved_orig = 1;
+
+ tcgetattr(STDIN_FILENO, &orig_tty);
+ new_tty = orig_tty;
+ new_tty.c_lflag &= ~(ICANON | ECHO);
+ new_tty.c_cc[VMIN] = 1;
+ tcsetattr(STDIN_FILENO, TCSANOW, &new_tty);
+
+ return grub_terminfo_input_init (term);
+}
+
+static grub_err_t
+grub_console_fini_input (struct grub_term_input *term
+ __attribute__ ((unused)))
+{
+ fcntl (STDIN_FILENO, F_SETFL, original_fl);
+ tcsetattr(STDIN_FILENO, TCSANOW, &orig_tty);
+ saved_orig = 0;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_console_init_output (struct grub_term_output *term)
+{
+ struct winsize size;
+ if (ioctl (STDOUT_FILENO, TIOCGWINSZ, &size) >= 0)
+ {
+ grub_console_terminfo_output.size.x = size.ws_col;
+ grub_console_terminfo_output.size.y = size.ws_row;
+ }
+ else
+ {
+ grub_console_terminfo_output.size.x = 80;
+ grub_console_terminfo_output.size.y = 24;
+ }
+
+ grub_terminfo_output_init (term);
+
+ return 0;
+}
+
+
+
+struct grub_terminfo_input_state grub_console_terminfo_input =
+ {
+ .readkey = readkey
+ };
+
+struct grub_terminfo_output_state grub_console_terminfo_output =
+ {
+ .put = put,
+ .size = { 80, 24 }
+ };
+
+static struct grub_term_input grub_console_term_input =
+ {
+ .name = "console",
+ .init = grub_console_init_input,
+ .fini = grub_console_fini_input,
+ .getkey = grub_terminfo_getkey,
+ .data = &grub_console_terminfo_input
+ };
+
+static struct grub_term_output grub_console_term_output =
+ {
+ .name = "console",
+ .init = grub_console_init_output,
+ .putchar = grub_terminfo_putchar,
+ .getxy = grub_terminfo_getxy,
+ .getwh = grub_terminfo_getwh,
+ .gotoxy = grub_terminfo_gotoxy,
+ .cls = grub_terminfo_cls,
+ .setcolorstate = grub_terminfo_setcolorstate,
+ .setcursor = grub_terminfo_setcursor,
+ .data = &grub_console_terminfo_output,
+ .progress_update_divisor = GRUB_PROGRESS_FAST
+ };
+
+void
+grub_console_init (void)
+{
+ const char *cs = nl_langinfo (CODESET);
+ if (cs && grub_strcasecmp (cs, "UTF-8"))
+ grub_console_term_output.flags = GRUB_TERM_CODE_TYPE_UTF8_LOGICAL;
+ else
+ grub_console_term_output.flags = GRUB_TERM_CODE_TYPE_ASCII;
+ grub_term_register_input ("console", &grub_console_term_input);
+ grub_term_register_output ("console", &grub_console_term_output);
+ grub_terminfo_init ();
+ grub_terminfo_output_register (&grub_console_term_output, "vt100-color");
+}
+
+void
+grub_console_fini (void)
+{
+ if (saved_orig)
+ {
+ fcntl (STDIN_FILENO, F_SETFL, original_fl);
+ tcsetattr(STDIN_FILENO, TCSANOW, &orig_tty);
+ }
+ saved_orig = 0;
+}
diff --git a/grub-core/osdep/unix/exec.c b/grub-core/osdep/unix/exec.c
new file mode 100644
index 0000000..e8db920
--- /dev/null
+++ b/grub-core/osdep/unix/exec.c
@@ -0,0 +1,245 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <grub/misc.h>
+#include <unistd.h>
+#include <grub/emu/exec.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/util/misc.h>
+#include <grub/disk.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/wait.h>
+
+int
+grub_util_exec_redirect_all (const char *const *argv, const char *stdin_file,
+ const char *stdout_file, const char *stderr_file)
+{
+ pid_t pid;
+ int status = -1;
+ char *str, *pstr;
+ const char *const *ptr;
+ grub_size_t strl = 0;
+ for (ptr = argv; *ptr; ptr++)
+ strl += grub_strlen (*ptr) + 1;
+ if (stdin_file)
+ strl += grub_strlen (stdin_file) + 2;
+ if (stdout_file)
+ strl += grub_strlen (stdout_file) + 2;
+ if (stderr_file)
+ strl += grub_strlen (stderr_file) + 3;
+
+ pstr = str = xmalloc (strl);
+ for (ptr = argv; *ptr; ptr++)
+ {
+ pstr = grub_stpcpy (pstr, *ptr);
+ *pstr++ = ' ';
+ }
+ if (stdin_file)
+ {
+ *pstr++ = '<';
+ pstr = grub_stpcpy (pstr, stdin_file);
+ *pstr++ = ' ';
+ }
+ if (stdout_file)
+ {
+ *pstr++ = '>';
+ pstr = grub_stpcpy (pstr, stdout_file);
+ *pstr++ = ' ';
+ }
+ if (stderr_file)
+ {
+ *pstr++ = '2';
+ *pstr++ = '>';
+ pstr = grub_stpcpy (pstr, stderr_file);
+ pstr++;
+ }
+ *--pstr = '\0';
+
+ grub_util_info ("executing %s", str);
+ grub_free (str);
+
+ pid = fork ();
+ if (pid < 0)
+ grub_util_error (_("Unable to fork: %s"), strerror (errno));
+ else if (pid == 0)
+ {
+ int fd;
+ /* Child. */
+
+ /* Close fd's. */
+#ifdef GRUB_UTIL
+ grub_util_devmapper_cleanup ();
+ grub_diskfilter_fini ();
+#endif
+
+ if (stdin_file)
+ {
+ fd = open (stdin_file, O_RDONLY);
+ if (fd < 0)
+ _exit (127);
+ dup2 (fd, STDIN_FILENO);
+ close (fd);
+ }
+
+ if (stdout_file)
+ {
+ fd = open (stdout_file, O_WRONLY | O_CREAT, 0700);
+ if (fd < 0)
+ _exit (127);
+ dup2 (fd, STDOUT_FILENO);
+ close (fd);
+ }
+
+ if (stderr_file)
+ {
+ fd = open (stderr_file, O_WRONLY | O_CREAT, 0700);
+ if (fd < 0)
+ _exit (127);
+ dup2 (fd, STDERR_FILENO);
+ close (fd);
+ }
+
+ /* Ensure child is not localised. */
+ setenv ("LC_ALL", "C", 1);
+
+ execvp ((char *) argv[0], (char **) argv);
+ _exit (127);
+ }
+ waitpid (pid, &status, 0);
+ if (!WIFEXITED (status))
+ return -1;
+ return WEXITSTATUS (status);
+}
+
+int
+grub_util_exec (const char *const *argv)
+{
+ return grub_util_exec_redirect_all (argv, NULL, NULL, NULL);
+}
+
+int
+grub_util_exec_redirect (const char *const *argv, const char *stdin_file,
+ const char *stdout_file)
+{
+ return grub_util_exec_redirect_all (argv, stdin_file, stdout_file, NULL);
+}
+
+int
+grub_util_exec_redirect_null (const char *const *argv)
+{
+ return grub_util_exec_redirect_all (argv, "/dev/null", "/dev/null", NULL);
+}
+
+pid_t
+grub_util_exec_pipe (const char *const *argv, int *fd)
+{
+ int pipe_fd[2];
+ pid_t pid;
+
+ *fd = 0;
+
+ if (pipe (pipe_fd) < 0)
+ {
+ grub_util_warn (_("Unable to create pipe: %s"),
+ strerror (errno));
+ return 0;
+ }
+ pid = fork ();
+ if (pid < 0)
+ grub_util_error (_("Unable to fork: %s"), strerror (errno));
+ else if (pid == 0)
+ {
+ /* Child. */
+
+ /* Close fd's. */
+#ifdef GRUB_UTIL
+ grub_util_devmapper_cleanup ();
+ grub_diskfilter_fini ();
+#endif
+
+ /* Ensure child is not localised. */
+ setenv ("LC_ALL", "C", 1);
+
+ close (pipe_fd[0]);
+ dup2 (pipe_fd[1], STDOUT_FILENO);
+ close (pipe_fd[1]);
+
+ execvp ((char *) argv[0], (char **) argv);
+ _exit (127);
+ }
+ else
+ {
+ close (pipe_fd[1]);
+ *fd = pipe_fd[0];
+ return pid;
+ }
+}
+
+pid_t
+grub_util_exec_pipe_stderr (const char *const *argv, int *fd)
+{
+ int pipe_fd[2];
+ pid_t pid;
+
+ *fd = 0;
+
+ if (pipe (pipe_fd) < 0)
+ {
+ grub_util_warn (_("Unable to create pipe: %s"),
+ strerror (errno));
+ return 0;
+ }
+ pid = fork ();
+ if (pid < 0)
+ grub_util_error (_("Unable to fork: %s"), strerror (errno));
+ else if (pid == 0)
+ {
+ /* Child. */
+
+ /* Close fd's. */
+#ifdef GRUB_UTIL
+ grub_util_devmapper_cleanup ();
+ grub_diskfilter_fini ();
+#endif
+
+ /* Ensure child is not localised. */
+ setenv ("LC_ALL", "C", 1);
+
+ close (pipe_fd[0]);
+ dup2 (pipe_fd[1], STDOUT_FILENO);
+ dup2 (pipe_fd[1], STDERR_FILENO);
+ close (pipe_fd[1]);
+
+ execvp ((char *) argv[0], (char **) argv);
+ _exit (127);
+ }
+ else
+ {
+ close (pipe_fd[1]);
+ *fd = pipe_fd[0];
+ return pid;
+ }
+}
diff --git a/grub-core/osdep/unix/getroot.c b/grub-core/osdep/unix/getroot.c
new file mode 100644
index 0000000..46d7116
--- /dev/null
+++ b/grub-core/osdep/unix/getroot.c
@@ -0,0 +1,787 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <grub/util/misc.h>
+#include <grub/emu/exec.h>
+
+#include <grub/cryptodisk.h>
+#include <grub/i18n.h>
+
+#if !defined (__MINGW32__) && !defined (__CYGWIN__) && !defined (__AROS__) && !defined (__HAIKU__)
+
+#ifdef __linux__
+#include <sys/ioctl.h> /* ioctl */
+#include <sys/mount.h>
+#ifndef FLOPPY_MAJOR
+# define FLOPPY_MAJOR 2
+#endif /* ! FLOPPY_MAJOR */
+#endif
+
+#include <sys/types.h>
+#if defined(MAJOR_IN_MKDEV)
+#include <sys/mkdev.h>
+#elif defined(MAJOR_IN_SYSMACROS)
+#include <sys/sysmacros.h>
+#endif
+
+#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
+# include <grub/util/libzfs.h>
+# include <grub/util/libnvpair.h>
+#endif
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+# define FLOPPY_MAJOR 2
+#endif
+
+#if defined (__FreeBSD__) || defined (__FreeBSD_kernel__)
+#include <sys/mount.h>
+#endif
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+# include <sys/ioctl.h>
+# include <sys/disklabel.h> /* struct disklabel */
+# include <sys/disk.h> /* struct dkwedge_info */
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif /* defined(__NetBSD__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) */
+
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+# ifdef HAVE_GETRAWPARTITION
+# include <util.h> /* getrawpartition */
+# endif /* HAVE_GETRAWPARTITION */
+#if defined(__NetBSD__)
+# include <sys/fdio.h>
+#endif
+# ifndef FLOPPY_MAJOR
+# define FLOPPY_MAJOR 2
+# endif /* ! FLOPPY_MAJOR */
+# ifndef RAW_FLOPPY_MAJOR
+# define RAW_FLOPPY_MAJOR 9
+# endif /* ! RAW_FLOPPY_MAJOR */
+#endif /* defined(__NetBSD__) */
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#define LVM_DEV_MAPPER_STRING "/dev/linux_lvm/"
+#else
+#define LVM_DEV_MAPPER_STRING "/dev/mapper/"
+#endif
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME)
+#include <sys/param.h>
+#include <sys/mount.h>
+#endif
+
+#include "save-cwd.h"
+
+#if !defined (__GNU__)
+static void
+strip_extra_slashes (char *dir)
+{
+ char *p = dir;
+
+ while ((p = strchr (p, '/')) != 0)
+ {
+ if (p[1] == '/')
+ {
+ memmove (p, p + 1, strlen (p));
+ continue;
+ }
+ else if (p[1] == '\0')
+ {
+ if (p > dir)
+ p[0] = '\0';
+ break;
+ }
+
+ p++;
+ }
+}
+
+static char *
+xgetcwd (void)
+{
+ size_t size = 10;
+ char *path;
+
+ path = xmalloc (size);
+ while (! getcwd (path, size))
+ {
+ size <<= 1;
+ path = xrealloc (path, size);
+ }
+
+ return path;
+}
+
+char **
+grub_util_find_root_devices_from_poolname (char *poolname)
+{
+ char **devices = 0;
+ size_t ndevices = 0;
+ size_t devices_allocated = 0;
+
+#if defined(HAVE_LIBZFS) && defined(HAVE_LIBNVPAIR)
+ zpool_handle_t *zpool;
+ libzfs_handle_t *libzfs;
+ nvlist_t *config, *vdev_tree;
+ nvlist_t **children;
+ unsigned int nvlist_count;
+ unsigned int i;
+ char *device = 0;
+
+ libzfs = grub_get_libzfs_handle ();
+ if (! libzfs)
+ return NULL;
+
+ zpool = zpool_open (libzfs, poolname);
+ config = zpool_get_config (zpool, NULL);
+
+ if (nvlist_lookup_nvlist (config, "vdev_tree", &vdev_tree) != 0)
+ error (1, errno, "nvlist_lookup_nvlist (\"vdev_tree\")");
+
+ if (nvlist_lookup_nvlist_array (vdev_tree, "children", &children, &nvlist_count) != 0)
+ error (1, errno, "nvlist_lookup_nvlist_array (\"children\")");
+ assert (nvlist_count > 0);
+
+ while (nvlist_lookup_nvlist_array (children[0], "children",
+ &children, &nvlist_count) == 0)
+ assert (nvlist_count > 0);
+
+ for (i = 0; i < nvlist_count; i++)
+ {
+ if (nvlist_lookup_string (children[i], "path", &device) != 0)
+ error (1, errno, "nvlist_lookup_string (\"path\")");
+
+ struct stat st;
+ if (stat (device, &st) == 0)
+ {
+#ifdef __sun__
+ if (grub_memcmp (device, "/dev/dsk/", sizeof ("/dev/dsk/") - 1)
+ == 0)
+ device = xasprintf ("/dev/rdsk/%s",
+ device + sizeof ("/dev/dsk/") - 1);
+ else if (grub_memcmp (device, "/devices", sizeof ("/devices") - 1)
+ == 0
+ && grub_memcmp (device + strlen (device) - 4,
+ ",raw", 4) != 0)
+ device = xasprintf ("%s,raw", device);
+ else
+#endif
+ device = xstrdup (device);
+ if (ndevices >= devices_allocated)
+ {
+ devices_allocated = 2 * (devices_allocated + 8);
+ devices = xrealloc (devices, sizeof (devices[0])
+ * devices_allocated);
+ }
+ devices[ndevices++] = device;
+ }
+
+ device = NULL;
+ }
+
+ zpool_close (zpool);
+#else
+ FILE *fp;
+ int ret;
+ char *line;
+ size_t len;
+ int st;
+
+ char name[PATH_MAX + 1], state[257], readlen[257], writelen[257];
+ char cksum[257], notes[257];
+ unsigned int dummy;
+ const char *argv[4];
+ pid_t pid;
+ int fd;
+
+ argv[0] = "zpool";
+ argv[1] = "status";
+ argv[2] = poolname;
+ argv[3] = NULL;
+
+ pid = grub_util_exec_pipe (argv, &fd);
+ if (!pid)
+ return NULL;
+
+ fp = fdopen (fd, "r");
+ if (!fp)
+ {
+ grub_util_warn (_("Unable to open stream from %s: %s"),
+ "zpool", strerror (errno));
+ goto out;
+ }
+
+ st = 0;
+ while (1)
+ {
+ line = NULL;
+ ret = getline (&line, &len, fp);
+ if (ret == -1)
+ break;
+
+ if (sscanf (line, " %s %256s %256s %256s %256s %256s",
+ name, state, readlen, writelen, cksum, notes) >= 5)
+ switch (st)
+ {
+ case 0:
+ if (!strcmp (name, "NAME")
+ && !strcmp (state, "STATE")
+ && !strcmp (readlen, "READ")
+ && !strcmp (writelen, "WRITE")
+ && !strcmp (cksum, "CKSUM"))
+ st++;
+ break;
+ case 1:
+ {
+ char *ptr = line;
+ while (1)
+ {
+ if (strncmp (ptr, poolname, strlen (poolname)) == 0
+ && grub_isspace(ptr[strlen (poolname)]))
+ st++;
+ if (!grub_isspace (*ptr))
+ break;
+ ptr++;
+ }
+ }
+ break;
+ case 2:
+ if (strcmp (name, "mirror") && !sscanf (name, "mirror-%u", &dummy)
+ && !sscanf (name, "raidz%u", &dummy)
+ && !sscanf (name, "raidz1%u", &dummy)
+ && !sscanf (name, "raidz2%u", &dummy)
+ && !sscanf (name, "raidz3%u", &dummy)
+ && !strcmp (state, "ONLINE"))
+ {
+ if (ndevices >= devices_allocated)
+ {
+ devices_allocated = 2 * (devices_allocated + 8);
+ devices = xrealloc (devices, sizeof (devices[0])
+ * devices_allocated);
+ }
+ if (name[0] == '/')
+ devices[ndevices++] = xstrdup (name);
+ else
+ devices[ndevices++] = xasprintf ("/dev/%s", name);
+ }
+ break;
+ }
+
+ free (line);
+ }
+
+ out:
+ close (fd);
+ waitpid (pid, NULL, 0);
+#endif
+ if (devices)
+ {
+ if (ndevices >= devices_allocated)
+ {
+ devices_allocated = 2 * (devices_allocated + 8);
+ devices = xrealloc (devices, sizeof (devices[0])
+ * devices_allocated);
+ }
+ devices[ndevices++] = 0;
+ }
+ return devices;
+}
+
+static char **
+find_root_devices_from_libzfs (const char *dir)
+{
+ char **devices = NULL;
+ char *poolname;
+ char *poolfs;
+
+ grub_find_zpool_from_dir (dir, &poolname, &poolfs);
+ if (! poolname)
+ return NULL;
+
+ devices = grub_util_find_root_devices_from_poolname (poolname);
+
+ free (poolname);
+ if (poolfs)
+ free (poolfs);
+
+ return devices;
+}
+
+char *
+grub_find_device (const char *dir, dev_t dev)
+{
+ DIR *dp;
+ struct saved_cwd saved_cwd;
+ struct dirent *ent;
+
+ if (! dir)
+ dir = "/dev";
+
+ dp = opendir (dir);
+ if (! dp)
+ return 0;
+
+ if (save_cwd (&saved_cwd) < 0)
+ {
+ grub_util_error ("%s", _("cannot save the original directory"));
+ closedir (dp);
+ return 0;
+ }
+
+ grub_util_info ("changing current directory to %s", dir);
+ if (chdir (dir) < 0)
+ {
+ free_cwd (&saved_cwd);
+ closedir (dp);
+ return 0;
+ }
+
+ while ((ent = readdir (dp)) != 0)
+ {
+ struct stat st;
+
+ /* Avoid:
+ - dotfiles (like "/dev/.tmp.md0") since they could be duplicates.
+ - dotdirs (like "/dev/.static") since they could contain duplicates. */
+ if (ent->d_name[0] == '.')
+ continue;
+
+ if (lstat (ent->d_name, &st) < 0)
+ /* Ignore any error. */
+ continue;
+
+ if (S_ISLNK (st.st_mode)) {
+#ifdef __linux__
+ if (strcmp (dir, "mapper") == 0 || strcmp (dir, "/dev/mapper") == 0) {
+ /* Follow symbolic links under /dev/mapper/; the canonical name
+ may be something like /dev/dm-0, but the names under
+ /dev/mapper/ are more human-readable and so we prefer them if
+ we can get them. */
+ if (stat (ent->d_name, &st) < 0)
+ continue;
+ } else
+#endif /* __linux__ */
+ /* Don't follow other symbolic links. */
+ continue;
+ }
+
+ if (S_ISDIR (st.st_mode))
+ {
+ /* Find it recursively. */
+ char *res;
+
+ res = grub_find_device (ent->d_name, dev);
+
+ if (res)
+ {
+ if (restore_cwd (&saved_cwd) < 0)
+ grub_util_error ("%s",
+ _("cannot restore the original directory"));
+
+ free_cwd (&saved_cwd);
+ closedir (dp);
+ return res;
+ }
+ }
+
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__APPLE__)
+ if (S_ISCHR (st.st_mode) && st.st_rdev == dev)
+#else
+ if (S_ISBLK (st.st_mode) && st.st_rdev == dev)
+#endif
+ {
+#ifdef __linux__
+ /* Skip device names like /dev/dm-0, which are short-hand aliases
+ to more descriptive device names, e.g. those under /dev/mapper.
+ Also, don't skip devices which names start with dm-[0-9] in
+ directories below /dev, e.g. /dev/mapper/dm-0-luks. */
+ if (strcmp (dir, "/dev") == 0 &&
+ ent->d_name[0] == 'd' &&
+ ent->d_name[1] == 'm' &&
+ ent->d_name[2] == '-' &&
+ ent->d_name[3] >= '0' &&
+ ent->d_name[3] <= '9')
+ continue;
+#endif
+
+ /* Found! */
+ char *res;
+ char *cwd;
+
+ cwd = xgetcwd ();
+ res = xmalloc (strlen (cwd) + strlen (ent->d_name) + 3);
+ sprintf (res,
+#if defined(__NetBSD__) || defined(__OpenBSD__)
+ /* Convert this block device to its character (raw) device. */
+ "%s/r%s",
+#else
+ /* Keep the device name as it is. */
+ "%s/%s",
+#endif
+ cwd, ent->d_name);
+ strip_extra_slashes (res);
+ free (cwd);
+
+ /* /dev/root is not a real block device keep looking, takes care
+ of situation where root filesystem is on the same partition as
+ grub files */
+
+ if (strcmp(res, "/dev/root") == 0)
+ {
+ free (res);
+ continue;
+ }
+
+ if (restore_cwd (&saved_cwd) < 0)
+ grub_util_error ("%s", _("cannot restore the original directory"));
+
+ free_cwd (&saved_cwd);
+ closedir (dp);
+ return res;
+ }
+ }
+
+ if (restore_cwd (&saved_cwd) < 0)
+ grub_util_error ("%s", _("cannot restore the original directory"));
+
+ free_cwd (&saved_cwd);
+ closedir (dp);
+ return 0;
+}
+
+char **
+grub_guess_root_devices (const char *dir_in)
+{
+ char **os_dev = NULL;
+ struct stat st;
+ dev_t dev;
+ char *dir = grub_canonicalize_file_name (dir_in);
+
+ if (!dir)
+ grub_util_error (_("failed to get canonical path of `%s'"), dir_in);
+
+#ifdef __linux__
+ if (!os_dev)
+ os_dev = grub_find_root_devices_from_mountinfo (dir, NULL);
+#endif /* __linux__ */
+
+ if (!os_dev)
+ os_dev = find_root_devices_from_libzfs (dir);
+
+ if (os_dev)
+ {
+ char **cur;
+ for (cur = os_dev; *cur; cur++)
+ {
+ char *tmp = *cur;
+ int root, dm;
+ if (strcmp (*cur, "/dev/root") == 0
+ || strncmp (*cur, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0)
+ *cur = tmp;
+ else
+ {
+ *cur = grub_canonicalize_file_name (tmp);
+ if (*cur == NULL)
+ grub_util_error (_("failed to get canonical path of `%s'"), tmp);
+ free (tmp);
+ }
+ root = (strcmp (*cur, "/dev/root") == 0);
+ dm = (strncmp (*cur, "/dev/dm-", sizeof ("/dev/dm-") - 1) == 0);
+ if (!dm && !root)
+ continue;
+ if (stat (*cur, &st) < 0)
+ break;
+ free (*cur);
+ dev = st.st_rdev;
+ *cur = grub_find_device (dm ? "/dev/mapper" : "/dev", dev);
+ }
+ if (!*cur)
+ return os_dev;
+ for (cur = os_dev; *cur; cur++)
+ free (*cur);
+ free (os_dev);
+ os_dev = 0;
+ }
+
+ if (stat (dir, &st) < 0)
+ grub_util_error (_("cannot stat `%s': %s"), dir, strerror (errno));
+ free (dir);
+
+ dev = st.st_dev;
+
+ os_dev = xmalloc (2 * sizeof (os_dev[0]));
+
+ /* This might be truly slow, but is there any better way? */
+ os_dev[0] = grub_find_device ("/dev", dev);
+
+ if (!os_dev[0])
+ {
+ free (os_dev);
+ return 0;
+ }
+
+ os_dev[1] = 0;
+
+ return os_dev;
+}
+
+#endif
+
+void
+grub_util_pull_lvm_by_command (const char *os_dev)
+{
+ const char *argv[8];
+ int fd;
+ pid_t pid;
+ FILE *vgs;
+ char *buf = NULL;
+ size_t len = 0;
+ char *vgname = NULL;
+ const char *iptr;
+ char *optr;
+ char *vgid = NULL;
+ grub_size_t vgidlen = 0;
+
+ vgid = grub_util_get_vg_uuid (os_dev);
+ if (vgid)
+ vgidlen = grub_strlen (vgid);
+
+ if (!vgid)
+ {
+ if (strncmp (os_dev, LVM_DEV_MAPPER_STRING,
+ sizeof (LVM_DEV_MAPPER_STRING) - 1)
+ != 0)
+ return;
+
+ vgname = xmalloc (strlen (os_dev + sizeof (LVM_DEV_MAPPER_STRING) - 1) + 1);
+ for (iptr = os_dev + sizeof (LVM_DEV_MAPPER_STRING) - 1, optr = vgname; *iptr; )
+ if (*iptr != '-')
+ *optr++ = *iptr++;
+ else if (iptr[0] == '-' && iptr[1] == '-')
+ {
+ iptr += 2;
+ *optr++ = '-';
+ }
+ else
+ break;
+ *optr = '\0';
+ }
+
+ /* by default PV name is left aligned in 10 character field, meaning that
+ we do not know where name ends. Using dummy --separator disables
+ alignment. We have a single field, so separator itself is not output */
+ argv[0] = "vgs";
+ argv[1] = "--options";
+ if (vgid)
+ argv[2] = "vg_uuid,pv_name";
+ else
+ argv[2] = "pv_name";
+ argv[3] = "--noheadings";
+ argv[4] = "--separator";
+ argv[5] = ":";
+ argv[6] = vgname;
+ argv[7] = NULL;
+
+ pid = grub_util_exec_pipe (argv, &fd);
+ free (vgname);
+
+ if (!pid)
+ {
+ free (vgid);
+ return;
+ }
+
+ /* Parent. Read vgs' output. */
+ vgs = fdopen (fd, "r");
+ if (! vgs)
+ {
+ grub_util_warn (_("Unable to open stream from %s: %s"),
+ "vgs", strerror (errno));
+ goto out;
+ }
+
+ while (getline (&buf, &len, vgs) > 0)
+ {
+ char *ptr;
+ /* LVM adds two spaces as standard prefix */
+ for (ptr = buf; ptr < buf + 2 && *ptr == ' '; ptr++);
+
+ if (vgid && (grub_strncmp (vgid, ptr, vgidlen) != 0
+ || ptr[vgidlen] != ':'))
+ continue;
+ if (vgid)
+ ptr += vgidlen + 1;
+ if (*ptr == '\0')
+ continue;
+ *(ptr + strlen (ptr) - 1) = '\0';
+ grub_util_pull_device (ptr);
+ }
+
+out:
+ close (fd);
+ waitpid (pid, NULL, 0);
+ free (buf);
+ free (vgid);
+}
+
+/* ZFS has similar problems to those of btrfs (see above). */
+void
+grub_find_zpool_from_dir (const char *dir, char **poolname, char **poolfs)
+{
+ char *slash;
+
+ *poolname = *poolfs = NULL;
+
+#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME) && defined(HAVE_STRUCT_STATFS_F_MNTFROMNAME)
+ /* FreeBSD and GNU/kFreeBSD. */
+ {
+ struct statfs mnt;
+
+ if (statfs (dir, &mnt) != 0)
+ return;
+
+ if (strcmp (mnt.f_fstypename, "zfs") != 0)
+ return;
+
+ *poolname = xstrdup (mnt.f_mntfromname);
+ }
+#elif defined(HAVE_GETEXTMNTENT)
+ /* Solaris. */
+ {
+ struct stat st;
+ struct extmnttab mnt;
+
+ if (stat (dir, &st) != 0)
+ return;
+
+ FILE *mnttab = grub_util_fopen ("/etc/mnttab", "r");
+ if (! mnttab)
+ return;
+
+ while (getextmntent (mnttab, &mnt, sizeof (mnt)) == 0)
+ {
+ if (makedev (mnt.mnt_major, mnt.mnt_minor) == st.st_dev
+ && !strcmp (mnt.mnt_fstype, "zfs"))
+ {
+ *poolname = xstrdup (mnt.mnt_special);
+ break;
+ }
+ }
+
+ fclose (mnttab);
+ }
+#endif
+
+ if (! *poolname)
+ return;
+
+ slash = strchr (*poolname, '/');
+ if (slash)
+ {
+ *slash = '\0';
+ *poolfs = xstrdup (slash + 1);
+ }
+ else
+ *poolfs = xstrdup ("");
+}
+
+int
+grub_util_biosdisk_is_floppy (grub_disk_t disk)
+{
+ struct stat st;
+ int fd;
+ const char *dname;
+
+ dname = grub_util_biosdisk_get_osdev (disk);
+
+ if (!dname)
+ return 0;
+
+ fd = open (dname, O_RDONLY);
+ /* Shouldn't happen. */
+ if (fd == -1)
+ return 0;
+
+ /* Shouldn't happen either. */
+ if (fstat (fd, &st) < 0)
+ {
+ close (fd);
+ return 0;
+ }
+
+ close (fd);
+
+#if defined(__NetBSD__)
+ if (major(st.st_rdev) == RAW_FLOPPY_MAJOR)
+ return 1;
+#endif
+
+#if defined(FLOPPY_MAJOR)
+ if (major(st.st_rdev) == FLOPPY_MAJOR)
+#else
+ /* Some kernels (e.g. kFreeBSD) don't have a static major number
+ for floppies, but they still use a "fd[0-9]" pathname. */
+ if (dname[5] == 'f'
+ && dname[6] == 'd'
+ && dname[7] >= '0'
+ && dname[7] <= '9')
+#endif
+ return 1;
+
+ return 0;
+}
+
+#else
+
+#include <grub/emu/getroot.h>
+
+void
+grub_util_pull_lvm_by_command (const char *os_dev __attribute__ ((unused)))
+{
+}
+
+#endif
diff --git a/grub-core/osdep/unix/hostdisk.c b/grub-core/osdep/unix/hostdisk.c
new file mode 100644
index 0000000..3a00d74
--- /dev/null
+++ b/grub-core/osdep/unix/hostdisk.c
@@ -0,0 +1,319 @@
+/* hostdisk.c - emulate biosdisk */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+#if !defined (__CYGWIN__) && !defined (__MINGW32__) && !defined (__AROS__)
+
+#ifdef __linux__
+# include <sys/ioctl.h> /* ioctl */
+# include <sys/mount.h>
+#endif /* __linux__ */
+
+grub_uint64_t
+grub_util_get_fd_size (grub_util_fd_t fd, const char *name, unsigned *log_secsize)
+{
+ struct stat st;
+ grub_int64_t ret = -1;
+
+ if (fstat (fd, &st) < 0)
+ /* TRANSLATORS: "stat" comes from the name of POSIX function. */
+ grub_util_error (_("cannot stat `%s': %s"), name, strerror (errno));
+#if GRUB_DISK_DEVS_ARE_CHAR
+ if (S_ISCHR (st.st_mode))
+#else
+ if (S_ISBLK (st.st_mode))
+#endif
+ ret = grub_util_get_fd_size_os (fd, name, log_secsize);
+ if (ret != -1LL)
+ return ret;
+
+ if (log_secsize)
+ *log_secsize = 9;
+
+ return st.st_size;
+}
+
+int
+grub_util_fd_seek (grub_util_fd_t fd, grub_uint64_t off)
+{
+#if SIZEOF_OFF_T == 8
+ off_t offset = (off_t) off;
+
+ if (lseek (fd, offset, SEEK_SET) != offset)
+ return -1;
+#elif SIZEOF_OFF64_T == 8
+ off64_t offset = (off64_t) off;
+
+ if (lseek64 (fd, offset, SEEK_SET) != offset)
+ return -1;
+#else
+#error "No large file support"
+#endif
+ return 0;
+}
+
+
+/* Read LEN bytes from FD in BUF. Return less than or equal to zero if an
+ error occurs, otherwise return LEN. */
+ssize_t
+grub_util_fd_read (grub_util_fd_t fd, char *buf, size_t len)
+{
+ ssize_t size = 0;
+
+ while (len)
+ {
+ ssize_t ret = read (fd, buf, len);
+
+ if (ret == 0)
+ break;
+
+ if (ret < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ return ret;
+ }
+
+ len -= ret;
+ buf += ret;
+ size += ret;
+ }
+
+ return size;
+}
+
+/* Write LEN bytes from BUF to FD. Return less than or equal to zero if an
+ error occurs, otherwise return LEN. */
+ssize_t
+grub_util_fd_write (grub_util_fd_t fd, const char *buf, size_t len)
+{
+ ssize_t size = 0;
+
+ while (len)
+ {
+ ssize_t ret = write (fd, buf, len);
+
+ if (ret == 0)
+ break;
+
+ if (ret < 0)
+ {
+ if (errno == EINTR)
+ continue;
+ else
+ return ret;
+ }
+
+ len -= ret;
+ buf += ret;
+ size += ret;
+ }
+
+ return size;
+}
+
+#if !defined (__NetBSD__) && !defined (__APPLE__) && !defined (__FreeBSD__) && !defined(__FreeBSD_kernel__)
+grub_util_fd_t
+grub_util_fd_open (const char *os_dev, int flags)
+{
+#ifdef O_LARGEFILE
+ flags |= O_LARGEFILE;
+#endif
+#ifdef O_BINARY
+ flags |= O_BINARY;
+#endif
+#ifdef O_CLOEXEC
+ flags |= O_CLOEXEC;
+#endif
+
+ return open (os_dev, flags, S_IROTH | S_IRGRP | S_IRUSR | S_IWUSR);
+}
+#endif
+
+const char *
+grub_util_fd_strerror (void)
+{
+ return strerror (errno);
+}
+
+static int allow_fd_syncs = 1;
+
+int
+grub_util_fd_sync (grub_util_fd_t fd)
+{
+ if (allow_fd_syncs)
+ return fsync (fd);
+ return 0;
+}
+
+int
+grub_util_file_sync (FILE *f)
+{
+ if (fflush (f) != 0)
+ return -1;
+ if (!allow_fd_syncs)
+ return 0;
+ return fsync (fileno (f));
+}
+
+void
+grub_util_disable_fd_syncs (void)
+{
+ allow_fd_syncs = 0;
+}
+
+int
+grub_util_fd_close (grub_util_fd_t fd)
+{
+ return close (fd);
+}
+
+char *
+grub_canonicalize_file_name (const char *path)
+{
+#if defined (PATH_MAX)
+ char *ret;
+
+ ret = xmalloc (PATH_MAX);
+ if (!realpath (path, ret))
+ return NULL;
+ return ret;
+#else
+ return realpath (path, NULL);
+#endif
+}
+
+FILE *
+grub_util_fopen (const char *path, const char *mode)
+{
+ return fopen (path, mode);
+}
+
+int
+grub_util_is_directory (const char *path)
+{
+ struct stat st;
+
+ if (stat (path, &st) == -1)
+ return 0;
+
+ return S_ISDIR (st.st_mode);
+}
+
+int
+grub_util_is_regular (const char *path)
+{
+ struct stat st;
+
+ if (stat (path, &st) == -1)
+ return 0;
+
+ return S_ISREG (st.st_mode);
+}
+
+grub_uint32_t
+grub_util_get_mtime (const char *path)
+{
+ struct stat st;
+
+ if (stat (path, &st) == -1)
+ return 0;
+
+ return st.st_mtime;
+}
+
+#endif
+
+#if defined (__CYGWIN__) || (!defined (__MINGW32__) && !defined (__AROS__))
+
+int
+grub_util_is_special_file (const char *path)
+{
+ struct stat st;
+
+ if (lstat (path, &st) == -1)
+ return 1;
+ return (!S_ISREG (st.st_mode) && !S_ISDIR (st.st_mode));
+}
+
+
+char *
+grub_util_make_temporary_file (void)
+{
+ const char *t = getenv ("TMPDIR");
+ size_t tl;
+ char *tmp;
+ if (!t)
+ t = "/tmp";
+ tl = strlen (t);
+ tmp = xmalloc (tl + sizeof ("/grub.XXXXXX"));
+ memcpy (tmp, t, tl);
+ memcpy (tmp + tl, "/grub.XXXXXX",
+ sizeof ("/grub.XXXXXX"));
+ if (mkstemp (tmp) == -1)
+ grub_util_error (_("cannot make temporary file: %s"), strerror (errno));
+ return tmp;
+}
+
+char *
+grub_util_make_temporary_dir (void)
+{
+ const char *t = getenv ("TMPDIR");
+ size_t tl;
+ char *tmp;
+ if (!t)
+ t = "/tmp";
+ tl = strlen (t);
+ tmp = xmalloc (tl + sizeof ("/grub.XXXXXX"));
+ memcpy (tmp, t, tl);
+ memcpy (tmp + tl, "/grub.XXXXXX",
+ sizeof ("/grub.XXXXXX"));
+ if (!mkdtemp (tmp))
+ grub_util_error (_("cannot make temporary directory: %s"),
+ strerror (errno));
+ return tmp;
+}
+
+#endif
diff --git a/grub-core/osdep/unix/password.c b/grub-core/osdep/unix/password.c
new file mode 100644
index 0000000..9996b24
--- /dev/null
+++ b/grub-core/osdep/unix/password.c
@@ -0,0 +1,75 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006
+ * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/crypto.h>
+#include <grub/mm.h>
+#include <grub/term.h>
+
+#include <termios.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+int
+grub_password_get (char buf[], unsigned buf_size)
+{
+ FILE *in;
+ struct termios s, t;
+ int tty_changed = 0;
+ char *ptr;
+
+ grub_refresh ();
+
+ /* Disable echoing. Based on glibc. */
+ in = fopen ("/dev/tty", "w+c");
+ if (in == NULL)
+ in = stdin;
+
+ if (tcgetattr (fileno (in), &t) == 0)
+ {
+ /* Save the old one. */
+ s = t;
+ /* Tricky, tricky. */
+ t.c_lflag &= ~(ECHO|ISIG);
+ tty_changed = (tcsetattr (fileno (in), TCSAFLUSH, &t) == 0);
+ }
+ else
+ tty_changed = 0;
+ grub_memset (buf, 0, buf_size);
+ if (!fgets (buf, buf_size, stdin))
+ {
+ if (in != stdin)
+ fclose (in);
+ return 0;
+ }
+ ptr = buf + strlen (buf) - 1;
+ while (buf <= ptr && (*ptr == '\n' || *ptr == '\r'))
+ *ptr-- = 0;
+ /* Restore the original setting. */
+ if (tty_changed)
+ (void) tcsetattr (fileno (in), TCSAFLUSH, &s);
+
+ grub_xputs ("\n");
+ grub_refresh ();
+
+ if (in != stdin)
+ fclose (in);
+
+ return 1;
+}
diff --git a/grub-core/osdep/unix/platform.c b/grub-core/osdep/unix/platform.c
new file mode 100644
index 0000000..55b8f40
--- /dev/null
+++ b/grub-core/osdep/unix/platform.c
@@ -0,0 +1,241 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <grub/util/install.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/util/misc.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/emu/exec.h>
+#include <sys/types.h>
+#include <dirent.h>
+#include <string.h>
+#include <errno.h>
+
+static char *
+get_ofpathname (const char *dev)
+{
+ size_t alloced = 4096;
+ char *ret = xmalloc (alloced);
+ size_t offset = 0;
+ int fd;
+ pid_t pid;
+
+ pid = grub_util_exec_pipe ((const char * []){ "ofpathname", dev, NULL }, &fd);
+ if (!pid)
+ goto fail;
+
+ FILE *fp = fdopen (fd, "r");
+ if (!fp)
+ goto fail;
+
+ while (!feof (fp))
+ {
+ size_t r;
+ if (alloced == offset)
+ {
+ alloced *= 2;
+ ret = xrealloc (ret, alloced);
+ }
+ r = fread (ret + offset, 1, alloced - offset, fp);
+ offset += r;
+ }
+
+ if (offset > 0 && ret[offset - 1] == '\n')
+ offset--;
+ if (offset > 0 && ret[offset - 1] == '\r')
+ offset--;
+ if (alloced == offset)
+ {
+ alloced++;
+ ret = xrealloc (ret, alloced);
+ }
+ ret[offset] = '\0';
+
+ fclose (fp);
+
+ return ret;
+
+ fail:
+ grub_util_error (_("couldn't find IEEE1275 device path for %s.\nYou will have to set `boot-device' variable manually"),
+ dev);
+}
+
+static int
+grub_install_remove_efi_entries_by_distributor (const char *efi_distributor)
+{
+ int fd;
+ pid_t pid = grub_util_exec_pipe ((const char * []){ "efibootmgr", NULL }, &fd);
+ char *line = NULL;
+ size_t len = 0;
+ int rc = 0;
+
+ if (!pid)
+ {
+ grub_util_warn (_("Unable to open stream from %s: %s"),
+ "efibootmgr", strerror (errno));
+ return errno;
+ }
+
+ FILE *fp = fdopen (fd, "r");
+ if (!fp)
+ {
+ grub_util_warn (_("Unable to open stream from %s: %s"),
+ "efibootmgr", strerror (errno));
+ return errno;
+ }
+
+ line = xmalloc (80);
+ len = 80;
+ while (1)
+ {
+ int ret;
+ char *bootnum;
+ ret = getline (&line, &len, fp);
+ if (ret == -1)
+ break;
+ if (grub_memcmp (line, "Boot", sizeof ("Boot") - 1) != 0
+ || line[sizeof ("Boot") - 1] < '0'
+ || line[sizeof ("Boot") - 1] > '9')
+ continue;
+ if (!strcasestr (line, efi_distributor))
+ continue;
+ bootnum = line + sizeof ("Boot") - 1;
+ bootnum[4] = '\0';
+ if (!verbosity)
+ rc = grub_util_exec ((const char * []){ "efibootmgr", "-q",
+ "-b", bootnum, "-B", NULL });
+ else
+ rc = grub_util_exec ((const char * []){ "efibootmgr",
+ "-b", bootnum, "-B", NULL });
+ }
+
+ free (line);
+ return rc;
+}
+
+int
+grub_install_register_efi (grub_device_t efidir_grub_dev,
+ const char *efifile_path,
+ const char *efi_distributor)
+{
+ const char * efidir_disk;
+ int efidir_part;
+ int ret;
+ efidir_disk = grub_util_biosdisk_get_osdev (efidir_grub_dev->disk);
+ efidir_part = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1;
+
+ if (grub_util_exec_redirect_null ((const char * []){ "efibootmgr", "--version", NULL }))
+ {
+ /* TRANSLATORS: This message is shown when required executable `%s'
+ isn't found. */
+ grub_util_error (_("%s: not found"), "efibootmgr");
+ }
+
+ /* On Linux, we need the efivars kernel modules. */
+#ifdef __linux__
+ grub_util_exec ((const char * []){ "modprobe", "-q", "efivars", NULL });
+#endif
+ /* Delete old entries from the same distributor. */
+ ret = grub_install_remove_efi_entries_by_distributor (efi_distributor);
+ if (ret)
+ return ret;
+
+ char *efidir_part_str = xasprintf ("%d", efidir_part);
+
+ if (!verbosity)
+ ret = grub_util_exec ((const char * []){ "efibootmgr", "-q",
+ "-c", "-d", efidir_disk,
+ "-p", efidir_part_str, "-w",
+ "-L", efi_distributor, "-l",
+ efifile_path, NULL });
+ else
+ ret = grub_util_exec ((const char * []){ "efibootmgr",
+ "-c", "-d", efidir_disk,
+ "-p", efidir_part_str, "-w",
+ "-L", efi_distributor, "-l",
+ efifile_path, NULL });
+ free (efidir_part_str);
+ return ret;
+}
+
+void
+grub_install_register_ieee1275 (int is_prep, const char *install_device,
+ int partno, const char *relpath)
+{
+ char *boot_device;
+
+ if (grub_util_exec_redirect_null ((const char * []){ "ofpathname", "--version", NULL }))
+ {
+ /* TRANSLATORS: This message is shown when required executable `%s'
+ isn't found. */
+ grub_util_error (_("%s: not found"), "ofpathname");
+ }
+
+ /* Get the Open Firmware device tree path translation. */
+ if (!is_prep)
+ {
+ char *ptr;
+ char *ofpath;
+ const char *iptr;
+
+ ofpath = get_ofpathname (install_device);
+ boot_device = xmalloc (strlen (ofpath) + 1
+ + sizeof ("XXXXXXXXXXXXXXXXXXXX")
+ + 1 + strlen (relpath) + 1);
+ ptr = grub_stpcpy (boot_device, ofpath);
+ *ptr++ = ':';
+ grub_snprintf (ptr, sizeof ("XXXXXXXXXXXXXXXXXXXX"), "%d",
+ partno);
+ ptr += strlen (ptr);
+ *ptr++ = ',';
+ for (iptr = relpath; *iptr; iptr++, ptr++)
+ {
+ if (*iptr == '/')
+ *ptr = '\\';
+ else
+ *ptr = *iptr;
+ }
+ *ptr = '\0';
+ }
+ else
+ boot_device = get_ofpathname (install_device);
+
+ if (grub_util_exec ((const char * []){ "nvsetenv", "boot-device",
+ boot_device, NULL }))
+ {
+ char *cmd = xasprintf ("setenv boot-device %s", boot_device);
+ grub_util_error (_("`nvsetenv' failed. \nYou will have to set `boot-device' variable manually. At the IEEE1275 prompt, type:\n %s\n"),
+ cmd);
+ free (cmd);
+ }
+
+ free (boot_device);
+}
+
+void
+grub_install_sgi_setup (const char *install_device,
+ const char *imgfile, const char *destname)
+{
+ grub_util_exec ((const char * []){ "dvhtool", "-d",
+ install_device, "--unix-to-vh",
+ imgfile, destname, NULL });
+ grub_util_warn ("%s", _("You will have to set `SystemPartition' and `OSLoader' manually."));
+}
diff --git a/grub-core/osdep/unix/random.c b/grub-core/osdep/unix/random.c
new file mode 100644
index 0000000..fa0101b
--- /dev/null
+++ b/grub-core/osdep/unix/random.c
@@ -0,0 +1,48 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1992-1999,2001,2003,2004,2005,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <grub/types.h>
+#include <grub/crypto.h>
+#include <grub/auth.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/i18n.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+int
+grub_get_random (void *out, grub_size_t len)
+{
+ FILE *f;
+ size_t rd;
+
+ f = grub_util_fopen ("/dev/urandom", "rb");
+ if (!f)
+ return 1;
+ rd = fread (out, 1, len, f);
+ fclose (f);
+
+ if (rd != len)
+ return 1;
+ return 0;
+}
diff --git a/grub-core/osdep/unix/relpath.c b/grub-core/osdep/unix/relpath.c
new file mode 100644
index 0000000..f719950
--- /dev/null
+++ b/grub-core/osdep/unix/relpath.c
@@ -0,0 +1,151 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <grub/util/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/mm.h>
+
+/* This function never prints trailing slashes (so that its output
+ can be appended a slash unconditionally). */
+char *
+grub_make_system_path_relative_to_its_root (const char *path)
+{
+ struct stat st;
+ char *p, *buf, *buf2, *buf3, *ret;
+ uintptr_t offset = 0;
+ dev_t num;
+ size_t len;
+ char *poolfs = NULL;
+
+ /* canonicalize. */
+ p = grub_canonicalize_file_name (path);
+ if (p == NULL)
+ grub_util_error (_("failed to get canonical path of `%s'"), path);
+
+#ifdef __linux__
+ ret = grub_make_system_path_relative_to_its_root_os (p);
+ if (ret)
+ {
+ free (p);
+ return ret;
+ }
+#endif
+
+ /* For ZFS sub-pool filesystems. */
+#ifndef __HAIKU__
+ {
+ char *dummy;
+ grub_find_zpool_from_dir (p, &dummy, &poolfs);
+ }
+#endif
+
+ len = strlen (p) + 1;
+ buf = xstrdup (p);
+ free (p);
+
+ if (stat (buf, &st) < 0)
+ grub_util_error (_("cannot stat `%s': %s"), buf, strerror (errno));
+
+ buf2 = xstrdup (buf);
+ num = st.st_dev;
+
+ /* This loop sets offset to the number of chars of the root
+ directory we're inspecting. */
+ while (1)
+ {
+ p = strrchr (buf, '/');
+ if (p == NULL)
+ /* This should never happen. */
+ grub_util_error ("%s",
+ /* TRANSLATORS: canonical pathname is the
+ complete one e.g. /etc/fstab. It has
+ to contain `/' normally, if it doesn't
+ we're in trouble and throw this error. */
+ _("no `/' in canonical filename"));
+ if (p != buf)
+ *p = 0;
+ else
+ *++p = 0;
+
+ if (stat (buf, &st) < 0)
+ grub_util_error (_("cannot stat `%s': %s"), buf, strerror (errno));
+
+ /* buf is another filesystem; we found it. */
+ if (st.st_dev != num)
+ {
+ /* offset == 0 means path given is the mount point.
+ This works around special-casing of "/" in Un*x. This function never
+ prints trailing slashes (so that its output can be appended a slash
+ unconditionally). Each slash in is considered a preceding slash, and
+ therefore the root directory is an empty string. */
+ if (offset == 0)
+ {
+ free (buf);
+ free (buf2);
+ if (poolfs)
+ return xasprintf ("/%s/@", poolfs);
+ return xstrdup ("");
+ }
+ else
+ break;
+ }
+
+ offset = p - buf;
+ /* offset == 1 means root directory. */
+ if (offset == 1)
+ {
+ /* Include leading slash. */
+ offset = 0;
+ break;
+ }
+ }
+ free (buf);
+ buf3 = xstrdup (buf2 + offset);
+ buf2[offset] = 0;
+
+ free (buf2);
+
+ /* Remove trailing slashes, return empty string if root directory. */
+ len = strlen (buf3);
+ while (len > 0 && buf3[len - 1] == '/')
+ {
+ buf3[len - 1] = '\0';
+ len--;
+ }
+
+ if (poolfs)
+ {
+ ret = xasprintf ("/%s/@%s", poolfs, buf3);
+ free (buf3);
+ }
+ else
+ ret = buf3;
+
+ return ret;
+}
diff --git a/grub-core/osdep/unix/sleep.c b/grub-core/osdep/unix/sleep.c
new file mode 100644
index 0000000..5b00a38
--- /dev/null
+++ b/grub-core/osdep/unix/sleep.c
@@ -0,0 +1,30 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <time.h>
+#include <grub/time.h>
+
+void
+grub_millisleep (grub_uint32_t ms)
+{
+ struct timespec ts;
+
+ ts.tv_sec = ms / 1000;
+ ts.tv_nsec = (ms % 1000) * 1000000;
+ nanosleep (&ts, NULL);
+}
diff --git a/grub-core/osdep/windows/blocklist.c b/grub-core/osdep/windows/blocklist.c
new file mode 100644
index 0000000..6d0809a
--- /dev/null
+++ b/grub-core/osdep/windows/blocklist.c
@@ -0,0 +1,118 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/fs.h>
+#include <grub/ntfs.h>
+#include <grub/fat.h>
+#include <grub/exfat.h>
+#include <grub/udf.h>
+#include <grub/util/misc.h>
+#include <grub/util/install.h>
+#include <grub/emu/getroot.h>
+#include <grub/emu/hostfile.h>
+
+#include <windows.h>
+#include <winioctl.h>
+
+void
+grub_install_get_blocklist (grub_device_t root_dev,
+ const char *core_path,
+ const char *core_img __attribute__ ((unused)),
+ size_t core_size,
+ void (*callback) (grub_disk_addr_t sector,
+ unsigned offset,
+ unsigned length,
+ void *data),
+ void *hook_data)
+{
+ grub_disk_addr_t first_lcn = 0;
+ HANDLE filehd;
+ DWORD rets;
+ RETRIEVAL_POINTERS_BUFFER *extbuf;
+ size_t extbuf_size;
+ DWORD i;
+ grub_uint64_t sec_per_lcn;
+ grub_uint64_t curvcn = 0;
+ STARTING_VCN_INPUT_BUFFER start_vcn;
+ grub_fs_t fs;
+ grub_err_t err;
+
+ fs = grub_fs_probe (root_dev);
+ if (!fs)
+ grub_util_error ("%s", grub_errmsg);
+
+ /* This is ugly but windows doesn't give all needed data. Or does anyone
+ have a pointer how to retrieve it?
+ */
+ if (grub_strcmp (fs->name, "ntfs") == 0)
+ {
+ struct grub_ntfs_bpb bpb;
+ err = grub_disk_read (root_dev->disk, 0, 0, sizeof (bpb), &bpb);
+ if (err)
+ grub_util_error ("%s", grub_errmsg);
+ sec_per_lcn = ((grub_uint32_t) bpb.sectors_per_cluster
+ * (grub_uint32_t) grub_le_to_cpu16 (bpb.bytes_per_sector))
+ >> 9;
+ first_lcn = 0;
+ }
+ else if (grub_strcmp (fs->name, "exfat") == 0)
+ first_lcn = grub_exfat_get_cluster_sector (root_dev->disk, &sec_per_lcn);
+ else if (grub_strcmp (fs->name, "fat") == 0)
+ first_lcn = grub_fat_get_cluster_sector (root_dev->disk, &sec_per_lcn);
+ else if (grub_strcmp (fs->name, "udf") == 0)
+ first_lcn = grub_udf_get_cluster_sector (root_dev->disk, &sec_per_lcn);
+ else
+ grub_util_error ("unsupported fs for blocklist on windows: %s",
+ fs->name);
+
+ grub_util_info ("sec_per_lcn = %" GRUB_HOST_PRIuLONG_LONG
+ ", first_lcn=%" GRUB_HOST_PRIuLONG_LONG,
+ (unsigned long long) sec_per_lcn,
+ (unsigned long long) first_lcn);
+
+ first_lcn += grub_partition_get_start (root_dev->disk->partition);
+
+ start_vcn.StartingVcn.QuadPart = 0;
+
+ filehd = grub_util_fd_open (core_path, GRUB_UTIL_FD_O_RDONLY);
+ if (!GRUB_UTIL_FD_IS_VALID (filehd))
+ grub_util_error (_("cannot open `%s': %s"), core_path,
+ grub_util_fd_strerror ());
+
+ extbuf_size = sizeof (*extbuf) + sizeof (extbuf->Extents[0])
+ * ((core_size + 511) / 512);
+ extbuf = xmalloc (extbuf_size);
+
+ if (!DeviceIoControl(filehd, FSCTL_GET_RETRIEVAL_POINTERS,
+ &start_vcn, sizeof (start_vcn),
+ extbuf, extbuf_size, &rets, NULL))
+ grub_util_error ("FSCTL_GET_RETRIEVAL_POINTERS fails: %s",
+ grub_util_fd_strerror ());
+
+ CloseHandle (filehd);
+
+ for (i = 0; i < extbuf->ExtentCount; i++)
+ callback (extbuf->Extents[i].Lcn.QuadPart
+ * sec_per_lcn + first_lcn,
+ 0, 512 * sec_per_lcn * (extbuf->Extents[i].NextVcn.QuadPart - curvcn), hook_data);
+ free (extbuf);
+}
diff --git a/grub-core/osdep/windows/config.c b/grub-core/osdep/windows/config.c
new file mode 100644
index 0000000..928ab1a
--- /dev/null
+++ b/grub-core/osdep/windows/config.c
@@ -0,0 +1,57 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <grub/emu/hostfile.h>
+#include <grub/emu/config.h>
+#include <grub/util/install.h>
+#include <grub/util/misc.h>
+
+void
+grub_util_load_config (struct grub_util_config *cfg)
+{
+ const char *cfgfile;
+ FILE *f = NULL;
+ const char *v;
+
+ cfgfile = grub_util_get_config_filename ();
+ if (!grub_util_is_regular (cfgfile))
+ return;
+
+ memset (cfg, 0, sizeof (*cfg));
+
+ v = getenv ("GRUB_ENABLE_CRYPTODISK");
+ if (v && v[0] == 'y' && v[1] == '\0')
+ cfg->is_cryptodisk_enabled = 1;
+
+ v = getenv ("GRUB_DISTRIBUTOR");
+ if (v)
+ cfg->grub_distributor = xstrdup (v);
+
+ f = grub_util_fopen (cfgfile, "r");
+ if (f)
+ {
+ grub_util_parse_config (f, cfg, 0);
+ fclose (f);
+ }
+ else
+ grub_util_warn (_("cannot open configuration file `%s': %s"),
+ cfgfile, strerror (errno));
+}
diff --git a/grub-core/osdep/windows/cputime.c b/grub-core/osdep/windows/cputime.c
new file mode 100644
index 0000000..3568aa2
--- /dev/null
+++ b/grub-core/osdep/windows/cputime.c
@@ -0,0 +1,19 @@
+#include <config.h>
+#include <config-util.h>
+
+#include <grub/emu/misc.h>
+#include <windows.h>
+
+grub_uint64_t
+grub_util_get_cpu_time_ms (void)
+{
+ FILETIME cr, ex, ke, us;
+ ULARGE_INTEGER us_ul;
+
+ GetProcessTimes (GetCurrentProcess (), &cr, &ex, &ke, &us);
+ us_ul.LowPart = us.dwLowDateTime;
+ us_ul.HighPart = us.dwHighDateTime;
+
+ return us_ul.QuadPart / 10000;
+}
+
diff --git a/grub-core/osdep/windows/dl.c b/grub-core/osdep/windows/dl.c
new file mode 100644
index 0000000..eec6a24
--- /dev/null
+++ b/grub-core/osdep/windows/dl.c
@@ -0,0 +1,59 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <grub/dl.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <stdlib.h>
+#include <string.h>
+#include <windows.h>
+
+void *
+grub_osdep_dl_memalign (grub_size_t align, grub_size_t size)
+{
+ void *ret;
+ if (align > 4096)
+ {
+ grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "too large alignment");
+ return NULL;
+ }
+
+ size = ALIGN_UP (size, 4096);
+
+ ret = VirtualAlloc (NULL, size, MEM_COMMIT | MEM_RESERVE,
+ PAGE_EXECUTE_READWRITE);
+
+ if (!ret)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ return NULL;
+ }
+
+ return ret;
+}
+
+void
+grub_dl_osdep_dl_free (void *ptr)
+{
+ if (!ptr)
+ return;
+ VirtualFree (ptr, 0, MEM_RELEASE);
+}
diff --git a/grub-core/osdep/windows/emuconsole.c b/grub-core/osdep/windows/emuconsole.c
new file mode 100644
index 0000000..4fb3693
--- /dev/null
+++ b/grub-core/osdep/windows/emuconsole.c
@@ -0,0 +1,308 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2008,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+
+#include <grub/term.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/err.h>
+
+#include <grub/emu/console.h>
+
+#include <windows.h>
+
+static HANDLE hStdin, hStdout;
+static DWORD orig_mode;
+static int saved_orig;
+
+
+static void
+grub_console_putchar (struct grub_term_output *term __attribute__ ((unused)),
+ const struct grub_unicode_glyph *c)
+{
+ TCHAR str[2 + 30];
+ unsigned i, j;
+ DWORD written;
+
+ /* For now, do not try to use a surrogate pair. */
+ if (c->base > 0xffff)
+ str[0] = '?';
+ else
+ str[0] = (c->base & 0xffff);
+ j = 1;
+ for (i = 0; i < c->ncomb && j+1 < ARRAY_SIZE (str); i++)
+ if (c->base < 0xffff)
+ str[j++] = grub_unicode_get_comb (c)[i].code;
+ str[j] = 0;
+
+ WriteConsole (hStdout, str, j, &written, NULL);
+}
+
+const unsigned windows_codes[] =
+ {
+ /* 0x21 */ [VK_PRIOR] = GRUB_TERM_KEY_PPAGE,
+ /* 0x22 */ [VK_NEXT] = GRUB_TERM_KEY_NPAGE,
+ /* 0x23 */ [VK_END] = GRUB_TERM_KEY_END,
+ /* 0x24 */ [VK_HOME] = GRUB_TERM_KEY_HOME,
+ /* 0x25 */ [VK_LEFT] = GRUB_TERM_KEY_LEFT,
+ /* 0x26 */ [VK_UP] = GRUB_TERM_KEY_UP,
+ /* 0x27 */ [VK_RIGHT] = GRUB_TERM_KEY_RIGHT,
+ /* 0x28 */ [VK_DOWN] = GRUB_TERM_KEY_DOWN,
+ /* 0x2e */ [VK_DELETE] = GRUB_TERM_KEY_DC,
+ /* 0x70 */ [VK_F1] = GRUB_TERM_KEY_F1,
+ /* 0x71 */ [VK_F2] = GRUB_TERM_KEY_F2,
+ /* 0x72 */ [VK_F3] = GRUB_TERM_KEY_F3,
+ /* 0x73 */ [VK_F4] = GRUB_TERM_KEY_F4,
+ /* 0x74 */ [VK_F5] = GRUB_TERM_KEY_F5,
+ /* 0x75 */ [VK_F6] = GRUB_TERM_KEY_F6,
+ /* 0x76 */ [VK_F7] = GRUB_TERM_KEY_F7,
+ /* 0x77 */ [VK_F8] = GRUB_TERM_KEY_F8,
+ /* 0x78 */ [VK_F9] = GRUB_TERM_KEY_F9,
+ /* 0x79 */ [VK_F10] = GRUB_TERM_KEY_F10,
+ /* 0x7a */ [VK_F11] = GRUB_TERM_KEY_F11,
+ /* 0x7b */ [VK_F12] = GRUB_TERM_KEY_F12,
+ };
+
+
+static int
+grub_console_getkey (struct grub_term_input *term __attribute__ ((unused)))
+{
+ while (1)
+ {
+ DWORD nev;
+ INPUT_RECORD ir;
+ int ret;
+
+ if (!GetNumberOfConsoleInputEvents (hStdin, &nev))
+ return GRUB_TERM_NO_KEY;
+
+ if (nev == 0)
+ return GRUB_TERM_NO_KEY;
+
+ if (!ReadConsoleInput (hStdin, &ir, 1,
+ &nev))
+ return GRUB_TERM_NO_KEY;
+
+ if (ir.EventType != KEY_EVENT)
+ continue;
+
+ if (!ir.Event.KeyEvent.bKeyDown)
+ continue;
+ ret = ir.Event.KeyEvent.uChar.UnicodeChar;
+ if (ret == 0)
+ {
+ unsigned kc = ir.Event.KeyEvent.wVirtualKeyCode;
+ if (kc < ARRAY_SIZE (windows_codes) && windows_codes[kc])
+ ret = windows_codes[kc];
+ else
+ continue;
+ if (ir.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED)
+ ret |= GRUB_TERM_SHIFT;
+ }
+ /* Workaround for AltGr bug. */
+ if (ir.Event.KeyEvent.dwControlKeyState & RIGHT_ALT_PRESSED)
+ return ret;
+ if (ir.Event.KeyEvent.dwControlKeyState & (LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED))
+ ret |= GRUB_TERM_ALT;
+ if (ir.Event.KeyEvent.dwControlKeyState & (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED))
+ ret |= GRUB_TERM_CTRL;
+ return ret;
+ }
+}
+
+static struct grub_term_coordinate
+grub_console_getwh (struct grub_term_output *term __attribute__ ((unused)))
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ csbi.dwSize.X = 80;
+ csbi.dwSize.Y = 25;
+
+ GetConsoleScreenBufferInfo (hStdout, &csbi);
+
+ return (struct grub_term_coordinate) { csbi.dwSize.X, csbi.dwSize.Y };
+}
+
+static struct grub_term_coordinate
+grub_console_getxy (struct grub_term_output *term __attribute__ ((unused)))
+{
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ GetConsoleScreenBufferInfo (hStdout, &csbi);
+
+ return (struct grub_term_coordinate) { csbi.dwCursorPosition.X, csbi.dwCursorPosition.Y };
+}
+
+static void
+grub_console_gotoxy (struct grub_term_output *term __attribute__ ((unused)),
+ struct grub_term_coordinate pos)
+{
+ COORD coord = { pos.x, pos.y };
+
+ SetConsoleCursorPosition (hStdout, coord);
+}
+
+static void
+grub_console_cls (struct grub_term_output *term)
+{
+ int tsz;
+ CONSOLE_SCREEN_BUFFER_INFO csbi;
+
+ struct grub_unicode_glyph c =
+ {
+ .base = ' ',
+ .variant = 0,
+ .attributes = 0,
+ .ncomb = 0,
+ .estimated_width = 1
+ };
+
+ GetConsoleScreenBufferInfo (hStdout, &csbi);
+
+ SetConsoleTextAttribute (hStdout, 0);
+ grub_console_gotoxy (term, (struct grub_term_coordinate) { 0, 0 });
+ tsz = csbi.dwSize.X * csbi.dwSize.Y;
+
+ while (tsz--)
+ grub_console_putchar (term, &c);
+
+ grub_console_gotoxy (term, (struct grub_term_coordinate) { 0, 0 });
+ SetConsoleTextAttribute (hStdout, csbi.wAttributes);
+}
+
+static void
+grub_console_setcolorstate (struct grub_term_output *term
+ __attribute__ ((unused)),
+ grub_term_color_state state)
+{
+
+
+ switch (state) {
+ case GRUB_TERM_COLOR_STANDARD:
+ SetConsoleTextAttribute (hStdout, GRUB_TERM_DEFAULT_STANDARD_COLOR
+ & 0x7f);
+ break;
+ case GRUB_TERM_COLOR_NORMAL:
+ SetConsoleTextAttribute (hStdout, grub_term_normal_color & 0x7f);
+ break;
+ case GRUB_TERM_COLOR_HIGHLIGHT:
+ SetConsoleTextAttribute (hStdout, grub_term_highlight_color & 0x7f);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+grub_console_setcursor (struct grub_term_output *term __attribute__ ((unused)),
+ int on)
+{
+ CONSOLE_CURSOR_INFO ci;
+ ci.dwSize = 5;
+ ci.bVisible = on;
+ SetConsoleCursorInfo (hStdout, &ci);
+}
+
+static grub_err_t
+grub_efi_console_init (struct grub_term_output *term)
+{
+ grub_console_setcursor (term, 1);
+ return 0;
+}
+
+static grub_err_t
+grub_efi_console_fini (struct grub_term_output *term)
+{
+ grub_console_setcursor (term, 1);
+ return 0;
+}
+
+
+static grub_err_t
+grub_console_init_input (struct grub_term_input *term)
+{
+ if (!saved_orig)
+ {
+ GetConsoleMode (hStdin, &orig_mode);
+ }
+
+ saved_orig = 1;
+
+ SetConsoleMode (hStdin, orig_mode & ~ENABLE_ECHO_INPUT
+ & ~ENABLE_LINE_INPUT & ~ENABLE_PROCESSED_INPUT);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_console_fini_input (struct grub_term_input *term
+ __attribute__ ((unused)))
+{
+ SetConsoleMode (hStdin, orig_mode);
+ saved_orig = 0;
+ return GRUB_ERR_NONE;
+}
+
+
+static struct grub_term_input grub_console_term_input =
+ {
+ .name = "console",
+ .getkey = grub_console_getkey,
+ .init = grub_console_init_input,
+ .fini = grub_console_fini_input,
+ };
+
+static struct grub_term_output grub_console_term_output =
+ {
+ .name = "console",
+ .init = grub_efi_console_init,
+ .fini = grub_efi_console_fini,
+ .putchar = grub_console_putchar,
+ .getwh = grub_console_getwh,
+ .getxy = grub_console_getxy,
+ .gotoxy = grub_console_gotoxy,
+ .cls = grub_console_cls,
+ .setcolorstate = grub_console_setcolorstate,
+ .setcursor = grub_console_setcursor,
+ .flags = GRUB_TERM_CODE_TYPE_VISUAL_GLYPHS,
+ .progress_update_divisor = GRUB_PROGRESS_FAST
+ };
+
+void
+grub_console_init (void)
+{
+ hStdin = GetStdHandle (STD_INPUT_HANDLE);
+ hStdout = GetStdHandle (STD_OUTPUT_HANDLE);
+
+ grub_term_register_input ("console", &grub_console_term_input);
+ grub_term_register_output ("console", &grub_console_term_output);
+}
+
+void
+grub_console_fini (void)
+{
+ if (saved_orig)
+ {
+ SetConsoleMode (hStdin, orig_mode);
+ saved_orig = 0;
+ }
+ grub_term_unregister_input (&grub_console_term_input);
+ grub_term_unregister_output (&grub_console_term_output);
+}
diff --git a/grub-core/osdep/windows/getroot.c b/grub-core/osdep/windows/getroot.c
new file mode 100644
index 0000000..eada663
--- /dev/null
+++ b/grub-core/osdep/windows/getroot.c
@@ -0,0 +1,355 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+#include <error.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <grub/types.h>
+
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/charset.h>
+#include <grub/util/windows.h>
+#include <windows.h>
+#include <winioctl.h>
+
+TCHAR *
+grub_get_mount_point (const TCHAR *path)
+{
+ const TCHAR *ptr;
+ TCHAR *out;
+ TCHAR letter = 0;
+ size_t allocsize;
+
+ for (ptr = path; *ptr; ptr++);
+ allocsize = (ptr - path + 10) * 2;
+ out = xcalloc (allocsize, sizeof (out[0]));
+
+ /* When pointing to EFI system partition GetVolumePathName fails
+ for ESP root and returns abberant information for everything
+ else. Since GetVolumePathName shouldn't fail for any valid
+ //?/X: we use it as indicator. */
+ if ((path[0] == '/' || path[0] == '\\')
+ && (path[1] == '/' || path[1] == '\\')
+ && (path[2] == '?' || path[2] == '.')
+ && (path[3] == '/' || path[3] == '\\')
+ && path[4]
+ && (path[5] == ':'))
+ letter = path[4];
+ if (path[0] && path[1] == ':')
+ letter = path[0];
+ if (letter)
+ {
+ TCHAR letterpath[10] = TEXT("\\\\?\\#:");
+ letterpath[4] = letter;
+ if (!GetVolumePathName (letterpath, out, allocsize))
+ {
+ if (path[1] == ':')
+ {
+ out[0] = path[0];
+ out[1] = ':';
+ out[2] = '\0';
+ return out;
+ }
+ memcpy (out, path, sizeof (out[0]) * 6);
+ out[6] = '\0';
+ return out;
+ }
+ }
+
+ if (!GetVolumePathName (path, out, allocsize))
+ {
+ free (out);
+ return NULL;
+ }
+ return out;
+}
+
+char **
+grub_guess_root_devices (const char *dir)
+{
+ char **os_dev = NULL;
+ TCHAR *dirwindows, *mntpointwindows;
+ TCHAR *ptr;
+ TCHAR volumename[100];
+
+ dirwindows = grub_util_get_windows_path (dir);
+ if (!dirwindows)
+ return 0;
+
+ mntpointwindows = grub_get_mount_point (dirwindows);
+
+ if (!mntpointwindows)
+ {
+ free (dirwindows);
+ grub_util_info ("can't get volume path name: %d", (int) GetLastError ());
+ return 0;
+ }
+
+ if (!mntpointwindows[0])
+ {
+ free (dirwindows);
+ free (mntpointwindows);
+ return 0;
+ }
+
+ for (ptr = mntpointwindows; *ptr; ptr++);
+ if (*(ptr - 1) != '\\')
+ {
+ *ptr = '\\';
+ *(ptr + 1) = '\0';
+ }
+
+ if (!GetVolumeNameForVolumeMountPoint (mntpointwindows,
+ volumename,
+ ARRAY_SIZE (volumename)))
+ {
+ TCHAR letter = 0;
+ if ((mntpointwindows[0] == '/' || mntpointwindows[0] == '\\')
+ && (mntpointwindows[1] == '/' || mntpointwindows[1] == '\\')
+ && (mntpointwindows[2] == '?' || mntpointwindows[2] == '.')
+ && (mntpointwindows[3] == '/' || mntpointwindows[3] == '\\')
+ && mntpointwindows[4]
+ && (mntpointwindows[5] == ':'))
+ letter = mntpointwindows[4];
+ if (mntpointwindows[0] && mntpointwindows[1] == ':')
+ letter = mntpointwindows[0];
+ if (!letter)
+ {
+ free (dirwindows);
+ free (mntpointwindows);
+ return 0;
+ }
+ volumename[0] = '\\';
+ volumename[1] = '\\';
+ volumename[2] = '?';
+ volumename[3] = '\\';
+ volumename[4] = letter;
+ volumename[5] = ':';
+ volumename[6] = '\0';
+ }
+ os_dev = xmalloc (2 * sizeof (os_dev[0]));
+
+ for (ptr = volumename; *ptr; ptr++);
+ while (ptr > volumename && *(ptr - 1) == '\\')
+ *--ptr = '\0';
+
+ os_dev[0] = grub_util_tchar_to_utf8 (volumename);
+ free (dirwindows);
+ free (mntpointwindows);
+
+ if (!os_dev[0])
+ {
+ free (os_dev);
+ return 0;
+ }
+
+ os_dev[1] = 0;
+
+ return os_dev;
+}
+
+static int tcharncasecmp (LPCTSTR a, const char *b, size_t sz)
+{
+ for (; sz; sz--, a++, b++)
+ {
+ char ac, bc;
+ if(*a >= 0x80)
+ return +1;
+ if (*b & 0x80)
+ return -1;
+ if (*a == '\0' && *b == '\0')
+ return 0;
+ ac = *a;
+ bc = *b;
+ if (ac >= 'A' && ac <= 'Z')
+ ac -= 'A' - 'a';
+ if (bc >= 'A' && bc <= 'Z')
+ bc -= 'A' - 'a';
+ if (ac > bc)
+ return +1;
+ if (ac < bc)
+ return -1;
+ }
+ return 0;
+}
+
+char *
+grub_util_part_to_disk (const char *os_dev,
+ struct stat *st __attribute__ ((unused)),
+ int *is_part)
+{
+ HANDLE hd;
+ LPTSTR name = grub_util_get_windows_path (os_dev);
+ VOLUME_DISK_EXTENTS exts;
+ DWORD extsbytes;
+ char *ret;
+
+ if (((name[0] == '/') || (name[0] == '\\')) &&
+ ((name[1] == '/') || (name[1] == '\\')) &&
+ ((name[2] == '.') || (name[2] == '?')) &&
+ ((name[3] == '/') || (name[3] == '\\'))
+ && (tcharncasecmp (name + 4, "PhysicalDrive", sizeof ("PhysicalDrive") - 1) == 0
+ || tcharncasecmp (name + 4, "Harddisk", sizeof ("Harddisk") - 1) == 0
+ || ((name[4] == 'A' || name[4] == 'a' || name[4] == 'B' || name[4] == 'b')
+ && name[5] == ':' && name[6] == '\0')))
+ {
+ grub_util_info ("Matches full disk pattern");
+ ret = grub_util_tchar_to_utf8 (name);
+ free (name);
+ return ret;
+ }
+
+ hd = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0, OPEN_EXISTING, 0, 0);
+ if (hd == INVALID_HANDLE_VALUE)
+ {
+ grub_util_info ("CreateFile failed");
+ ret = grub_util_tchar_to_utf8 (name);
+ free (name);
+ return ret;
+ }
+
+ if (!DeviceIoControl(hd, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
+ NULL, 0, &exts, sizeof (exts), &extsbytes, NULL))
+ {
+ grub_util_info ("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed");
+ ret = grub_util_tchar_to_utf8 (name);
+ CloseHandle (hd);
+ free (name);
+ return ret;
+ }
+
+ CloseHandle (hd);
+
+ *is_part = 1;
+ free (name);
+ return xasprintf ("\\\\?\\PhysicalDrive%lu", (unsigned long) exts.Extents[0].DiskNumber);
+}
+
+enum grub_dev_abstraction_types
+grub_util_get_dev_abstraction_os (const char *os_dev __attribute__((unused)))
+{
+ return GRUB_DEV_ABSTRACTION_NONE;
+}
+
+int
+grub_util_pull_device_os (const char *os_dev __attribute__ ((unused)),
+ enum grub_dev_abstraction_types ab __attribute__ ((unused)))
+{
+ return 0;
+}
+
+char *
+grub_util_get_grub_dev_os (const char *os_dev __attribute__ ((unused)))
+{
+ return NULL;
+}
+
+
+grub_disk_addr_t
+grub_util_find_partition_start_os (const char *os_dev)
+{
+ HANDLE hd;
+ LPTSTR name = grub_util_get_windows_path (os_dev);
+ VOLUME_DISK_EXTENTS exts;
+ DWORD extsbytes;
+ char *ret;
+
+ if (((name[0] == '/') || (name[0] == '\\')) &&
+ ((name[1] == '/') || (name[1] == '\\')) &&
+ ((name[2] == '.') || (name[2] == '?')) &&
+ ((name[3] == '/') || (name[3] == '\\'))
+ && (tcharncasecmp (name + 4, "PhysicalDrive", sizeof ("PhysicalDrive") - 1) == 0
+ || tcharncasecmp (name + 4, "Harddisk", sizeof ("Harddisk") - 1) == 0
+ || ((name[4] == 'A' || name[4] == 'a' || name[4] == 'B' || name[4] == 'b')
+ && name[5] == ':' && name[6] == '\0')))
+ {
+ ret = grub_util_tchar_to_utf8 (name);
+ free (name);
+ return 0;
+ }
+
+ hd = CreateFile (name, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0, OPEN_EXISTING, 0, 0);
+ if (hd == INVALID_HANDLE_VALUE)
+ {
+ ret = grub_util_tchar_to_utf8 (name);
+ free (name);
+ return 0;
+ }
+
+ if (!DeviceIoControl(hd, IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
+ NULL, 0, &exts, sizeof (exts), &extsbytes, NULL))
+ {
+ ret = grub_util_tchar_to_utf8 (name);
+ CloseHandle (hd);
+ free (name);
+ return 0;
+ }
+
+ CloseHandle (hd);
+ free (name);
+ return exts.Extents[0].StartingOffset.QuadPart / 512;
+}
+
+int
+grub_util_biosdisk_is_floppy (grub_disk_t disk)
+{
+ int ret;
+ const char *dname;
+ LPTSTR name;
+
+ dname = grub_util_biosdisk_get_osdev (disk);
+
+ if (!dname)
+ return 0;
+
+ name = grub_util_get_windows_path (dname);
+
+ ret = (((name[0] == '/') || (name[0] == '\\')) &&
+ ((name[1] == '/') || (name[1] == '\\')) &&
+ ((name[2] == '.') || (name[2] == '?')) &&
+ ((name[3] == '/') || (name[3] == '\\'))
+ && (name[4] == 'A' || name[4] == 'a' || name[4] == 'B' || name[4] == 'b')
+ && name[5] == ':' && name[6] == '\0');
+ free (name);
+
+ return ret;
+}
diff --git a/grub-core/osdep/windows/hostdisk.c b/grub-core/osdep/windows/hostdisk.c
new file mode 100644
index 0000000..0be3273
--- /dev/null
+++ b/grub-core/osdep/windows/hostdisk.c
@@ -0,0 +1,689 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2004,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <grub/disk.h>
+#include <grub/partition.h>
+#include <grub/msdos_partition.h>
+#include <grub/types.h>
+#include <grub/err.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/misc.h>
+#include <grub/i18n.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <grub/util/windows.h>
+#include <grub/charset.h>
+
+#include <windows.h>
+#include <winioctl.h>
+#include <wincrypt.h>
+
+#ifdef __CYGWIN__
+#include <sys/cygwin.h>
+#endif
+
+#if SIZEOF_TCHAR == 1
+
+LPTSTR
+grub_util_utf8_to_tchar (const char *in)
+{
+ return xstrdup (in);
+}
+
+char *
+grub_util_tchar_to_utf8 (LPCTSTR in)
+{
+ return xstrdup (in);
+}
+
+#elif SIZEOF_TCHAR == 2
+
+LPTSTR
+grub_util_utf8_to_tchar (const char *in)
+{
+ LPTSTR ret;
+ size_t ssz = strlen (in);
+ size_t tsz = 2 * (GRUB_MAX_UTF16_PER_UTF8 * ssz + 1);
+ ret = xmalloc (tsz);
+ tsz = grub_utf8_to_utf16 (ret, tsz,
+ (const grub_uint8_t *) in, ssz, NULL);
+ ret[tsz] = 0;
+ return ret;
+}
+
+char *
+grub_util_tchar_to_utf8 (LPCTSTR in)
+{
+ size_t ssz;
+ for (ssz = 0; in[ssz]; ssz++);
+
+ size_t tsz = GRUB_MAX_UTF8_PER_UTF16 * ssz + 1;
+ grub_uint8_t *ret = xmalloc (tsz);
+ *grub_utf16_to_utf8 (ret, in, ssz) = '\0';
+ return (char *) ret;
+}
+
+#else
+#error "Unsupported TCHAR size"
+#endif
+
+
+static LPTSTR
+grub_util_get_windows_path_real (const char *path)
+{
+ LPTSTR fpa;
+ LPTSTR tpath;
+ size_t alloc, len;
+
+ tpath = grub_util_utf8_to_tchar (path);
+
+ alloc = PATH_MAX;
+
+ while (1)
+ {
+ fpa = xcalloc (alloc, sizeof (fpa[0]));
+
+ len = GetFullPathName (tpath, alloc, fpa, NULL);
+ if (len >= alloc)
+ {
+ free (fpa);
+ alloc = 2 * (len + 2);
+ continue;
+ }
+ if (len == 0)
+ {
+ free (fpa);
+ return tpath;
+ }
+
+ free (tpath);
+ return fpa;
+ }
+}
+
+#ifdef __CYGWIN__
+LPTSTR
+grub_util_get_windows_path (const char *path)
+{
+ LPTSTR winpath;
+ /* Workaround cygwin bugs with //?/. */
+ if ((path[0] == '\\' || path[0] == '/')
+ && (path[1] == '\\' || path[1] == '/')
+ && (path[2] == '?' || path[2] == '.')
+ && (path[3] == '\\' || path[3] == '/'))
+ return grub_util_get_windows_path_real (path);
+
+ winpath = xmalloc (sizeof (winpath[0]) * PATH_MAX);
+ memset (winpath, 0, sizeof (winpath[0]) * PATH_MAX);
+ if (cygwin_conv_path ((sizeof (winpath[0]) == 1 ? CCP_POSIX_TO_WIN_A
+ : CCP_POSIX_TO_WIN_W) | CCP_ABSOLUTE, path, winpath,
+ sizeof (winpath[0]) * PATH_MAX))
+ grub_util_error ("%s", _("cygwin_conv_path() failed"));
+ return winpath;
+}
+#else
+LPTSTR
+grub_util_get_windows_path (const char *path)
+{
+ return grub_util_get_windows_path_real (path);
+}
+#endif
+
+grub_uint64_t
+grub_util_get_fd_size (grub_util_fd_t hd, const char *name_in,
+ unsigned *log_secsize)
+{
+ grub_int64_t size = -1LL;
+ int log_sector_size = 9;
+ LPTSTR name = grub_util_get_windows_path (name_in);
+
+ if (log_secsize)
+ *log_secsize = log_sector_size;
+
+ if (((name[0] == '/') || (name[0] == '\\')) &&
+ ((name[1] == '/') || (name[1] == '\\')) &&
+ ((name[2] == '.') || (name[2] == '?')) &&
+ ((name[3] == '/') || (name[3] == '\\')))
+ {
+ DWORD nr;
+ DISK_GEOMETRY g;
+
+ if (! DeviceIoControl (hd, IOCTL_DISK_GET_DRIVE_GEOMETRY,
+ 0, 0, &g, sizeof (g), &nr, 0))
+ goto fail;
+
+ size = g.Cylinders.QuadPart;
+ size *= g.TracksPerCylinder * g.SectorsPerTrack * g.BytesPerSector;
+
+ for (log_sector_size = 0;
+ (1 << log_sector_size) < g.BytesPerSector;
+ log_sector_size++);
+ }
+ else
+ {
+ ULARGE_INTEGER s;
+
+ s.LowPart = GetFileSize (hd, &s.HighPart);
+ size = s.QuadPart;
+ }
+
+ fail:
+
+ if (log_secsize)
+ *log_secsize = log_sector_size;
+
+ free (name);
+
+ return size;
+}
+
+void
+grub_hostdisk_flush_initial_buffer (const char *os_dev __attribute__ ((unused)))
+{
+}
+
+int
+grub_util_fd_seek (grub_util_fd_t fd, grub_uint64_t off)
+{
+ LARGE_INTEGER offset;
+ offset.QuadPart = off;
+
+ if (!SetFilePointerEx (fd, offset, NULL, FILE_BEGIN))
+ return -1;
+ return 0;
+}
+
+grub_util_fd_t
+grub_util_fd_open (const char *os_dev, int flags)
+{
+ DWORD flg = 0, crt;
+ LPTSTR dev = grub_util_get_windows_path (os_dev);
+ grub_util_fd_t ret;
+
+ if (flags & GRUB_UTIL_FD_O_WRONLY)
+ flg |= GENERIC_WRITE;
+ if (flags & GRUB_UTIL_FD_O_RDONLY)
+ flg |= GENERIC_READ;
+
+ if (flags & GRUB_UTIL_FD_O_CREATTRUNC)
+ crt = CREATE_ALWAYS;
+ else
+ crt = OPEN_EXISTING;
+
+ ret = CreateFile (dev, flg, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ 0, crt, 0, 0);
+ free (dev);
+ return ret;
+}
+
+ssize_t
+grub_util_fd_read (grub_util_fd_t fd, char *buf, size_t len)
+{
+ DWORD real_read;
+ if (!ReadFile(fd, buf, len, &real_read, NULL))
+ {
+ grub_util_info ("read err %x", (int) GetLastError ());
+ return -1;
+ }
+ grub_util_info ("successful read");
+ return real_read;
+}
+
+ssize_t
+grub_util_fd_write (grub_util_fd_t fd, const char *buf, size_t len)
+{
+ DWORD real_read;
+ if (!WriteFile(fd, buf, len, &real_read, NULL))
+ {
+ grub_util_info ("write err %x", (int) GetLastError ());
+ return -1;
+ }
+
+ grub_util_info ("successful write");
+ return real_read;
+}
+
+static int allow_fd_syncs = 1;
+
+int
+grub_util_fd_sync (grub_util_fd_t fd)
+{
+ if (allow_fd_syncs)
+ {
+ if (!FlushFileBuffers (fd))
+ {
+ grub_util_info ("flush err %x", (int) GetLastError ());
+ return -1;
+ }
+ }
+ return 0;
+}
+
+void
+grub_util_disable_fd_syncs (void)
+{
+ allow_fd_syncs = 0;
+}
+
+int
+grub_util_fd_close (grub_util_fd_t fd)
+{
+ if (!CloseHandle (fd))
+ {
+ grub_util_info ("close err %x", (int) GetLastError ());
+ return -1;
+ }
+ return 0;
+}
+
+const char *
+grub_util_fd_strerror (void)
+{
+ DWORD err = GetLastError ();
+ LPTSTR tstr = NULL;
+ static char *last;
+ char *ret, *ptr;
+
+ free (last);
+ last = 0;
+
+ FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, err, 0, (void *) &tstr,
+ 0, NULL);
+
+ if (!tstr)
+ return "unknown error";
+
+ ret = grub_util_tchar_to_utf8 (tstr);
+
+ LocalFree (tstr);
+
+ last = ret;
+
+ for (ptr = ret + strlen (ret) - 1;
+ ptr >= ret && (*ptr == '\n' || *ptr == '\r');
+ ptr--);
+ ptr[1] = '\0';
+
+ return ret;
+}
+
+char *
+grub_canonicalize_file_name (const char *path)
+{
+ char *ret;
+ LPTSTR windows_path;
+ ret = xmalloc (PATH_MAX);
+
+ windows_path = grub_util_get_windows_path (path);
+ if (!windows_path)
+ return NULL;
+ ret = grub_util_tchar_to_utf8 (windows_path);
+ free (windows_path);
+
+ return ret;
+}
+
+void
+grub_util_mkdir (const char *dir)
+{
+ LPTSTR windows_name;
+
+ windows_name = grub_util_get_windows_path (dir);
+ CreateDirectory (windows_name, NULL);
+ free (windows_name);
+}
+
+int
+grub_util_rename (const char *from, const char *to)
+{
+ LPTSTR windows_from, windows_to;
+ int ret;
+
+ windows_from = grub_util_get_windows_path (from);
+ windows_to = grub_util_get_windows_path (to);
+ ret = !MoveFile (windows_from, windows_to);
+ free (windows_from);
+ free (windows_to);
+ return ret;
+}
+
+struct grub_util_fd_dir
+{
+ WIN32_FIND_DATA fd;
+ HANDLE hnd;
+ int is_end;
+ char *last;
+};
+
+grub_util_fd_dir_t
+grub_util_fd_opendir (const char *name)
+{
+ struct grub_util_fd_dir *ret;
+ LPTSTR name_windows;
+ LPTSTR pattern;
+ ssize_t l;
+
+ name_windows = grub_util_get_windows_path (name);
+ for (l = 0; name_windows[l]; l++);
+ for (l--; l >= 0 && (name_windows[l] == '\\' || name_windows[l] == '/'); l--);
+ l++;
+ pattern = xcalloc (l + 3, sizeof (pattern[0]));
+ memcpy (pattern, name_windows, l * sizeof (pattern[0]));
+ pattern[l] = '\\';
+ pattern[l + 1] = '*';
+ pattern[l + 2] = '\0';
+
+ ret = xmalloc (sizeof (*ret));
+ memset (ret, 0, sizeof (*ret));
+
+ ret->hnd = FindFirstFile (pattern, &ret->fd);
+
+ free (name_windows);
+ free (pattern);
+
+ if (ret->hnd == INVALID_HANDLE_VALUE)
+ {
+ DWORD err = GetLastError ();
+ if (err == ERROR_FILE_NOT_FOUND)
+ {
+ ret->is_end = 1;
+ return ret;
+ }
+ return NULL;
+ }
+ return ret;
+}
+
+void
+grub_util_fd_closedir (grub_util_fd_dir_t dirp)
+{
+ if (dirp->hnd != INVALID_HANDLE_VALUE)
+ CloseHandle (dirp->hnd);
+ free (dirp->last);
+ free (dirp);
+}
+
+grub_util_fd_dirent_t
+grub_util_fd_readdir (grub_util_fd_dir_t dirp)
+{
+ char *ret;
+ free (dirp->last);
+ dirp->last = NULL;
+
+ if (dirp->is_end)
+ return NULL;
+
+ ret = grub_util_tchar_to_utf8 (dirp->fd.cFileName);
+ dirp->last = ret;
+
+ if (!FindNextFile (dirp->hnd, &dirp->fd))
+ dirp->is_end = 1;
+ return (grub_util_fd_dirent_t) ret;
+}
+
+int
+grub_util_unlink (const char *name)
+{
+ LPTSTR name_windows;
+ int ret;
+
+ name_windows = grub_util_get_windows_path (name);
+
+ ret = !DeleteFile (name_windows);
+ free (name_windows);
+ return ret;
+}
+
+int
+grub_util_rmdir (const char *name)
+{
+ LPTSTR name_windows;
+ int ret;
+
+ name_windows = grub_util_get_windows_path (name);
+
+ ret = !RemoveDirectory (name_windows);
+ free (name_windows);
+ return ret;
+}
+
+#ifndef __CYGWIN__
+
+static char *
+get_temp_name (void)
+{
+ TCHAR rt[1024];
+ TCHAR *ptr;
+ HCRYPTPROV hCryptProv;
+ grub_uint8_t rnd[5];
+ int i;
+
+ GetTempPath (ARRAY_SIZE (rt) - 100, rt);
+
+ if (!CryptAcquireContext (&hCryptProv,
+ NULL,
+ MS_DEF_PROV,
+ PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT)
+ || !CryptGenRandom (hCryptProv, 5, rnd))
+ grub_util_error ("%s", _("couldn't retrieve random data"));
+
+ CryptReleaseContext (hCryptProv, 0);
+
+ for (ptr = rt; *ptr; ptr++);
+ memcpy (ptr, TEXT("\\GRUB."), sizeof (TEXT("\\GRUB.")));
+ ptr += sizeof ("\\GRUB.") - 1;
+
+ for (i = 0; i < 8; i++)
+ {
+ grub_size_t b = i * 5;
+ grub_uint8_t r;
+ grub_size_t f1 = GRUB_CHAR_BIT - b % GRUB_CHAR_BIT;
+ grub_size_t f2;
+ if (f1 > 5)
+ f1 = 5;
+ f2 = 5 - f1;
+ r = (rnd[b / GRUB_CHAR_BIT] >> (b % GRUB_CHAR_BIT)) & ((1 << f1) - 1);
+ if (f2)
+ r |= (rnd[b / GRUB_CHAR_BIT + 1] & ((1 << f2) - 1)) << f1;
+ if (r < 10)
+ *ptr++ = '0' + r;
+ else
+ *ptr++ = 'a' + (r - 10);
+ }
+ *ptr = '\0';
+
+ return grub_util_tchar_to_utf8 (rt);
+}
+
+char *
+grub_util_make_temporary_file (void)
+{
+ char *ret = get_temp_name ();
+ FILE *f;
+
+ f = grub_util_fopen (ret, "wb");
+ if (f)
+ fclose (f);
+ return ret;
+}
+
+char *
+grub_util_make_temporary_dir (void)
+{
+ char *ret = get_temp_name ();
+
+ grub_util_mkdir (ret);
+
+ return ret;
+}
+
+#endif
+
+int
+grub_util_is_directory (const char *name)
+{
+ LPTSTR name_windows;
+ DWORD attr;
+
+ name_windows = grub_util_get_windows_path (name);
+ if (!name_windows)
+ return 0;
+
+ attr = GetFileAttributes (name_windows);
+ grub_free (name_windows);
+
+ return !!(attr & FILE_ATTRIBUTE_DIRECTORY);
+}
+
+int
+grub_util_is_regular (const char *name)
+{
+ LPTSTR name_windows;
+ DWORD attr;
+
+ name_windows = grub_util_get_windows_path (name);
+ if (!name_windows)
+ return 0;
+
+ attr = GetFileAttributes (name_windows);
+ grub_free (name_windows);
+
+ return !(attr & FILE_ATTRIBUTE_DIRECTORY)
+ && !(attr & FILE_ATTRIBUTE_REPARSE_POINT) && attr;
+}
+
+grub_uint32_t
+grub_util_get_mtime (const char *path)
+{
+ LPTSTR name_windows;
+ BOOL b;
+ WIN32_FILE_ATTRIBUTE_DATA attr;
+ ULARGE_INTEGER us_ul;
+
+ name_windows = grub_util_get_windows_path (path);
+ if (!name_windows)
+ return 0;
+
+ b = GetFileAttributesEx (name_windows, GetFileExInfoStandard, &attr);
+ grub_free (name_windows);
+
+ if (!b)
+ return 0;
+
+ us_ul.LowPart = attr.ftLastWriteTime.dwLowDateTime;
+ us_ul.HighPart = attr.ftLastWriteTime.dwHighDateTime;
+
+ return (us_ul.QuadPart / 10000000)
+ - 86400ULL * 365 * (1970 - 1601)
+ - 86400ULL * ((1970 - 1601) / 4) + 86400ULL * ((1970 - 1601) / 100);
+}
+
+
+#ifdef __MINGW32__
+
+FILE *
+grub_util_fopen (const char *path, const char *mode)
+{
+ LPTSTR tpath;
+ FILE *ret;
+ tpath = grub_util_get_windows_path (path);
+#if SIZEOF_TCHAR == 1
+ ret = fopen (tpath, tmode);
+#else
+ LPTSTR tmode;
+ tmode = grub_util_utf8_to_tchar (mode);
+ ret = _wfopen (tpath, tmode);
+ free (tmode);
+#endif
+ free (tpath);
+ return ret;
+}
+
+int
+grub_util_file_sync (FILE *f)
+{
+ HANDLE hnd;
+
+ if (fflush (f) != 0)
+ {
+ grub_util_info ("fflush err %x", (int) GetLastError ());
+ return -1;
+ }
+ if (!allow_fd_syncs)
+ return 0;
+ hnd = (HANDLE) _get_osfhandle (fileno (f));
+ if (!FlushFileBuffers (hnd))
+ {
+ grub_util_info ("flush err %x", (int) GetLastError ());
+ return -1;
+ }
+ return 0;
+}
+
+int
+grub_util_is_special_file (const char *name)
+{
+ LPTSTR name_windows;
+ DWORD attr;
+
+ name_windows = grub_util_get_windows_path (name);
+ if (!name_windows)
+ return 1;
+
+ attr = GetFileAttributes (name_windows);
+ grub_free (name_windows);
+
+ return !!(attr & FILE_ATTRIBUTE_REPARSE_POINT) || !attr;
+}
+
+#else
+
+void
+grub_util_file_sync (FILE *f)
+{
+ fflush (f);
+ if (!allow_fd_syncs)
+ return;
+ fsync (fileno (f));
+}
+
+FILE *
+grub_util_fopen (const char *path, const char *mode)
+{
+ return fopen (path, mode);
+}
+
+#endif
diff --git a/grub-core/osdep/windows/init.c b/grub-core/osdep/windows/init.c
new file mode 100644
index 0000000..6297de6
--- /dev/null
+++ b/grub-core/osdep/windows/init.c
@@ -0,0 +1,190 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+#include <config-util.h>
+#include <grub/util/misc.h>
+#include <grub/osdep/hostfile.h>
+#include <grub/util/windows.h>
+#include <grub/emu/config.h>
+
+#include <wincon.h>
+#include <windows.h>
+
+#include <grub/util/misc.h>
+
+#include "progname.h"
+
+struct grub_windows_console_font_infoex {
+ ULONG cbSize;
+ DWORD nFont;
+ COORD dwFontSize;
+ UINT FontFamily;
+ UINT FontWeight;
+ WCHAR FaceName[LF_FACESIZE];
+};
+
+static int
+check_is_raster (HMODULE kernel32, HANDLE hnd)
+{
+ CONSOLE_FONT_INFO console_font_info;
+ BOOL (WINAPI * func_GetCurrentConsoleFont) (HANDLE, BOOL,
+ PCONSOLE_FONT_INFO);
+
+ func_GetCurrentConsoleFont = (void *)
+ GetProcAddress (kernel32, "GetCurrentConsoleFont");
+
+ if (!func_GetCurrentConsoleFont)
+ return 1;
+
+ if (!func_GetCurrentConsoleFont (hnd, FALSE, &console_font_info))
+ return 1;
+ return console_font_info.nFont < 12;
+}
+
+static void
+set_console_unicode_font (void)
+{
+ BOOL (WINAPI * func_SetCurrentConsoleFontEx) (HANDLE, BOOL,
+ struct grub_windows_console_font_infoex *);
+ BOOL (WINAPI * func_SetConsoleFont)(HANDLE, DWORD);
+ HMODULE kernel32;
+ HANDLE out_handle = GetStdHandle (STD_OUTPUT_HANDLE);
+ HANDLE err_handle = GetStdHandle (STD_ERROR_HANDLE);
+ int out_raster, err_raster;
+
+ kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+ if (!kernel32)
+ return;
+
+ out_raster = check_is_raster (kernel32, out_handle);
+ err_raster = check_is_raster (kernel32, err_handle);
+
+ if (!out_raster && !err_raster)
+ return;
+
+ func_SetCurrentConsoleFontEx = (void *) GetProcAddress (kernel32, "SetCurrentConsoleFontEx");
+
+ /* Newer windows versions. */
+ if (func_SetCurrentConsoleFontEx)
+ {
+ struct grub_windows_console_font_infoex new_console_font_info;
+ new_console_font_info.cbSize = sizeof (new_console_font_info);
+ new_console_font_info.nFont = 12;
+ new_console_font_info.dwFontSize.X = 7;
+ new_console_font_info.dwFontSize.Y = 12;
+ new_console_font_info.FontFamily = FF_DONTCARE;
+ new_console_font_info.FontWeight = 400;
+ memcpy (new_console_font_info.FaceName, TEXT("Lucida Console"),
+ sizeof (TEXT("Lucida Console")));
+ if (out_raster)
+ func_SetCurrentConsoleFontEx (out_handle, FALSE,
+ &new_console_font_info);
+ if (err_raster)
+ func_SetCurrentConsoleFontEx (err_handle, FALSE,
+ &new_console_font_info);
+ return;
+ }
+
+ /* Fallback for older versions. */
+ func_SetConsoleFont = (void *) GetProcAddress (kernel32, "SetConsoleFont");
+ if (func_SetConsoleFont)
+ {
+ if (out_raster)
+ func_SetConsoleFont (out_handle, 12);
+ if (err_raster)
+ func_SetConsoleFont (err_handle, 12);
+ }
+}
+
+static char *grub_util_base_directory;
+static char *locale_dir;
+
+const char *
+grub_util_get_config_filename (void)
+{
+ static char *value = NULL;
+ if (!value)
+ value = grub_util_path_concat (2, grub_util_base_directory, "grub.cfg");
+ return value;
+}
+
+const char *
+grub_util_get_pkgdatadir (void)
+{
+ return grub_util_base_directory;
+}
+
+const char *
+grub_util_get_localedir (void)
+{
+ return locale_dir;
+}
+
+const char *
+grub_util_get_pkglibdir (void)
+{
+ return grub_util_base_directory;
+}
+
+void
+grub_util_host_init (int *argc __attribute__ ((unused)),
+ char ***argv)
+{
+ char *ptr;
+
+ SetConsoleOutputCP (CP_UTF8);
+ SetConsoleCP (CP_UTF8);
+
+ set_console_unicode_font ();
+
+#if SIZEOF_TCHAR == 1
+
+#elif SIZEOF_TCHAR == 2
+ LPWSTR tcmdline = GetCommandLineW ();
+ int i;
+ LPWSTR *targv;
+
+ targv = CommandLineToArgvW (tcmdline, argc);
+ *argv = xcalloc (*argc + 1, sizeof (argv[0]));
+
+ for (i = 0; i < *argc; i++)
+ (*argv)[i] = grub_util_tchar_to_utf8 (targv[i]);
+ (*argv)[i] = NULL;
+#else
+#error "Unsupported TCHAR size"
+#endif
+
+ grub_util_base_directory = grub_canonicalize_file_name ((*argv)[0]);
+ if (!grub_util_base_directory)
+ grub_util_base_directory = xstrdup ((*argv)[0]);
+ for (ptr = grub_util_base_directory + strlen (grub_util_base_directory) - 1;
+ ptr >= grub_util_base_directory && *ptr != '/' && *ptr != '\\'; ptr--);
+ if (ptr >= grub_util_base_directory)
+ *ptr = '\0';
+
+ locale_dir = grub_util_path_concat (2, grub_util_base_directory, "locale");
+
+ set_program_name ((*argv)[0]);
+
+#if (defined (GRUB_UTIL) && defined(ENABLE_NLS) && ENABLE_NLS)
+ setlocale (LC_ALL, "");
+ bindtextdomain (PACKAGE, locale_dir);
+ textdomain (PACKAGE);
+#endif /* (defined(ENABLE_NLS) && ENABLE_NLS) */
+}
diff --git a/grub-core/osdep/windows/password.c b/grub-core/osdep/windows/password.c
new file mode 100644
index 0000000..1d3af0c
--- /dev/null
+++ b/grub-core/osdep/windows/password.c
@@ -0,0 +1,51 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2006
+ * 2007, 2008, 2009, 2010, 2011, 2012, 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/crypto.h>
+#include <grub/mm.h>
+#include <grub/term.h>
+
+#include <windows.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+int
+grub_password_get (char buf[], unsigned buf_size)
+{
+ HANDLE hStdin = GetStdHandle (STD_INPUT_HANDLE);
+ DWORD mode = 0;
+ char *ptr;
+
+ grub_refresh ();
+
+ GetConsoleMode (hStdin, &mode);
+ SetConsoleMode (hStdin, mode & (~ENABLE_ECHO_INPUT));
+
+ fgets (buf, buf_size, stdin);
+ ptr = buf + strlen (buf) - 1;
+ while (buf <= ptr && (*ptr == '\n' || *ptr == '\r'))
+ *ptr-- = 0;
+
+ SetConsoleMode (hStdin, mode);
+
+ grub_refresh ();
+
+ return 1;
+}
diff --git a/grub-core/osdep/windows/platform.c b/grub-core/osdep/windows/platform.c
new file mode 100644
index 0000000..253f8d1
--- /dev/null
+++ b/grub-core/osdep/windows/platform.c
@@ -0,0 +1,426 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+
+#include <windows.h>
+#include <grub/util/install.h>
+#include <grub/util/misc.h>
+#include <grub/efi/api.h>
+#include <grub/charset.h>
+#include <grub/gpt_partition.h>
+
+#define GRUB_EFI_GLOBAL_VARIABLE_GUID_WINDOWS_STR L"{8be4df61-93ca-11d2-aa0d-00e098032b8c}"
+
+static enum { PLAT_UNK, PLAT_BIOS, PLAT_EFI } platform;
+static DWORD (WINAPI * func_GetFirmwareEnvironmentVariableW) (LPCWSTR lpName,
+ LPCWSTR lpGuid,
+ PVOID pBuffer,
+ DWORD nSize);
+static BOOL (WINAPI * func_SetFirmwareEnvironmentVariableW) (LPCWSTR lpName,
+ LPCWSTR lpGuid,
+ PVOID pBuffer,
+ DWORD nSize);
+static void (WINAPI * func_GetNativeSystemInfo) (LPSYSTEM_INFO lpSystemInfo);
+
+static int
+get_efi_privilegies (void)
+{
+ int ret = 1;
+ HANDLE hSelf;
+ TOKEN_PRIVILEGES tkp;
+
+ if (!OpenProcessToken (GetCurrentProcess(),
+ TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hSelf))
+ return 0;
+
+ LookupPrivilegeValue (NULL, SE_SYSTEM_ENVIRONMENT_NAME,
+ &tkp.Privileges[0].Luid);
+ tkp.PrivilegeCount = 1;
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ if (!AdjustTokenPrivileges (hSelf, FALSE, &tkp, 0, NULL, 0))
+ ret = 0;
+ if (GetLastError () != ERROR_SUCCESS)
+ ret = 0;
+ CloseHandle (hSelf);
+ return 1;
+}
+
+static void
+get_platform (void)
+{
+ HMODULE kernel32;
+ char buffer[256];
+
+ if (platform != PLAT_UNK)
+ return;
+
+ kernel32 = GetModuleHandle(TEXT("kernel32.dll"));
+ if (!kernel32)
+ {
+ platform = PLAT_BIOS;
+ return;
+ }
+
+ func_GetFirmwareEnvironmentVariableW = (void *)
+ GetProcAddress (kernel32, "GetFirmwareEnvironmentVariableW");
+ func_SetFirmwareEnvironmentVariableW = (void *)
+ GetProcAddress (kernel32, "SetFirmwareEnvironmentVariableW");
+ func_GetNativeSystemInfo = (void *)
+ GetProcAddress (kernel32, "GetNativeSystemInfo");
+ if (!func_GetNativeSystemInfo)
+ func_GetNativeSystemInfo = GetSystemInfo;
+ if (!func_GetFirmwareEnvironmentVariableW
+ || !func_SetFirmwareEnvironmentVariableW)
+ {
+ platform = PLAT_BIOS;
+ return;
+ }
+
+ if (!get_efi_privilegies ())
+ {
+ grub_util_warn (_("Insufficient privileges to access firmware, assuming BIOS"));
+ platform = PLAT_BIOS;
+ }
+
+ if (!func_GetFirmwareEnvironmentVariableW (L"BootOrder", GRUB_EFI_GLOBAL_VARIABLE_GUID_WINDOWS_STR,
+ buffer, sizeof (buffer))
+ && GetLastError () == ERROR_INVALID_FUNCTION)
+ {
+ platform = PLAT_BIOS;
+ return;
+ }
+ platform = PLAT_EFI;
+ return;
+}
+
+const char *
+grub_install_get_default_x86_platform (void)
+{
+ SYSTEM_INFO si;
+
+ get_platform ();
+ if (platform != PLAT_EFI)
+ return "i386-pc";
+
+ /* EFI */
+ /* Assume 64-bit in case of failure. */
+ si.wProcessorArchitecture = PROCESSOR_ARCHITECTURE_AMD64;
+ func_GetNativeSystemInfo (&si);
+ if (si.wProcessorArchitecture != PROCESSOR_ARCHITECTURE_INTEL)
+ return "x86_64-efi";
+ else
+ return "i386-efi";
+}
+
+static void *
+get_efi_variable (const wchar_t *varname, ssize_t *len)
+{
+ void *ret = NULL;
+ size_t alloc_size = 256, read_size;
+ get_platform ();
+ while (1)
+ {
+ DWORD err;
+ ret = xmalloc (alloc_size);
+ read_size = func_GetFirmwareEnvironmentVariableW (varname, GRUB_EFI_GLOBAL_VARIABLE_GUID_WINDOWS_STR,
+ ret, alloc_size);
+ err = GetLastError ();
+ if (read_size)
+ {
+ *len = read_size;
+ return ret;
+ }
+ if (err == ERROR_INSUFFICIENT_BUFFER
+ && alloc_size * 2 != 0)
+ {
+ alloc_size *= 2;
+ free (ret);
+ continue;
+ }
+ if (err == ERROR_ENVVAR_NOT_FOUND)
+ {
+ *len = -1;
+ return NULL;
+ }
+ *len = -2;
+ return NULL;
+ }
+}
+
+static void
+set_efi_variable (const wchar_t *varname, void *in, grub_size_t len)
+{
+ get_platform ();
+ func_SetFirmwareEnvironmentVariableW (varname, GRUB_EFI_GLOBAL_VARIABLE_GUID_WINDOWS_STR,
+ in, len);
+}
+
+static char
+bin2hex (int v)
+{
+ if (v < 10)
+ return '0' + v;
+ return 'A' + v - 10;
+}
+
+static void *
+get_efi_variable_bootn (grub_uint16_t n, ssize_t *len)
+{
+ wchar_t varname[20] = L"Boot0000";
+ varname[7] = bin2hex (n & 0xf);
+ varname[6] = bin2hex ((n >> 4) & 0xf);
+ varname[5] = bin2hex ((n >> 8) & 0xf);
+ varname[4] = bin2hex ((n >> 12) & 0xf);
+ return get_efi_variable (varname, len);
+}
+
+static void
+set_efi_variable_bootn (grub_uint16_t n, void *in, grub_size_t len)
+{
+ wchar_t varname[20] = L"Boot0000";
+ varname[7] = bin2hex (n & 0xf);
+ varname[6] = bin2hex ((n >> 4) & 0xf);
+ varname[5] = bin2hex ((n >> 8) & 0xf);
+ varname[4] = bin2hex ((n >> 12) & 0xf);
+ set_efi_variable (varname, in, len);
+}
+
+int
+grub_install_register_efi (grub_device_t efidir_grub_dev,
+ const char *efifile_path,
+ const char *efi_distributor)
+{
+ grub_uint16_t *boot_order, *new_boot_order;
+ grub_uint16_t *distributor16;
+ grub_uint8_t *entry;
+ grub_size_t distrib8_len, distrib16_len, path16_len, path8_len;
+ ssize_t boot_order_len, new_boot_order_len;
+ grub_uint16_t order_num = 0;
+ int have_order_num = 0;
+ grub_size_t max_path_length;
+ grub_uint8_t *path;
+ void *pathptr;
+ struct grub_efi_hard_drive_device_path *hddp;
+ struct grub_efi_file_path_device_path *filep;
+ struct grub_efi_device_path *endp;
+
+ get_platform ();
+ if (platform != PLAT_EFI)
+ grub_util_error ("%s", _("no EFI routines are available when running in BIOS mode"));
+
+ distrib8_len = grub_strlen (efi_distributor);
+ distributor16 = xcalloc (distrib8_len + 1,
+ GRUB_MAX_UTF16_PER_UTF8 * sizeof (grub_uint16_t));
+ distrib16_len = grub_utf8_to_utf16 (distributor16, distrib8_len * GRUB_MAX_UTF16_PER_UTF8,
+ (const grub_uint8_t *) efi_distributor,
+ distrib8_len, 0);
+ distributor16[distrib16_len] = 0;
+
+ /* Windows doesn't allow to list variables so first look for bootorder to
+ find if there is an entry from the same distributor. If not try sequentially
+ until we find same distributor or empty spot. */
+ boot_order = get_efi_variable (L"BootOrder", &boot_order_len);
+ if (boot_order_len < -1)
+ grub_util_error ("%s", _("unexpected EFI error"));
+ if (boot_order_len > 0)
+ {
+ size_t i;
+ for (i = 0; i < boot_order_len / 2; i++)
+ {
+ void *current = NULL;
+ ssize_t current_len;
+ current = get_efi_variable_bootn (i, &current_len);
+ if (current_len < 0)
+ continue; /* FIXME Should we abort on error? */
+ if (current_len < (distrib16_len + 1) * sizeof (grub_uint16_t)
+ + 6)
+ {
+ grub_free (current);
+ continue;
+ }
+ if (grub_memcmp ((grub_uint16_t *) current + 3,
+ distributor16,
+ (distrib16_len + 1) * sizeof (grub_uint16_t)) != 0)
+ {
+ grub_free (current);
+ continue;
+ }
+ order_num = i;
+ have_order_num = 1;
+ grub_util_info ("Found matching distributor at Boot%04x",
+ order_num);
+ grub_free (current);
+ break;
+ }
+ }
+ if (!have_order_num)
+ {
+ size_t i;
+ for (i = 0; i < 0x10000; i++)
+ {
+ void *current = NULL;
+ ssize_t current_len;
+ current = get_efi_variable_bootn (i, &current_len);
+ if (current_len < -1)
+ continue; /* FIXME Should we abort on error? */
+ if (current_len == -1)
+ {
+ if (!have_order_num)
+ {
+ order_num = i;
+ have_order_num = 1;
+ grub_util_info ("Creating new entry at Boot%04x",
+ order_num);
+ }
+ continue;
+ }
+ if (current_len < (distrib16_len + 1) * sizeof (grub_uint16_t)
+ + 6)
+ {
+ grub_free (current);
+ continue;
+ }
+ if (grub_memcmp ((grub_uint16_t *) current + 3,
+ distributor16,
+ (distrib16_len + 1) * sizeof (grub_uint16_t)) != 0)
+ {
+ grub_free (current);
+ continue;
+ }
+ order_num = i;
+ have_order_num = 1;
+ grub_util_info ("Found matching distributor at Boot%04x",
+ order_num);
+ grub_free (current);
+ break;
+ }
+ }
+ if (!have_order_num)
+ grub_util_error ("%s", _("Couldn't find a free BootNNNN slot"));
+ path8_len = grub_strlen (efifile_path);
+ max_path_length = sizeof (*hddp) + sizeof (*filep) + (path8_len * GRUB_MAX_UTF16_PER_UTF8 + 1) * sizeof (grub_uint16_t) + sizeof (*endp);
+ entry = xmalloc (6 + (distrib16_len + 1) * sizeof (grub_uint16_t) + max_path_length);
+ /* attributes: active. */
+ entry[0] = 1;
+ entry[1] = 0;
+ entry[2] = 0;
+ entry[3] = 0;
+ grub_memcpy (entry + 6,
+ distributor16,
+ (distrib16_len + 1) * sizeof (grub_uint16_t));
+
+ path = entry + 6 + (distrib16_len + 1) * sizeof (grub_uint16_t);
+ pathptr = path;
+
+ hddp = pathptr;
+ grub_memset (hddp, 0, sizeof (*hddp));
+ hddp->header.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE;
+ hddp->header.subtype = GRUB_EFI_HARD_DRIVE_DEVICE_PATH_SUBTYPE;
+ hddp->header.length = sizeof (*hddp);
+ hddp->partition_number = efidir_grub_dev->disk->partition ? efidir_grub_dev->disk->partition->number + 1 : 1;
+ if (efidir_grub_dev->disk->partition
+ && grub_strcmp (efidir_grub_dev->disk->partition->partmap->name, "msdos") == 0)
+ {
+ grub_partition_t p;
+
+ p = efidir_grub_dev->disk->partition;
+ efidir_grub_dev->disk->partition = p->parent;
+ if (grub_disk_read (efidir_grub_dev->disk, 0, 440,
+ 4, hddp->partition_signature))
+ grub_util_error ("%s", grub_errmsg);
+ efidir_grub_dev->disk->partition = p;
+
+ hddp->partmap_type = 1;
+ hddp->signature_type = 1;
+ }
+ else if (efidir_grub_dev->disk->partition
+ && grub_strcmp (efidir_grub_dev->disk->partition->partmap->name, "gpt") == 0)
+ {
+ struct grub_gpt_partentry gptdata;
+ grub_partition_t p;
+
+ p = efidir_grub_dev->disk->partition;
+ efidir_grub_dev->disk->partition = p->parent;
+ if (grub_disk_read (efidir_grub_dev->disk,
+ p->offset, p->index,
+ sizeof (gptdata), &gptdata))
+ grub_util_error ("%s", grub_errmsg);
+ efidir_grub_dev->disk->partition = p;
+ grub_memcpy (hddp->partition_signature,
+ &gptdata.guid, 16);
+
+ hddp->partmap_type = 2;
+ hddp->signature_type = 2;
+ }
+
+ hddp->partition_start = grub_partition_get_start (efidir_grub_dev->disk->partition)
+ >> (efidir_grub_dev->disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
+ hddp->partition_size = grub_disk_native_sectors (efidir_grub_dev->disk)
+ >> (efidir_grub_dev->disk->log_sector_size - GRUB_DISK_SECTOR_BITS);
+
+ pathptr = hddp + 1;
+ filep = pathptr;
+ filep->header.type = GRUB_EFI_MEDIA_DEVICE_PATH_TYPE;
+ filep->header.subtype = GRUB_EFI_FILE_PATH_DEVICE_PATH_SUBTYPE;
+
+ path16_len = grub_utf8_to_utf16 (filep->path_name,
+ path8_len * GRUB_MAX_UTF16_PER_UTF8,
+ (const grub_uint8_t *) efifile_path,
+ path8_len, 0);
+ filep->path_name[path16_len] = 0;
+ filep->header.length = sizeof (*filep) + (path16_len + 1) * sizeof (grub_uint16_t);
+ pathptr = &filep->path_name[path16_len + 1];
+ endp = pathptr;
+ endp->type = GRUB_EFI_END_DEVICE_PATH_TYPE;
+ endp->subtype = GRUB_EFI_END_ENTIRE_DEVICE_PATH_SUBTYPE;
+ endp->length = sizeof (*endp);
+ pathptr = endp + 1;
+
+ entry[4] = (grub_uint8_t *) pathptr - path;
+ entry[5] = ((grub_uint8_t *) pathptr - path) >> 8;
+
+ new_boot_order = xmalloc ((boot_order_len > 0 ? boot_order_len : 0) + 2);
+ new_boot_order[0] = order_num;
+ new_boot_order_len = 1;
+ {
+ ssize_t i;
+ for (i = 0; i < boot_order_len / 2; i++)
+ if (boot_order[i] != order_num)
+ new_boot_order[new_boot_order_len++] = boot_order[i];
+ }
+
+ set_efi_variable_bootn (order_num, entry, (grub_uint8_t *) pathptr - entry);
+ set_efi_variable (L"BootOrder", new_boot_order, new_boot_order_len * sizeof (grub_uint16_t));
+
+ return 0;
+}
+
+void
+grub_install_register_ieee1275 (int is_prep, const char *install_device,
+ int partno, const char *relpath)
+{
+ grub_util_error ("%s", _("no IEEE1275 routines are available for your platform"));
+}
+
+void
+grub_install_sgi_setup (const char *install_device,
+ const char *imgfile, const char *destname)
+{
+ grub_util_error ("%s", _("no SGI routines are available for your platform"));
+}
diff --git a/grub-core/osdep/windows/random.c b/grub-core/osdep/windows/random.c
new file mode 100644
index 0000000..78f5082
--- /dev/null
+++ b/grub-core/osdep/windows/random.c
@@ -0,0 +1,55 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1992-1999,2001,2003,2004,2005,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <grub/types.h>
+#include <grub/crypto.h>
+#include <grub/auth.h>
+#include <grub/emu/misc.h>
+#include <grub/util/misc.h>
+#include <grub/i18n.h>
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <windows.h>
+#include <wincrypt.h>
+
+int
+grub_get_random (void *out, grub_size_t len)
+{
+ HCRYPTPROV hCryptProv;
+ if (!CryptAcquireContext (&hCryptProv,
+ NULL,
+ MS_DEF_PROV,
+ PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT))
+ return 1;
+ if (!CryptGenRandom (hCryptProv, len, out))
+ {
+ CryptReleaseContext (hCryptProv, 0);
+ return 1;
+ }
+
+ CryptReleaseContext (hCryptProv, 0);
+
+ return 0;
+}
diff --git a/grub-core/osdep/windows/relpath.c b/grub-core/osdep/windows/relpath.c
new file mode 100644
index 0000000..478e8ef
--- /dev/null
+++ b/grub-core/osdep/windows/relpath.c
@@ -0,0 +1,96 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 1999,2000,2001,2002,2003,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <grub/types.h>
+
+#include <grub/util/misc.h>
+
+#include <grub/mm.h>
+#include <grub/misc.h>
+#include <grub/emu/misc.h>
+#include <grub/emu/hostdisk.h>
+#include <grub/emu/getroot.h>
+#include <grub/charset.h>
+#include <grub/util/windows.h>
+#include <windows.h>
+#include <winioctl.h>
+
+static size_t
+tclen (const TCHAR *s)
+{
+ const TCHAR *s0 = s;
+ while (*s)
+ s++;
+ return s - s0;
+}
+
+char *
+grub_make_system_path_relative_to_its_root (const char *path)
+{
+ TCHAR *dirwindows, *mntpointwindows;
+ TCHAR *ptr;
+ size_t offset, flen;
+ TCHAR *ret;
+ char *cret;
+
+ dirwindows = grub_util_get_windows_path (path);
+ if (!dirwindows)
+ return xstrdup (path);
+
+ mntpointwindows = grub_get_mount_point (dirwindows);
+
+ if (!mntpointwindows)
+ {
+ offset = 0;
+ if (dirwindows[0] && dirwindows[1] == ':')
+ offset = 2;
+ }
+ offset = tclen (mntpointwindows);
+ free (mntpointwindows);
+ flen = tclen (dirwindows);
+ if (offset > flen)
+ {
+ offset = 0;
+ if (dirwindows[0] && dirwindows[1] == ':')
+ offset = 2;
+ }
+ ret = xcalloc (flen - offset + 2, sizeof (ret[0]));
+ if (dirwindows[offset] != '\\'
+ && dirwindows[offset] != '/'
+ && dirwindows[offset])
+ {
+ ret[0] = '\\';
+ memcpy (ret + 1, dirwindows + offset, (flen - offset + 1) * sizeof (ret[0]));
+ }
+ else
+ memcpy (ret, dirwindows + offset, (flen - offset + 1) * sizeof (ret[0]));
+
+ free (dirwindows);
+
+ for (ptr = ret; *ptr; ptr++)
+ if (*ptr == '\\')
+ *ptr = '/';
+
+ cret = grub_util_tchar_to_utf8 (ret);
+ free (ret);
+
+ return cret;
+}
diff --git a/grub-core/osdep/windows/sleep.c b/grub-core/osdep/windows/sleep.c
new file mode 100644
index 0000000..03b846b
--- /dev/null
+++ b/grub-core/osdep/windows/sleep.c
@@ -0,0 +1,31 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2010,2011,2012,2013 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config-util.h>
+#include <config.h>
+
+#include <windows.h>
+#include <winioctl.h>
+#include <grub/time.h>
+
+void
+grub_millisleep (grub_uint32_t ms)
+{
+ Sleep (ms);
+}
+