diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:29:51 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 16:29:51 +0000 |
commit | 6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e (patch) | |
tree | 32451fa3cdd9321fb2591fada9891b2cb70a9cd1 /grub-core/osdep/unix | |
parent | Initial commit. (diff) | |
download | grub2-6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e.tar.xz grub2-6e7a315eb67cb6c113cf37e1d66c4f11a51a2b3e.zip |
Adding upstream version 2.06.upstream/2.06upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'grub-core/osdep/unix')
-rw-r--r-- | grub-core/osdep/unix/compress.c | 41 | ||||
-rw-r--r-- | grub-core/osdep/unix/config.c | 139 | ||||
-rw-r--r-- | grub-core/osdep/unix/cputime.c | 22 | ||||
-rw-r--r-- | grub-core/osdep/unix/dl.c | 61 | ||||
-rw-r--r-- | grub-core/osdep/unix/emuconsole.c | 184 | ||||
-rw-r--r-- | grub-core/osdep/unix/exec.c | 245 | ||||
-rw-r--r-- | grub-core/osdep/unix/getroot.c | 787 | ||||
-rw-r--r-- | grub-core/osdep/unix/hostdisk.c | 319 | ||||
-rw-r--r-- | grub-core/osdep/unix/password.c | 75 | ||||
-rw-r--r-- | grub-core/osdep/unix/platform.c | 241 | ||||
-rw-r--r-- | grub-core/osdep/unix/random.c | 48 | ||||
-rw-r--r-- | grub-core/osdep/unix/relpath.c | 151 | ||||
-rw-r--r-- | grub-core/osdep/unix/sleep.c | 30 |
13 files changed, 2343 insertions, 0 deletions
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); +} |