diff options
Diffstat (limited to 'grub-core/osdep')
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, §or_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, ¶ms); + 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, §or_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, §or_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, §or_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, ¤t_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, ¤t_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); +} + |