Status = gRT->SetVariable(L"VentoyRamDisk", &VarGuid,
EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
sizeof(g_ramdisk_param), &(g_ramdisk_param));
- debug("set efi variable %r", Status);
+ debug("set ramdisk variable %r", Status);
return Status;
}
size = StrDecimalToUintn(pPos + 5);
debug("memory addr:%p size:%lu", chain, size);
-
- g_chain = AllocatePool(size);
- CopyMem(g_chain, chain, size);
if (StrStr(pCmdLine, L"memdisk"))
{
- g_iso_buf_size = size;
+ g_iso_data_buf = (UINT8 *)chain + sizeof(ventoy_chain_head);
+ g_iso_buf_size = size - sizeof(ventoy_chain_head);
+ debug("memdisk mode iso_buf_size:%u", g_iso_buf_size);
+
+ g_chain = chain;
gMemdiskMode = TRUE;
}
else
{
+ debug("This is normal mode");
+ g_chain = AllocatePool(size);
+ CopyMem(g_chain, chain, size);
+
g_chunk = (ventoy_img_chunk *)((char *)g_chain + g_chain->img_chunk_offset);
g_img_chunk_num = g_chain->img_chunk_num;
g_override_chunk = (ventoy_override_chunk *)((char *)g_chain + g_chain->override_chunk_offset);
}
}
+ ventoy_debug_pause();
+
FreePool(pCmdLine);
return EFI_SUCCESS;
}
if (gMemdiskMode)
{
- g_ramdisk_param.PhyAddr = (UINT64)(UINTN)g_chain;
+ g_ramdisk_param.PhyAddr = (UINT64)(UINTN)g_iso_data_buf;
g_ramdisk_param.DiskSize = (UINT64)g_iso_buf_size;
ventoy_save_ramdisk_param();
+
+ if (gLoadIsoEfi)
+ {
+ ventoy_find_iso_disk(ImageHandle);
+ ventoy_find_iso_disk_fs(ImageHandle);
+ ventoy_load_isoefi_driver(ImageHandle);
+ }
ventoy_install_blockio(ImageHandle, g_iso_buf_size);
+ ventoy_debug_pause();
+
Status = ventoy_boot(ImageHandle);
ventoy_delete_ramdisk_param();
+
+ if (gLoadIsoEfi && gBlockData.IsoDriverImage)
+ {
+ gBS->UnloadImage(gBlockData.IsoDriverImage);
+ }
}
else
{
extern UINT32 g_sector_flag_num;
extern BOOLEAN gMemdiskMode;
extern UINTN g_iso_buf_size;
+extern UINT8 *g_iso_data_buf;
extern ventoy_grub_param_file_replace *g_file_replace_list;
extern BOOLEAN g_fixup_iso9660_secover_enable;
extern EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *g_con_simple_input_ex;
#include <Protocol/SimpleFileSystem.h>
#include <Ventoy.h>
+UINT8 *g_iso_data_buf = NULL;
UINTN g_iso_buf_size = 0;
BOOLEAN gMemdiskMode = FALSE;
(VOID)This;
(VOID)MediaId;
- CopyMem(Buffer, (char *)g_chain + (Lba * 2048), BufferSize);
+ CopyMem(Buffer, g_iso_data_buf + (Lba * 2048), BufferSize);
if (g_blockio_start_record_bcd && FALSE == g_blockio_bcd_read_done)
{
common = commands/blocklist.c;
};
+module = {
+ name = blscfg;
+ common = commands/blscfg.c;
+ common = commands/loadenv.h;
+ enable = powerpc_ieee1275;
+ enable = efi;
+ enable = i386_pc;
+ enable = emu;
+};
+
module = {
name = boot;
common = commands/boot.c;
module = {
name = loadenv;
common = commands/loadenv.c;
+ common = commands/loadenv.h;
common = lib/envblk.c;
};
--- /dev/null
+/*-*- Mode: C; c-basic-offset: 2; indent-tabs-mode: t -*-*/
+
+/* bls.c - implementation of the boot loader spec */
+
+/*
+ * GRUB -- GRand Unified Bootloader
+ *
+ * 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/list.h>
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/fs.h>
+#include <grub/env.h>
+#include <grub/file.h>
+#include <grub/normal.h>
+#include <grub/lib/envblk.h>
+
+#include <stdbool.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#include "loadenv.h"
+
+#define GRUB_BLS_CONFIG_PATH "/loader/entries/"
+#ifdef GRUB_MACHINE_EMU
+#define GRUB_BOOT_DEVICE "/boot"
+#else
+#define GRUB_BOOT_DEVICE "($root)"
+#endif
+
+struct keyval
+{
+ const char *key;
+ char *val;
+};
+
+static struct bls_entry *entries = NULL;
+
+#define FOR_BLS_ENTRIES(var) FOR_LIST_ELEMENTS (var, entries)
+
+static int bls_add_keyval(struct bls_entry *entry, char *key, char *val)
+{
+ char *k, *v;
+ struct keyval **kvs, *kv;
+ int new_n = entry->nkeyvals + 1;
+
+ kvs = grub_realloc (entry->keyvals, new_n * sizeof (struct keyval *));
+ if (!kvs)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't find space for BLS entry");
+ entry->keyvals = kvs;
+
+ kv = grub_malloc (sizeof (struct keyval));
+ if (!kv)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't find space for BLS entry");
+
+ k = grub_strdup (key);
+ if (!k)
+ {
+ grub_free (kv);
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't find space for BLS entry");
+ }
+
+ v = grub_strdup (val);
+ if (!v)
+ {
+ grub_free (k);
+ grub_free (kv);
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY,
+ "couldn't find space for BLS entry");
+ }
+
+ kv->key = k;
+ kv->val = v;
+
+ entry->keyvals[entry->nkeyvals] = kv;
+ grub_dprintf("blscfg", "new keyval at %p:%s:%s\n", entry->keyvals[entry->nkeyvals], k, v);
+ entry->nkeyvals = new_n;
+
+ return 0;
+}
+
+/* Find they value of the key named by keyname. If there are allowed to be
+ * more than one, pass a pointer to an int set to -1 the first time, and pass
+ * the same pointer through each time after, and it'll return them in sorted
+ * order as defined in the BLS fragment file */
+static char *bls_get_val(struct bls_entry *entry, const char *keyname, int *last)
+{
+ int idx, start = 0;
+ struct keyval *kv = NULL;
+
+ if (last)
+ start = *last + 1;
+
+ for (idx = start; idx < entry->nkeyvals; idx++) {
+ kv = entry->keyvals[idx];
+
+ if (!grub_strcmp (keyname, kv->key))
+ break;
+ }
+
+ if (idx == entry->nkeyvals) {
+ if (last)
+ *last = -1;
+ return NULL;
+ }
+
+ if (last)
+ *last = idx;
+
+ return kv->val;
+}
+
+#define goto_return(x) ({ ret = (x); goto finish; })
+
+/* compare alpha and numeric segments of two versions */
+/* return 1: a is newer than b */
+/* 0: a and b are the same version */
+/* -1: b is newer than a */
+static int vercmp(const char * a, const char * b)
+{
+ char oldch1, oldch2;
+ char *abuf, *bbuf;
+ char *str1, *str2;
+ char * one, * two;
+ int rc;
+ int isnum;
+ int ret = 0;
+
+ grub_dprintf("blscfg", "%s comparing %s and %s\n", __func__, a, b);
+ if (!grub_strcmp(a, b))
+ return 0;
+
+ abuf = grub_malloc(grub_strlen(a) + 1);
+ bbuf = grub_malloc(grub_strlen(b) + 1);
+ str1 = abuf;
+ str2 = bbuf;
+ grub_strcpy(str1, a);
+ grub_strcpy(str2, b);
+
+ one = str1;
+ two = str2;
+
+ /* loop through each version segment of str1 and str2 and compare them */
+ while (*one || *two) {
+ while (*one && !grub_isalnum(*one) && *one != '~') one++;
+ while (*two && !grub_isalnum(*two) && *two != '~') two++;
+
+ /* handle the tilde separator, it sorts before everything else */
+ if (*one == '~' || *two == '~') {
+ if (*one != '~') goto_return (1);
+ if (*two != '~') goto_return (-1);
+ one++;
+ two++;
+ continue;
+ }
+
+ /* If we ran to the end of either, we are finished with the loop */
+ if (!(*one && *two)) break;
+
+ str1 = one;
+ str2 = two;
+
+ /* grab first completely alpha or completely numeric segment */
+ /* leave one and two pointing to the start of the alpha or numeric */
+ /* segment and walk str1 and str2 to end of segment */
+ if (grub_isdigit(*str1)) {
+ while (*str1 && grub_isdigit(*str1)) str1++;
+ while (*str2 && grub_isdigit(*str2)) str2++;
+ isnum = 1;
+ } else {
+ while (*str1 && grub_isalpha(*str1)) str1++;
+ while (*str2 && grub_isalpha(*str2)) str2++;
+ isnum = 0;
+ }
+
+ /* save character at the end of the alpha or numeric segment */
+ /* so that they can be restored after the comparison */
+ oldch1 = *str1;
+ *str1 = '\0';
+ oldch2 = *str2;
+ *str2 = '\0';
+
+ /* this cannot happen, as we previously tested to make sure that */
+ /* the first string has a non-null segment */
+ if (one == str1) goto_return(-1); /* arbitrary */
+
+ /* take care of the case where the two version segments are */
+ /* different types: one numeric, the other alpha (i.e. empty) */
+ /* numeric segments are always newer than alpha segments */
+ /* XXX See patch #60884 (and details) from bugzilla #50977. */
+ if (two == str2) goto_return (isnum ? 1 : -1);
+
+ if (isnum) {
+ grub_size_t onelen, twolen;
+ /* this used to be done by converting the digit segments */
+ /* to ints using atoi() - it's changed because long */
+ /* digit segments can overflow an int - this should fix that. */
+
+ /* throw away any leading zeros - it's a number, right? */
+ while (*one == '0') one++;
+ while (*two == '0') two++;
+
+ /* whichever number has more digits wins */
+ onelen = grub_strlen(one);
+ twolen = grub_strlen(two);
+ if (onelen > twolen) goto_return (1);
+ if (twolen > onelen) goto_return (-1);
+ }
+
+ /* grub_strcmp will return which one is greater - even if the two */
+ /* segments are alpha or if they are numeric. don't return */
+ /* if they are equal because there might be more segments to */
+ /* compare */
+ rc = grub_strcmp(one, two);
+ if (rc) goto_return (rc < 1 ? -1 : 1);
+
+ /* restore character that was replaced by null above */
+ *str1 = oldch1;
+ one = str1;
+ *str2 = oldch2;
+ two = str2;
+ }
+
+ /* this catches the case where all numeric and alpha segments have */
+ /* compared identically but the segment sepparating characters were */
+ /* different */
+ if ((!*one) && (!*two)) goto_return (0);
+
+ /* whichever version still has characters left over wins */
+ if (!*one) goto_return (-1); else goto_return (1);
+
+finish:
+ grub_free (abuf);
+ grub_free (bbuf);
+ return ret;
+}
+
+/* returns name/version/release */
+/* NULL string pointer returned if nothing found */
+static void
+split_package_string (char *package_string, char **name,
+ char **version, char **release)
+{
+ char *package_version, *package_release;
+
+ /* Release */
+ package_release = grub_strrchr (package_string, '-');
+
+ if (package_release != NULL)
+ *package_release++ = '\0';
+
+ *release = package_release;
+
+ if (name == NULL)
+ {
+ *version = package_string;
+ }
+ else
+ {
+ /* Version */
+ package_version = grub_strrchr(package_string, '-');
+
+ if (package_version != NULL)
+ *package_version++ = '\0';
+
+ *version = package_version;
+ /* Name */
+ *name = package_string;
+ }
+
+ /* Bubble up non-null values from release to name */
+ if (name != NULL && *name == NULL)
+ {
+ *name = (*version == NULL ? *release : *version);
+ *version = *release;
+ *release = NULL;
+ }
+ if (*version == NULL)
+ {
+ *version = *release;
+ *release = NULL;
+ }
+}
+
+static int
+split_cmp(char *nvr0, char *nvr1, int has_name)
+{
+ int ret = 0;
+ char *name0, *version0, *release0;
+ char *name1, *version1, *release1;
+
+ split_package_string(nvr0, has_name ? &name0 : NULL, &version0, &release0);
+ split_package_string(nvr1, has_name ? &name1 : NULL, &version1, &release1);
+
+ if (has_name)
+ {
+ ret = vercmp(name0 == NULL ? "" : name0,
+ name1 == NULL ? "" : name1);
+ if (ret != 0)
+ return ret;
+ }
+
+ ret = vercmp(version0 == NULL ? "" : version0,
+ version1 == NULL ? "" : version1);
+ if (ret != 0)
+ return ret;
+
+ ret = vercmp(release0 == NULL ? "" : release0,
+ release1 == NULL ? "" : release1);
+ return ret;
+}
+
+/* return 1: e0 is newer than e1 */
+/* 0: e0 and e1 are the same version */
+/* -1: e1 is newer than e0 */
+static int bls_cmp(const struct bls_entry *e0, const struct bls_entry *e1)
+{
+ char *id0, *id1;
+ int r;
+
+ id0 = grub_strdup(e0->filename);
+ id1 = grub_strdup(e1->filename);
+
+ r = split_cmp(id0, id1, 1);
+
+ grub_free(id0);
+ grub_free(id1);
+
+ return r;
+}
+
+static void list_add_tail(struct bls_entry *head, struct bls_entry *item)
+{
+ item->next = head;
+ if (head->prev)
+ head->prev->next = item;
+ item->prev = head->prev;
+ head->prev = item;
+}
+
+static int bls_add_entry(struct bls_entry *entry)
+{
+ struct bls_entry *e, *last = NULL;
+ int rc;
+
+ if (!entries) {
+ grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename);
+ entries = entry;
+ return 0;
+ }
+
+ FOR_BLS_ENTRIES(e) {
+ rc = bls_cmp(entry, e);
+
+ if (!rc)
+ return GRUB_ERR_BAD_ARGUMENT;
+
+ if (rc == 1) {
+ grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename);
+ list_add_tail (e, entry);
+ if (e == entries) {
+ entries = entry;
+ entry->prev = NULL;
+ }
+ return 0;
+ }
+ last = e;
+ }
+
+ if (last) {
+ grub_dprintf ("blscfg", "Add entry with id \"%s\"\n", entry->filename);
+ last->next = entry;
+ entry->prev = last;
+ }
+
+ return 0;
+}
+
+struct read_entry_info {
+ const char *devid;
+ const char *dirname;
+ grub_file_t file;
+};
+
+static int read_entry (
+ const char *filename,
+ const struct grub_dirhook_info *dirhook_info UNUSED,
+ void *data)
+{
+ grub_size_t m = 0, n, clip = 0;
+ int rc = 0;
+ char *p = NULL;
+ grub_file_t f = NULL;
+ struct bls_entry *entry;
+ struct read_entry_info *info = (struct read_entry_info *)data;
+
+ grub_dprintf ("blscfg", "filename: \"%s\"\n", filename);
+
+ n = grub_strlen (filename);
+
+ if (info->file)
+ {
+ f = info->file;
+ }
+ else
+ {
+ if (filename[0] == '.')
+ return 0;
+
+ if (n <= 5)
+ return 0;
+
+ if (grub_strcmp (filename + n - 5, ".conf") != 0)
+ return 0;
+
+ p = grub_xasprintf ("(%s)%s/%s", info->devid, info->dirname, filename);
+
+ f = grub_file_open (p, GRUB_FILE_TYPE_CONFIG);
+ if (!f)
+ goto finish;
+ }
+
+ entry = grub_zalloc (sizeof (*entry));
+ if (!entry)
+ goto finish;
+
+ if (info->file)
+ {
+ char *slash;
+
+ if (n > 5 && !grub_strcmp (filename + n - 5, ".conf") == 0)
+ clip = 5;
+
+ slash = grub_strrchr (filename, '/');
+ if (!slash)
+ slash = grub_strrchr (filename, '\\');
+
+ while (*slash == '/' || *slash == '\\')
+ slash++;
+
+ m = slash ? slash - filename : 0;
+ }
+ else
+ {
+ m = 0;
+ clip = 5;
+ }
+ n -= m;
+
+ entry->filename = grub_strndup(filename + m, n - clip);
+ if (!entry->filename)
+ goto finish;
+
+ entry->filename[n - 5] = '\0';
+
+ for (;;)
+ {
+ char *buf;
+ char *separator;
+
+ buf = grub_file_getline (f);
+ if (!buf)
+ break;
+
+ while (buf && buf[0] && (buf[0] == ' ' || buf[0] == '\t'))
+ buf++;
+ if (buf[0] == '#')
+ continue;
+
+ separator = grub_strchr (buf, ' ');
+
+ if (!separator)
+ separator = grub_strchr (buf, '\t');
+
+ if (!separator || separator[1] == '\0')
+ {
+ grub_free (buf);
+ break;
+ }
+
+ separator[0] = '\0';
+
+ do {
+ separator++;
+ } while (*separator == ' ' || *separator == '\t');
+
+ rc = bls_add_keyval (entry, buf, separator);
+ grub_free (buf);
+ if (rc < 0)
+ break;
+ }
+
+ if (!rc)
+ bls_add_entry(entry);
+
+finish:
+ if (p)
+ grub_free (p);
+
+ if (f)
+ grub_file_close (f);
+
+ return 0;
+}
+
+static grub_envblk_t saved_env = NULL;
+
+static int UNUSED
+save_var (const char *name, const char *value, void *whitelist UNUSED)
+{
+ const char *val = grub_env_get (name);
+ grub_dprintf("blscfg", "saving \"%s\"\n", name);
+
+ if (val)
+ grub_envblk_set (saved_env, name, value);
+
+ return 0;
+}
+
+static int UNUSED
+unset_var (const char *name, const char *value UNUSED, void *whitelist)
+{
+ grub_dprintf("blscfg", "restoring \"%s\"\n", name);
+ if (! whitelist)
+ {
+ grub_env_unset (name);
+ return 0;
+ }
+
+ if (test_whitelist_membership (name,
+ (const grub_env_whitelist_t *) whitelist))
+ grub_env_unset (name);
+
+ return 0;
+}
+
+static char **bls_make_list (struct bls_entry *entry, const char *key, int *num)
+{
+ int last = -1;
+ char *val;
+
+ int nlist = 0;
+ char **list = NULL;
+
+ list = grub_malloc (sizeof (char *));
+ if (!list)
+ return NULL;
+ list[0] = NULL;
+
+ while (1)
+ {
+ char **new;
+
+ val = bls_get_val (entry, key, &last);
+ if (!val)
+ break;
+
+ new = grub_realloc (list, (nlist + 2) * sizeof (char *));
+ if (!new)
+ break;
+
+ list = new;
+ list[nlist++] = val;
+ list[nlist] = NULL;
+ }
+
+ if (num)
+ *num = nlist;
+
+ return list;
+}
+
+static char *field_append(bool is_var, char *buffer, char *start, char *end)
+{
+ char *temp = grub_strndup(start, end - start + 1);
+ const char *field = temp;
+
+ if (is_var) {
+ field = grub_env_get (temp);
+ if (!field)
+ return buffer;
+ }
+
+ if (!buffer) {
+ buffer = grub_strdup(field);
+ if (!buffer)
+ return NULL;
+ } else {
+ buffer = grub_realloc (buffer, grub_strlen(buffer) + grub_strlen(field));
+ if (!buffer)
+ return NULL;
+
+ grub_stpcpy (buffer + grub_strlen(buffer), field);
+ }
+
+ return buffer;
+}
+
+static char *expand_val(char *value)
+{
+ char *buffer = NULL;
+ char *start = value;
+ char *end = value;
+ bool is_var = false;
+
+ if (!value)
+ return NULL;
+
+ while (*value) {
+ if (*value == '$') {
+ if (start != end) {
+ buffer = field_append(is_var, buffer, start, end);
+ if (!buffer)
+ return NULL;
+ }
+
+ is_var = true;
+ start = value + 1;
+ } else if (is_var) {
+ if (!grub_isalnum(*value) && *value != '_') {
+ buffer = field_append(is_var, buffer, start, end);
+ is_var = false;
+ start = value;
+ }
+ }
+
+ end = value;
+ value++;
+ }
+
+ if (start != end) {
+ buffer = field_append(is_var, buffer, start, end);
+ if (!buffer)
+ return NULL;
+ }
+
+ return buffer;
+}
+
+static char **early_initrd_list (const char *initrd)
+{
+ int nlist = 0;
+ char **list = NULL;
+ char *separator;
+
+ while ((separator = grub_strchr (initrd, ' ')))
+ {
+ list = grub_realloc (list, (nlist + 2) * sizeof (char *));
+ if (!list)
+ return NULL;
+
+ list[nlist++] = grub_strndup(initrd, separator - initrd);
+ list[nlist] = NULL;
+ initrd = separator + 1;
+ }
+
+ list = grub_realloc (list, (nlist + 2) * sizeof (char *));
+ if (!list)
+ return NULL;
+
+ list[nlist++] = grub_strndup(initrd, grub_strlen(initrd));
+ list[nlist] = NULL;
+
+ return list;
+}
+
+static void create_entry (struct bls_entry *entry)
+{
+ int argc = 0;
+ const char **argv = NULL;
+
+ char *title = NULL;
+ char *clinux = NULL;
+ char *options = NULL;
+ char **initrds = NULL;
+ char *initrd = NULL;
+ const char *early_initrd = NULL;
+ char **early_initrds = NULL;
+ char *initrd_prefix = NULL;
+ char *id = entry->filename;
+ char *dotconf = id;
+ char *hotkey = NULL;
+
+ char *users = NULL;
+ char **classes = NULL;
+
+ char **args = NULL;
+
+ char *src = NULL;
+ int bootlen;
+ const char *bootdev;
+ int i, index;
+
+ grub_dprintf("blscfg", "%s got here\n", __func__);
+ clinux = bls_get_val (entry, "linux", NULL);
+ if (!clinux)
+ {
+ grub_dprintf ("blscfg", "Skipping file %s with no 'linux' key.\n", entry->filename);
+ goto finish;
+ }
+
+ bootdev = grub_env_get("ventoy_bls_bootdev");
+ if (!bootdev)
+ {
+ bootdev = GRUB_BOOT_DEVICE;
+ }
+ bootlen = grub_strlen(bootdev) + 2;//space and \0
+
+ /*
+ * strip the ".conf" off the end before we make it our "id" field.
+ */
+ do
+ {
+ dotconf = grub_strstr(dotconf, ".conf");
+ } while (dotconf != NULL && dotconf[5] != '\0');
+ if (dotconf)
+ dotconf[0] = '\0';
+
+ title = bls_get_val (entry, "title", NULL);
+ options = expand_val (bls_get_val (entry, "options", NULL));
+
+ if (!options)
+ options = expand_val ((char *)grub_env_get("default_kernelopts"));
+
+ initrds = bls_make_list (entry, "initrd", NULL);
+
+ hotkey = bls_get_val (entry, "grub_hotkey", NULL);
+ users = expand_val (bls_get_val (entry, "grub_users", NULL));
+ classes = bls_make_list (entry, "grub_class", NULL);
+ args = bls_make_list (entry, "grub_arg", &argc);
+
+ argc += 1;
+ argv = grub_malloc ((argc + 1) * sizeof (char *));
+ argv[0] = title ? title : clinux;
+ for (i = 1; i < argc; i++)
+ argv[i] = args[i-1];
+ argv[argc] = NULL;
+
+ early_initrd = grub_env_get("early_initrd");
+
+ grub_dprintf ("blscfg", "adding menu entry for \"%s\" with id \"%s\"\n",
+ title, id);
+ if (early_initrd)
+ {
+ early_initrds = early_initrd_list(early_initrd);
+ if (!early_initrds)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ goto finish;
+ }
+
+ if (initrds != NULL && initrds[0] != NULL)
+ {
+ initrd_prefix = grub_strrchr (initrds[0], '/');
+ initrd_prefix = grub_strndup(initrds[0], initrd_prefix - initrds[0] + 1);
+ }
+ else
+ {
+ initrd_prefix = grub_strrchr (clinux, '/');
+ initrd_prefix = grub_strndup(clinux, initrd_prefix - clinux + 1);
+ }
+
+ if (!initrd_prefix)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ goto finish;
+ }
+ }
+
+ if (early_initrds || initrds)
+ {
+ int initrd_size = sizeof ("initrd");
+ char *tmp;
+
+ for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
+ initrd_size += bootlen \
+ + grub_strlen(initrd_prefix) \
+ + grub_strlen (early_initrds[i]) + 1;
+
+ for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
+ initrd_size += bootlen \
+ + grub_strlen (initrds[i]) + 1;
+ initrd_size += 1;
+
+ initrd = grub_malloc (initrd_size);
+ if (!initrd)
+ {
+ grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("out of memory"));
+ goto finish;
+ }
+
+
+ tmp = grub_stpcpy(initrd, "initrd");
+ for (i = 0; early_initrds != NULL && early_initrds[i] != NULL; i++)
+ {
+ grub_dprintf ("blscfg", "adding early initrd %s\n", early_initrds[i]);
+ tmp = grub_stpcpy (tmp, " ");
+ tmp = grub_stpcpy (tmp, bootdev);
+ tmp = grub_stpcpy (tmp, initrd_prefix);
+ tmp = grub_stpcpy (tmp, early_initrds[i]);
+ grub_free(early_initrds[i]);
+ }
+
+ for (i = 0; initrds != NULL && initrds[i] != NULL; i++)
+ {
+ grub_dprintf ("blscfg", "adding initrd %s\n", initrds[i]);
+ tmp = grub_stpcpy (tmp, " ");
+ tmp = grub_stpcpy (tmp, bootdev);
+ tmp = grub_stpcpy (tmp, initrds[i]);
+ }
+ tmp = grub_stpcpy (tmp, "\n");
+ }
+
+ src = grub_xasprintf ("load_video\n"
+ "set gfxpayload=keep\n"
+ "insmod gzio\n"
+ "linux %s%s%s%s\n"
+ "%s",
+ bootdev, clinux, options ? " " : "", options ? options : "",
+ initrd ? initrd : "");
+
+ grub_normal_add_menu_entry (argc, argv, classes, id, users, hotkey, NULL, src, 0, &index, entry);
+ grub_dprintf ("blscfg", "Added entry %d id:\"%s\"\n", index, id);
+
+finish:
+ grub_free (initrd);
+ grub_free (initrd_prefix);
+ grub_free (early_initrds);
+ grub_free (initrds);
+ grub_free (options);
+ grub_free (classes);
+ grub_free (args);
+ grub_free (argv);
+ grub_free (src);
+}
+
+struct find_entry_info {
+ const char *dirname;
+ const char *devid;
+ grub_device_t dev;
+ grub_fs_t fs;
+};
+
+/*
+ * info: the filesystem object the file is on.
+ */
+static int find_entry (struct find_entry_info *info)
+{
+ struct read_entry_info read_entry_info;
+ grub_fs_t blsdir_fs = NULL;
+ grub_device_t blsdir_dev = NULL;
+ const char *blsdir = info->dirname;
+ int fallback = 0;
+ int r = 0;
+
+ if (!blsdir) {
+ blsdir = grub_env_get ("blsdir");
+ if (!blsdir)
+ blsdir = GRUB_BLS_CONFIG_PATH;
+ }
+
+ read_entry_info.file = NULL;
+ read_entry_info.dirname = blsdir;
+
+ grub_dprintf ("blscfg", "scanning blsdir: %s\n", blsdir);
+
+ blsdir_dev = info->dev;
+ blsdir_fs = info->fs;
+ read_entry_info.devid = info->devid;
+
+read_fallback:
+ r = blsdir_fs->fs_dir (blsdir_dev, read_entry_info.dirname, read_entry,
+ &read_entry_info);
+ if (r != 0) {
+ grub_dprintf ("blscfg", "read_entry returned error\n");
+ grub_err_t e;
+ do
+ {
+ e = grub_error_pop();
+ } while (e);
+ }
+
+ if (r && !info->dirname && !fallback) {
+ read_entry_info.dirname = "/boot" GRUB_BLS_CONFIG_PATH;
+ grub_dprintf ("blscfg", "Entries weren't found in %s, fallback to %s\n",
+ blsdir, read_entry_info.dirname);
+ fallback = 1;
+ goto read_fallback;
+ }
+
+ return 0;
+}
+
+static grub_err_t
+bls_load_entries (const char *path)
+{
+ grub_size_t len;
+ grub_fs_t fs;
+ grub_device_t dev;
+ static grub_err_t r;
+ const char *devid = NULL;
+ char *blsdir = NULL;
+ struct find_entry_info info = {
+ .dev = NULL,
+ .fs = NULL,
+ .dirname = NULL,
+ };
+ struct read_entry_info rei = {
+ .devid = NULL,
+ .dirname = NULL,
+ };
+
+ if (path) {
+ len = grub_strlen (path);
+ if (grub_strcmp (path + len - 5, ".conf") == 0) {
+ rei.file = grub_file_open (path, GRUB_FILE_TYPE_CONFIG);
+ if (!rei.file)
+ return grub_errno;
+ /*
+ * read_entry() closes the file
+ */
+ return read_entry(path, NULL, &rei);
+ } else if (path[0] == '(') {
+ devid = path + 1;
+
+ blsdir = grub_strchr (path, ')');
+ if (!blsdir)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("Filepath isn't correct"));
+
+ *blsdir = '\0';
+ blsdir = blsdir + 1;
+ }
+ }
+
+ if (!devid) {
+#ifdef GRUB_MACHINE_EMU
+ devid = "host";
+#elif defined(GRUB_MACHINE_EFI)
+ devid = grub_env_get ("root");
+#else
+ devid = grub_env_get ("boot");
+ if (!devid)
+ {
+ devid = grub_env_get ("root");
+ }
+#endif
+ if (!devid)
+ return grub_error (GRUB_ERR_FILE_NOT_FOUND,
+ N_("variable `%s' isn't set"), "boot");
+ }
+
+ grub_dprintf ("blscfg", "opening %s\n", devid);
+ dev = grub_device_open (devid);
+ if (!dev)
+ return grub_errno;
+
+ grub_dprintf ("blscfg", "probing fs\n");
+ fs = grub_fs_probe (dev);
+ if (!fs)
+ {
+ r = grub_errno;
+ goto finish;
+ }
+
+ info.dirname = blsdir;
+ info.devid = devid;
+ info.dev = dev;
+ info.fs = fs;
+ find_entry(&info);
+
+finish:
+ if (dev)
+ grub_device_close (dev);
+
+ return r;
+}
+
+static bool
+is_default_entry(const char *def_entry, struct bls_entry *entry, int idx)
+{
+ const char *title;
+ int def_idx;
+
+ if (!def_entry)
+ return false;
+
+ if (grub_strcmp(def_entry, entry->filename) == 0)
+ return true;
+
+ title = bls_get_val(entry, "title", NULL);
+
+ if (title && grub_strcmp(def_entry, title) == 0)
+ return true;
+
+ def_idx = (int)grub_strtol(def_entry, NULL, 0);
+ if (grub_errno == GRUB_ERR_BAD_NUMBER) {
+ grub_errno = GRUB_ERR_NONE;
+ return false;
+ }
+
+ if (def_idx == idx)
+ return true;
+
+ return false;
+}
+
+static grub_err_t
+bls_create_entries (bool show_default, bool show_non_default, char *entry_id)
+{
+ const char *def_entry = NULL;
+ struct bls_entry *entry = NULL;
+ int idx = 0;
+
+ def_entry = grub_env_get("default");
+
+ grub_dprintf ("blscfg", "%s Creating entries from bls\n", __func__);
+ FOR_BLS_ENTRIES(entry) {
+ if (entry->visible) {
+ idx++;
+ continue;
+ }
+
+ if ((show_default && is_default_entry(def_entry, entry, idx)) ||
+ (show_non_default && !is_default_entry(def_entry, entry, idx)) ||
+ (entry_id && grub_strcmp(entry_id, entry->filename) == 0)) {
+ create_entry(entry);
+ entry->visible = 1;
+ }
+ idx++;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_blscfg (grub_extcmd_context_t ctxt UNUSED,
+ int argc, char **args)
+{
+ grub_err_t r;
+ char *path = NULL;
+ char *entry_id = NULL;
+ bool show_default = true;
+ bool show_non_default = true;
+
+ if (argc == 1) {
+ if (grub_strcmp (args[0], "default") == 0) {
+ show_non_default = false;
+ } else if (grub_strcmp (args[0], "non-default") == 0) {
+ show_default = false;
+ } else if (args[0][0] == '(') {
+ path = args[0];
+ } else {
+ entry_id = args[0];
+ show_default = false;
+ show_non_default = false;
+ }
+ }
+
+ r = bls_load_entries(path);
+ if (r)
+ return r;
+
+ return bls_create_entries(show_default, show_non_default, entry_id);
+}
+
+static grub_extcmd_t cmd;
+static grub_extcmd_t oldcmd;
+
+GRUB_MOD_INIT(blscfg)
+{
+ grub_dprintf("blscfg", "%s got here\n", __func__);
+ cmd = grub_register_extcmd ("blscfg",
+ grub_cmd_blscfg,
+ 0,
+ NULL,
+ N_("Import Boot Loader Specification snippets."),
+ NULL);
+ oldcmd = grub_register_extcmd ("bls_import",
+ grub_cmd_blscfg,
+ 0,
+ NULL,
+ N_("Import Boot Loader Specification snippets."),
+ NULL);
+}
+
+GRUB_MOD_FINI(blscfg)
+{
+ grub_unregister_extcmd (cmd);
+ grub_unregister_extcmd (oldcmd);
+}
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000, 2001, 2010 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/misc.h>
+#include <grub/command.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/file.h>
+#include <grub/normal.h>
+#include <grub/script_sh.h>
+#include <grub/i18n.h>
+#include <grub/term.h>
+#include <grub/legacy_parse.h>
+#include <grub/crypto.h>
+#include <grub/auth.h>
+#include <grub/disk.h>
+#include <grub/partition.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+/* Helper for legacy_file. */
+static grub_err_t
+legacy_file_getline (char **line, int cont __attribute__ ((unused)),
+ void *data __attribute__ ((unused)))
+{
+ *line = 0;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+legacy_file (const char *filename)
+{
+ grub_file_t file;
+ char *entryname = NULL, *entrysrc = NULL;
+ grub_menu_t menu;
+ char *suffix = grub_strdup ("");
+
+ if (!suffix)
+ return grub_errno;
+
+ file = grub_file_open (filename, GRUB_FILE_TYPE_CONFIG);
+ if (! file)
+ {
+ grub_free (suffix);
+ return grub_errno;
+ }
+
+ menu = grub_env_get_menu ();
+ if (! menu)
+ {
+ menu = grub_zalloc (sizeof (*menu));
+ if (! menu)
+ {
+ grub_free (suffix);
+ return grub_errno;
+ }
+
+ grub_env_set_menu (menu);
+ }
+
+ while (1)
+ {
+ char *buf = grub_file_getline (file);
+ char *parsed = NULL;
+
+ if (!buf && grub_errno)
+ {
+ grub_file_close (file);
+ grub_free (suffix);
+ return grub_errno;
+ }
+
+ if (!buf)
+ break;
+
+ {
+ char *oldname = NULL;
+ char *newsuffix;
+ char *ptr;
+
+ for (ptr = buf; *ptr && grub_isspace (*ptr); ptr++);
+
+ oldname = entryname;
+ parsed = grub_legacy_parse (ptr, &entryname, &newsuffix);
+ grub_free (buf);
+ buf = NULL;
+ if (newsuffix)
+ {
+ char *t;
+
+ t = suffix;
+ suffix = grub_realloc (suffix, grub_strlen (suffix)
+ + grub_strlen (newsuffix) + 1);
+ if (!suffix)
+ {
+ grub_free (t);
+ grub_free (entrysrc);
+ grub_free (parsed);
+ grub_free (newsuffix);
+ grub_free (suffix);
+ return grub_errno;
+ }
+ grub_memcpy (suffix + grub_strlen (suffix), newsuffix,
+ grub_strlen (newsuffix) + 1);
+ grub_free (newsuffix);
+ newsuffix = NULL;
+ }
+ if (oldname != entryname && oldname)
+ {
+ const char **args = grub_malloc (sizeof (args[0]));
+ if (!args)
+ {
+ grub_file_close (file);
+ return grub_errno;
+ }
+ args[0] = oldname;
+ grub_normal_add_menu_entry (1, args, NULL, NULL, "legacy",
+ NULL, NULL,
+ entrysrc, 0, NULL, NULL);
+ grub_free (args);
+ entrysrc[0] = 0;
+ grub_free (oldname);
+ }
+ }
+
+ if (parsed && !entryname)
+ {
+ grub_normal_parse_line (parsed, legacy_file_getline, NULL);
+ grub_print_error ();
+ grub_free (parsed);
+ parsed = NULL;
+ }
+ else if (parsed)
+ {
+ if (!entrysrc)
+ entrysrc = parsed;
+ else
+ {
+ char *t;
+
+ t = entrysrc;
+ entrysrc = grub_realloc (entrysrc, grub_strlen (entrysrc)
+ + grub_strlen (parsed) + 1);
+ if (!entrysrc)
+ {
+ grub_free (t);
+ grub_free (parsed);
+ grub_free (suffix);
+ return grub_errno;
+ }
+ grub_memcpy (entrysrc + grub_strlen (entrysrc), parsed,
+ grub_strlen (parsed) + 1);
+ grub_free (parsed);
+ parsed = NULL;
+ }
+ }
+ }
+ grub_file_close (file);
+
+ if (entryname)
+ {
+ const char **args = grub_malloc (sizeof (args[0]));
+ if (!args)
+ {
+ grub_file_close (file);
+ grub_free (suffix);
+ grub_free (entrysrc);
+ return grub_errno;
+ }
+ args[0] = entryname;
+ grub_normal_add_menu_entry (1, args, NULL, NULL, NULL,
+ NULL, NULL, entrysrc, 0, NULL,
+ NULL);
+ grub_free (args);
+ }
+
+ grub_normal_parse_line (suffix, legacy_file_getline, NULL);
+ grub_print_error ();
+ grub_free (suffix);
+ grub_free (entrysrc);
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_legacy_source (struct grub_command *cmd,
+ int argc, char **args)
+{
+ int new_env, extractor;
+ grub_err_t ret;
+
+ if (argc != 1)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ extractor = (cmd->name[0] == 'e');
+ new_env = (cmd->name[extractor ? (sizeof ("extract_legacy_entries_") - 1)
+ : (sizeof ("legacy_") - 1)] == 'c');
+
+ if (new_env)
+ grub_cls ();
+
+ if (new_env && !extractor)
+ grub_env_context_open ();
+ if (extractor)
+ grub_env_extractor_open (!new_env);
+
+ ret = legacy_file (args[0]);
+
+ if (new_env)
+ {
+ grub_menu_t menu;
+ menu = grub_env_get_menu ();
+ if (menu && menu->size)
+ grub_show_menu (menu, 1, 0);
+ if (!extractor)
+ grub_env_context_close ();
+ }
+ if (extractor)
+ grub_env_extractor_close (!new_env);
+
+ return ret;
+}
+
+static enum
+ {
+ GUESS_IT, LINUX, MULTIBOOT, KFREEBSD, KNETBSD, KOPENBSD
+ } kernel_type;
+
+static grub_err_t
+grub_cmd_legacy_kernel (struct grub_command *mycmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ int i;
+#ifdef TODO
+ int no_mem_option = 0;
+#endif
+ struct grub_command *cmd;
+ char **cutargs;
+ int cutargc;
+ grub_err_t err = GRUB_ERR_NONE;
+
+ for (i = 0; i < 2; i++)
+ {
+ /* FIXME: really support this. */
+ if (argc >= 1 && grub_strcmp (args[0], "--no-mem-option") == 0)
+ {
+#ifdef TODO
+ no_mem_option = 1;
+#endif
+ argc--;
+ args++;
+ continue;
+ }
+
+ /* linux16 handles both zImages and bzImages. */
+ if (argc >= 1 && (grub_strcmp (args[0], "--type=linux") == 0
+ || grub_strcmp (args[0], "--type=biglinux") == 0))
+ {
+ kernel_type = LINUX;
+ argc--;
+ args++;
+ continue;
+ }
+
+ if (argc >= 1 && grub_strcmp (args[0], "--type=multiboot") == 0)
+ {
+ kernel_type = MULTIBOOT;
+ argc--;
+ args++;
+ continue;
+ }
+
+ if (argc >= 1 && grub_strcmp (args[0], "--type=freebsd") == 0)
+ {
+ kernel_type = KFREEBSD;
+ argc--;
+ args++;
+ continue;
+ }
+
+ if (argc >= 1 && grub_strcmp (args[0], "--type=openbsd") == 0)
+ {
+ kernel_type = KOPENBSD;
+ argc--;
+ args++;
+ continue;
+ }
+
+ if (argc >= 1 && grub_strcmp (args[0], "--type=netbsd") == 0)
+ {
+ kernel_type = KNETBSD;
+ argc--;
+ args++;
+ continue;
+ }
+ }
+
+ if (argc < 2)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+
+ cutargs = grub_malloc (sizeof (cutargs[0]) * (argc - 1));
+ if (!cutargs)
+ return grub_errno;
+ cutargc = argc - 1;
+ grub_memcpy (cutargs + 1, args + 2, sizeof (cutargs[0]) * (argc - 2));
+ cutargs[0] = args[0];
+
+ do
+ {
+ /* First try Linux. */
+ if (kernel_type == GUESS_IT || kernel_type == LINUX)
+ {
+#ifdef GRUB_MACHINE_PCBIOS
+ cmd = grub_command_find ("linux16");
+#else
+ cmd = grub_command_find ("linux");
+#endif
+ if (cmd)
+ {
+ if (!(cmd->func) (cmd, cutargc, cutargs))
+ {
+ kernel_type = LINUX;
+ goto out;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ /* Then multiboot. */
+ if (kernel_type == GUESS_IT || kernel_type == MULTIBOOT)
+ {
+ cmd = grub_command_find ("multiboot");
+ if (cmd)
+ {
+ if (!(cmd->func) (cmd, argc, args))
+ {
+ kernel_type = MULTIBOOT;
+ goto out;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ {
+ int bsd_device = -1;
+ int bsd_slice = -1;
+ int bsd_part = -1;
+ {
+ grub_device_t dev;
+ const char *hdbiasstr;
+ int hdbias = 0;
+ hdbiasstr = grub_env_get ("legacy_hdbias");
+ if (hdbiasstr)
+ {
+ hdbias = grub_strtoul (hdbiasstr, 0, 0);
+ grub_errno = GRUB_ERR_NONE;
+ }
+ dev = grub_device_open (0);
+ if (dev && dev->disk
+ && dev->disk->dev->id == GRUB_DISK_DEVICE_BIOSDISK_ID
+ && dev->disk->id >= 0x80 && dev->disk->id <= 0x90)
+ {
+ struct grub_partition *part = dev->disk->partition;
+ bsd_device = dev->disk->id - 0x80 - hdbias;
+ if (part && (grub_strcmp (part->partmap->name, "netbsd") == 0
+ || grub_strcmp (part->partmap->name, "openbsd") == 0
+ || grub_strcmp (part->partmap->name, "bsd") == 0))
+ {
+ bsd_part = part->number;
+ part = part->parent;
+ }
+ if (part && grub_strcmp (part->partmap->name, "msdos") == 0)
+ bsd_slice = part->number;
+ }
+ if (dev)
+ grub_device_close (dev);
+ }
+
+ /* k*BSD didn't really work well with grub-legacy. */
+ if (kernel_type == GUESS_IT || kernel_type == KFREEBSD)
+ {
+ char buf[sizeof("adXXXXXXXXXXXXsXXXXXXXXXXXXYYY")];
+ if (bsd_device != -1)
+ {
+ if (bsd_slice != -1 && bsd_part != -1)
+ grub_snprintf(buf, sizeof(buf), "ad%ds%d%c", bsd_device,
+ bsd_slice, 'a' + bsd_part);
+ else if (bsd_slice != -1)
+ grub_snprintf(buf, sizeof(buf), "ad%ds%d", bsd_device,
+ bsd_slice);
+ else
+ grub_snprintf(buf, sizeof(buf), "ad%d", bsd_device);
+ grub_env_set ("kFreeBSD.vfs.root.mountfrom", buf);
+ }
+ else
+ grub_env_unset ("kFreeBSD.vfs.root.mountfrom");
+ cmd = grub_command_find ("kfreebsd");
+ if (cmd)
+ {
+ if (!(cmd->func) (cmd, cutargc, cutargs))
+ {
+ kernel_type = KFREEBSD;
+ goto out;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+ {
+ char **bsdargs;
+ int bsdargc;
+ char bsddevname[sizeof ("wdXXXXXXXXXXXXY")];
+ int found = 0;
+
+ if (bsd_device == -1)
+ {
+ bsdargs = cutargs;
+ bsdargc = cutargc;
+ }
+ else
+ {
+ char rbuf[3] = "-r";
+ bsdargc = cutargc + 2;
+ bsdargs = grub_malloc (sizeof (bsdargs[0]) * bsdargc);
+ if (!bsdargs)
+ {
+ err = grub_errno;
+ goto out;
+ }
+ grub_memcpy (bsdargs, args, argc * sizeof (bsdargs[0]));
+ bsdargs[argc] = rbuf;
+ bsdargs[argc + 1] = bsddevname;
+ grub_snprintf (bsddevname, sizeof (bsddevname),
+ "wd%d%c", bsd_device,
+ bsd_part != -1 ? bsd_part + 'a' : 'c');
+ }
+ if (kernel_type == GUESS_IT || kernel_type == KNETBSD)
+ {
+ cmd = grub_command_find ("knetbsd");
+ if (cmd)
+ {
+ if (!(cmd->func) (cmd, bsdargc, bsdargs))
+ {
+ kernel_type = KNETBSD;
+ found = 1;
+ goto free_bsdargs;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+ if (kernel_type == GUESS_IT || kernel_type == KOPENBSD)
+ {
+ cmd = grub_command_find ("kopenbsd");
+ if (cmd)
+ {
+ if (!(cmd->func) (cmd, bsdargc, bsdargs))
+ {
+ kernel_type = KOPENBSD;
+ found = 1;
+ goto free_bsdargs;
+ }
+ }
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+free_bsdargs:
+ if (bsdargs != cutargs)
+ grub_free (bsdargs);
+ if (found)
+ goto out;
+ }
+ }
+ }
+ while (0);
+
+ err = grub_error (GRUB_ERR_BAD_OS, "couldn't load file %s",
+ args[0]);
+out:
+ grub_free (cutargs);
+ return err;
+}
+
+static grub_err_t
+grub_cmd_legacy_initrd (struct grub_command *mycmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ struct grub_command *cmd;
+
+ if (kernel_type == LINUX)
+ {
+#ifdef GRUB_MACHINE_PCBIOS
+ cmd = grub_command_find ("initrd16");
+#else
+ cmd = grub_command_find ("initrd");
+#endif
+ if (!cmd)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
+#ifdef GRUB_MACHINE_PCBIOS
+ "initrd16"
+#else
+ "initrd"
+#endif
+ );
+
+ return cmd->func (cmd, argc ? 1 : 0, args);
+ }
+ if (kernel_type == MULTIBOOT)
+ {
+ cmd = grub_command_find ("module");
+ if (!cmd)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
+ "module");
+
+ return cmd->func (cmd, argc, args);
+ }
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("you need to load the kernel first"));
+}
+
+static grub_err_t
+grub_cmd_legacy_initrdnounzip (struct grub_command *mycmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ struct grub_command *cmd;
+
+ if (kernel_type == LINUX)
+ {
+ cmd = grub_command_find ("initrd16");
+ if (!cmd)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
+ "initrd16");
+
+ return cmd->func (cmd, argc, args);
+ }
+ if (kernel_type == MULTIBOOT)
+ {
+ char **newargs;
+ grub_err_t err;
+ char nounzipbuf[10] = "--nounzip";
+
+ cmd = grub_command_find ("module");
+ if (!cmd)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("can't find command `%s'"),
+ "module");
+
+ newargs = grub_malloc ((argc + 1) * sizeof (newargs[0]));
+ if (!newargs)
+ return grub_errno;
+ grub_memcpy (newargs + 1, args, argc * sizeof (newargs[0]));
+ newargs[0] = nounzipbuf;
+
+ err = cmd->func (cmd, argc + 1, newargs);
+ grub_free (newargs);
+ return err;
+ }
+
+ return grub_error (GRUB_ERR_BAD_ARGUMENT,
+ N_("you need to load the kernel first"));
+}
+
+static grub_err_t
+check_password_deny (const char *user __attribute__ ((unused)),
+ const char *entered __attribute__ ((unused)),
+ void *password __attribute__ ((unused)))
+{
+ return GRUB_ACCESS_DENIED;
+}
+
+#define MD5_HASHLEN 16
+
+struct legacy_md5_password
+{
+ grub_uint8_t *salt;
+ int saltlen;
+ grub_uint8_t hash[MD5_HASHLEN];
+};
+
+static int
+check_password_md5_real (const char *entered,
+ struct legacy_md5_password *pw)
+{
+ grub_size_t enteredlen = grub_strlen (entered);
+ unsigned char alt_result[MD5_HASHLEN];
+ unsigned char *digest;
+ grub_uint8_t *ctx;
+ grub_size_t i;
+ int ret;
+
+ ctx = grub_zalloc (GRUB_MD_MD5->contextsize);
+ if (!ctx)
+ return 0;
+
+ GRUB_MD_MD5->init (ctx);
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+ GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3);
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+ digest = GRUB_MD_MD5->read (ctx);
+ GRUB_MD_MD5->final (ctx);
+ grub_memcpy (alt_result, digest, MD5_HASHLEN);
+
+ GRUB_MD_MD5->init (ctx);
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+ GRUB_MD_MD5->write (ctx, pw->salt, pw->saltlen); /* include the $1$ header */
+ for (i = enteredlen; i > 16; i -= 16)
+ GRUB_MD_MD5->write (ctx, alt_result, 16);
+ GRUB_MD_MD5->write (ctx, alt_result, i);
+
+ for (i = enteredlen; i > 0; i >>= 1)
+ GRUB_MD_MD5->write (ctx, entered + ((i & 1) ? enteredlen : 0), 1);
+ digest = GRUB_MD_MD5->read (ctx);
+ GRUB_MD_MD5->final (ctx);
+
+ for (i = 0; i < 1000; i++)
+ {
+ grub_memcpy (alt_result, digest, 16);
+
+ GRUB_MD_MD5->init (ctx);
+ if ((i & 1) != 0)
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+ else
+ GRUB_MD_MD5->write (ctx, alt_result, 16);
+
+ if (i % 3 != 0)
+ GRUB_MD_MD5->write (ctx, pw->salt + 3, pw->saltlen - 3);
+
+ if (i % 7 != 0)
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+
+ if ((i & 1) != 0)
+ GRUB_MD_MD5->write (ctx, alt_result, 16);
+ else
+ GRUB_MD_MD5->write (ctx, entered, enteredlen);
+ digest = GRUB_MD_MD5->read (ctx);
+ GRUB_MD_MD5->final (ctx);
+ }
+
+ ret = (grub_crypto_memcmp (digest, pw->hash, MD5_HASHLEN) == 0);
+ grub_free (ctx);
+ return ret;
+}
+
+static grub_err_t
+check_password_md5 (const char *user,
+ const char *entered,
+ void *password)
+{
+ if (!check_password_md5_real (entered, password))
+ return GRUB_ACCESS_DENIED;
+
+ grub_auth_authenticate (user);
+
+ return GRUB_ERR_NONE;
+}
+
+static inline int
+ib64t (char c)
+{
+ if (c == '.')
+ return 0;
+ if (c == '/')
+ return 1;
+ if (c >= '0' && c <= '9')
+ return c - '0' + 2;
+ if (c >= 'A' && c <= 'Z')
+ return c - 'A' + 12;
+ if (c >= 'a' && c <= 'z')
+ return c - 'a' + 38;
+ return -1;
+}
+
+static struct legacy_md5_password *
+parse_legacy_md5 (int argc, char **args)
+{
+ const char *salt, *saltend;
+ struct legacy_md5_password *pw = NULL;
+ int i;
+ const char *p;
+
+ if (grub_memcmp (args[0], "--md5", sizeof ("--md5")) != 0)
+ goto fail;
+ if (argc == 1)
+ goto fail;
+ if (grub_strlen(args[1]) <= 3)
+ goto fail;
+ salt = args[1];
+ saltend = grub_strchr (salt + 3, '$');
+ if (!saltend)
+ goto fail;
+ pw = grub_malloc (sizeof (*pw));
+ if (!pw)
+ goto fail;
+
+ p = saltend + 1;
+ for (i = 0; i < 5; i++)
+ {
+ int n;
+ grub_uint32_t w = 0;
+
+ for (n = 0; n < 4; n++)
+ {
+ int ww = ib64t(*p++);
+ if (ww == -1)
+ goto fail;
+ w |= ww << (n * 6);
+ }
+ pw->hash[i == 4 ? 5 : 12+i] = w & 0xff;
+ pw->hash[6+i] = (w >> 8) & 0xff;
+ pw->hash[i] = (w >> 16) & 0xff;
+ }
+ {
+ int n;
+ grub_uint32_t w = 0;
+ for (n = 0; n < 2; n++)
+ {
+ int ww = ib64t(*p++);
+ if (ww == -1)
+ goto fail;
+ w |= ww << (6 * n);
+ }
+ if (w >= 0x100)
+ goto fail;
+ pw->hash[11] = w;
+ }
+
+ pw->saltlen = saltend - salt;
+ pw->salt = (grub_uint8_t *) grub_strndup (salt, pw->saltlen);
+ if (!pw->salt)
+ goto fail;
+
+ return pw;
+
+ fail:
+ grub_free (pw);
+ return NULL;
+}
+
+static grub_err_t
+grub_cmd_legacy_password (struct grub_command *mycmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ struct legacy_md5_password *pw = NULL;
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ if (args[0][0] != '-' || args[0][1] != '-')
+ return grub_normal_set_password ("legacy", args[0]);
+
+ pw = parse_legacy_md5 (argc, args);
+
+ if (pw)
+ return grub_auth_register_authentication ("legacy", check_password_md5, pw);
+ else
+ /* This is to imitate minor difference between grub-legacy in GRUB2.
+ If 2 password commands are executed in a row and second one fails
+ on GRUB2 the password of first one is used, whereas in grub-legacy
+ authenthication is denied. In case of no password command was executed
+ early both versions deny any access. */
+ return grub_auth_register_authentication ("legacy", check_password_deny,
+ NULL);
+}
+
+int
+grub_legacy_check_md5_password (int argc, char **args,
+ char *entered)
+{
+ struct legacy_md5_password *pw = NULL;
+ int ret;
+
+ if (args[0][0] != '-' || args[0][1] != '-')
+ {
+ char correct[GRUB_AUTH_MAX_PASSLEN];
+
+ grub_memset (correct, 0, sizeof (correct));
+ grub_strncpy (correct, args[0], sizeof (correct));
+
+ return grub_crypto_memcmp (entered, correct, GRUB_AUTH_MAX_PASSLEN) == 0;
+ }
+
+ pw = parse_legacy_md5 (argc, args);
+
+ if (!pw)
+ return 0;
+
+ ret = check_password_md5_real (entered, pw);
+ grub_free (pw);
+ return ret;
+}
+
+static grub_err_t
+grub_cmd_legacy_check_password (struct grub_command *mycmd __attribute__ ((unused)),
+ int argc, char **args)
+{
+ char entered[GRUB_AUTH_MAX_PASSLEN];
+
+ if (argc == 0)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, N_("one argument expected"));
+ grub_puts_ (N_("Enter password: "));
+ if (!grub_password_get (entered, GRUB_AUTH_MAX_PASSLEN))
+ return GRUB_ACCESS_DENIED;
+
+ if (!grub_legacy_check_md5_password (argc, args,
+ entered))
+ return GRUB_ACCESS_DENIED;
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_command_t cmd_source, cmd_configfile;
+static grub_command_t cmd_source_extract, cmd_configfile_extract;
+static grub_command_t cmd_kernel, cmd_initrd, cmd_initrdnounzip;
+static grub_command_t cmd_password, cmd_check_password;
+
+GRUB_MOD_INIT(legacycfg)
+{
+ cmd_source
+ = grub_register_command ("legacy_source",
+ grub_cmd_legacy_source,
+ N_("FILE"),
+ /* TRANSLATORS: "legacy config" means
+ "config as used by grub-legacy". */
+ N_("Parse legacy config in same context"));
+ cmd_configfile
+ = grub_register_command ("legacy_configfile",
+ grub_cmd_legacy_source,
+ N_("FILE"),
+ N_("Parse legacy config in new context"));
+ cmd_source_extract
+ = grub_register_command ("extract_legacy_entries_source",
+ grub_cmd_legacy_source,
+ N_("FILE"),
+ N_("Parse legacy config in same context taking only menu entries"));
+ cmd_configfile_extract
+ = grub_register_command ("extract_legacy_entries_configfile",
+ grub_cmd_legacy_source,
+ N_("FILE"),
+ N_("Parse legacy config in new context taking only menu entries"));
+
+ cmd_kernel = grub_register_command ("legacy_kernel",
+ grub_cmd_legacy_kernel,
+ N_("[--no-mem-option] [--type=TYPE] FILE [ARG ...]"),
+ N_("Simulate grub-legacy `kernel' command"));
+
+ cmd_initrd = grub_register_command ("legacy_initrd",
+ grub_cmd_legacy_initrd,
+ N_("FILE [ARG ...]"),
+ N_("Simulate grub-legacy `initrd' command"));
+ cmd_initrdnounzip = grub_register_command ("legacy_initrd_nounzip",
+ grub_cmd_legacy_initrdnounzip,
+ N_("FILE [ARG ...]"),
+ N_("Simulate grub-legacy `modulenounzip' command"));
+
+ cmd_password = grub_register_command ("legacy_password",
+ grub_cmd_legacy_password,
+ N_("[--md5] PASSWD [FILE]"),
+ N_("Simulate grub-legacy `password' command"));
+
+ cmd_check_password = grub_register_command ("legacy_check_password",
+ grub_cmd_legacy_check_password,
+ N_("[--md5] PASSWD [FILE]"),
+ N_("Simulate grub-legacy `password' command in menu entry mode"));
+
+}
+
+GRUB_MOD_FINI(legacycfg)
+{
+ grub_unregister_command (cmd_source);
+ grub_unregister_command (cmd_configfile);
+ grub_unregister_command (cmd_source_extract);
+ grub_unregister_command (cmd_configfile_extract);
+
+ grub_unregister_command (cmd_kernel);
+ grub_unregister_command (cmd_initrd);
+ grub_unregister_command (cmd_initrdnounzip);
+
+ grub_unregister_command (cmd_password);
+ grub_unregister_command (cmd_check_password);
+}
--- /dev/null
+/* loadenv.c - command to load/save environment variable. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008,2009,2010 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/dl.h>
+#include <grub/mm.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/misc.h>
+#include <grub/env.h>
+#include <grub/partition.h>
+#include <grub/lib/envblk.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+
+#include "loadenv.h"
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+static const struct grub_arg_option options[] =
+ {
+ /* TRANSLATORS: This option is used to override default filename
+ for loading and storing environment. */
+ {"file", 'f', 0, N_("Specify filename."), 0, ARG_TYPE_PATHNAME},
+ {"skip-sig", 's', 0,
+ N_("Skip signature-checking of the environment file."), 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+/* Opens 'filename' with compression filters disabled. Optionally disables the
+ PUBKEY filter (that insists upon properly signed files) as well. PUBKEY
+ filter is restored before the function returns. */
+static grub_file_t
+open_envblk_file (char *filename,
+ enum grub_file_type type)
+{
+ grub_file_t file;
+ char *buf = 0;
+
+ if (! filename)
+ {
+ const char *prefix;
+ int len;
+
+ prefix = grub_env_get ("prefix");
+ if (! prefix)
+ {
+ grub_error (GRUB_ERR_FILE_NOT_FOUND, N_("variable `%s' isn't set"), "prefix");
+ return 0;
+ }
+
+ len = grub_strlen (prefix);
+ buf = grub_malloc (len + 1 + sizeof (GRUB_ENVBLK_DEFCFG));
+ if (! buf)
+ return 0;
+ filename = buf;
+
+ grub_strcpy (filename, prefix);
+ filename[len] = '/';
+ grub_strcpy (filename + len + 1, GRUB_ENVBLK_DEFCFG);
+ }
+
+ file = grub_file_open (filename, type);
+
+ grub_free (buf);
+ return file;
+}
+
+static grub_err_t
+grub_cmd_load_env (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_file_t file;
+ grub_envblk_t envblk;
+ grub_env_whitelist_t whitelist;
+
+ whitelist.len = argc;
+ whitelist.list = args;
+
+ /* state[0] is the -f flag; state[1] is the --skip-sig flag */
+ file = open_envblk_file ((state[0].set) ? state[0].arg : 0,
+ GRUB_FILE_TYPE_LOADENV
+ | (state[1].set
+ ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE));
+ if (! file)
+ return grub_errno;
+
+ envblk = read_envblk_file (file);
+ if (! envblk)
+ goto fail;
+
+ /* argc > 0 indicates caller provided a whitelist of variables to read. */
+ grub_envblk_iterate (envblk, argc > 0 ? &whitelist : 0, set_var);
+ grub_envblk_close (envblk);
+
+ fail:
+ grub_file_close (file);
+ return grub_errno;
+}
+
+/* Print all variables in current context. */
+static int
+print_var (const char *name, const char *value,
+ void *hook_data __attribute__ ((unused)))
+{
+ grub_printf ("%s=%s\n", name, value);
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_list_env (grub_extcmd_context_t ctxt,
+ int argc __attribute__ ((unused)),
+ char **args __attribute__ ((unused)))
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_file_t file;
+ grub_envblk_t envblk;
+
+ file = open_envblk_file ((state[0].set) ? state[0].arg : 0,
+ GRUB_FILE_TYPE_LOADENV
+ | (state[1].set
+ ? GRUB_FILE_TYPE_SKIP_SIGNATURE : GRUB_FILE_TYPE_NONE));
+ if (! file)
+ return grub_errno;
+
+ envblk = read_envblk_file (file);
+ if (! envblk)
+ goto fail;
+
+ grub_envblk_iterate (envblk, NULL, print_var);
+ grub_envblk_close (envblk);
+
+ fail:
+ grub_file_close (file);
+ return grub_errno;
+}
+
+/* Used to maintain a variable length of blocklists internally. */
+struct blocklist
+{
+ grub_disk_addr_t sector;
+ unsigned offset;
+ unsigned length;
+ struct blocklist *next;
+};
+
+static void
+free_blocklists (struct blocklist *p)
+{
+ struct blocklist *q;
+
+ for (; p; p = q)
+ {
+ q = p->next;
+ grub_free (p);
+ }
+}
+
+static grub_err_t
+check_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
+ grub_file_t file)
+{
+ grub_size_t total_length;
+ grub_size_t index;
+ grub_disk_t disk;
+ grub_disk_addr_t part_start;
+ struct blocklist *p;
+ char *buf;
+
+ /* Sanity checks. */
+ total_length = 0;
+ for (p = blocklists; p; p = p->next)
+ {
+ struct blocklist *q;
+ /* Check if any pair of blocks overlap. */
+ for (q = p->next; q; q = q->next)
+ {
+ grub_disk_addr_t s1, s2;
+ grub_disk_addr_t e1, e2;
+
+ s1 = p->sector;
+ e1 = s1 + ((p->length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
+
+ s2 = q->sector;
+ e2 = s2 + ((q->length + GRUB_DISK_SECTOR_SIZE - 1) >> GRUB_DISK_SECTOR_BITS);
+
+ if (s1 < e2 && s2 < e1)
+ {
+ /* This might be actually valid, but it is unbelievable that
+ any filesystem makes such a silly allocation. */
+ return grub_error (GRUB_ERR_BAD_FS, "malformed file");
+ }
+ }
+
+ total_length += p->length;
+ }
+
+ if (total_length != grub_file_size (file))
+ {
+ /* Maybe sparse, unallocated sectors. No way in GRUB. */
+ return grub_error (GRUB_ERR_BAD_FILE_TYPE, "sparse file not allowed");
+ }
+
+ /* One more sanity check. Re-read all sectors by blocklists, and compare
+ those with the data read via a file. */
+ disk = file->device->disk;
+
+ part_start = grub_partition_get_start (disk->partition);
+
+ buf = grub_envblk_buffer (envblk);
+ char *blockbuf = NULL;
+ grub_size_t blockbuf_len = 0;
+ for (p = blocklists, index = 0; p; index += p->length, p = p->next)
+ {
+ if (p->length > blockbuf_len)
+ {
+ grub_free (blockbuf);
+ blockbuf_len = 2 * p->length;
+ blockbuf = grub_malloc (blockbuf_len);
+ if (!blockbuf)
+ return grub_errno;
+ }
+
+ if (grub_disk_read (disk, p->sector - part_start,
+ p->offset, p->length, blockbuf))
+ return grub_errno;
+
+ if (grub_memcmp (buf + index, blockbuf, p->length) != 0)
+ return grub_error (GRUB_ERR_FILE_READ_ERROR, "invalid blocklist");
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static int
+write_blocklists (grub_envblk_t envblk, struct blocklist *blocklists,
+ grub_file_t file)
+{
+ char *buf;
+ grub_disk_t disk;
+ grub_disk_addr_t part_start;
+ struct blocklist *p;
+ grub_size_t index;
+
+ buf = grub_envblk_buffer (envblk);
+ disk = file->device->disk;
+ part_start = grub_partition_get_start (disk->partition);
+
+ index = 0;
+ for (p = blocklists; p; index += p->length, p = p->next)
+ {
+ if (grub_disk_write (disk, p->sector - part_start,
+ p->offset, p->length, buf + index))
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Context for grub_cmd_save_env. */
+struct grub_cmd_save_env_ctx
+{
+ struct blocklist *head, *tail;
+};
+
+/* Store blocklists in a linked list. */
+static void
+save_env_read_hook (grub_disk_addr_t sector, unsigned offset, unsigned length,
+ void *data)
+{
+ struct grub_cmd_save_env_ctx *ctx = data;
+ struct blocklist *block;
+
+ block = grub_malloc (sizeof (*block));
+ if (! block)
+ return;
+
+ block->sector = sector;
+ block->offset = offset;
+ block->length = length;
+
+ /* Slightly complicated, because the list should be FIFO. */
+ block->next = 0;
+ if (ctx->tail)
+ ctx->tail->next = block;
+ ctx->tail = block;
+ if (! ctx->head)
+ ctx->head = block;
+}
+
+static grub_err_t
+grub_cmd_save_env (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ struct grub_arg_list *state = ctxt->state;
+ grub_file_t file;
+ grub_envblk_t envblk;
+ struct grub_cmd_save_env_ctx ctx = {
+ .head = 0,
+ .tail = 0
+ };
+
+ if (! argc)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no variable is specified");
+
+ file = open_envblk_file ((state[0].set) ? state[0].arg : 0,
+ GRUB_FILE_TYPE_SAVEENV
+ | GRUB_FILE_TYPE_SKIP_SIGNATURE);
+ if (! file)
+ return grub_errno;
+
+ if (! file->device->disk)
+ {
+ grub_file_close (file);
+ return grub_error (GRUB_ERR_BAD_DEVICE, "disk device required");
+ }
+
+ file->read_hook = save_env_read_hook;
+ file->read_hook_data = &ctx;
+ envblk = read_envblk_file (file);
+ file->read_hook = 0;
+ if (! envblk)
+ goto fail;
+
+ if (check_blocklists (envblk, ctx.head, file))
+ goto fail;
+
+ while (argc)
+ {
+ const char *value;
+
+ value = grub_env_get (args[0]);
+ if (value)
+ {
+ if (! grub_envblk_set (envblk, args[0], value))
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, "environment block too small");
+ goto fail;
+ }
+ }
+ else
+ grub_envblk_delete (envblk, args[0]);
+
+ argc--;
+ args++;
+ }
+
+ write_blocklists (envblk, ctx.head, file);
+
+ fail:
+ if (envblk)
+ grub_envblk_close (envblk);
+ free_blocklists (ctx.head);
+ grub_file_close (file);
+ return grub_errno;
+}
+
+static grub_extcmd_t cmd_load, cmd_list, cmd_save;
+
+GRUB_MOD_INIT(loadenv)
+{
+ cmd_load =
+ grub_register_extcmd ("load_env", grub_cmd_load_env, 0,
+ N_("[-f FILE] [-s|--skip-sig] [variable_name_to_whitelist] [...]"),
+ N_("Load variables from environment block file."),
+ options);
+ cmd_list =
+ grub_register_extcmd ("list_env", grub_cmd_list_env, 0, N_("[-f FILE]"),
+ N_("List variables from environment block file."),
+ options);
+ cmd_save =
+ grub_register_extcmd ("save_env", grub_cmd_save_env, 0,
+ N_("[-f FILE] variable_name [...]"),
+ N_("Save variables to environment block file."),
+ options);
+}
+
+GRUB_MOD_FINI(loadenv)
+{
+ grub_unregister_extcmd (cmd_load);
+ grub_unregister_extcmd (cmd_list);
+ grub_unregister_extcmd (cmd_save);
+}
--- /dev/null
+/* loadenv.c - command to load/save environment variable. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2008,2009,2010 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/>.
+ */
+
+static grub_envblk_t UNUSED
+read_envblk_file (grub_file_t file)
+{
+ grub_off_t offset = 0;
+ char *buf;
+ grub_size_t size = grub_file_size (file);
+ grub_envblk_t envblk;
+
+ buf = grub_malloc (size);
+ if (! buf)
+ return 0;
+
+ while (size > 0)
+ {
+ grub_ssize_t ret;
+
+ ret = grub_file_read (file, buf + offset, size);
+ if (ret <= 0)
+ {
+ grub_free (buf);
+ return 0;
+ }
+
+ size -= ret;
+ offset += ret;
+ }
+
+ envblk = grub_envblk_open (buf, offset);
+ if (! envblk)
+ {
+ grub_free (buf);
+ grub_error (GRUB_ERR_BAD_FILE_TYPE, "invalid environment block");
+ return 0;
+ }
+
+ return envblk;
+}
+
+struct grub_env_whitelist
+{
+ grub_size_t len;
+ char **list;
+};
+typedef struct grub_env_whitelist grub_env_whitelist_t;
+
+static int UNUSED
+test_whitelist_membership (const char* name,
+ const grub_env_whitelist_t* whitelist)
+{
+ grub_size_t i;
+
+ for (i = 0; i < whitelist->len; i++)
+ if (grub_strcmp (name, whitelist->list[i]) == 0)
+ return 1; /* found it */
+
+ return 0; /* not found */
+}
+
+/* Helper for grub_cmd_load_env. */
+static int UNUSED
+set_var (const char *name, const char *value, void *whitelist)
+{
+ if (! whitelist)
+ {
+ grub_env_set (name, value);
+ return 0;
+ }
+
+ if (test_whitelist_membership (name,
+ (const grub_env_whitelist_t *) whitelist))
+ grub_env_set (name, value);
+
+ return 0;
+}
--- /dev/null
+/* menuentry.c - menuentry command */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2010 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/misc.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/extcmd.h>
+#include <grub/i18n.h>
+#include <grub/normal.h>
+
+static const struct grub_arg_option options[] =
+ {
+ {"class", 1, GRUB_ARG_OPTION_REPEATABLE,
+ N_("Menu entry type."), N_("STRING"), ARG_TYPE_STRING},
+ {"users", 2, 0,
+ N_("List of users allowed to boot this entry."), N_("USERNAME[,USERNAME]"),
+ ARG_TYPE_STRING},
+ {"hotkey", 3, 0,
+ N_("Keyboard key to quickly boot this entry."), N_("KEYBOARD_KEY"), ARG_TYPE_STRING},
+ {"source", 4, 0,
+ N_("Use STRING as menu entry body."), N_("STRING"), ARG_TYPE_STRING},
+ {"id", 0, 0, N_("Menu entry identifier."), N_("STRING"), ARG_TYPE_STRING},
+ /* TRANSLATORS: menu entry can either be bootable by anyone or only by
+ handful of users. By default when security is active only superusers can
+ boot a given menu entry. With --unrestricted (this option)
+ anyone can boot it. */
+ {"unrestricted", 0, 0, N_("This entry can be booted by any user."),
+ 0, ARG_TYPE_NONE},
+ {0, 0, 0, 0, 0, 0}
+ };
+
+static struct
+{
+ const char *name;
+ int key;
+} hotkey_aliases[] =
+ {
+ {"backspace", GRUB_TERM_BACKSPACE},
+ {"tab", GRUB_TERM_TAB},
+ {"delete", GRUB_TERM_KEY_DC},
+ {"insert", GRUB_TERM_KEY_INSERT},
+ {"f1", GRUB_TERM_KEY_F1},
+ {"f2", GRUB_TERM_KEY_F2},
+ {"f3", GRUB_TERM_KEY_F3},
+ {"f4", GRUB_TERM_KEY_F4},
+ {"f5", GRUB_TERM_KEY_F5},
+ {"f6", GRUB_TERM_KEY_F6},
+ {"f7", GRUB_TERM_KEY_F7},
+ {"f8", GRUB_TERM_KEY_F8},
+ {"f9", GRUB_TERM_KEY_F9},
+ {"f10", GRUB_TERM_KEY_F10},
+ {"f11", GRUB_TERM_KEY_F11},
+ {"f12", GRUB_TERM_KEY_F12},
+ };
+
+/* Add a menu entry to the current menu context (as given by the environment
+ variable data slot `menu'). As the configuration file is read, the script
+ parser calls this when a menu entry is to be created. */
+grub_err_t
+grub_normal_add_menu_entry (int argc, const char **args,
+ char **classes, const char *id,
+ const char *users, const char *hotkey,
+ const char *prefix, const char *sourcecode,
+ int submenu, int *index, struct bls_entry *bls)
+{
+ int menu_hotkey = 0;
+ char **menu_args = NULL;
+ char *menu_users = NULL;
+ char *menu_title = NULL;
+ char *menu_sourcecode = NULL;
+ char *menu_id = NULL;
+ struct grub_menu_entry_class *menu_classes = NULL;
+
+ grub_menu_t menu;
+ grub_menu_entry_t *last;
+
+ menu = grub_env_get_menu ();
+ if (! menu)
+ return grub_error (GRUB_ERR_MENU, "no menu context");
+
+ last = &menu->entry_list;
+
+ menu_sourcecode = grub_xasprintf ("%s%s", prefix ?: "", sourcecode);
+ if (! menu_sourcecode)
+ return grub_errno;
+
+ if (classes && classes[0])
+ {
+ int i;
+ for (i = 0; classes[i]; i++); /* count # of menuentry classes */
+ menu_classes = grub_zalloc (sizeof (struct grub_menu_entry_class)
+ * (i + 1));
+ if (! menu_classes)
+ goto fail;
+
+ for (i = 0; classes[i]; i++)
+ {
+ menu_classes[i].name = grub_strdup (classes[i]);
+ if (! menu_classes[i].name)
+ goto fail;
+ menu_classes[i].next = classes[i + 1] ? &menu_classes[i + 1] : NULL;
+ }
+ }
+
+ if (users)
+ {
+ menu_users = grub_strdup (users);
+ if (! menu_users)
+ goto fail;
+ }
+
+ if (hotkey)
+ {
+ unsigned i;
+ for (i = 0; i < ARRAY_SIZE (hotkey_aliases); i++)
+ if (grub_strcmp (hotkey, hotkey_aliases[i].name) == 0)
+ {
+ menu_hotkey = hotkey_aliases[i].key;
+ break;
+ }
+ if (i == ARRAY_SIZE (hotkey_aliases))
+ menu_hotkey = hotkey[0];
+ }
+
+ if (! argc)
+ {
+ grub_error (GRUB_ERR_MENU, "menuentry is missing title");
+ goto fail;
+ }
+
+ menu_title = grub_strdup (args[0]);
+ if (! menu_title)
+ goto fail;
+
+ grub_dprintf ("menu", "id:\"%s\"\n", id);
+ grub_dprintf ("menu", "title:\"%s\"\n", menu_title);
+ menu_id = grub_strdup (id ? : menu_title);
+ if (! menu_id)
+ goto fail;
+ grub_dprintf ("menu", "menu_id:\"%s\"\n", menu_id);
+
+ /* Save argc, args to pass as parameters to block arg later. */
+ menu_args = grub_malloc (sizeof (char*) * (argc + 1));
+ if (! menu_args)
+ goto fail;
+
+ {
+ int i;
+ for (i = 0; i < argc; i++)
+ {
+ menu_args[i] = grub_strdup (args[i]);
+ if (! menu_args[i])
+ goto fail;
+ }
+ menu_args[argc] = NULL;
+ }
+
+ /* Add the menu entry at the end of the list. */
+ int ind=0;
+ while (*last)
+ {
+ ind++;
+ last = &(*last)->next;
+ }
+
+ *last = grub_zalloc (sizeof (**last));
+ if (! *last)
+ goto fail;
+
+ (*last)->title = menu_title;
+ (*last)->id = menu_id;
+ (*last)->hotkey = menu_hotkey;
+ (*last)->classes = menu_classes;
+ if (menu_users)
+ (*last)->restricted = 1;
+ (*last)->users = menu_users;
+ (*last)->argc = argc;
+ (*last)->args = menu_args;
+ (*last)->sourcecode = menu_sourcecode;
+ (*last)->submenu = submenu;
+ (*last)->bls = bls;
+
+ menu->size++;
+ if (index)
+ *index = ind;
+ return GRUB_ERR_NONE;
+
+ fail:
+
+ grub_free (menu_sourcecode);
+ {
+ int i;
+ for (i = 0; menu_classes && menu_classes[i].name; i++)
+ grub_free (menu_classes[i].name);
+ grub_free (menu_classes);
+ }
+
+ {
+ int i;
+ for (i = 0; menu_args && menu_args[i]; i++)
+ grub_free (menu_args[i]);
+ grub_free (menu_args);
+ }
+
+ grub_free (menu_users);
+ grub_free (menu_title);
+ grub_free (menu_id);
+ return grub_errno;
+}
+
+static char *
+setparams_prefix (int argc, char **args)
+{
+ int i;
+ int j;
+ char *p;
+ char *result;
+ grub_size_t len = 10;
+
+ /* Count resulting string length */
+ for (i = 0; i < argc; i++)
+ {
+ len += 3; /* 3 = 1 space + 2 quotes */
+ p = args[i];
+ while (*p)
+ len += (*p++ == '\'' ? 3 : 1);
+ }
+
+ result = grub_malloc (len + 2);
+ if (! result)
+ return 0;
+
+ grub_strcpy (result, "setparams");
+ p = result + 9;
+
+ for (j = 0; j < argc; j++)
+ {
+ *p++ = ' ';
+ *p++ = '\'';
+ p = grub_strchrsub (p, args[j], '\'', "'\\''");
+ *p++ = '\'';
+ }
+ *p++ = '\n';
+ *p = '\0';
+ return result;
+}
+
+static grub_err_t
+grub_cmd_menuentry (grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ char ch;
+ char *src;
+ char *prefix;
+ unsigned len;
+ grub_err_t r;
+ const char *users;
+
+ if (! argc)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "missing arguments");
+
+ if (ctxt->state[3].set && ctxt->script)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "multiple menuentry definitions");
+
+ if (! ctxt->state[3].set && ! ctxt->script)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "no menuentry definition");
+
+ if (ctxt->state[1].set)
+ users = ctxt->state[1].arg;
+ else if (ctxt->state[5].set)
+ users = NULL;
+ else
+ users = "";
+
+ if (! ctxt->script)
+ return grub_normal_add_menu_entry (argc, (const char **) args,
+ (ctxt->state[0].set ? ctxt->state[0].args
+ : NULL),
+ ctxt->state[4].arg,
+ users,
+ ctxt->state[2].arg, 0,
+ ctxt->state[3].arg,
+ ctxt->extcmd->cmd->name[0] == 's',
+ NULL, NULL);
+
+ src = args[argc - 1];
+ args[argc - 1] = NULL;
+
+ len = grub_strlen(src);
+ ch = src[len - 1];
+ src[len - 1] = '\0';
+
+ prefix = setparams_prefix (argc - 1, args);
+ if (! prefix)
+ return grub_errno;
+
+ r = grub_normal_add_menu_entry (argc - 1, (const char **) args,
+ ctxt->state[0].args, ctxt->state[4].arg,
+ users,
+ ctxt->state[2].arg, prefix, src + 1,
+ ctxt->extcmd->cmd->name[0] == 's', NULL,
+ NULL);
+
+ src[len - 1] = ch;
+ args[argc - 1] = src;
+ grub_free (prefix);
+ return r;
+}
+
+static grub_extcmd_t cmd, cmd_sub;
+
+void
+grub_menu_init (void)
+{
+ cmd = grub_register_extcmd ("menuentry", grub_cmd_menuentry,
+ GRUB_COMMAND_FLAG_BLOCKS
+ | GRUB_COMMAND_ACCEPT_DASH
+ | GRUB_COMMAND_FLAG_EXTRACTOR,
+ N_("BLOCK"), N_("Define a menu entry."), options);
+ cmd_sub = grub_register_extcmd ("submenu", grub_cmd_menuentry,
+ GRUB_COMMAND_FLAG_BLOCKS
+ | GRUB_COMMAND_ACCEPT_DASH
+ | GRUB_COMMAND_FLAG_EXTRACTOR,
+ N_("BLOCK"), N_("Define a submenu."),
+ options);
+}
+
+void
+grub_menu_fini (void)
+{
+ grub_unregister_extcmd (cmd);
+ grub_unregister_extcmd (cmd_sub);
+}
return grub_strdup (val);
}
+static int g_ventoy_hook_root = 0;
+void ventoy_env_hook_root(int hook)
+{
+ g_ventoy_hook_root = hook;
+}
+
+static char *
+ventoy_env_write_root (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val)
+{
+ const char *pos = val;
+ char buf[256];
+
+ if (g_ventoy_hook_root == 0)
+ {
+ return grub_env_write_root(var, val);
+ }
+
+ if (pos[0] == '(')
+ {
+ pos++;
+ }
+
+ if (grub_strncmp(pos, "vtimghd", 7) == 0)
+ {
+ return grub_env_write_root(var, val);
+ }
+
+ pos = grub_strchr(val, ',');
+ if (!pos)
+ {
+ return grub_env_write_root(var, val);
+ }
+
+ if (val[0] == '(')
+ {
+ grub_snprintf(buf, sizeof(buf), "(vtimghd%s", pos);
+ }
+ else
+ {
+ grub_snprintf(buf, sizeof(buf), "vtimghd%s", pos);
+ }
+
+ return grub_env_write_root(var, buf);
+}
+
static void
grub_set_prefix_and_root (void)
{
if (header->type == OBJ_TYPE_PREFIX)
prefix = (char *) header + sizeof (struct grub_module_header);
- grub_register_variable_hook ("root", 0, grub_env_write_root);
+ grub_register_variable_hook ("root", 0, ventoy_env_write_root);
grub_machine_get_bootlocation (&fwdevice, &fwpath);
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2006,2007,2008,2009,2010 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/loader.h>
+#include <grub/memory.h>
+#include <grub/normal.h>
+#include <grub/file.h>
+#include <grub/disk.h>
+#include <grub/err.h>
+#include <grub/misc.h>
+#include <grub/types.h>
+#include <grub/dl.h>
+#include <grub/mm.h>
+#include <grub/term.h>
+#include <grub/cpu/linux.h>
+#include <grub/video.h>
+#include <grub/video_fb.h>
+#include <grub/command.h>
+#include <grub/i386/relocator.h>
+#include <grub/i18n.h>
+#include <grub/lib/cmdline.h>
+#include <grub/linux.h>
+#include <grub/machine/kernel.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#ifdef GRUB_MACHINE_PCBIOS
+#include <grub/i386/pc/vesa_modes_table.h>
+#endif
+
+#ifdef GRUB_MACHINE_EFI
+#include <grub/efi/efi.h>
+#define HAS_VGA_TEXT 0
+#define DEFAULT_VIDEO_MODE "auto"
+#define ACCEPTS_PURE_TEXT 0
+#elif defined (GRUB_MACHINE_IEEE1275)
+#include <grub/ieee1275/ieee1275.h>
+#define HAS_VGA_TEXT 0
+#define DEFAULT_VIDEO_MODE "text"
+#define ACCEPTS_PURE_TEXT 1
+#else
+#include <grub/i386/pc/vbe.h>
+#include <grub/i386/pc/console.h>
+#define HAS_VGA_TEXT 1
+#define DEFAULT_VIDEO_MODE "text"
+#define ACCEPTS_PURE_TEXT 1
+#endif
+
+static grub_dl_t my_mod;
+
+static grub_size_t linux_mem_size;
+static int loaded;
+static void *prot_mode_mem;
+static grub_addr_t prot_mode_target;
+static void *initrd_mem;
+static grub_addr_t initrd_mem_target;
+static grub_size_t prot_init_space;
+static struct grub_relocator *relocator = NULL;
+static void *efi_mmap_buf;
+static grub_size_t maximal_cmdline_size;
+static struct linux_kernel_params linux_params;
+static char *linux_cmdline;
+#ifdef GRUB_MACHINE_EFI
+static grub_efi_uintn_t efi_mmap_size;
+#else
+static const grub_size_t efi_mmap_size = 0;
+#endif
+
+#define LINUX_MAX_ARGC 1024
+static int ventoy_debug = 0;
+static int ventoy_initrd_called = 0;
+static int ventoy_linux_argc = 0;
+static char **ventoy_linux_args = NULL;
+static grub_err_t
+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]);
+
+/* FIXME */
+#if 0
+struct idt_descriptor
+{
+ grub_uint16_t limit;
+ void *base;
+} GRUB_PACKED;
+
+static struct idt_descriptor idt_desc =
+ {
+ 0,
+ 0
+ };
+#endif
+
+static inline grub_size_t
+page_align (grub_size_t size)
+{
+ return (size + (1 << 12) - 1) & (~((1 << 12) - 1));
+}
+
+/* Helper for find_mmap_size. */
+static int
+count_hook (grub_uint64_t addr __attribute__ ((unused)),
+ grub_uint64_t size __attribute__ ((unused)),
+ grub_memory_type_t type __attribute__ ((unused)), void *data)
+{
+ grub_size_t *count = data;
+
+ (*count)++;
+ return 0;
+}
+
+/* Find the optimal number of pages for the memory map. */
+static grub_size_t
+find_mmap_size (void)
+{
+ grub_size_t count = 0, mmap_size;
+
+ grub_mmap_iterate (count_hook, &count);
+
+ mmap_size = count * sizeof (struct grub_e820_mmap);
+
+ /* Increase the size a bit for safety, because GRUB allocates more on
+ later. */
+ mmap_size += (1 << 12);
+
+ return page_align (mmap_size);
+}
+
+static void
+free_pages (void)
+{
+ grub_relocator_unload (relocator);
+ relocator = NULL;
+ prot_mode_mem = initrd_mem = 0;
+ prot_mode_target = initrd_mem_target = 0;
+}
+
+/* Allocate pages for the real mode code and the protected mode code
+ for linux as well as a memory map buffer. */
+static grub_err_t
+allocate_pages (grub_size_t prot_size, grub_size_t *align,
+ grub_size_t min_align, int relocatable,
+ grub_uint64_t preferred_address)
+{
+ grub_err_t err;
+
+ if (prot_size == 0)
+ prot_size = 1;
+
+ prot_size = page_align (prot_size);
+
+ /* Initialize the memory pointers with NULL for convenience. */
+ free_pages ();
+
+ relocator = grub_relocator_new ();
+ if (!relocator)
+ {
+ err = grub_errno;
+ goto fail;
+ }
+
+ /* FIXME: Should request low memory from the heap when this feature is
+ implemented. */
+
+ {
+ grub_relocator_chunk_t ch;
+ if (relocatable)
+ {
+ err = grub_relocator_alloc_chunk_align (relocator, &ch,
+ preferred_address,
+ preferred_address,
+ prot_size, 1,
+ GRUB_RELOCATOR_PREFERENCE_LOW,
+ 1);
+ for (; err && *align + 1 > min_align; (*align)--)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ err = grub_relocator_alloc_chunk_align (relocator, &ch,
+ 0x1000000,
+ 0xffffffff & ~prot_size,
+ prot_size, 1 << *align,
+ GRUB_RELOCATOR_PREFERENCE_LOW,
+ 1);
+ }
+ if (err)
+ goto fail;
+ }
+ else
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch,
+ preferred_address,
+ prot_size);
+ if (err)
+ goto fail;
+ prot_mode_mem = get_virtual_current_address (ch);
+ prot_mode_target = get_physical_target_address (ch);
+ }
+
+ grub_dprintf ("linux", "prot_mode_mem = %p, prot_mode_target = %lx, prot_size = %x\n",
+ prot_mode_mem, (unsigned long) prot_mode_target,
+ (unsigned) prot_size);
+ return GRUB_ERR_NONE;
+
+ fail:
+ free_pages ();
+ return err;
+}
+
+static grub_err_t
+grub_e820_add_region (struct grub_e820_mmap *e820_map, int *e820_num,
+ grub_uint64_t start, grub_uint64_t size,
+ grub_uint32_t type)
+{
+ int n = *e820_num;
+
+ if ((n > 0) && (e820_map[n - 1].addr + e820_map[n - 1].size == start) &&
+ (e820_map[n - 1].type == type))
+ e820_map[n - 1].size += size;
+ else
+ {
+ e820_map[n].addr = start;
+ e820_map[n].size = size;
+ e820_map[n].type = type;
+ (*e820_num)++;
+ }
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_linux_setup_video (struct linux_kernel_params *params)
+{
+ struct grub_video_mode_info mode_info;
+ void *framebuffer;
+ grub_err_t err;
+ grub_video_driver_id_t driver_id;
+ const char *gfxlfbvar = grub_env_get ("gfxpayloadforcelfb");
+
+ driver_id = grub_video_get_driver_id ();
+
+ if (driver_id == GRUB_VIDEO_DRIVER_NONE)
+ return 1;
+
+ err = grub_video_get_info_and_fini (&mode_info, &framebuffer);
+
+ if (err)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ return 1;
+ }
+
+ params->lfb_width = mode_info.width;
+ params->lfb_height = mode_info.height;
+ params->lfb_depth = mode_info.bpp;
+ params->lfb_line_len = mode_info.pitch;
+
+ params->lfb_base = (grub_size_t) framebuffer;
+
+#if defined (GRUB_MACHINE_EFI) && defined (__x86_64__)
+ params->ext_lfb_base = (grub_size_t) (((grub_uint64_t)(grub_size_t) framebuffer) >> 32);
+ params->capabilities |= VIDEO_CAPABILITY_64BIT_BASE;
+#endif
+
+ params->lfb_size = ALIGN_UP (params->lfb_line_len * params->lfb_height, 65536);
+
+ params->red_mask_size = mode_info.red_mask_size;
+ params->red_field_pos = mode_info.red_field_pos;
+ params->green_mask_size = mode_info.green_mask_size;
+ params->green_field_pos = mode_info.green_field_pos;
+ params->blue_mask_size = mode_info.blue_mask_size;
+ params->blue_field_pos = mode_info.blue_field_pos;
+ params->reserved_mask_size = mode_info.reserved_mask_size;
+ params->reserved_field_pos = mode_info.reserved_field_pos;
+
+ if (gfxlfbvar && (gfxlfbvar[0] == '1' || gfxlfbvar[0] == 'y'))
+ params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
+ else
+ {
+ switch (driver_id)
+ {
+ case GRUB_VIDEO_DRIVER_VBE:
+ params->lfb_size >>= 16;
+ params->have_vga = GRUB_VIDEO_LINUX_TYPE_VESA;
+ break;
+
+ case GRUB_VIDEO_DRIVER_EFI_UGA:
+ case GRUB_VIDEO_DRIVER_EFI_GOP:
+ params->have_vga = GRUB_VIDEO_LINUX_TYPE_EFIFB;
+ break;
+
+ /* FIXME: check if better id is available. */
+ case GRUB_VIDEO_DRIVER_SM712:
+ case GRUB_VIDEO_DRIVER_SIS315PRO:
+ case GRUB_VIDEO_DRIVER_VGA:
+ case GRUB_VIDEO_DRIVER_CIRRUS:
+ case GRUB_VIDEO_DRIVER_BOCHS:
+ case GRUB_VIDEO_DRIVER_RADEON_FULOONG2E:
+ case GRUB_VIDEO_DRIVER_RADEON_YEELOONG3A:
+ case GRUB_VIDEO_DRIVER_IEEE1275:
+ case GRUB_VIDEO_DRIVER_COREBOOT:
+ /* Make gcc happy. */
+ case GRUB_VIDEO_DRIVER_XEN:
+ case GRUB_VIDEO_DRIVER_SDL:
+ case GRUB_VIDEO_DRIVER_NONE:
+ case GRUB_VIDEO_ADAPTER_CAPTURE:
+ params->have_vga = GRUB_VIDEO_LINUX_TYPE_SIMPLE;
+ break;
+ }
+ }
+
+#ifdef GRUB_MACHINE_PCBIOS
+ /* VESA packed modes may come with zeroed mask sizes, which need
+ to be set here according to DAC Palette width. If we don't,
+ this results in Linux displaying a black screen. */
+ if (driver_id == GRUB_VIDEO_DRIVER_VBE && mode_info.bpp <= 8)
+ {
+ struct grub_vbe_info_block controller_info;
+ int status;
+ int width = 8;
+
+ status = grub_vbe_bios_get_controller_info (&controller_info);
+
+ if (status == GRUB_VBE_STATUS_OK &&
+ (controller_info.capabilities & GRUB_VBE_CAPABILITY_DACWIDTH))
+ status = grub_vbe_bios_set_dac_palette_width (&width);
+
+ if (status != GRUB_VBE_STATUS_OK)
+ /* 6 is default after mode reset. */
+ width = 6;
+
+ params->red_mask_size = params->green_mask_size
+ = params->blue_mask_size = width;
+ params->reserved_mask_size = 0;
+ }
+#endif
+
+ return GRUB_ERR_NONE;
+}
+
+/* Context for grub_linux_boot. */
+struct grub_linux_boot_ctx
+{
+ grub_addr_t real_mode_target;
+ grub_size_t real_size;
+ struct linux_kernel_params *params;
+ int e820_num;
+};
+
+/* Helper for grub_linux_boot. */
+static int
+grub_linux_boot_mmap_find (grub_uint64_t addr, grub_uint64_t size,
+ grub_memory_type_t type, void *data)
+{
+ struct grub_linux_boot_ctx *ctx = data;
+
+ /* We must put real mode code in the traditional space. */
+ if (type != GRUB_MEMORY_AVAILABLE || addr > 0x90000)
+ return 0;
+
+ if (addr + size < 0x10000)
+ return 0;
+
+ if (addr < 0x10000)
+ {
+ size += addr - 0x10000;
+ addr = 0x10000;
+ }
+
+ if (addr + size > 0x90000)
+ size = 0x90000 - addr;
+
+ if (ctx->real_size + efi_mmap_size > size)
+ return 0;
+
+ grub_dprintf ("linux", "addr = %lx, size = %x, need_size = %x\n",
+ (unsigned long) addr,
+ (unsigned) size,
+ (unsigned) (ctx->real_size + efi_mmap_size));
+ ctx->real_mode_target = ((addr + size) - (ctx->real_size + efi_mmap_size));
+ return 1;
+}
+
+/* GRUB types conveniently match E820 types. */
+static int
+grub_linux_boot_mmap_fill (grub_uint64_t addr, grub_uint64_t size,
+ grub_memory_type_t type, void *data)
+{
+ struct grub_linux_boot_ctx *ctx = data;
+
+ if (grub_e820_add_region (ctx->params->e820_map, &ctx->e820_num,
+ addr, size, type))
+ return 1;
+
+ return 0;
+}
+
+static void ventoy_debug_pause(void)
+{
+ char key;
+
+ if (0 == ventoy_debug)
+ {
+ return;
+ }
+
+ grub_printf("press Enter to continue ......\n");
+ while (1)
+ {
+ key = grub_getkey();
+ if (key == '\n' || key == '\r')
+ {
+ break;
+ }
+ }
+}
+
+static int ventoy_preboot(void)
+{
+ char buf[128];
+ char *argv[2];
+
+ if (ventoy_debug)
+ {
+ grub_printf("ventoy_preboot %d %d\n", ventoy_linux_argc, ventoy_initrd_called);
+ ventoy_debug_pause();
+ }
+
+ if (ventoy_linux_argc == 0)
+ {
+ return 0;
+ }
+
+ if (ventoy_initrd_called)
+ {
+ ventoy_initrd_called = 0;
+ return 0;
+ }
+
+ grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
+
+ argv[0] = buf;
+ argv[1] = NULL;
+ grub_cmd_initrd(NULL, 1, argv);
+
+ if (ventoy_debug)
+ {
+ grub_printf("add initrd %s\n", buf);
+ ventoy_debug_pause();
+ }
+
+ return 0;
+}
+
+static int ventoy_boot_opt_filter(char *opt)
+{
+ if (grub_strcmp(opt, "noinitrd") == 0)
+ {
+ return 1;
+ }
+
+ if (grub_strncmp(opt, "rdinit=", 7) == 0)
+ {
+ if (grub_strcmp(opt, "rdinit=/vtoy/vtoy") != 0)
+ {
+ opt[0] = 'v';
+ opt[1] = 't';
+ }
+ return 0;
+ }
+
+ if (ventoy_debug)
+ {
+ if (grub_strcmp(opt, "quiet") == 0)
+ {
+ return 1;
+ }
+
+ if (grub_strncmp(opt, "loglevel=", 9) == 0)
+ {
+ return 1;
+ }
+
+ if (grub_strcmp(opt, "splash") == 0)
+ {
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+static int ventoy_bootopt_hook(int argc, char *argv[])
+{
+ int i;
+ int count = 0;
+ const char *env;
+ char c;
+ char *newenv;
+ char *last, *pos;
+
+ //grub_printf("ventoy_bootopt_hook: %d %d\n", argc, ventoy_linux_argc);
+
+ if (ventoy_linux_argc == 0)
+ {
+ return 0;
+ }
+
+ for (i = 0; i < argc; i++)
+ {
+ if (ventoy_boot_opt_filter(argv[i]))
+ {
+ continue;
+ }
+
+ ventoy_linux_args[count++] = grub_strdup(argv[i]);
+ }
+
+ for (i = 0; i < ventoy_linux_argc; i++)
+ {
+ ventoy_linux_args[count] = ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)];
+ ventoy_linux_args[i + (LINUX_MAX_ARGC / 2)] = NULL;
+
+ if (ventoy_linux_args[count][0] == '@')
+ {
+ env = grub_env_get(ventoy_linux_args[count] + 1);
+ if (env)
+ {
+ grub_free(ventoy_linux_args[count]);
+
+ newenv = grub_strdup(env);
+ last = newenv;
+
+ while (*last)
+ {
+ while (*last)
+ {
+ if (*last != ' ' && *last != '\t')
+ {
+ break;
+ }
+ last++;
+ }
+
+ if (*last == 0)
+ {
+ break;
+ }
+
+ for (pos = last; *pos; pos++)
+ {
+ if (*pos == ' ' || *pos == '\t')
+ {
+ c = *pos;
+ *pos = 0;
+ if (0 == ventoy_boot_opt_filter(last))
+ {
+ ventoy_linux_args[count++] = grub_strdup(last);
+ }
+ *pos = c;
+ break;
+ }
+ }
+
+ if (*pos == 0)
+ {
+ if (0 == ventoy_boot_opt_filter(last))
+ {
+ ventoy_linux_args[count++] = grub_strdup(last);
+ }
+ break;
+ }
+
+ last = pos + 1;
+ }
+ }
+ else
+ {
+ count++;
+ }
+ }
+ else
+ {
+ count++;
+ }
+ }
+
+ if (ventoy_debug)
+ {
+ ventoy_linux_args[count++] = grub_strdup("loglevel=10");
+ }
+
+ ventoy_linux_argc = count;
+
+ if (ventoy_debug)
+ {
+ grub_printf("========== bootoption ==========\n");
+ for (i = 0; i < count; i++)
+ {
+ grub_printf("%s ", ventoy_linux_args[i]);
+ }
+ grub_printf("\n================================\n");
+ }
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_set_boot_opt (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ int i;
+ const char *vtdebug;
+
+ for (i = 0; i < argc; i++)
+ {
+ ventoy_linux_args[ventoy_linux_argc + (LINUX_MAX_ARGC / 2) ] = grub_strdup(argv[i]);
+ ventoy_linux_argc++;
+ }
+
+ vtdebug = grub_env_get("vtdebug_flag");
+ if (vtdebug && vtdebug[0])
+ {
+ ventoy_debug = 1;
+ }
+
+ if (ventoy_debug) grub_printf("ventoy set boot opt %d\n", ventoy_linux_argc);
+
+ return 0;
+}
+
+static grub_err_t
+grub_cmd_unset_boot_opt (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ int i;
+
+ (void)argc;
+ (void)argv;
+
+ for (i = 0; i < LINUX_MAX_ARGC; i++)
+ {
+ if (ventoy_linux_args[i])
+ {
+ grub_free(ventoy_linux_args[i]);
+ }
+ }
+
+ ventoy_debug = 0;
+ ventoy_linux_argc = 0;
+ ventoy_initrd_called = 0;
+ grub_memset(ventoy_linux_args, 0, sizeof(char *) * LINUX_MAX_ARGC);
+ return 0;
+}
+
+
+static grub_err_t
+grub_linux_boot (void)
+{
+ grub_err_t err = 0;
+ const char *modevar;
+ char *tmp;
+ struct grub_relocator32_state state;
+ void *real_mode_mem;
+ struct grub_linux_boot_ctx ctx = {
+ .real_mode_target = 0
+ };
+ grub_size_t mmap_size;
+ grub_size_t cl_offset;
+
+ ventoy_preboot();
+
+#ifdef GRUB_MACHINE_IEEE1275
+ {
+ const char *bootpath;
+ grub_ssize_t len;
+
+ bootpath = grub_env_get ("root");
+ if (bootpath)
+ grub_ieee1275_set_property (grub_ieee1275_chosen,
+ "bootpath", bootpath,
+ grub_strlen (bootpath) + 1,
+ &len);
+ linux_params.ofw_signature = GRUB_LINUX_OFW_SIGNATURE;
+ linux_params.ofw_num_items = 1;
+ linux_params.ofw_cif_handler = (grub_uint32_t) grub_ieee1275_entry_fn;
+ linux_params.ofw_idt = 0;
+ }
+#endif
+
+ modevar = grub_env_get ("gfxpayload");
+
+ /* Now all graphical modes are acceptable.
+ May change in future if we have modes without framebuffer. */
+ if (modevar && *modevar != 0)
+ {
+ tmp = grub_xasprintf ("%s;" DEFAULT_VIDEO_MODE, modevar);
+ if (! tmp)
+ return grub_errno;
+#if ACCEPTS_PURE_TEXT
+ err = grub_video_set_mode (tmp, 0, 0);
+#else
+ err = grub_video_set_mode (tmp, GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
+#endif
+ grub_free (tmp);
+ }
+ else /* We can't go back to text mode from coreboot fb. */
+#ifdef GRUB_MACHINE_COREBOOT
+ if (grub_video_get_driver_id () == GRUB_VIDEO_DRIVER_COREBOOT)
+ err = GRUB_ERR_NONE;
+ else
+#endif
+ {
+#if ACCEPTS_PURE_TEXT
+ err = grub_video_set_mode (DEFAULT_VIDEO_MODE, 0, 0);
+#else
+ err = grub_video_set_mode (DEFAULT_VIDEO_MODE,
+ GRUB_VIDEO_MODE_TYPE_PURE_TEXT, 0);
+#endif
+ }
+
+ if (err)
+ {
+ grub_print_error ();
+ grub_puts_ (N_("Booting in blind mode"));
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ if (grub_linux_setup_video (&linux_params))
+ {
+#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) || defined (GRUB_MACHINE_QEMU)
+ linux_params.have_vga = GRUB_VIDEO_LINUX_TYPE_TEXT;
+ linux_params.video_mode = 0x3;
+#else
+ linux_params.have_vga = 0;
+ linux_params.video_mode = 0;
+ linux_params.video_width = 0;
+ linux_params.video_height = 0;
+#endif
+ }
+
+
+#ifndef GRUB_MACHINE_IEEE1275
+ if (linux_params.have_vga == GRUB_VIDEO_LINUX_TYPE_TEXT)
+#endif
+ {
+ grub_term_output_t term;
+ int found = 0;
+ FOR_ACTIVE_TERM_OUTPUTS(term)
+ if (grub_strcmp (term->name, "vga_text") == 0
+ || grub_strcmp (term->name, "console") == 0
+ || grub_strcmp (term->name, "ofconsole") == 0)
+ {
+ struct grub_term_coordinate pos = grub_term_getxy (term);
+ linux_params.video_cursor_x = pos.x;
+ linux_params.video_cursor_y = pos.y;
+ linux_params.video_width = grub_term_width (term);
+ linux_params.video_height = grub_term_height (term);
+ found = 1;
+ break;
+ }
+ if (!found)
+ {
+ linux_params.video_cursor_x = 0;
+ linux_params.video_cursor_y = 0;
+ linux_params.video_width = 80;
+ linux_params.video_height = 25;
+ }
+ }
+
+#ifdef GRUB_KERNEL_USE_RSDP_ADDR
+ linux_params.acpi_rsdp_addr = grub_le_to_cpu64 (grub_rsdp_addr);
+#endif
+
+ mmap_size = find_mmap_size ();
+ /* Make sure that each size is aligned to a page boundary. */
+ cl_offset = ALIGN_UP (mmap_size + sizeof (linux_params), 4096);
+ if (cl_offset < ((grub_size_t) linux_params.setup_sects << GRUB_DISK_SECTOR_BITS))
+ cl_offset = ALIGN_UP ((grub_size_t) (linux_params.setup_sects
+ << GRUB_DISK_SECTOR_BITS), 4096);
+ ctx.real_size = ALIGN_UP (cl_offset + maximal_cmdline_size, 4096);
+
+#ifdef GRUB_MACHINE_EFI
+ efi_mmap_size = grub_efi_find_mmap_size ();
+ if (efi_mmap_size == 0)
+ return grub_errno;
+#endif
+
+ grub_dprintf ("linux", "real_size = %x, mmap_size = %x\n",
+ (unsigned) ctx.real_size, (unsigned) mmap_size);
+
+#ifdef GRUB_MACHINE_EFI
+ grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 1);
+ if (! ctx.real_mode_target)
+ grub_efi_mmap_iterate (grub_linux_boot_mmap_find, &ctx, 0);
+#else
+ grub_mmap_iterate (grub_linux_boot_mmap_find, &ctx);
+#endif
+ grub_dprintf ("linux", "real_mode_target = %lx, real_size = %x, efi_mmap_size = %x\n",
+ (unsigned long) ctx.real_mode_target,
+ (unsigned) ctx.real_size,
+ (unsigned) efi_mmap_size);
+
+ if (! ctx.real_mode_target)
+ return grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate real mode pages");
+
+ {
+ grub_relocator_chunk_t ch;
+ err = grub_relocator_alloc_chunk_addr (relocator, &ch,
+ ctx.real_mode_target,
+ (ctx.real_size + efi_mmap_size));
+ if (err)
+ return err;
+ real_mode_mem = get_virtual_current_address (ch);
+ }
+ efi_mmap_buf = (grub_uint8_t *) real_mode_mem + ctx.real_size;
+
+ grub_dprintf ("linux", "real_mode_mem = %p\n",
+ real_mode_mem);
+
+ ctx.params = real_mode_mem;
+
+ *ctx.params = linux_params;
+ ctx.params->cmd_line_ptr = ctx.real_mode_target + cl_offset;
+ grub_memcpy ((char *) ctx.params + cl_offset, linux_cmdline,
+ maximal_cmdline_size);
+
+ grub_dprintf ("linux", "code32_start = %x\n",
+ (unsigned) ctx.params->code32_start);
+
+ ctx.e820_num = 0;
+ if (grub_mmap_iterate (grub_linux_boot_mmap_fill, &ctx))
+ return grub_errno;
+ ctx.params->mmap_size = ctx.e820_num;
+
+#ifdef GRUB_MACHINE_EFI
+ {
+ grub_efi_uintn_t efi_desc_size;
+ grub_size_t efi_mmap_target;
+ grub_efi_uint32_t efi_desc_version;
+ err = grub_efi_finish_boot_services (&efi_mmap_size, efi_mmap_buf, NULL,
+ &efi_desc_size, &efi_desc_version);
+ if (err)
+ return err;
+
+ /* Note that no boot services are available from here. */
+ efi_mmap_target = ctx.real_mode_target
+ + ((grub_uint8_t *) efi_mmap_buf - (grub_uint8_t *) real_mode_mem);
+ /* Pass EFI parameters. */
+ if (grub_le_to_cpu16 (ctx.params->version) >= 0x0208)
+ {
+ ctx.params->v0208.efi_mem_desc_size = efi_desc_size;
+ ctx.params->v0208.efi_mem_desc_version = efi_desc_version;
+ ctx.params->v0208.efi_mmap = efi_mmap_target;
+ ctx.params->v0208.efi_mmap_size = efi_mmap_size;
+
+#ifdef __x86_64__
+ ctx.params->v0208.efi_mmap_hi = (efi_mmap_target >> 32);
+#endif
+ }
+ else if (grub_le_to_cpu16 (ctx.params->version) >= 0x0206)
+ {
+ ctx.params->v0206.efi_mem_desc_size = efi_desc_size;
+ ctx.params->v0206.efi_mem_desc_version = efi_desc_version;
+ ctx.params->v0206.efi_mmap = efi_mmap_target;
+ ctx.params->v0206.efi_mmap_size = efi_mmap_size;
+ }
+ else if (grub_le_to_cpu16 (ctx.params->version) >= 0x0204)
+ {
+ ctx.params->v0204.efi_mem_desc_size = efi_desc_size;
+ ctx.params->v0204.efi_mem_desc_version = efi_desc_version;
+ ctx.params->v0204.efi_mmap = efi_mmap_target;
+ ctx.params->v0204.efi_mmap_size = efi_mmap_size;
+ }
+ }
+#endif
+
+ /* FIXME. */
+ /* asm volatile ("lidt %0" : : "m" (idt_desc)); */
+ state.ebp = state.edi = state.ebx = 0;
+ state.esi = ctx.real_mode_target;
+ state.esp = ctx.real_mode_target;
+ state.eip = ctx.params->code32_start;
+ return grub_relocator32_boot (relocator, state, 0);
+}
+
+static grub_err_t
+grub_linux_unload (void)
+{
+ grub_dl_unref (my_mod);
+ loaded = 0;
+ grub_free (linux_cmdline);
+ linux_cmdline = 0;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_file_t file = 0;
+ struct linux_i386_kernel_header lh;
+ grub_uint8_t setup_sects;
+ grub_size_t real_size, prot_size, prot_file_size;
+ grub_ssize_t len;
+ int i;
+ grub_size_t align, min_align;
+ int relocatable;
+ grub_uint64_t preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
+
+ grub_dl_ref (my_mod);
+
+ if (argc == 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ goto fail;
+ }
+
+ file = grub_file_open (argv[0], GRUB_FILE_TYPE_LINUX_KERNEL);
+ if (! file)
+ goto fail;
+
+ if (ventoy_linux_argc)
+ {
+ const char *tip = grub_env_get("ventoy_loading_tip");
+ if (tip)
+ {
+ grub_printf("%s\n", tip);
+ grub_refresh();
+ }
+ }
+
+ if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh))
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ argv[0]);
+ goto fail;
+ }
+
+ if (lh.boot_flag != grub_cpu_to_le16_compile_time (0xaa55))
+ {
+ grub_error (GRUB_ERR_BAD_OS, "invalid magic number");
+ goto fail;
+ }
+
+ if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS)
+ {
+ grub_error (GRUB_ERR_BAD_OS, "too many setup sectors");
+ goto fail;
+ }
+
+ /* FIXME: 2.03 is not always good enough (Linux 2.4 can be 2.03 and
+ still not support 32-bit boot. */
+ if (lh.header != grub_cpu_to_le32_compile_time (GRUB_LINUX_I386_MAGIC_SIGNATURE)
+ || grub_le_to_cpu16 (lh.version) < 0x0203)
+ {
+ grub_error (GRUB_ERR_BAD_OS, "version too old for 32-bit boot"
+#ifdef GRUB_MACHINE_PCBIOS
+ " (try with `linux16')"
+#endif
+ );
+ goto fail;
+ }
+
+ if (! (lh.loadflags & GRUB_LINUX_FLAG_BIG_KERNEL))
+ {
+ grub_error (GRUB_ERR_BAD_OS, "zImage doesn't support 32-bit boot"
+#ifdef GRUB_MACHINE_PCBIOS
+ " (try with `linux16')"
+#endif
+ );
+ goto fail;
+ }
+
+ if (grub_le_to_cpu16 (lh.version) >= 0x0206)
+ maximal_cmdline_size = grub_le_to_cpu32 (lh.cmdline_size) + 1;
+ else
+ maximal_cmdline_size = 256;
+
+ if (maximal_cmdline_size < 128)
+ maximal_cmdline_size = 128;
+
+ setup_sects = lh.setup_sects;
+
+ /* If SETUP_SECTS is not set, set it to the default (4). */
+ if (! setup_sects)
+ setup_sects = GRUB_LINUX_DEFAULT_SETUP_SECTS;
+
+ real_size = setup_sects << GRUB_DISK_SECTOR_BITS;
+ prot_file_size = grub_file_size (file) - real_size - GRUB_DISK_SECTOR_SIZE;
+
+ if (grub_le_to_cpu16 (lh.version) >= 0x205
+ && lh.kernel_alignment != 0
+ && ((lh.kernel_alignment - 1) & lh.kernel_alignment) == 0)
+ {
+ for (align = 0; align < 32; align++)
+ if (grub_le_to_cpu32 (lh.kernel_alignment) & (1 << align))
+ break;
+ relocatable = grub_le_to_cpu32 (lh.relocatable);
+ }
+ else
+ {
+ align = 0;
+ relocatable = 0;
+ }
+
+ if (grub_le_to_cpu16 (lh.version) >= 0x020a)
+ {
+ min_align = lh.min_alignment;
+ prot_size = grub_le_to_cpu32 (lh.init_size);
+ prot_init_space = page_align (prot_size);
+ if (relocatable)
+ preferred_address = grub_le_to_cpu64 (lh.pref_address);
+ else
+ preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
+ }
+ else
+ {
+ min_align = align;
+ prot_size = prot_file_size;
+ preferred_address = GRUB_LINUX_BZIMAGE_ADDR;
+ /* Usually, the compression ratio is about 50%. */
+ prot_init_space = page_align (prot_size) * 3;
+ }
+
+ if (allocate_pages (prot_size, &align,
+ min_align, relocatable,
+ preferred_address))
+ goto fail;
+
+ grub_memset (&linux_params, 0, sizeof (linux_params));
+ grub_memcpy (&linux_params.setup_sects, &lh.setup_sects, sizeof (lh) - 0x1F1);
+
+ linux_params.code32_start = prot_mode_target + lh.code32_start - GRUB_LINUX_BZIMAGE_ADDR;
+ linux_params.kernel_alignment = (1 << align);
+ linux_params.ps_mouse = linux_params.padding10 = 0;
+
+ /*
+ * The Linux 32-bit boot protocol defines the setup header end
+ * to be at 0x202 + the byte value at 0x201.
+ */
+ len = 0x202 + *((char *) &linux_params.jump + 1);
+
+ /* Verify the struct is big enough so we do not write past the end. */
+ if (len > (char *) &linux_params.edd_mbr_sig_buffer - (char *) &linux_params) {
+ grub_error (GRUB_ERR_BAD_OS, "Linux setup header too big");
+ goto fail;
+ }
+
+ /* We've already read lh so there is no need to read it second time. */
+ len -= sizeof(lh);
+
+ if (grub_file_read (file, (char *) &linux_params + sizeof (lh), len) != len)
+ {
+ if (!grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ argv[0]);
+ goto fail;
+ }
+
+ linux_params.type_of_loader = GRUB_LINUX_BOOT_LOADER_TYPE;
+
+ /* These two are used (instead of cmd_line_ptr) by older versions of Linux,
+ and otherwise ignored. */
+ linux_params.cl_magic = GRUB_LINUX_CL_MAGIC;
+ linux_params.cl_offset = 0x1000;
+
+ linux_params.ramdisk_image = 0;
+ linux_params.ramdisk_size = 0;
+
+ linux_params.heap_end_ptr = GRUB_LINUX_HEAP_END_OFFSET;
+ linux_params.loadflags |= GRUB_LINUX_FLAG_CAN_USE_HEAP;
+
+ /* These are not needed to be precise, because Linux uses these values
+ only to raise an error when the decompression code cannot find good
+ space. */
+ linux_params.ext_mem = ((32 * 0x100000) >> 10);
+ linux_params.alt_mem = ((32 * 0x100000) >> 10);
+
+ /* Ignored by Linux. */
+ linux_params.video_page = 0;
+
+ /* Only used when `video_mode == 0x7', otherwise ignored. */
+ linux_params.video_ega_bx = 0;
+
+ linux_params.font_size = 16; /* XXX */
+
+#ifdef GRUB_MACHINE_EFI
+#ifdef __x86_64__
+ if (grub_le_to_cpu16 (linux_params.version) < 0x0208 &&
+ ((grub_addr_t) grub_efi_system_table >> 32) != 0)
+ return grub_error(GRUB_ERR_BAD_OS,
+ "kernel does not support 64-bit addressing");
+#endif
+
+ if (grub_le_to_cpu16 (linux_params.version) >= 0x0208)
+ {
+ linux_params.v0208.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
+ linux_params.v0208.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table;
+#ifdef __x86_64__
+ linux_params.v0208.efi_system_table_hi = (grub_uint32_t) ((grub_uint64_t) grub_efi_system_table >> 32);
+#endif
+ }
+ else if (grub_le_to_cpu16 (linux_params.version) >= 0x0206)
+ {
+ linux_params.v0206.efi_signature = GRUB_LINUX_EFI_SIGNATURE;
+ linux_params.v0206.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table;
+ }
+ else if (grub_le_to_cpu16 (linux_params.version) >= 0x0204)
+ {
+ linux_params.v0204.efi_signature = GRUB_LINUX_EFI_SIGNATURE_0204;
+ linux_params.v0204.efi_system_table = (grub_uint32_t) (grub_addr_t) grub_efi_system_table;
+ }
+#endif
+
+ /* The other parameters are filled when booting. */
+
+ grub_file_seek (file, real_size + GRUB_DISK_SECTOR_SIZE);
+
+ grub_dprintf ("linux", "bzImage, setup=0x%x, size=0x%x\n",
+ (unsigned) real_size, (unsigned) prot_size);
+
+ /* Look for memory size and video mode specified on the command line. */
+ linux_mem_size = 0;
+ for (i = 1; i < argc; i++)
+#ifdef GRUB_MACHINE_PCBIOS
+ if (grub_memcmp (argv[i], "vga=", 4) == 0)
+ {
+ /* Video mode selection support. */
+ char *val = argv[i] + 4;
+ unsigned vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
+ struct grub_vesa_mode_table_entry *linux_mode;
+ grub_err_t err;
+ char *buf;
+
+ grub_dl_load ("vbe");
+
+ if (grub_strcmp (val, "normal") == 0)
+ vid_mode = GRUB_LINUX_VID_MODE_NORMAL;
+ else if (grub_strcmp (val, "ext") == 0)
+ vid_mode = GRUB_LINUX_VID_MODE_EXTENDED;
+ else if (grub_strcmp (val, "ask") == 0)
+ {
+ grub_puts_ (N_("Legacy `ask' parameter no longer supported."));
+
+ /* We usually would never do this in a loader, but "vga=ask" means user
+ requested interaction, so it can't hurt to request keyboard input. */
+ grub_wait_after_message ();
+
+ goto fail;
+ }
+ else
+ vid_mode = (grub_uint16_t) grub_strtoul (val, 0, 0);
+
+ switch (vid_mode)
+ {
+ case 0:
+ case GRUB_LINUX_VID_MODE_NORMAL:
+ grub_env_set ("gfxpayload", "text");
+ grub_printf_ (N_("%s is deprecated. "
+ "Use set gfxpayload=%s before "
+ "linux command instead.\n"),
+ argv[i], "text");
+ break;
+
+ case 1:
+ case GRUB_LINUX_VID_MODE_EXTENDED:
+ /* FIXME: support 80x50 text. */
+ grub_env_set ("gfxpayload", "text");
+ grub_printf_ (N_("%s is deprecated. "
+ "Use set gfxpayload=%s before "
+ "linux command instead.\n"),
+ argv[i], "text");
+ break;
+ default:
+ /* Ignore invalid values. */
+ if (vid_mode < GRUB_VESA_MODE_TABLE_START ||
+ vid_mode > GRUB_VESA_MODE_TABLE_END)
+ {
+ grub_env_set ("gfxpayload", "text");
+ /* TRANSLATORS: "x" has to be entered in, like an identifier,
+ so please don't use better Unicode codepoints. */
+ grub_printf_ (N_("%s is deprecated. VGA mode %d isn't recognized. "
+ "Use set gfxpayload=WIDTHxHEIGHT[xDEPTH] "
+ "before linux command instead.\n"),
+ argv[i], vid_mode);
+ break;
+ }
+
+ linux_mode = &grub_vesa_mode_table[vid_mode
+ - GRUB_VESA_MODE_TABLE_START];
+
+ buf = grub_xasprintf ("%ux%ux%u,%ux%u",
+ linux_mode->width, linux_mode->height,
+ linux_mode->depth,
+ linux_mode->width, linux_mode->height);
+ if (! buf)
+ goto fail;
+
+ grub_printf_ (N_("%s is deprecated. "
+ "Use set gfxpayload=%s before "
+ "linux command instead.\n"),
+ argv[i], buf);
+ err = grub_env_set ("gfxpayload", buf);
+ grub_free (buf);
+ if (err)
+ goto fail;
+ }
+ }
+ else
+#endif /* GRUB_MACHINE_PCBIOS */
+ if (grub_memcmp (argv[i], "mem=", 4) == 0)
+ {
+ char *val = argv[i] + 4;
+
+ linux_mem_size = grub_strtoul (val, &val, 0);
+
+ if (grub_errno)
+ {
+ grub_errno = GRUB_ERR_NONE;
+ linux_mem_size = 0;
+ }
+ else
+ {
+ int shift = 0;
+
+ switch (grub_tolower (val[0]))
+ {
+ case 'g':
+ shift += 10;
+ /* FALLTHROUGH */
+ case 'm':
+ shift += 10;
+ /* FALLTHROUGH */
+ case 'k':
+ shift += 10;
+ /* FALLTHROUGH */
+ default:
+ break;
+ }
+
+ /* Check an overflow. */
+ if (linux_mem_size > (~0UL >> shift))
+ linux_mem_size = 0;
+ else
+ linux_mem_size <<= shift;
+ }
+ }
+ else if (grub_memcmp (argv[i], "quiet", sizeof ("quiet") - 1) == 0)
+ {
+ linux_params.loadflags |= GRUB_LINUX_FLAG_QUIET;
+ }
+
+ /* Create kernel command line. */
+ linux_cmdline = grub_zalloc (maximal_cmdline_size + 1);
+ if (!linux_cmdline)
+ goto fail;
+ grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE));
+ {
+ grub_err_t err;
+
+ if (ventoy_linux_argc)
+ {
+ ventoy_bootopt_hook(argc, argv);
+ err = grub_create_loader_cmdline (ventoy_linux_argc, ventoy_linux_args,
+ linux_cmdline
+ + sizeof (LINUX_IMAGE) - 1,
+ maximal_cmdline_size
+ - (sizeof (LINUX_IMAGE) - 1),
+ GRUB_VERIFY_KERNEL_CMDLINE);
+ }
+ else
+ {
+ err = grub_create_loader_cmdline (argc, argv,
+ linux_cmdline
+ + sizeof (LINUX_IMAGE) - 1,
+ maximal_cmdline_size
+ - (sizeof (LINUX_IMAGE) - 1),
+ GRUB_VERIFY_KERNEL_CMDLINE);
+ }
+
+ if (err)
+ goto fail;
+ }
+
+ len = prot_file_size;
+ if (grub_file_read (file, prot_mode_mem, len) != len && !grub_errno)
+ grub_error (GRUB_ERR_BAD_OS, N_("premature end of file %s"),
+ argv[0]);
+
+ if (grub_errno == GRUB_ERR_NONE)
+ {
+ grub_loader_set (grub_linux_boot, grub_linux_unload,
+ 0 /* set noreturn=0 in order to avoid grub_console_fini() */);
+ loaded = 1;
+ }
+
+ fail:
+
+ if (file)
+ grub_file_close (file);
+
+ if (grub_errno != GRUB_ERR_NONE)
+ {
+ grub_dl_unref (my_mod);
+ loaded = 0;
+ }
+
+ return grub_errno;
+}
+
+static grub_err_t
+grub_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ grub_size_t size = 0, aligned_size = 0;
+ grub_addr_t addr_min, addr_max;
+ grub_addr_t addr;
+ grub_err_t err;
+ struct grub_linux_initrd_context initrd_ctx = { 0, 0, 0 };
+
+ if (argc == 0)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected"));
+ goto fail;
+ }
+
+ if (! loaded)
+ {
+ grub_error (GRUB_ERR_BAD_ARGUMENT, N_("you need to load the kernel first"));
+ goto fail;
+ }
+
+ if (grub_initrd_init (argc, argv, &initrd_ctx))
+ goto fail;
+
+ size = grub_get_initrd_size (&initrd_ctx);
+ aligned_size = ALIGN_UP (size, 4096);
+
+ /* Get the highest address available for the initrd. */
+ if (grub_le_to_cpu16 (linux_params.version) >= 0x0203)
+ {
+ addr_max = grub_cpu_to_le32 (linux_params.initrd_addr_max);
+
+ /* XXX in reality, Linux specifies a bogus value, so
+ it is necessary to make sure that ADDR_MAX does not exceed
+ 0x3fffffff. */
+ if (addr_max > GRUB_LINUX_INITRD_MAX_ADDRESS)
+ addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
+ }
+ else
+ addr_max = GRUB_LINUX_INITRD_MAX_ADDRESS;
+
+ if (linux_mem_size != 0 && linux_mem_size < addr_max)
+ addr_max = linux_mem_size;
+
+ /* Linux 2.3.xx has a bug in the memory range check, so avoid
+ the last page.
+ Linux 2.2.xx has a bug in the memory range check, which is
+ worse than that of Linux 2.3.xx, so avoid the last 64kb. */
+ addr_max -= 0x10000;
+
+ addr_min = (grub_addr_t) prot_mode_target + prot_init_space;
+
+ /* Put the initrd as high as possible, 4KiB aligned. */
+ addr = (addr_max - aligned_size) & ~0xFFF;
+
+ if (addr < addr_min)
+ {
+ grub_error (GRUB_ERR_OUT_OF_RANGE, "the initrd is too big");
+ goto fail;
+ }
+
+ {
+ grub_relocator_chunk_t ch;
+ err = grub_relocator_alloc_chunk_align (relocator, &ch,
+ addr_min, addr, aligned_size,
+ 0x1000,
+ GRUB_RELOCATOR_PREFERENCE_HIGH,
+ 1);
+ if (err)
+ return err;
+ initrd_mem = get_virtual_current_address (ch);
+ initrd_mem_target = get_physical_target_address (ch);
+ }
+
+ if (grub_initrd_load (&initrd_ctx, argv, initrd_mem))
+ goto fail;
+
+ grub_dprintf ("linux", "Initrd, addr=0x%x, size=0x%x\n",
+ (unsigned) addr, (unsigned) size);
+
+ linux_params.ramdisk_image = initrd_mem_target;
+ linux_params.ramdisk_size = size;
+ linux_params.root_dev = 0x0100; /* XXX */
+
+ fail:
+ grub_initrd_close (&initrd_ctx);
+
+ return grub_errno;
+}
+
+static grub_err_t
+ventoy_cmd_initrd (grub_command_t cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ int i;
+ char buf[64];
+ char *newargv[32] = {NULL};
+
+ if (ventoy_debug) grub_printf("ventoy_cmd_initrd %d\n", ventoy_linux_argc);
+
+ if (ventoy_linux_argc == 0)
+ {
+ return grub_cmd_initrd(cmd, argc, argv);
+ }
+
+ grub_snprintf(buf, sizeof(buf), "mem:%s:size:%s", grub_env_get("ventoy_cpio_addr"), grub_env_get("ventoy_cpio_size"));
+
+ if (ventoy_debug) grub_printf("membuf=%s\n", buf);
+
+ newargv[0] = buf;
+ for (i = 0; i < argc; i++)
+ {
+ newargv[i + 1] = argv[i];
+ }
+
+ ventoy_initrd_called = 1;
+
+ return grub_cmd_initrd(cmd, argc + 1, newargv);
+}
+
+
+static grub_command_t cmd_linux, cmd_initrd, cmd_linuxefi, cmd_initrdefi, cmd_set_bootopt, cmd_unset_bootopt;
+
+GRUB_MOD_INIT(linux)
+{
+ cmd_linux = grub_register_command ("linux", grub_cmd_linux,
+ 0, N_("Load Linux."));
+ cmd_initrd = grub_register_command ("initrd", ventoy_cmd_initrd,
+ 0, N_("Load initrd."));
+
+ cmd_linuxefi = grub_register_command ("linuxefi", grub_cmd_linux,
+ 0, N_("Load Linux."));
+ cmd_initrdefi = grub_register_command ("initrdefi", ventoy_cmd_initrd,
+ 0, N_("Load initrd."));
+ cmd_set_bootopt = grub_register_command ("vt_set_boot_opt", grub_cmd_set_boot_opt, 0, N_("set ext boot opt"));
+ cmd_unset_bootopt = grub_register_command ("vt_unset_boot_opt", grub_cmd_unset_boot_opt, 0, N_("unset ext boot opt"));
+
+ ventoy_linux_args = grub_zalloc(sizeof(char *) * LINUX_MAX_ARGC);
+
+ my_mod = mod;
+}
+
+GRUB_MOD_FINI(linux)
+{
+ grub_unregister_command (cmd_linux);
+ grub_unregister_command (cmd_initrd);
+}
--- /dev/null
+/* main.c - the normal mode main routine */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2000,2001,2002,2003,2005,2006,2007,2008,2009 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/kernel.h>
+#include <grub/normal.h>
+#include <grub/dl.h>
+#include <grub/menu.h>
+#include <grub/misc.h>
+#include <grub/file.h>
+#include <grub/mm.h>
+#include <grub/term.h>
+#include <grub/env.h>
+#include <grub/parser.h>
+#include <grub/reader.h>
+#include <grub/menu_viewer.h>
+#include <grub/auth.h>
+#include <grub/i18n.h>
+#include <grub/charset.h>
+#include <grub/script_sh.h>
+#include <grub/bufio.h>
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+#define GRUB_DEFAULT_HISTORY_SIZE 50
+
+static int nested_level = 0;
+int grub_normal_exit_level = 0;
+
+void
+grub_normal_free_menu (grub_menu_t menu)
+{
+ grub_menu_entry_t entry = menu->entry_list;
+
+ while (entry)
+ {
+ grub_menu_entry_t next_entry = entry->next;
+ grub_size_t i;
+
+ if (entry->classes)
+ {
+ struct grub_menu_entry_class *class;
+ for (class = entry->classes; class; class = class->next)
+ grub_free (class->name);
+ grub_free (entry->classes);
+ }
+
+ if (entry->args)
+ {
+ for (i = 0; entry->args[i]; i++)
+ grub_free (entry->args[i]);
+ grub_free (entry->args);
+ }
+
+ if (entry->bls)
+ {
+ entry->bls->visible = 0;
+ }
+
+ grub_free ((void *) entry->id);
+ grub_free ((void *) entry->users);
+ grub_free ((void *) entry->title);
+ grub_free ((void *) entry->sourcecode);
+ grub_free (entry);
+ entry = next_entry;
+ }
+
+ grub_free (menu);
+ grub_env_unset_menu ();
+}
+
+/* Helper for read_config_file. */
+static grub_err_t
+read_config_file_getline (char **line, int cont __attribute__ ((unused)),
+ void *data)
+{
+ grub_file_t file = data;
+
+ while (1)
+ {
+ char *buf;
+
+ *line = buf = grub_file_getline (file);
+ if (! buf)
+ return grub_errno;
+
+ if (buf[0] == '#')
+ grub_free (*line);
+ else
+ break;
+ }
+
+ return GRUB_ERR_NONE;
+}
+
+static grub_menu_t
+read_config_file (const char *config)
+{
+ grub_file_t rawfile, file;
+ char *old_file = 0, *old_dir = 0;
+ char *config_dir, *ptr = 0;
+ const char *ctmp;
+
+ grub_menu_t newmenu;
+
+ newmenu = grub_env_get_menu ();
+ if (! newmenu)
+ {
+ newmenu = grub_zalloc (sizeof (*newmenu));
+ if (! newmenu)
+ return 0;
+
+ grub_env_set_menu (newmenu);
+ }
+
+ /* Try to open the config file. */
+ rawfile = grub_file_open (config, GRUB_FILE_TYPE_CONFIG);
+ if (! rawfile)
+ return 0;
+
+ file = grub_bufio_open (rawfile, 0);
+ if (! file)
+ {
+ grub_file_close (rawfile);
+ return 0;
+ }
+
+ ctmp = grub_env_get ("config_file");
+ if (ctmp)
+ old_file = grub_strdup (ctmp);
+ ctmp = grub_env_get ("config_directory");
+ if (ctmp)
+ old_dir = grub_strdup (ctmp);
+ if (*config == '(')
+ {
+ grub_env_set ("config_file", config);
+ config_dir = grub_strdup (config);
+ }
+ else
+ {
+ /* $root is guranteed to be defined, otherwise open above would fail */
+ config_dir = grub_xasprintf ("(%s)%s", grub_env_get ("root"), config);
+ if (config_dir)
+ grub_env_set ("config_file", config_dir);
+ }
+ if (config_dir)
+ {
+ ptr = grub_strrchr (config_dir, '/');
+ if (ptr)
+ *ptr = 0;
+ grub_env_set ("config_directory", config_dir);
+ grub_free (config_dir);
+ }
+
+ grub_env_export ("config_file");
+ grub_env_export ("config_directory");
+
+ while (1)
+ {
+ char *line;
+
+ /* Print an error, if any. */
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+
+ if ((read_config_file_getline (&line, 0, file)) || (! line))
+ break;
+
+ grub_normal_parse_line (line, read_config_file_getline, file);
+ grub_free (line);
+ }
+
+ if (old_file)
+ grub_env_set ("config_file", old_file);
+ else
+ grub_env_unset ("config_file");
+ if (old_dir)
+ grub_env_set ("config_directory", old_dir);
+ else
+ grub_env_unset ("config_directory");
+ grub_free (old_file);
+ grub_free (old_dir);
+
+ grub_file_close (file);
+
+ return newmenu;
+}
+
+/* Initialize the screen. */
+void
+grub_normal_init_page (struct grub_term_output *term,
+ int y)
+{
+ grub_ssize_t msg_len;
+ int posx;
+ char *msg_formatted;
+ grub_uint32_t *unicode_msg;
+ grub_uint32_t *last_position;
+
+ grub_term_cls (term);
+
+ msg_formatted = grub_xasprintf (_("GNU GRUB version %s"), PACKAGE_VERSION);
+ if (!msg_formatted)
+ return;
+
+ msg_len = grub_utf8_to_ucs4_alloc (msg_formatted,
+ &unicode_msg, &last_position);
+ grub_free (msg_formatted);
+
+ if (msg_len < 0)
+ {
+ return;
+ }
+
+ posx = grub_getstringwidth (unicode_msg, last_position, term);
+ posx = ((int) grub_term_width (term) - posx) / 2;
+ if (posx < 0)
+ posx = 0;
+ grub_term_gotoxy (term, (struct grub_term_coordinate) { posx, y });
+
+ grub_print_ucs4 (unicode_msg, last_position, 0, 0, term);
+ grub_putcode ('\n', term);
+ grub_putcode ('\n', term);
+ grub_free (unicode_msg);
+}
+
+static void
+read_lists (const char *val)
+{
+ if (! grub_no_modules)
+ {
+ read_command_list (val);
+ read_fs_list (val);
+ read_crypto_list (val);
+ read_terminal_list (val);
+ }
+ grub_gettext_reread_prefix (val);
+}
+
+static char *
+read_lists_hook (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val)
+{
+ read_lists (val);
+ return val ? grub_strdup (val) : NULL;
+}
+
+/* Read the config file CONFIG and execute the menu interface or
+ the command line interface if BATCH is false. */
+void
+grub_normal_execute (const char *config, int nested, int batch)
+{
+ grub_menu_t menu = 0;
+ const char *prefix;
+
+ if (! nested)
+ {
+ prefix = grub_env_get ("prefix");
+ read_lists (prefix);
+ grub_register_variable_hook ("prefix", NULL, read_lists_hook);
+ }
+
+ grub_boot_time ("Executing config file");
+
+ if (config)
+ {
+ menu = read_config_file (config);
+
+ /* Ignore any error. */
+ grub_errno = GRUB_ERR_NONE;
+ }
+
+ grub_boot_time ("Executed config file");
+
+ if (! batch)
+ {
+ if (menu && menu->size)
+ {
+
+ grub_boot_time ("Entering menu");
+ grub_show_menu (menu, nested, 0);
+ if (nested)
+ grub_normal_free_menu (menu);
+ }
+ }
+}
+
+/* This starts the normal mode. */
+void
+grub_enter_normal_mode (const char *config)
+{
+ grub_boot_time ("Entering normal mode");
+ nested_level++;
+ grub_normal_execute (config, 0, 0);
+ grub_boot_time ("Entering shell");
+ grub_cmdline_run (0, 1);
+ nested_level--;
+ if (grub_normal_exit_level)
+ grub_normal_exit_level--;
+ grub_boot_time ("Exiting normal mode");
+}
+
+/* Enter normal mode from rescue mode. */
+static grub_err_t
+grub_cmd_normal (struct grub_command *cmd __attribute__ ((unused)),
+ int argc, char *argv[])
+{
+ if (argc == 0)
+ {
+ /* Guess the config filename. It is necessary to make CONFIG static,
+ so that it won't get broken by longjmp. */
+ char *config;
+ const char *prefix;
+
+ prefix = grub_env_get ("prefix");
+ if (prefix)
+ {
+ config = grub_xasprintf ("%s/grub.cfg", prefix);
+ if (! config)
+ goto quit;
+
+ grub_enter_normal_mode (config);
+ grub_free (config);
+ }
+ else
+ grub_enter_normal_mode (0);
+ }
+ else
+ grub_enter_normal_mode (argv[0]);
+
+quit:
+ return 0;
+}
+
+/* Exit from normal mode to rescue mode. */
+static grub_err_t
+grub_cmd_normal_exit (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ if (nested_level <= grub_normal_exit_level)
+ return grub_error (GRUB_ERR_BAD_ARGUMENT, "not in normal environment");
+ grub_normal_exit_level++;
+ return GRUB_ERR_NONE;
+}
+
+static grub_err_t
+grub_normal_reader_init (int nested)
+{
+ struct grub_term_output *term;
+ const char *msg_esc = _("ESC at any time exits.");
+ char *msg_formatted;
+
+ msg_formatted = grub_xasprintf (_("Minimal BASH-like line editing is supported. For "
+ "the first word, TAB lists possible command completions. Anywhere "
+ "else TAB lists possible device or file completions. %s"),
+ nested ? msg_esc : "");
+ if (!msg_formatted)
+ return grub_errno;
+
+ FOR_ACTIVE_TERM_OUTPUTS(term)
+ {
+ grub_normal_init_page (term, 1);
+ grub_term_setcursor (term, 1);
+
+ if (grub_term_width (term) > 3 + STANDARD_MARGIN + 20)
+ grub_print_message_indented (msg_formatted, 3, STANDARD_MARGIN, term);
+ else
+ grub_print_message_indented (msg_formatted, 0, 0, term);
+ grub_putcode ('\n', term);
+ grub_putcode ('\n', term);
+ grub_putcode ('\n', term);
+ }
+ grub_free (msg_formatted);
+
+ return 0;
+}
+
+static grub_err_t
+grub_normal_read_line_real (char **line, int cont, int nested)
+{
+ const char *prompt;
+
+ if (cont)
+ /* TRANSLATORS: it's command line prompt. */
+ prompt = _(">");
+ else
+ /* TRANSLATORS: it's command line prompt. */
+ prompt = _("grub>");
+
+ if (!prompt)
+ return grub_errno;
+
+ while (1)
+ {
+ *line = grub_cmdline_get (prompt);
+ if (*line)
+ return 0;
+
+ if (cont || nested)
+ {
+ grub_free (*line);
+ *line = 0;
+ return grub_errno;
+ }
+ }
+
+}
+
+static grub_err_t
+grub_normal_read_line (char **line, int cont,
+ void *data __attribute__ ((unused)))
+{
+ return grub_normal_read_line_real (line, cont, 0);
+}
+
+void
+grub_cmdline_run (int nested, int force_auth)
+{
+ grub_err_t err = GRUB_ERR_NONE;
+
+ do
+ {
+ err = grub_auth_check_authentication (NULL);
+ }
+ while (err && force_auth);
+
+ if (err)
+ {
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+ return;
+ }
+
+ grub_normal_reader_init (nested);
+
+ while (1)
+ {
+ char *line = NULL;
+
+ if (grub_normal_exit_level)
+ break;
+
+ /* Print an error, if any. */
+ grub_print_error ();
+ grub_errno = GRUB_ERR_NONE;
+
+ grub_normal_read_line_real (&line, 0, nested);
+ if (! line)
+ break;
+
+ grub_normal_parse_line (line, grub_normal_read_line, NULL);
+ grub_free (line);
+ }
+}
+
+static char *
+grub_env_write_pager (struct grub_env_var *var __attribute__ ((unused)),
+ const char *val)
+{
+ grub_set_more ((*val == '1'));
+ return grub_strdup (val);
+}
+
+/* clear */
+static grub_err_t
+grub_mini_cmd_clear (struct grub_command *cmd __attribute__ ((unused)),
+ int argc __attribute__ ((unused)),
+ char *argv[] __attribute__ ((unused)))
+{
+ grub_cls ();
+ return 0;
+}
+
+static grub_command_t cmd_clear;
+
+static void (*grub_xputs_saved) (const char *str);
+static const char *features[] = {
+ "feature_chainloader_bpb", "feature_ntldr", "feature_platform_search_hint",
+ "feature_default_font_path", "feature_all_video_module",
+ "feature_menuentry_id", "feature_menuentry_options", "feature_200_final",
+ "feature_nativedisk_cmd", "feature_timeout_style"
+};
+
+GRUB_MOD_INIT(normal)
+{
+ unsigned i;
+
+ grub_boot_time ("Preparing normal module");
+
+ /* Previously many modules depended on gzio. Be nice to user and load it. */
+ grub_dl_load ("gzio");
+ grub_errno = 0;
+
+ grub_normal_auth_init ();
+ grub_context_init ();
+ grub_script_init ();
+ grub_menu_init ();
+
+ grub_xputs_saved = grub_xputs;
+ grub_xputs = grub_xputs_normal;
+
+ /* Normal mode shouldn't be unloaded. */
+ if (mod)
+ grub_dl_ref (mod);
+
+ cmd_clear =
+ grub_register_command ("clear", grub_mini_cmd_clear,
+ 0, N_("Clear the screen."));
+
+ grub_set_history (GRUB_DEFAULT_HISTORY_SIZE);
+
+ grub_register_variable_hook ("pager", 0, grub_env_write_pager);
+ grub_env_export ("pager");
+
+ /* Register a command "normal" for the rescue mode. */
+ grub_register_command ("normal", grub_cmd_normal,
+ 0, N_("Enter normal mode."));
+ grub_register_command ("normal_exit", grub_cmd_normal_exit,
+ 0, N_("Exit from normal mode."));
+
+ /* Reload terminal colors when these variables are written to. */
+ grub_register_variable_hook ("color_normal", NULL, grub_env_write_color_normal);
+ grub_register_variable_hook ("color_highlight", NULL, grub_env_write_color_highlight);
+
+ /* Preserve hooks after context changes. */
+ grub_env_export ("color_normal");
+ grub_env_export ("color_highlight");
+
+ /* Set default color names. */
+ grub_env_set ("color_normal", "light-gray/black");
+ grub_env_set ("color_highlight", "black/light-gray");
+
+ for (i = 0; i < ARRAY_SIZE (features); i++)
+ {
+ grub_env_set (features[i], "y");
+ grub_env_export (features[i]);
+ }
+ grub_env_set ("grub_cpu", GRUB_TARGET_CPU);
+ grub_env_export ("grub_cpu");
+ grub_env_set ("grub_platform", GRUB_PLATFORM);
+ grub_env_export ("grub_platform");
+
+ grub_boot_time ("Normal module prepared");
+}
+
+GRUB_MOD_FINI(normal)
+{
+ grub_context_fini ();
+ grub_script_fini ();
+ grub_menu_fini ();
+ grub_normal_auth_fini ();
+
+ grub_xputs = grub_xputs_saved;
+
+ grub_set_history (0);
+ grub_register_variable_hook ("pager", 0, 0);
+ grub_fs_autoload_hook = 0;
+ grub_unregister_command (cmd_clear);
+}
goto refresh;
case GRUB_TERM_KEY_F2:
+ case '2':
if (0 == g_ventoy_fn_mutex) {
cmdstr = grub_env_get("VTOY_F2_CMD");
if (cmdstr)
}
break;
case GRUB_TERM_KEY_F3:
+ case '3':
if (0 == g_ventoy_fn_mutex) {
cmdstr = grub_env_get("VTOY_F3_CMD");
if (cmdstr)
}
break;
case GRUB_TERM_KEY_F4:
+ case '4':
if (0 == g_ventoy_fn_mutex) {
cmdstr = grub_env_get("VTOY_F4_CMD");
if (cmdstr)
}
break;
case GRUB_TERM_KEY_F5:
+ case '5':
if (0 == g_ventoy_fn_mutex) {
cmdstr = grub_env_get("VTOY_F5_CMD");
if (cmdstr)
}
break;
case GRUB_TERM_KEY_F6:
+ case '6':
if (0 == g_ventoy_fn_mutex) {
cmdstr = grub_env_get("VTOY_F6_CMD");
if (cmdstr)
}
break;
case GRUB_TERM_KEY_F7:
+ case '7':
cmdstr = grub_env_get("VTOY_F7_CMD");
if (cmdstr)
{
}
break;
case GRUB_TERM_KEY_F1:
+ case '1':
menu_fini ();
g_ventoy_memdisk_mode = 1 - g_ventoy_memdisk_mode;
g_ventoy_menu_refresh = 1;
if (nested)
{
+ #if 0
ret += grub_print_message_indented_real
(_("Press enter to boot the selected OS, "
"`e' to edit the commands before booting "
"or `c' for a command-line. ESC to return previous menu."),
STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ #endif
}
else
{
ret += grub_print_message_indented_real("\n", STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
ret += grub_print_message_indented_real(grub_env_get("VTOY_HOTKEY_TIP"),
- STANDARD_MARGIN, STANDARD_MARGIN, term, dry_run);
+ 3, 6, term, dry_run);
}
}
return ret;
#include <grub/i18n.h>
#include <grub/net.h>
#include <grub/misc.h>
+#include <grub/kernel.h>
#ifdef GRUB_MACHINE_EFI
#include <grub/efi/efi.h>
#endif
return (grub_strstr(args[0], args[1])) ? 0 : 1;
}
+static grub_err_t ventoy_cmd_strbegin(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ char *c0, *c1;
+
+ (void)ctxt;
+
+ if (argc != 2)
+ {
+ return 1;
+ }
+
+ c0 = args[0];
+ c1 = args[1];
+
+ while (*c0 && *c1)
+ {
+ if (*c0 != *c1)
+ {
+ return 1;
+ }
+ c0++;
+ c1++;
+ }
+
+ if (*c1)
+ {
+ return 1;
+ }
+
+ return 0;
+}
+
static grub_err_t ventoy_cmd_incr(grub_extcmd_context_t ctxt, int argc, char **args)
{
long value_long = 0;
return 0;
}
-static grub_err_t ventoy_cmd_load_iso_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
+static int ventoy_load_efiboot_template(char **buf, int *datalen, int *direntoff)
+{
+ int len;
+ grub_file_t file;
+ char exec[128];
+ char *data = NULL;
+ grub_uint32_t offset;
+
+ file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s/ventoy/ventoy_efiboot.img.xz", ventoy_get_env("vtoy_efi_part"));
+ if (file == NULL)
+ {
+ debug("failed to open file <%s>\n", "ventoy_efiboot.img.xz");
+ return 1;
+ }
+
+ len = (int)file->size;
+
+ data = (char *)grub_malloc(file->size);
+ if (!data)
+ {
+ return 1;
+ }
+
+ grub_file_read(file, data, file->size);
+ grub_file_close(file);
+
+ grub_snprintf(exec, sizeof(exec), "loopback efiboot mem:0x%llx:size:%d", (ulonglong)(ulong)data, len);
+ grub_script_execute_sourcecode(exec);
+
+ file = grub_file_open("(efiboot)/EFI/BOOT/BOOTX64.EFI", GRUB_FILE_TYPE_LINUX_INITRD);
+ offset = (grub_uint32_t)grub_iso9660_get_last_file_dirent_pos(file);
+ grub_file_close(file);
+
+ grub_script_execute_sourcecode("loopback -d efiboot");
+
+ *buf = data;
+ *datalen = len;
+ *direntoff = offset + 2;
+
+ return 0;
+}
+
+static grub_err_t ventoy_cmd_concat_efi_iso(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ int len = 0;
+ int totlen = 0;
+ int offset = 0;
+ grub_file_t file;
+ char name[32];
+ char value[32];
+ char *buf = NULL;
+ char *data = NULL;
+ ventoy_iso9660_override *dirent;
+
+ (void)ctxt;
+
+ if (argc != 2)
+ {
+ return 1;
+ }
+
+ totlen = sizeof(ventoy_chain_head);
+
+ if (ventoy_load_efiboot_template(&buf, &len, &offset))
+ {
+ debug("failed to load efiboot template %d\n", len);
+ return 1;
+ }
+
+ totlen += len;
+
+ debug("efiboot template len:%d offset:%d\n", len, offset);
+
+ file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
+ if (file == NULL)
+ {
+ debug("failed to open file <%s>\n", args[0]);
+ return 1;
+ }
+
+ totlen += ventoy_align_2k(file->size);
+
+ dirent = (ventoy_iso9660_override *)(buf + offset);
+ dirent->first_sector = len / 2048;
+ dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
+ dirent->size = (grub_uint32_t)file->size;
+ dirent->size_be = grub_swap_bytes32(dirent->size);
+
+ debug("rawiso len:%d efilen:%d total:%d\n", len, (int)file->size, totlen);
+
+#ifdef GRUB_MACHINE_EFI
+ data = (char *)grub_efi_allocate_iso_buf(totlen);
+#else
+ data = (char *)grub_malloc(totlen);
+#endif
+
+ ventoy_fill_os_param(file, (ventoy_os_param *)data);
+
+ grub_memcpy(data + sizeof(ventoy_chain_head), buf, len);
+ grub_check_free(buf);
+
+ grub_file_read(file, data + sizeof(ventoy_chain_head) + len, file->size);
+ grub_file_close(file);
+
+ grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
+ grub_snprintf(value, sizeof(value), "0x%llx", (ulonglong)(ulong)data);
+ grub_env_set(name, value);
+
+ grub_snprintf(name, sizeof(name), "%s_size", args[1]);
+ grub_snprintf(value, sizeof(value), "%d", (int)(totlen));
+ grub_env_set(name, value);
+
+ return 0;
+}
+
+static grub_err_t ventoy_cmd_load_file_to_mem(grub_extcmd_context_t ctxt, int argc, char **args)
{
int rc = 1;
char name[32];
file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
if (file == NULL)
{
- debug("failed to open file <%s> for udf check\n", args[0]);
+ debug("failed to open file <%s>\n", args[0]);
return 1;
}
return rc;
}
+static grub_err_t ventoy_cmd_load_img_memdisk(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ int rc = 1;
+ int headlen;
+ char name[32];
+ char value[32];
+ char *buf = NULL;
+ grub_file_t file;
+
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ if (argc != 2)
+ {
+ return rc;
+ }
+
+ file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
+ if (file == NULL)
+ {
+ debug("failed to open file <%s> for udf check\n", args[0]);
+ return 1;
+ }
+
+ headlen = sizeof(ventoy_chain_head);
+
+#ifdef GRUB_MACHINE_EFI
+ buf = (char *)grub_efi_allocate_iso_buf(headlen + file->size);
+#else
+ buf = (char *)grub_malloc(headlen + file->size);
+#endif
+
+ ventoy_fill_os_param(file, (ventoy_os_param *)buf);
+
+ grub_file_read(file, buf + headlen, file->size);
+
+ grub_snprintf(name, sizeof(name), "%s_addr", args[1]);
+ grub_snprintf(value, sizeof(value), "0x%llx", (unsigned long long)(unsigned long)buf);
+ grub_env_set(name, value);
+
+ grub_snprintf(name, sizeof(name), "%s_size", args[1]);
+ grub_snprintf(value, sizeof(value), "%llu", (unsigned long long)file->size);
+ grub_env_set(name, value);
+
+ grub_file_close(file);
+ rc = 0;
+
+ return rc;
+}
+
static grub_err_t ventoy_cmd_iso9660_nojoliet(grub_extcmd_context_t ctxt, int argc, char **args)
{
(void)ctxt;
type = img_type_efi;
}
#endif
+ else if (0 == grub_strcasecmp(filename + len - 4, ".img"))
+ {
+ if (len == 18 && grub_strncmp(filename, "ventoy_wimboot", 14) == 0)
+ {
+ return 0;
+ }
+ type = img_type_img;
+ }
else
{
return 0;
static grub_err_t ventoy_cmd_chosen_img_path(grub_extcmd_context_t ctxt, int argc, char **args)
{
int img_id = 0;
+ char value[32];
char *pos = NULL;
const char *id = NULL;
img_info *cur = g_ventoy_img_list;
(void)ctxt;
- if (argc != 1)
+ if (argc < 1 || argc > 2)
{
return grub_error(GRUB_ERR_BAD_ARGUMENT, "Usage: %s {var}", cmd_raw_name);
}
grub_env_set(args[0], cur->path);
+ if (argc > 1)
+ {
+ grub_snprintf(value, sizeof(value), "%llu", (ulonglong)(cur->size));
+ grub_env_set(args[1], value);
+ }
+
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
return 0;
}
+static grub_err_t ventoy_cmd_img_hook_root(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ ventoy_env_hook_root(1);
+
+ return 0;
+}
+
+static grub_err_t ventoy_cmd_img_unhook_root(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ ventoy_env_hook_root(0);
+
+ return 0;
+}
+
grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...)
{
grub_uint64_t size = 0;
{
{ "vt_incr", ventoy_cmd_incr, 0, NULL, "{Var} {INT}", "Increase integer variable", NULL },
{ "vt_strstr", ventoy_cmd_strstr, 0, NULL, "", "", NULL },
+ { "vt_str_begin", ventoy_cmd_strbegin, 0, NULL, "", "", NULL },
{ "vt_debug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
{ "vtdebug", ventoy_cmd_debug, 0, NULL, "{on|off}", "turn debug on/off", NULL },
{ "vtbreak", ventoy_cmd_break, 0, NULL, "{level}", "set debug break", NULL },
{ "vt_img_sector", ventoy_cmd_img_sector, 0, NULL, "{imageName}", "", NULL },
{ "vt_dump_img_sector", ventoy_cmd_dump_img_sector, 0, NULL, "", "", NULL },
{ "vt_load_wimboot", ventoy_cmd_load_wimboot, 0, NULL, "", "", NULL },
+
{ "vt_load_cpio", ventoy_cmd_load_cpio, 0, NULL, "", "", NULL },
+ { "vt_trailer_cpio", ventoy_cmd_trailer_cpio, 0, NULL, "", "", NULL },
+
{ "vt_find_first_bootable_hd", ventoy_cmd_find_bootable_hdd, 0, NULL, "", "", NULL },
{ "vt_dump_menu", ventoy_cmd_dump_menu, 0, NULL, "", "", NULL },
{ "vt_dynamic_menu", ventoy_cmd_dynamic_menu, 0, NULL, "", "", NULL },
{ "vt_iso9660_nojoliet", ventoy_cmd_iso9660_nojoliet, 0, NULL, "", "", NULL },
{ "vt_is_udf", ventoy_cmd_is_udf, 0, NULL, "", "", NULL },
{ "vt_file_size", ventoy_cmd_file_size, 0, NULL, "", "", NULL },
- { "vt_load_iso_to_mem", ventoy_cmd_load_iso_to_mem, 0, NULL, "", "", NULL },
+ { "vt_load_file_to_mem", ventoy_cmd_load_file_to_mem, 0, NULL, "", "", NULL },
+ { "vt_load_img_memdisk", ventoy_cmd_load_img_memdisk, 0, NULL, "", "", NULL },
+ { "vt_concat_efi_iso", ventoy_cmd_concat_efi_iso, 0, NULL, "", "", NULL },
{ "vt_linux_parse_initrd_isolinux", ventoy_cmd_isolinux_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
{ "vt_linux_parse_initrd_grub", ventoy_cmd_grub_initrd_collect, 0, NULL, "{cfgfile}", "", NULL },
{ "vt_unix_replace_ko", ventoy_cmd_unix_replace_ko, 0, NULL, "", "", NULL },
{ "vt_unix_chain_data", ventoy_cmd_unix_chain_data, 0, NULL, "", "", NULL },
+ { "vt_img_hook_root", ventoy_cmd_img_hook_root, 0, NULL, "", "", NULL },
+ { "vt_img_unhook_root", ventoy_cmd_img_unhook_root, 0, NULL, "", "", NULL },
+
};
grub_err_t ventoy_cmd_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args);
grub_err_t ventoy_cmd_valid_initrd_count(grub_extcmd_context_t ctxt, int argc, char **args);
grub_err_t ventoy_cmd_load_cpio(grub_extcmd_context_t ctxt, int argc, char **args);
+grub_err_t ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt, int argc, char **args);
int ventoy_cpio_newc_fill_head(void *buf, int filesize, const void *filedata, const char *name);
grub_file_t ventoy_grub_file_open(enum grub_file_type type, const char *fmt, ...);
grub_uint64_t ventoy_grub_get_file_size(const char *fmt, ...);
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
+static int ventoy_cpio_newc_get_int(char *value)
+{
+ char buf[16] = {0};
+
+ grub_memcpy(buf, value, 8);
+ return (int)grub_strtoul(buf, NULL, 16);
+}
+
static void ventoy_cpio_newc_fill_int(grub_uint32_t value, char *buf, int buflen)
{
int i;
VENTOY_CMD_RETURN(GRUB_ERR_NONE);
}
+grub_err_t ventoy_cmd_trailer_cpio(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ int mod;
+ int bufsize;
+ int namelen;
+ int offset;
+ char *name;
+ grub_uint8_t *bufend;
+ cpio_newc_header *head;
+ grub_file_t file;
+ char value[64];
+ const grub_uint8_t trailler[124] = {
+ 0x30, 0x37, 0x30, 0x37, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x31, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
+ 0x30, 0x30, 0x30, 0x30, 0x30, 0x42, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x54, 0x52,
+ 0x41, 0x49, 0x4C, 0x45, 0x52, 0x21, 0x21, 0x21, 0x00, 0x00, 0x00, 0x00
+ };
+
+ (void)ctxt;
+ (void)argc;
+
+ file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s%s", args[0], args[1]);
+ if (!file)
+ {
+ return 1;
+ }
+
+ grub_memset(g_ventoy_runtime_buf, 0, sizeof(ventoy_os_param));
+ ventoy_fill_os_param(file, (ventoy_os_param *)g_ventoy_runtime_buf);
+
+ grub_file_close(file);
+
+ grub_memcpy(g_ventoy_initrd_head, trailler, sizeof(trailler));
+ bufend = (grub_uint8_t *)g_ventoy_initrd_head + sizeof(trailler);
+
+ bufsize = (int)(bufend - g_ventoy_cpio_buf);
+ mod = bufsize % 512;
+ if (mod)
+ {
+ grub_memset(bufend, 0, 512 - mod);
+ bufsize += 512 - mod;
+ }
+
+ if (argc > 1 && grub_strcmp(args[2], "noinit") == 0)
+ {
+ head = (cpio_newc_header *)g_ventoy_cpio_buf;
+ name = (char *)(head + 1);
+
+ while (grub_strcmp(name, "TRAILER!!!"))
+ {
+ if (grub_strcmp(name, "init") == 0)
+ {
+ grub_memcpy(name, "xxxx", 4);
+ }
+ else if (grub_strcmp(name, "linuxrc") == 0)
+ {
+ grub_memcpy(name, "vtoyxrc", 7);
+ }
+ else if (grub_strcmp(name, "sbin") == 0)
+ {
+ grub_memcpy(name, "vtoy", 4);
+ }
+ else if (grub_strcmp(name, "sbin/init") == 0)
+ {
+ grub_memcpy(name, "vtoy/vtoy", 9);
+ }
+
+ namelen = ventoy_cpio_newc_get_int(head->c_namesize);
+ offset = sizeof(cpio_newc_header) + namelen;
+ offset = ventoy_align(offset, 4);
+ offset += ventoy_cpio_newc_get_int(head->c_filesize);
+ offset = ventoy_align(offset, 4);
+
+ head = (cpio_newc_header *)((char *)head + offset);
+ name = (char *)(head + 1);
+ }
+ }
+
+ grub_snprintf(value, sizeof(value), "0x%llx", (ulonglong)(ulong)g_ventoy_cpio_buf);
+ ventoy_set_env("ventoy_cpio_addr", value);
+ grub_snprintf(value, sizeof(value), "%d", bufsize);
+ ventoy_set_env("ventoy_cpio_size", value);
+
+ VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+
grub_err_t ventoy_cmd_linux_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
{
grub_printf("display_mode: %s\n", value);
}
+ value = vtoy_json_get_string_ex(json->pstChild, "serial_param");
+ if (value)
+ {
+ grub_printf("serial_param %s\n", value);
+ }
+
value = vtoy_json_get_string_ex(json->pstChild, "ventoy_left");
if (value)
{
debug("display_mode %s\n", value);
grub_env_set("vtoy_display_mode", value);
}
+
+ value = vtoy_json_get_string_ex(json->pstChild, "serial_param");
+ if (value)
+ {
+ debug("serial_param %s\n", value);
+ grub_env_set("vtoy_serial_param", value);
+ }
value = vtoy_json_get_string_ex(json->pstChild, "ventoy_left");
if (value)
--- /dev/null
+/******************************************************************************
+ * ventoy_unix.c
+ *
+ * Copyright (c) 2020, longpanda <admin@ventoy.net>
+ *
+ * This program 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.
+ *
+ * This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <grub/types.h>
+#include <grub/misc.h>
+#include <grub/mm.h>
+#include <grub/err.h>
+#include <grub/dl.h>
+#include <grub/disk.h>
+#include <grub/device.h>
+#include <grub/term.h>
+#include <grub/partition.h>
+#include <grub/file.h>
+#include <grub/normal.h>
+#include <grub/extcmd.h>
+#include <grub/datetime.h>
+#include <grub/i18n.h>
+#include <grub/net.h>
+#include <grub/time.h>
+#include <grub/ventoy.h>
+#include "ventoy_def.h"
+
+GRUB_MOD_LICENSE ("GPLv3+");
+
+char g_ko_mod_path[256];
+int g_conf_new_len = 0;
+char *g_conf_new_data = NULL;
+
+int g_mod_new_len = 0;
+char *g_mod_new_data = NULL;
+
+grub_uint64_t g_mod_override_offset = 0;
+grub_uint64_t g_conf_override_offset = 0;
+
+static int ventoy_get_file_override(const char *filename, grub_uint64_t *offset)
+{
+ grub_file_t file;
+
+ *offset = 0;
+
+ file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "(loop)%s", filename);
+ if (!file)
+ {
+ return 1;
+ }
+
+ *offset = grub_iso9660_get_last_file_dirent_pos(file) + 2;
+
+ grub_file_close(file);
+
+ return 0;
+}
+
+static grub_uint32_t ventoy_unix_get_override_chunk_count(void)
+{
+ grub_uint32_t count = 0;
+
+ if (g_conf_new_len > 0)
+ {
+ count++;
+ }
+
+ if (g_mod_new_len > 0)
+ {
+ count++;
+ }
+
+ return count;
+}
+
+static grub_uint32_t ventoy_unix_get_virt_chunk_count(void)
+{
+ grub_uint32_t count = 0;
+
+ if (g_conf_new_len > 0)
+ {
+ count++;
+ }
+
+ if (g_mod_new_len > 0)
+ {
+ count++;
+ }
+
+ return count;
+}
+static grub_uint32_t ventoy_unix_get_virt_chunk_size(void)
+{
+ grub_uint32_t size;
+
+ size = sizeof(ventoy_virt_chunk) * ventoy_unix_get_virt_chunk_count();
+
+ if (g_conf_new_len > 0)
+ {
+ size += ventoy_align_2k(g_conf_new_len);
+ }
+
+ if (g_mod_new_len > 0)
+ {
+ size += ventoy_align_2k(g_mod_new_len);
+ }
+
+ return size;
+}
+
+static void ventoy_unix_fill_override_data( grub_uint64_t isosize, void *override)
+{
+ grub_uint64_t sector;
+ ventoy_override_chunk *cur;
+ ventoy_iso9660_override *dirent;
+
+ sector = (isosize + 2047) / 2048;
+
+ cur = (ventoy_override_chunk *)override;
+
+ if (g_conf_new_len > 0)
+ {
+ /* loader.conf */
+ cur->img_offset = g_conf_override_offset;
+ cur->override_size = sizeof(ventoy_iso9660_override);
+ dirent = (ventoy_iso9660_override *)cur->override_data;
+ dirent->first_sector = (grub_uint32_t)sector;
+ dirent->size = (grub_uint32_t)g_conf_new_len;
+ dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
+ dirent->size_be = grub_swap_bytes32(dirent->size);
+ sector += (dirent->size + 2047) / 2048;
+ }
+
+ if (g_mod_new_len > 0)
+ {
+ /* mod.ko */
+ cur++;
+ cur->img_offset = g_mod_override_offset;
+ cur->override_size = sizeof(ventoy_iso9660_override);
+ dirent = (ventoy_iso9660_override *)cur->override_data;
+ dirent->first_sector = (grub_uint32_t)sector;
+ dirent->size = (grub_uint32_t)g_mod_new_len;
+ dirent->first_sector_be = grub_swap_bytes32(dirent->first_sector);
+ dirent->size_be = grub_swap_bytes32(dirent->size);
+ sector += (dirent->size + 2047) / 2048;
+ }
+
+ return;
+}
+
+static void ventoy_unix_fill_virt_data( grub_uint64_t isosize, ventoy_chain_head *chain)
+{
+ grub_uint64_t sector;
+ grub_uint32_t offset;
+ grub_uint32_t data_secs;
+ char *override;
+ ventoy_virt_chunk *cur;
+
+ override = (char *)chain + chain->virt_chunk_offset;
+ cur = (ventoy_virt_chunk *)override;
+
+ sector = (isosize + 2047) / 2048;
+ offset = 2 * sizeof(ventoy_virt_chunk);
+
+ if (g_conf_new_len > 0)
+ {
+ ventoy_unix_fill_virt(g_conf_new_data, g_conf_new_len);
+ }
+
+ if (g_mod_new_len > 0)
+ {
+ ventoy_unix_fill_virt(g_mod_new_data, g_mod_new_len);
+ }
+
+ return;
+}
+
+static int ventoy_freebsd_append_conf(char *buf, const char *isopath)
+{
+ int pos = 0;
+ grub_uint32_t i;
+ grub_disk_t disk;
+ grub_file_t isofile;
+ char uuid[64] = {0};
+ ventoy_img_chunk *chunk;
+ grub_uint8_t disk_guid[16];
+
+ debug("ventoy_freebsd_append_conf %s\n", isopath);
+
+ isofile = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", isopath);
+ if (!isofile)
+ {
+ return 1;
+ }
+
+ vtoy_ssprintf(buf, pos, "ventoy_load=\"%s\"\n", "YES");
+ vtoy_ssprintf(buf, pos, "ventoy_name=\"%s\"\n", g_ko_mod_path);
+
+ disk = isofile->device->disk;
+
+ ventoy_get_disk_guid(isofile->name, disk_guid);
+
+ for (i = 0; i < 16; i++)
+ {
+ grub_snprintf(uuid + i * 2, sizeof(uuid), "%02x", disk_guid[i]);
+ }
+
+ vtoy_ssprintf(buf, pos, "hint.ventoy.0.disksize=%llu\n", (ulonglong)(disk->total_sectors * (1 << disk->log_sector_size)));
+ vtoy_ssprintf(buf, pos, "hint.ventoy.0.diskuuid=\"%s\"\n", uuid);
+ vtoy_ssprintf(buf, pos, "hint.ventoy.0.segnum=%u\n", g_img_chunk_list.cur_chunk);
+
+ for (i = 0; i < g_img_chunk_list.cur_chunk; i++)
+ {
+ chunk = g_img_chunk_list.chunk + i;
+ vtoy_ssprintf(buf, pos, "hint.ventoy.%u.seg=\"0x%llx@0x%llx\"\n",
+ i, (ulonglong)(chunk->disk_start_sector * 512),
+ (ulonglong)((chunk->disk_end_sector + 1) * 512));
+ }
+
+ grub_file_close(isofile);
+
+ return pos;
+}
+
+grub_err_t ventoy_cmd_unix_reset(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ g_conf_new_len = 0;
+ g_mod_new_len = 0;
+ g_mod_override_offset = 0;
+ g_conf_override_offset = 0;
+
+ check_free(g_mod_new_data, grub_free);
+ check_free(g_conf_new_data, grub_free);
+
+ VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+
+grub_err_t ventoy_cmd_parse_freenas_ver(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ grub_file_t file;
+ const char *ver = NULL;
+ char *buf = NULL;
+ VTOY_JSON *json = NULL;
+
+ (void)ctxt;
+ (void)argc;
+
+ file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
+ if (!file)
+ {
+ debug("Failed to open file %s\n", args[0]);
+ return 1;
+ }
+
+ buf = grub_malloc(file->size + 2);
+ if (!buf)
+ {
+ grub_file_close(file);
+ return 0;
+ }
+ grub_file_read(file, buf, file->size);
+ buf[file->size] = 0;
+
+ json = vtoy_json_create();
+ if (!json)
+ {
+ goto end;
+ }
+
+ if (vtoy_json_parse(json, buf))
+ {
+ goto end;
+ }
+
+ ver = vtoy_json_get_string_ex(json->pstChild, "Version");
+ if (ver)
+ {
+ debug("freenas version:<%s>\n", ver);
+ ventoy_set_env(args[1], ver);
+ }
+ else
+ {
+ debug("freenas version:<%s>\n", "NOT FOUND");
+ grub_env_unset(args[1]);
+ }
+
+end:
+ grub_check_free(buf);
+ check_free(json, vtoy_json_destroy);
+ grub_file_close(file);
+
+ VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+
+grub_err_t ventoy_cmd_unix_freebsd_ver(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ grub_file_t file;
+ char *buf;
+ char *start = NULL;
+ char *nextline = NULL;
+
+ (void)ctxt;
+ (void)argc;
+ (void)args;
+
+ file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[0]);
+ if (!file)
+ {
+ debug("Failed to open file %s\n", args[0]);
+ return 1;
+ }
+
+ buf = grub_zalloc(file->size + 2);
+ if (!buf)
+ {
+ grub_file_close(file);
+ return 0;
+ }
+ grub_file_read(file, buf, file->size);
+
+ for (start = buf; start; start = nextline)
+ {
+ if (grub_strncmp(start, "USERLAND_VERSION", 16) == 0)
+ {
+ nextline = start;
+ while (*nextline && *nextline != '\r' && *nextline != '\n')
+ {
+ nextline++;
+ }
+
+ *nextline = 0;
+ break;
+ }
+ nextline = ventoy_get_line(start);
+ }
+
+ if (start)
+ {
+ debug("freebsd version:<%s>\n", start);
+ ventoy_set_env(args[1], start);
+ }
+ else
+ {
+ debug("freebsd version:<%s>\n", "NOT FOUND");
+ grub_env_unset(args[1]);
+ }
+
+ grub_free(buf);
+ grub_file_close(file);
+
+ VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+
+grub_err_t ventoy_cmd_unix_replace_conf(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ grub_uint32_t i;
+ char *data;
+ grub_uint64_t offset;
+ grub_file_t file;
+ const char *confile = NULL;
+ const char * loader_conf[] =
+ {
+ "/boot/loader.conf",
+ "/boot/defaults/loader.conf",
+ };
+
+ (void)ctxt;
+
+ if (argc != 2)
+ {
+ debug("Replace conf invalid argc %d\n", argc);
+ return 1;
+ }
+
+ for (i = 0; i < sizeof(loader_conf) / sizeof(loader_conf[0]); i++)
+ {
+ if (ventoy_get_file_override(loader_conf[i], &offset) == 0)
+ {
+ confile = loader_conf[i];
+ g_conf_override_offset = offset;
+ break;
+ }
+ }
+
+ if (confile == NULL)
+ {
+ debug("Can't find loader.conf file from %u locations\n", i);
+ return 1;
+ }
+
+ file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "(loop)/%s", confile);
+ if (!file)
+ {
+ debug("Failed to open %s \n", confile);
+ return 1;
+ }
+
+ debug("old conf file size:%d\n", (int)file->size);
+
+ data = grub_malloc(VTOY_MAX_SCRIPT_BUF);
+ if (!data)
+ {
+ grub_file_close(file);
+ return 1;
+ }
+
+ grub_file_read(file, data, file->size);
+ grub_file_close(file);
+
+ g_conf_new_data = data;
+ g_conf_new_len = (int)file->size;
+
+ if (grub_strcmp(args[0], "FreeBSD") == 0)
+ {
+ g_conf_new_len += ventoy_freebsd_append_conf(data + file->size, args[1]);
+ }
+
+ VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+
+grub_err_t ventoy_cmd_unix_replace_ko(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ char *data;
+ grub_uint64_t offset;
+ grub_file_t file;
+
+ (void)ctxt;
+
+ if (argc != 2)
+ {
+ debug("Replace ko invalid argc %d\n", argc);
+ return 1;
+ }
+
+ debug("replace ko %s\n", args[0]);
+
+ if (ventoy_get_file_override(args[0], &offset) == 0)
+ {
+ grub_snprintf(g_ko_mod_path, sizeof(g_ko_mod_path), "%s", args[0]);
+ g_mod_override_offset = offset;
+ }
+ else
+ {
+ debug("Can't find replace ko file from %s\n", args[0]);
+ return 1;
+ }
+
+ file = ventoy_grub_file_open(GRUB_FILE_TYPE_LINUX_INITRD, "%s", args[1]);
+ if (!file)
+ {
+ debug("Failed to open %s \n", args[1]);
+ return 1;
+ }
+
+ debug("new ko file size:%d\n", (int)file->size);
+
+ data = grub_malloc(file->size);
+ if (!data)
+ {
+ grub_file_close(file);
+ return 1;
+ }
+
+ grub_file_read(file, data, file->size);
+ grub_file_close(file);
+
+ g_mod_new_data = data;
+ g_mod_new_len = (int)file->size;
+
+ VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+
+grub_err_t ventoy_cmd_unix_chain_data(grub_extcmd_context_t ctxt, int argc, char **args)
+{
+ int ventoy_compatible = 0;
+ grub_uint32_t size = 0;
+ grub_uint64_t isosize = 0;
+ grub_uint32_t boot_catlog = 0;
+ grub_uint32_t img_chunk_size = 0;
+ grub_uint32_t override_count = 0;
+ grub_uint32_t override_size = 0;
+ grub_uint32_t virt_chunk_size = 0;
+ grub_file_t file;
+ grub_disk_t disk;
+ const char *pLastChain = NULL;
+ const char *compatible;
+ ventoy_chain_head *chain;
+ char envbuf[64];
+
+ (void)ctxt;
+ (void)argc;
+
+ compatible = grub_env_get("ventoy_compatible");
+ if (compatible && compatible[0] == 'Y')
+ {
+ ventoy_compatible = 1;
+ }
+
+ if (NULL == g_img_chunk_list.chunk)
+ {
+ grub_printf("ventoy not ready\n");
+ return 1;
+ }
+
+ file = ventoy_grub_file_open(VENTOY_FILE_TYPE, "%s", args[0]);
+ if (!file)
+ {
+ return 1;
+ }
+
+ isosize = file->size;
+
+ boot_catlog = ventoy_get_iso_boot_catlog(file);
+ if (boot_catlog)
+ {
+ if (ventoy_is_efi_os() && (!ventoy_has_efi_eltorito(file, boot_catlog)))
+ {
+ grub_env_set("LoadIsoEfiDriver", "on");
+ }
+ }
+ else
+ {
+ if (ventoy_is_efi_os())
+ {
+ grub_env_set("LoadIsoEfiDriver", "on");
+ }
+ else
+ {
+ return grub_error(GRUB_ERR_BAD_ARGUMENT, "File %s is not bootable", args[0]);
+ }
+ }
+
+ img_chunk_size = g_img_chunk_list.cur_chunk * sizeof(ventoy_img_chunk);
+
+ if (ventoy_compatible)
+ {
+ size = sizeof(ventoy_chain_head) + img_chunk_size;
+ }
+ else
+ {
+ override_count = ventoy_unix_get_override_chunk_count();
+ override_size = override_count * sizeof(ventoy_override_chunk);
+
+ virt_chunk_size = ventoy_unix_get_virt_chunk_size();
+ size = sizeof(ventoy_chain_head) + img_chunk_size + override_size + virt_chunk_size;
+ }
+
+ pLastChain = grub_env_get("vtoy_chain_mem_addr");
+ if (pLastChain)
+ {
+ chain = (ventoy_chain_head *)grub_strtoul(pLastChain, NULL, 16);
+ if (chain)
+ {
+ debug("free last chain memory %p\n", chain);
+ grub_free(chain);
+ }
+ }
+
+ chain = grub_malloc(size);
+ if (!chain)
+ {
+ grub_printf("Failed to alloc chain memory size %u\n", size);
+ grub_file_close(file);
+ return 1;
+ }
+
+ grub_snprintf(envbuf, sizeof(envbuf), "0x%lx", (unsigned long)chain);
+ grub_env_set("vtoy_chain_mem_addr", envbuf);
+ grub_snprintf(envbuf, sizeof(envbuf), "%u", size);
+ grub_env_set("vtoy_chain_mem_size", envbuf);
+
+ grub_memset(chain, 0, sizeof(ventoy_chain_head));
+
+ /* part 1: os parameter */
+ g_ventoy_chain_type = ventoy_chain_linux;
+ ventoy_fill_os_param(file, &(chain->os_param));
+
+ /* part 2: chain head */
+ disk = file->device->disk;
+ chain->disk_drive = disk->id;
+ chain->disk_sector_size = (1 << disk->log_sector_size);
+ chain->real_img_size_in_bytes = file->size;
+ chain->virt_img_size_in_bytes = (file->size + 2047) / 2048 * 2048;
+ chain->boot_catalog = boot_catlog;
+
+ if (!ventoy_is_efi_os())
+ {
+ grub_file_seek(file, boot_catlog * 2048);
+ grub_file_read(file, chain->boot_catalog_sector, sizeof(chain->boot_catalog_sector));
+ }
+
+ /* part 3: image chunk */
+ chain->img_chunk_offset = sizeof(ventoy_chain_head);
+ chain->img_chunk_num = g_img_chunk_list.cur_chunk;
+ grub_memcpy((char *)chain + chain->img_chunk_offset, g_img_chunk_list.chunk, img_chunk_size);
+
+ if (ventoy_compatible)
+ {
+ return 0;
+ }
+
+ /* part 4: override chunk */
+ chain->override_chunk_offset = chain->img_chunk_offset + img_chunk_size;
+ chain->override_chunk_num = override_count;
+ ventoy_unix_fill_override_data(isosize, (char *)chain + chain->override_chunk_offset);
+
+ /* part 5: virt chunk */
+ chain->virt_chunk_offset = chain->override_chunk_offset + override_size;
+ chain->virt_chunk_num = ventoy_unix_get_virt_chunk_count();
+ ventoy_unix_fill_virt_data(isosize, chain);
+
+ grub_file_close(file);
+
+ VENTOY_CMD_RETURN(GRUB_ERR_NONE);
+}
+
--- /dev/null
+/* compiler.h - macros for various compiler features */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2005,2006,2007,2008,2009,2010,2014 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/>.
+ */
+
+#ifndef GRUB_COMPILER_HEADER
+#define GRUB_COMPILER_HEADER 1
+
+/* GCC version checking borrowed from glibc. */
+#if defined(__GNUC__) && defined(__GNUC_MINOR__)
+# define GNUC_PREREQ(maj,min) \
+ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min))
+#else
+# define GNUC_PREREQ(maj,min) 0
+#endif
+
+/* Does this compiler support compile-time error attributes? */
+#if GNUC_PREREQ(4,3)
+# define ATTRIBUTE_ERROR(msg) \
+ __attribute__ ((__error__ (msg)))
+#else
+# define ATTRIBUTE_ERROR(msg) __attribute__ ((noreturn))
+#endif
+
+#if GNUC_PREREQ(4,4)
+# define GNU_PRINTF gnu_printf
+#else
+# define GNU_PRINTF printf
+#endif
+
+#if GNUC_PREREQ(3,4)
+# define WARN_UNUSED_RESULT __attribute__ ((warn_unused_result))
+#else
+# define WARN_UNUSED_RESULT
+#endif
+
+#define UNUSED __attribute__((__unused__))
+
+#endif /* ! GRUB_COMPILER_HEADER */
--- /dev/null
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2005,2006,2007,2008,2009 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/>.
+ */
+
+#ifndef GRUB_KERNEL_HEADER
+#define GRUB_KERNEL_HEADER 1
+
+#include <grub/types.h>
+#include <grub/symbol.h>
+
+enum
+{
+ OBJ_TYPE_ELF,
+ OBJ_TYPE_MEMDISK,
+ OBJ_TYPE_CONFIG,
+ OBJ_TYPE_PREFIX,
+ OBJ_TYPE_PUBKEY,
+ OBJ_TYPE_DTB
+};
+
+/* The module header. */
+struct grub_module_header
+{
+ /* The type of object. */
+ grub_uint32_t type;
+ /* The size of object (including this header). */
+ grub_uint32_t size;
+};
+
+/* "gmim" (GRUB Module Info Magic). */
+#define GRUB_MODULE_MAGIC 0x676d696d
+
+struct grub_module_info32
+{
+ /* Magic number so we know we have modules present. */
+ grub_uint32_t magic;
+ /* The offset of the modules. */
+ grub_uint32_t offset;
+ /* The size of all modules plus this header. */
+ grub_uint32_t size;
+};
+
+struct grub_module_info64
+{
+ /* Magic number so we know we have modules present. */
+ grub_uint32_t magic;
+ grub_uint32_t padding;
+ /* The offset of the modules. */
+ grub_uint64_t offset;
+ /* The size of all modules plus this header. */
+ grub_uint64_t size;
+};
+
+#ifndef GRUB_UTIL
+/* Space isn't reusable on some platforms. */
+/* On Qemu the preload space is readonly. */
+/* On emu there is no preload space. */
+/* On ieee1275 our code assumes that heap is p=v which isn't guaranteed for module space. */
+#if defined (GRUB_MACHINE_QEMU) || defined (GRUB_MACHINE_EMU) \
+ || defined (GRUB_MACHINE_EFI) \
+ || (defined (GRUB_MACHINE_IEEE1275) && !defined (__sparc__))
+#define GRUB_KERNEL_PRELOAD_SPACE_REUSABLE 0
+#endif
+
+#if defined (GRUB_MACHINE_PCBIOS) || defined (GRUB_MACHINE_COREBOOT) \
+ || defined (GRUB_MACHINE_MULTIBOOT) || defined (GRUB_MACHINE_MIPS_QEMU_MIPS) \
+ || defined (GRUB_MACHINE_MIPS_LOONGSON) || defined (GRUB_MACHINE_ARC) \
+ || (defined (__sparc__) && defined (GRUB_MACHINE_IEEE1275)) \
+ || defined (GRUB_MACHINE_UBOOT) || defined (GRUB_MACHINE_XEN) \
+ || defined(GRUB_MACHINE_XEN_PVH)
+/* FIXME: stack is between 2 heap regions. Move it. */
+#define GRUB_KERNEL_PRELOAD_SPACE_REUSABLE 1
+#endif
+
+#ifndef GRUB_KERNEL_PRELOAD_SPACE_REUSABLE
+#error "Please check if preload space is reusable on this platform!"
+#endif
+
+#if GRUB_TARGET_SIZEOF_VOID_P == 8
+#define grub_module_info grub_module_info64
+#else
+#define grub_module_info grub_module_info32
+#endif
+
+extern grub_addr_t EXPORT_VAR (grub_modbase);
+
+void EXPORT_FUNC(ventoy_env_hook_root)(int hook);
+
+#define FOR_MODULES(var) for (\
+ var = (grub_modbase && ((((struct grub_module_info *) grub_modbase)->magic) == GRUB_MODULE_MAGIC)) ? (struct grub_module_header *) \
+ (grub_modbase + (((struct grub_module_info *) grub_modbase)->offset)) : 0;\
+ var && (grub_addr_t) var \
+ < (grub_modbase + (((struct grub_module_info *) grub_modbase)->size)); \
+ var = (struct grub_module_header *) \
+ (((grub_uint32_t *) var) + ((((struct grub_module_header *) var)->size + sizeof (grub_addr_t) - 1) / sizeof (grub_addr_t)) * (sizeof (grub_addr_t) / sizeof (grub_uint32_t))))
+
+grub_addr_t grub_modules_get_end (void);
+
+#endif
+
+/* The start point of the C code. */
+void grub_main (void) __attribute__ ((noreturn));
+
+/* The machine-specific initialization. This must initialize memory. */
+void grub_machine_init (void);
+
+/* The machine-specific finalization. */
+void EXPORT_FUNC(grub_machine_fini) (int flags);
+
+/* The machine-specific prefix initialization. */
+void
+grub_machine_get_bootlocation (char **device, char **path);
+
+/* Register all the exported symbols. This is automatically generated. */
+void grub_register_exported_symbols (void);
+
+extern void (*EXPORT_VAR(grub_net_poll_cards_idle)) (void);
+
+#endif /* ! GRUB_KERNEL_HEADER */
--- /dev/null
+/* menu.h - Menu model function prototypes and data structures. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/>.
+ */
+
+#ifndef GRUB_MENU_HEADER
+#define GRUB_MENU_HEADER 1
+
+struct bls_entry
+{
+ struct bls_entry *next;
+ struct bls_entry *prev;
+ struct keyval **keyvals;
+ int nkeyvals;
+ char *filename;
+ int visible;
+};
+
+struct grub_menu_entry_class
+{
+ char *name;
+ struct grub_menu_entry_class *next;
+};
+
+/* The menu entry. */
+struct grub_menu_entry
+{
+ /* The title name. */
+ const char *title;
+
+ /* The identifier. */
+ const char *id;
+
+ /* If set means not everybody is allowed to boot this entry. */
+ int restricted;
+
+ /* Allowed users. */
+ const char *users;
+
+ /* The classes associated with the menu entry:
+ used to choose an icon or other style attributes.
+ This is a dummy head node for the linked list, so for an entry E,
+ E.classes->next is the first class if it is not NULL. */
+ struct grub_menu_entry_class *classes;
+
+ /* The sourcecode of the menu entry, used by the editor. */
+ const char *sourcecode;
+
+ /* Parameters to be passed to menu definition. */
+ int argc;
+ char **args;
+
+ int hotkey;
+
+ int submenu;
+
+ /* The next element. */
+ struct grub_menu_entry *next;
+
+ /* BLS used to populate the entry */
+ struct bls_entry *bls;
+};
+typedef struct grub_menu_entry *grub_menu_entry_t;
+
+/* The menu. */
+struct grub_menu
+{
+ /* The size of a menu. */
+ int size;
+
+ /* The list of menu entries. */
+ grub_menu_entry_t entry_list;
+};
+typedef struct grub_menu *grub_menu_t;
+
+/* Callback structure menu viewers can use to provide user feedback when
+ default entries are executed, possibly including fallback entries. */
+typedef struct grub_menu_execute_callback
+{
+ /* Called immediately before ENTRY is booted. */
+ void (*notify_booting) (grub_menu_entry_t entry, void *userdata);
+
+ /* Called when executing one entry has failed, and another entry, ENTRY, will
+ be executed as a fallback. The implementation of this function should
+ delay for a period of at least 2 seconds before returning in order to
+ allow the user time to read the information before it can be lost by
+ executing ENTRY. */
+ void (*notify_fallback) (grub_menu_entry_t entry, void *userdata);
+
+ /* Called when an entry has failed to execute and there is no remaining
+ fallback entry to attempt. */
+ void (*notify_failure) (void *userdata);
+}
+*grub_menu_execute_callback_t;
+
+grub_menu_entry_t grub_menu_get_entry (grub_menu_t menu, int no);
+int grub_menu_get_timeout (void);
+void grub_menu_set_timeout (int timeout);
+void grub_menu_entry_run (grub_menu_entry_t entry);
+int grub_menu_get_default_entry_index (grub_menu_t menu);
+
+void grub_menu_init (void);
+void grub_menu_fini (void);
+
+#endif /* GRUB_MENU_HEADER */
--- /dev/null
+/* normal.h - prototypes for the normal mode */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2003,2005,2006,2007,2008,2009 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/>.
+ */
+
+#ifndef GRUB_NORMAL_HEADER
+#define GRUB_NORMAL_HEADER 1
+
+#include <grub/term.h>
+#include <grub/symbol.h>
+#include <grub/err.h>
+#include <grub/env.h>
+#include <grub/menu.h>
+#include <grub/command.h>
+#include <grub/file.h>
+
+/* The standard left and right margin for some messages. */
+#define STANDARD_MARGIN 6
+
+/* The type of a completion item. */
+enum grub_completion_type
+ {
+ GRUB_COMPLETION_TYPE_COMMAND,
+ GRUB_COMPLETION_TYPE_DEVICE,
+ GRUB_COMPLETION_TYPE_PARTITION,
+ GRUB_COMPLETION_TYPE_FILE,
+ GRUB_COMPLETION_TYPE_ARGUMENT
+ };
+typedef enum grub_completion_type grub_completion_type_t;
+
+extern struct grub_menu_viewer grub_normal_text_menu_viewer;
+extern int grub_normal_exit_level;
+
+/* Defined in `main.c'. */
+void grub_enter_normal_mode (const char *config);
+void grub_normal_execute (const char *config, int nested, int batch);
+struct grub_term_screen_geometry
+{
+ /* The number of entries shown at a time. */
+ int num_entries;
+ int first_entry_y;
+ int first_entry_x;
+ int entry_width;
+ int timeout_y;
+ int timeout_lines;
+ int border;
+ int right_margin;
+};
+
+void grub_menu_init_page (int nested, int edit,
+ struct grub_term_screen_geometry *geo,
+ struct grub_term_output *term);
+void grub_normal_init_page (struct grub_term_output *term, int y);
+char *grub_file_getline (grub_file_t file);
+void grub_cmdline_run (int nested, int force_auth);
+
+/* Defined in `cmdline.c'. */
+char *grub_cmdline_get (const char *prompt);
+grub_err_t grub_set_history (int newsize);
+
+/* Defined in `completion.c'. */
+char *grub_normal_do_completion (char *buf, int *restore,
+ void (*hook) (const char *item, grub_completion_type_t type, int count));
+
+/* Defined in `misc.c'. */
+grub_err_t grub_normal_print_device_info (const char *name);
+
+/* Defined in `color.c'. */
+char *grub_env_write_color_normal (struct grub_env_var *var, const char *val);
+char *grub_env_write_color_highlight (struct grub_env_var *var, const char *val);
+int grub_parse_color_name_pair (grub_uint8_t *ret, const char *name);
+
+/* Defined in `menu_text.c'. */
+void grub_wait_after_message (void);
+void
+grub_print_ucs4 (const grub_uint32_t * str,
+ const grub_uint32_t * last_position,
+ int margin_left, int margin_right,
+ struct grub_term_output *term);
+
+void
+grub_print_ucs4_menu (const grub_uint32_t * str,
+ const grub_uint32_t * last_position,
+ int margin_left, int margin_right,
+ struct grub_term_output *term,
+ int skip_lines, int max_lines, grub_uint32_t contchar,
+ struct grub_term_pos *pos);
+int
+grub_ucs4_count_lines (const grub_uint32_t * str,
+ const grub_uint32_t * last_position,
+ int margin_left, int margin_right,
+ struct grub_term_output *term);
+grub_size_t grub_getstringwidth (grub_uint32_t * str,
+ const grub_uint32_t * last_position,
+ struct grub_term_output *term);
+void grub_print_message_indented (const char *msg, int margin_left,
+ int margin_right,
+ struct grub_term_output *term);
+void
+grub_menu_text_register_instances (int entry, grub_menu_t menu, int nested);
+grub_err_t
+grub_show_menu (grub_menu_t menu, int nested, int autobooted);
+
+/* Defined in `handler.c'. */
+void read_handler_list (void);
+void free_handler_list (void);
+
+/* Defined in `dyncmd.c'. */
+void read_command_list (const char *prefix);
+
+/* Defined in `autofs.c'. */
+void read_fs_list (const char *prefix);
+
+void grub_context_init (void);
+void grub_context_fini (void);
+
+void read_crypto_list (const char *prefix);
+
+void read_terminal_list (const char *prefix);
+
+void grub_set_more (int onoff);
+
+void grub_normal_reset_more (void);
+
+void grub_xputs_normal (const char *str);
+
+extern int grub_extractor_level;
+
+grub_err_t
+grub_normal_add_menu_entry (int argc, const char **args, char **classes,
+ const char *id,
+ const char *users, const char *hotkey,
+ const char *prefix, const char *sourcecode,
+ int submenu, int *index, struct bls_entry *bls);
+
+grub_err_t
+grub_normal_set_password (const char *user, const char *password);
+
+void grub_normal_free_menu (grub_menu_t menu);
+
+void grub_normal_auth_init (void);
+void grub_normal_auth_fini (void);
+
+void
+grub_xnputs (const char *str, grub_size_t msg_len);
+
+grub_command_t
+grub_dyncmd_get_cmd (grub_command_t cmd);
+
+void
+grub_gettext_reread_prefix (const char *val);
+
+enum grub_human_size_type
+ {
+ GRUB_HUMAN_SIZE_NORMAL,
+ GRUB_HUMAN_SIZE_SHORT,
+ GRUB_HUMAN_SIZE_SPEED,
+ };
+
+const char *
+grub_get_human_size (grub_uint64_t size, enum grub_human_size_type type);
+
+#endif /* ! GRUB_NORMAL_HEADER */
fi
cd $VTOY_PATH
-xz -d ventoy.sh.xz
+xz -d ventoy_chain.sh.xz
+xz -d ventoy_loop.sh.xz
if [ -n "$VTOY_REDT_BUG" ]; then
xz -d -c hook.cpio.xz | cpio -idm
--- /dev/null
+# Copyright (C) 2009 Red Hat, Inc. All rights reserved.
+#
+# This file is part of LVM2.
+
+# Udev rules for device-mapper devices.
+#
+# These rules create a DM control node in /dev/mapper directory.
+# The rules also create nodes named dm-x (x is a number) in /dev
+# directory and symlinks to these nodes with names given by
+# the actual DM names. Some udev environment variables are set
+# for use in later rules:
+# DM_NAME - actual DM device's name
+# DM_UUID - UUID set for DM device (blank if not specified)
+# DM_SUSPENDED - suspended state of DM device (0 or 1)
+# DM_UDEV_RULES_VSN - DM udev rules version
+#
+# These rules cover only basic device-mapper functionality in udev.
+#
+# Various DM subsystems may contain further subsystem-specific rules
+# in 11-dm-<subsystem_name>.rules which should be installed together
+# with the DM subsystem and which extend these basic rules.
+# For example:
+# 11-dm-lvm.rules for LVM subsystem
+# 11-dm-mpath.rules for multipath subsystem (since version 0.6.0, recommended!)
+#
+# Even more specific rules may be required by subsystems so always
+# check subsystem's upstream repository for recent set of rules.
+# Also, keep in mind that recent rules may also require recent
+# subsystem-specific binaries.
+
+KERNEL=="device-mapper", NAME="mapper/control"
+
+SUBSYSTEM!="block", GOTO="dm_end"
+KERNEL!="dm-[0-9]*", GOTO="dm_end"
+
+
+# Device created, major and minor number assigned - "add" event generated.
+# Table loaded - no event generated.
+# Device resumed (or renamed) - "change" event generated.
+# Device removed - "remove" event generated.
+#
+# The dm-X nodes are always created, even on "add" event, we can't suppress
+# that (the node is created even earlier with devtmpfs). All the symlinks
+# (e.g. /dev/mapper) are created in right time after a device has its table
+# loaded and is properly resumed. For this reason, direct use of dm-X nodes
+# is not recommended.
+ACTION!="add|change", GOTO="dm_end"
+
+# Decode udev control flags and set environment variables appropriately.
+# These flags are encoded in DM_COOKIE variable that was introduced in
+# kernel version 2.6.31. Therefore, we can use this feature with
+# kernels >= 2.6.31 only. Cookie is not decoded for remove event.
+ENV{DM_COOKIE}=="?*", IMPORT{program}="/usr/sbin/dmsetup udevflags $env{DM_COOKIE}"
+
+# Rule out easy-to-detect inappropriate events first.
+ENV{DISK_RO}=="1", GOTO="dm_disable"
+
+# There is no cookie set nor any flags encoded in events not originating
+# in libdevmapper so we need to detect this and try to behave correctly.
+# For such spurious events, regenerate all flags from current udev database content
+# (this information would normally be inaccessible for spurious ADD and CHANGE events).
+ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}=="1", ENV{DM_ACTIVATION}="1", GOTO="dm_flags_done"
+IMPORT{db}="DM_UDEV_DISABLE_DM_RULES_FLAG"
+IMPORT{db}="DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG"
+IMPORT{db}="DM_UDEV_DISABLE_DISK_RULES_FLAG"
+IMPORT{db}="DM_UDEV_DISABLE_OTHER_RULES_FLAG"
+IMPORT{db}="DM_UDEV_LOW_PRIORITY_FLAG"
+IMPORT{db}="DM_UDEV_DISABLE_LIBRARY_FALLBACK_FLAG"
+IMPORT{db}="DM_UDEV_PRIMARY_SOURCE_FLAG"
+IMPORT{db}="DM_UDEV_FLAG7"
+IMPORT{db}="DM_UDEV_RULES_VSN"
+LABEL="dm_flags_done"
+
+# Normally, we operate on "change" events. But when coldplugging, there's an
+# "add" event present. We have to recognize this and do our actions in this
+# particular situation, too. Also, we don't want the nodes to be created
+# prematurely on "add" events while not coldplugging. We check
+# DM_UDEV_PRIMARY_SOURCE_FLAG to see if the device was activated correctly
+# before and if not, we ignore the "add" event totally. This way we can support
+# udev triggers generating "add" events (e.g. "udevadm trigger --action=add" or
+# "echo add > /sys/block/<dm_device>/uevent"). The trigger with "add" event is
+# also used at boot to reevaluate udev rules for all existing devices activated
+# before (e.g. in initrd). If udev is used in initrd, we require the udev init
+# script to not remove the existing udev database so we can reuse the information
+# stored at the time of device activation in the initrd.
+ACTION!="add", GOTO="dm_no_coldplug"
+ENV{DM_UDEV_RULES_VSN}!="1", ENV{DM_UDEV_PRIMARY_SOURCE_FLAG}!="1", GOTO="dm_disable"
+ENV{DM_ACTIVATION}="1"
+LABEL="dm_no_coldplug"
+
+# Putting it together, following table is used to recognize genuine and spurious events.
+# N.B. Spurious events are generated based on use of the WATCH udev
+# rule or by triggering an event manually by "udevadm trigger" call
+# or by "echo <event_name> > /sys/block/dm-X/uevent".
+#
+# EVENT DM_UDEV_PRIMARY_SOURCE_FLAG DM_ACTIVATION
+# ======================================================================
+# add event (genuine) 0 0
+# change event (genuine) 1 1
+# add event (spurious)
+# |_ dev still not active 0 0
+# \_ dev already active 1 1
+# change event (spurious)
+# |_ dev still not active 0 0
+# \_ dev already active 1 0
+
+# "dm" sysfs subdirectory is available in newer versions of DM
+# only (kernels >= 2.6.29). We have to check for its existence
+# and use dmsetup tool instead to get the DM name, uuid and
+# suspended state if the "dm" subdirectory is not present.
+# The "suspended" item was added even later (kernels >= 2.6.31),
+# so we also have to call dmsetup if the kernel version used
+# is in between these releases.
+TEST=="dm", ENV{DM_NAME}="$attr{dm/name}", ENV{DM_UUID}="$attr{dm/uuid}", ENV{DM_SUSPENDED}="$attr{dm/suspended}"
+TEST!="dm", IMPORT{program}="/usr/sbin/dmsetup info -j %M -m %m -c --nameprefixes --noheadings --rows -o name,uuid,suspended"
+ENV{DM_SUSPENDED}!="?*", IMPORT{program}="/usr/sbin/dmsetup info -j %M -m %m -c --nameprefixes --noheadings --rows -o suspended"
+
+# dmsetup tool provides suspended state information in textual
+# form with values "Suspended"/"Active". We translate it to
+# 0/1 respectively to be consistent with sysfs values.
+ENV{DM_SUSPENDED}=="Active", ENV{DM_SUSPENDED}="0"
+ENV{DM_SUSPENDED}=="Suspended", ENV{DM_SUSPENDED}="1"
+
+# This variable provides a reliable way to check that device-mapper
+# rules were installed. It means that all needed variables are set
+# by these rules directly so there's no need to acquire them again
+# later. Other rules can alternate the functionality based on this
+# fact (e.g. fallback to rules that behave correctly even without
+# these rules installed). It also provides versioning for any
+# possible future changes.
+# VSN 1 - original rules
+# VSN 2 - add support for synthesized events
+ENV{DM_UDEV_RULES_VSN}="2"
+
+ENV{DM_UDEV_DISABLE_DM_RULES_FLAG}!="1", ENV{DM_NAME}=="?*", SYMLINK+="mapper/$env{DM_NAME}"
+
+# Avoid processing and scanning a DM device in the other (foreign)
+# rules if it is in suspended state. However, we still keep 'disk'
+# and 'DM subsystem' related rules enabled in this case.
+ENV{DM_SUSPENDED}=="1", ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1"
+
+GOTO="dm_end"
+
+LABEL="dm_disable"
+ENV{DM_UDEV_DISABLE_SUBSYSTEM_RULES_FLAG}="1"
+ENV{DM_UDEV_DISABLE_DISK_RULES_FLAG}="1"
+ENV{DM_UDEV_DISABLE_OTHER_RULES_FLAG}="1"
+OPTIONS:="nowatch"
+
+LABEL="dm_end"
is_inotify_ventoy_part() {
- if echo $1 | grep -q "2$"; then
+ if echo $1 | $GREP -q "2$"; then
if ! [ -e /sys/block/$1 ]; then
if [ -e /sys/class/block/$1 ]; then
if [ -e /dev/${1:0:-1} ]; then
ventoy_set_inotify_script() {
echo $VTOY_PATH/hook/$1 > $VTOY_PATH/inotifyd-hook-script.txt
}
+
+ventoy_set_loop_inotify_script() {
+ echo $VTOY_PATH/loop/$1 > $VTOY_PATH/inotifyd-loop-script.txt
+}
+
+
# #
####################################################################
[ -d /proc ] || mkdir /proc; mount -t proc proc /proc
-vtcmdline=$(cat /proc/cmdline)
-vtkerver=$(cat /proc/version)
+vtoy_cmdline=$(cat /proc/cmdline)
umount /proc; rm -rf /proc
-echo "kenel version=$vtkerver" >>$VTLOG
-echo "kenel cmdline=$vtcmdline" >>$VTLOG
-
-#break here for debug
-if [ "$VTOY_BREAK_LEVEL" = "01" ] || [ "$VTOY_BREAK_LEVEL" = "11" ]; then
- sleep 5
- echo -e "\n\n\033[32m ################################################# \033[0m"
- echo -e "\033[32m ################ VENTOY DEBUG ################### \033[0m"
- echo -e "\033[32m ################################################# \033[0m \n"
-
- if [ "$VTOY_BREAK_LEVEL" = "11" ]; then
- cat $VTLOG
- fi
- exec $BUSYBOX_PATH/sh
-fi
-
-
-####################################################################
-# #
-# Step 2 : extract real initramfs to / #
-# #
-####################################################################
-cd /
-rm -rf /init /linuxrc /dev/ /root
-
-vtSbinFileNum=$(ls -1 /sbin | wc -l)
-if [ $vtSbinFileNum -eq 1 ]; then
- echo "remove whole sbin directory" >> $VTLOG
- rm -rf /sbin
+if echo $vtoy_cmdline | grep -q 'rdinit=/vtoy/vtoy'; then
+ echo "handover to init_loop" >>$VTLOG
+ rm -f /xxxx /vtoyxrc
+ exec $BUSYBOX_PATH/sh $VTOY_PATH/init_loop
else
- echo "remove only sbin/init file" >> $VTLOG
- ls -l /sbin >> $VTLOG
- rm -f /sbin/init
-fi
-
-ventoy_is_initrd_ramdisk() {
- #As I known, PCLinuxOS use ramdisk
- if echo $vtkerver | grep -i -q 'PCLinuxOS'; then
- true
- else
- false
- fi
-}
-
-ventoy_mount_squashfs() {
- mkdir /dev
- mount -t devtmpfs devtmpfs /dev
- dd if=$1 of=/dev/ram0 status=none
- umount /dev && rm -rf /dev
-}
-
-# param: file skip magic tmp
-ventoy_unpack_initramfs() {
- vtfile=$1; vtskip=$2; vtmagic=$3; vttmp=$4
- echo "=====ventoy_unpack_initramfs: #$*#" >> $VTLOG
-
- #special process
- #if [ "${vtmagic:0:4}" = '5678' ]; then
- # echo -en '\x1F\x8B' | dd status=none of=$vtfile bs=1 count=2 conv=notrunc
- # vtmagic='1F8B'
- #fi
-
- if [ "${vtmagic:0:4}" = '6873' ]; then
- ventoy_mount_squashfs $vtfile
- return
- fi
-
- for vtx in '1F8B zcat' '1F9E zcat' '425A bzcat' '5D00 lzcat' 'FD37 xzcat' '894C lzopcat' '0221 lz4cat' '28B5 zstdcat' '3037 cat'; do
- if [ "${vtx:0:4}" = "${vtmagic:0:4}" ]; then
- echo "vtx=$vtx" >> $VTLOG
- if [ $vtskip -eq 0 ]; then
- if [ "${vtx:5}" = "xzcat" ]; then
- rm -f $VTOY_PATH/xzlog
- ${vtx:5} $vtfile 2> $VTOY_PATH/xzlog | (cpio -idmu 2>>$VTLOG; cat > $vttmp)
-
- if grep -q 'corrupted data' $VTOY_PATH/xzlog; then
- echo 'xzcat failed, now try xzminidec...' >> $VTLOG
- cat $vtfile | xzminidec | (cpio -idmu 2>>$VTLOG; cat > $vttmp)
- fi
-
- else
- ${vtx:5} $vtfile | (cpio -idmu 2>>$VTLOG; cat > $vttmp)
- fi
- else
- dd if=$vtfile skip=$vtskip iflag=skip_bytes status=none | ${vtx:5} | (cpio -idmu 2>>$VTLOG; cat > $vttmp)
- fi
- break
- fi
- done
-}
-
-# param: file magic tmp
-ventoy_unpack_initrd() {
- vtfile=$1; vtmagic=$2; vttmp=$3
- echo "=====ventoy_unpack_initrd: #$*#" >> $VTLOG
-
- for vtx in '1F8B zcat' '1F9E zcat' '425A bzcat' '5D00 lzcat' 'FD37 xzcat' '894C lzopcat' '0221 lz4cat' '28B5 zstdcat' '3037 cat'; do
- if [ "${vtx:0:4}" = "${vtmagic:0:4}" ]; then
- echo "vtx=$vtx" >> $VTLOG
- ${vtx:5} $vtfile > $vttmp
- break
- fi
- done
-}
-
-
-# This export is for busybox cpio command
-export EXTRACT_UNSAFE_SYMLINKS=1
-
-for vtfile in $(ls /initrd*); do
- #decompress first initrd
- vtmagic=$(hexdump -n 2 -e '2/1 "%02X"' $vtfile)
-
- if ventoy_is_initrd_ramdisk; then
- ventoy_unpack_initrd $vtfile $vtmagic ${vtfile}_tmp
- mv ${vtfile}_tmp $vtfile
- break
- else
- ventoy_unpack_initramfs $vtfile 0 $vtmagic ${vtfile}_tmp
- fi
-
- #only for cpio,cpio,...,initrd sequence, initrd,cpio or initrd,initrd sequence is not supported
- while [ -e ${vtfile}_tmp ] && [ $(stat -c '%s' ${vtfile}_tmp) -gt 512 ]; do
- mv ${vtfile}_tmp $vtfile
- vtdump=$(hexdump -n 512 -e '512/1 "%02X"' $vtfile)
- vtmagic=$(echo $vtdump | sed 's/^\(00\)*//')
- let vtoffset="(${#vtdump}-${#vtmagic})/2"
-
- if [ -z "$vtmagic" ]; then
- echo "terminate with all zero data file" >> $VTLOG
- break
- fi
-
- ventoy_unpack_initramfs $vtfile $vtoffset ${vtmagic:0:4} ${vtfile}_tmp
- done
-
- rm -f $vtfile ${vtfile}_tmp
-done
-
-
-#break here for debug
-if [ "$VTOY_BREAK_LEVEL" = "02" ] || [ "$VTOY_BREAK_LEVEL" = "12" ]; then
- sleep 5
- echo -e "\n\n\033[32m ################################################# \033[0m"
- echo -e "\033[32m ################ VENTOY DEBUG ################### \033[0m"
- echo -e "\033[32m ################################################# \033[0m \n"
- if [ "$VTOY_BREAK_LEVEL" = "12" ]; then
- cat $VTOY_PATH/log
- fi
- exec $BUSYBOX_PATH/sh
-fi
-
-
-####################################################################
-# #
-# Step 3 : Extract injection archive #
-# #
-####################################################################
-ventoy_unpack_injection() {
- vtmagic=$(hexdump -n 2 -e '2/1 "%02X"' $VTOY_PATH/ventoy_injection)
- echo "ventoy_unpack_injection vtmagic=$vtmagic ..."
-
- if [ "1F8B" = "$vtmagic" ] || [ "1F9E" = "$vtmagic" ]; then
- echo "tar.gz tar -xzvf"
- tar -xzvf $VTOY_PATH/ventoy_injection -C /
- elif [ "425A" = "$vtmagic" ]; then
- echo "tar.bz2 tar -xjvf"
- tar -xjvf $VTOY_PATH/ventoy_injection -C /
- elif [ "FD37" = "$vtmagic" ]; then
- echo "tar.xz tar -xJvf"
- tar -xJvf $VTOY_PATH/ventoy_injection -C /
- elif [ "5D00" = "$vtmagic" ]; then
- echo "tar.lzma tar -xavf"
- tar -xavf $VTOY_PATH/ventoy_injection -C /
- else
- echo "unzip -o"
- unzip -o $VTOY_PATH/ventoy_injection -d /
- fi
-}
-
-if [ -e $VTOY_PATH/ventoy_injection ]; then
- echo "### decompress injection ... ###" >>$VTLOG
- ventoy_unpack_injection > $VTOY_PATH/injection.log 2>&1
+ echo "handover to init_chain" >>$VTLOG
+ exec $BUSYBOX_PATH/sh $VTOY_PATH/init_chain
fi
-
-
-####################################################################
-# #
-# Step 4 : Hand over to ventoy.sh #
-# #
-####################################################################
-echo "Now hand over to ventoy.sh" >>$VTLOG
-. $VTOY_PATH/tool/vtoytool_install.sh
-
-export PATH=$VTOY_ORG_PATH
-exec $BUSYBOX_PATH/sh $VTOY_PATH/ventoy.sh
--- /dev/null
+#!/ventoy/busybox/sh
+#************************************************************************************
+# Copyright (c) 2020, longpanda <admin@ventoy.net>
+#
+# This program 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.
+#
+# This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+#
+#************************************************************************************
+
+
+###################################################################
+# #
+# Step 1 : parse kernel debug parameter #
+# #
+####################################################################
+[ -d /proc ] || mkdir /proc; mount -t proc proc /proc
+vtcmdline=$(cat /proc/cmdline)
+vtkerver=$(cat /proc/version)
+umount /proc; rm -rf /proc
+
+echo "kenel version=$vtkerver" >>$VTLOG
+echo "kenel cmdline=$vtcmdline" >>$VTLOG
+
+#break here for debug
+if [ "$VTOY_BREAK_LEVEL" = "01" ] || [ "$VTOY_BREAK_LEVEL" = "11" ]; then
+ sleep 5
+ echo -e "\n\n\033[32m ################################################# \033[0m"
+ echo -e "\033[32m ################ VENTOY DEBUG ################### \033[0m"
+ echo -e "\033[32m ################################################# \033[0m \n"
+
+ if [ "$VTOY_BREAK_LEVEL" = "11" ]; then
+ cat $VTLOG
+ fi
+ exec $BUSYBOX_PATH/sh
+fi
+
+
+####################################################################
+# #
+# Step 2 : extract real initramfs to / #
+# #
+####################################################################
+cd /
+rm -rf /init /linuxrc /dev/ /root
+
+vtSbinFileNum=$(ls -1 /sbin | wc -l)
+if [ $vtSbinFileNum -eq 1 ]; then
+ echo "remove whole sbin directory" >> $VTLOG
+ rm -rf /sbin
+else
+ echo "remove only sbin/init file" >> $VTLOG
+ ls -l /sbin >> $VTLOG
+ rm -f /sbin/init
+fi
+
+ventoy_is_initrd_ramdisk() {
+ #As I known, PCLinuxOS use ramdisk
+ if echo $vtkerver | grep -i -q 'PCLinuxOS'; then
+ true
+ else
+ false
+ fi
+}
+
+ventoy_mount_squashfs() {
+ mkdir /dev
+ mount -t devtmpfs devtmpfs /dev
+ dd if=$1 of=/dev/ram0 status=none
+ umount /dev && rm -rf /dev
+}
+
+# param: file skip magic tmp
+ventoy_unpack_initramfs() {
+ vtfile=$1; vtskip=$2; vtmagic=$3; vttmp=$4
+ echo "=====ventoy_unpack_initramfs: #$*#" >> $VTLOG
+
+ #special process
+ #if [ "${vtmagic:0:4}" = '5678' ]; then
+ # echo -en '\x1F\x8B' | dd status=none of=$vtfile bs=1 count=2 conv=notrunc
+ # vtmagic='1F8B'
+ #fi
+
+ if [ "${vtmagic:0:4}" = '6873' ]; then
+ ventoy_mount_squashfs $vtfile
+ return
+ fi
+
+ for vtx in '1F8B zcat' '1F9E zcat' '425A bzcat' '5D00 lzcat' 'FD37 xzcat' '894C lzopcat' '0221 lz4cat' '28B5 zstdcat' '3037 cat'; do
+ if [ "${vtx:0:4}" = "${vtmagic:0:4}" ]; then
+ echo "vtx=$vtx" >> $VTLOG
+ if [ $vtskip -eq 0 ]; then
+ if [ "${vtx:5}" = "xzcat" ]; then
+ rm -f $VTOY_PATH/xzlog
+ ${vtx:5} $vtfile 2> $VTOY_PATH/xzlog | (cpio -idmu 2>>$VTLOG; cat > $vttmp)
+
+ if grep -q 'corrupted data' $VTOY_PATH/xzlog; then
+ echo 'xzcat failed, now try xzminidec...' >> $VTLOG
+ cat $vtfile | xzminidec | (cpio -idmu 2>>$VTLOG; cat > $vttmp)
+ fi
+
+ else
+ ${vtx:5} $vtfile | (cpio -idmu 2>>$VTLOG; cat > $vttmp)
+ fi
+ else
+ dd if=$vtfile skip=$vtskip iflag=skip_bytes status=none | ${vtx:5} | (cpio -idmu 2>>$VTLOG; cat > $vttmp)
+ fi
+ break
+ fi
+ done
+}
+
+# param: file magic tmp
+ventoy_unpack_initrd() {
+ vtfile=$1; vtmagic=$2; vttmp=$3
+ echo "=====ventoy_unpack_initrd: #$*#" >> $VTLOG
+
+ for vtx in '1F8B zcat' '1F9E zcat' '425A bzcat' '5D00 lzcat' 'FD37 xzcat' '894C lzopcat' '0221 lz4cat' '28B5 zstdcat' '3037 cat'; do
+ if [ "${vtx:0:4}" = "${vtmagic:0:4}" ]; then
+ echo "vtx=$vtx" >> $VTLOG
+ ${vtx:5} $vtfile > $vttmp
+ break
+ fi
+ done
+}
+
+
+# This export is for busybox cpio command
+export EXTRACT_UNSAFE_SYMLINKS=1
+
+for vtfile in $(ls /initrd*); do
+ #decompress first initrd
+ vtmagic=$(hexdump -n 2 -e '2/1 "%02X"' $vtfile)
+
+ if ventoy_is_initrd_ramdisk; then
+ ventoy_unpack_initrd $vtfile $vtmagic ${vtfile}_tmp
+ mv ${vtfile}_tmp $vtfile
+ break
+ else
+ ventoy_unpack_initramfs $vtfile 0 $vtmagic ${vtfile}_tmp
+ fi
+
+ #only for cpio,cpio,...,initrd sequence, initrd,cpio or initrd,initrd sequence is not supported
+ while [ -e ${vtfile}_tmp ] && [ $(stat -c '%s' ${vtfile}_tmp) -gt 512 ]; do
+ mv ${vtfile}_tmp $vtfile
+ vtdump=$(hexdump -n 512 -e '512/1 "%02X"' $vtfile)
+ vtmagic=$(echo $vtdump | sed 's/^\(00\)*//')
+ let vtoffset="(${#vtdump}-${#vtmagic})/2"
+
+ if [ -z "$vtmagic" ]; then
+ echo "terminate with all zero data file" >> $VTLOG
+ break
+ fi
+
+ ventoy_unpack_initramfs $vtfile $vtoffset ${vtmagic:0:4} ${vtfile}_tmp
+ done
+
+ rm -f $vtfile ${vtfile}_tmp
+done
+
+
+#break here for debug
+if [ "$VTOY_BREAK_LEVEL" = "02" ] || [ "$VTOY_BREAK_LEVEL" = "12" ]; then
+ sleep 5
+ echo -e "\n\n\033[32m ################################################# \033[0m"
+ echo -e "\033[32m ################ VENTOY DEBUG ################### \033[0m"
+ echo -e "\033[32m ################################################# \033[0m \n"
+ if [ "$VTOY_BREAK_LEVEL" = "12" ]; then
+ cat $VTOY_PATH/log
+ fi
+ exec $BUSYBOX_PATH/sh
+fi
+
+
+####################################################################
+# #
+# Step 3 : Extract injection archive #
+# #
+####################################################################
+ventoy_unpack_injection() {
+ vtmagic=$(hexdump -n 2 -e '2/1 "%02X"' $VTOY_PATH/ventoy_injection)
+ echo "ventoy_unpack_injection vtmagic=$vtmagic ..."
+
+ if [ "1F8B" = "$vtmagic" ] || [ "1F9E" = "$vtmagic" ]; then
+ echo "tar.gz tar -xzvf"
+ tar -xzvf $VTOY_PATH/ventoy_injection -C /
+ elif [ "425A" = "$vtmagic" ]; then
+ echo "tar.bz2 tar -xjvf"
+ tar -xjvf $VTOY_PATH/ventoy_injection -C /
+ elif [ "FD37" = "$vtmagic" ]; then
+ echo "tar.xz tar -xJvf"
+ tar -xJvf $VTOY_PATH/ventoy_injection -C /
+ elif [ "5D00" = "$vtmagic" ]; then
+ echo "tar.lzma tar -xavf"
+ tar -xavf $VTOY_PATH/ventoy_injection -C /
+ else
+ echo "unzip -o"
+ unzip -o $VTOY_PATH/ventoy_injection -d /
+ fi
+}
+
+if [ -e $VTOY_PATH/ventoy_injection ]; then
+ echo "### decompress injection ... ###" >>$VTLOG
+ ventoy_unpack_injection > $VTOY_PATH/injection.log 2>&1
+fi
+
+
+####################################################################
+# #
+# Step 4 : Hand over to ventoy_chain.sh #
+# #
+####################################################################
+echo "Now hand over to ventoy.sh" >>$VTLOG
+. $VTOY_PATH/tool/vtoytool_install.sh
+
+export PATH=$VTOY_ORG_PATH
+exec $BUSYBOX_PATH/sh $VTOY_PATH/ventoy_chain.sh
--- /dev/null
+#!/ventoy/busybox/sh
+#************************************************************************************
+# Copyright (c) 2020, longpanda <admin@ventoy.net>
+#
+# This program 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.
+#
+# This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+#
+#************************************************************************************
+
+
+###################################################################
+# #
+# Step 1 : parse kernel debug parameter #
+# #
+####################################################################
+[ -d /proc ] || mkdir /proc; mount -t proc proc /proc
+vtcmdline=$(cat /proc/cmdline)
+vtkerver=$(cat /proc/version)
+umount /proc; rm -rf /proc
+
+echo "kenel version=$vtkerver" >>$VTLOG
+echo "kenel cmdline=$vtcmdline" >>$VTLOG
+
+#break here for debug
+if [ "$VTOY_BREAK_LEVEL" = "01" ] || [ "$VTOY_BREAK_LEVEL" = "11" ]; then
+ sleep 5
+ echo -e "\n\n\033[32m ################################################# \033[0m"
+ echo -e "\033[32m ################ VENTOY DEBUG ################### \033[0m"
+ echo -e "\033[32m ################################################# \033[0m \n"
+
+ if [ "$VTOY_BREAK_LEVEL" = "11" ]; then
+ cat $VTLOG
+ fi
+ exec $BUSYBOX_PATH/sh
+fi
+
+
+####################################################################
+# #
+# Step 2 : Extract injection archive #
+# #
+####################################################################
+ventoy_unpack_injection() {
+ vtmagic=$(hexdump -n 2 -e '2/1 "%02X"' $VTOY_PATH/ventoy_injection)
+ echo "ventoy_unpack_injection vtmagic=$vtmagic ..."
+
+ if [ "1F8B" = "$vtmagic" ] || [ "1F9E" = "$vtmagic" ]; then
+ echo "tar.gz tar -xzvf"
+ tar -xzvf $VTOY_PATH/ventoy_injection -C /
+ elif [ "425A" = "$vtmagic" ]; then
+ echo "tar.bz2 tar -xjvf"
+ tar -xjvf $VTOY_PATH/ventoy_injection -C /
+ elif [ "FD37" = "$vtmagic" ]; then
+ echo "tar.xz tar -xJvf"
+ tar -xJvf $VTOY_PATH/ventoy_injection -C /
+ elif [ "5D00" = "$vtmagic" ]; then
+ echo "tar.lzma tar -xavf"
+ tar -xavf $VTOY_PATH/ventoy_injection -C /
+ else
+ echo "unzip -o"
+ unzip -o $VTOY_PATH/ventoy_injection -d /
+ fi
+}
+
+if [ -e $VTOY_PATH/ventoy_injection ]; then
+ echo "### decompress injection ... ###" >>$VTLOG
+ ventoy_unpack_injection > $VTOY_PATH/injection.log 2>&1
+fi
+
+
+####################################################################
+# #
+# Step 3 : Hand over to ventoy_loop.sh #
+# #
+####################################################################
+echo "Now hand over to ventoy.sh" >>$VTLOG
+. $VTOY_PATH/tool/vtoytool_install.sh
+
+export PATH=$VTOY_ORG_PATH
+exec $BUSYBOX_PATH/sh $VTOY_PATH/ventoy_loop.sh
--- /dev/null
+#!/bin/sh
+#************************************************************************************
+# Copyright (c) 2020, longpanda <admin@ventoy.net>
+#
+# This program 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.
+#
+# This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+#
+#************************************************************************************
+
+cd /ventoy
+xzcat tool.cpio.xz | cpio -idmu
+/ventoy/tool/vtoytool/00/vtoytool_64 --install
+
+while [ -n "Y" ]; do
+ line=$(/ventoy/tool/vtoydump -f /ventoy/ventoy_os_param)
+ if [ $? -eq 0 ]; then
+ vtdiskname=${line%%#*}
+ break
+ else
+ sleep 1
+ fi
+done
+
+echo "ventoy disk is $vtdiskname" >> /ventoy/log
+/ventoy/tool/vtoydm -p -f /ventoy/ventoy_image_map -d $vtdiskname > /ventoy/ventoy_dm_table
+dmsetup create ventoy /ventoy/ventoy_dm_table --readonly
--- /dev/null
+#!/bin/sh
+#************************************************************************************
+# Copyright (c) 2020, longpanda <admin@ventoy.net>
+#
+# This program 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.
+#
+# This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+#
+#************************************************************************************
+
+sed "/^mountroot$/i\\sh /ventoy/loop/deepin/ventoy-disk.sh" -i /init
+exec /init
--- /dev/null
+#!/ventoy/busybox/sh
+#************************************************************************************
+# Copyright (c) 2020, longpanda <admin@ventoy.net>
+#
+# This program 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.
+#
+# This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+#
+#************************************************************************************
+
+. $VTOY_PATH/hook/ventoy-os-lib.sh
+
+END_UDEV_DIR=$(ventoy_get_udev_conf_dir)
+
+if ! [ -e "$END_UDEV_DIR/10-dm.rules" ]; then
+ echo 'Copy dm rule file' >> $VTLOG
+ $CAT $VTOY_PATH/hook/default/10-dm.rules > "$END_UDEV_DIR/10-dm.rules"
+fi
+
+if ! [ -e "$END_UDEV_DIR/13-dm-disk.rules" ]; then
+ echo 'Copy dm-disk rule file' >> $VTLOG
+ $CAT $VTOY_PATH/hook/default/13-dm-disk.rules > "$END_UDEV_DIR/13-dm-disk.rules"
+fi
+
+ventoy_set_loop_inotify_script endless/ventoy-inotifyd-hook.sh
+$BUSYBOX_PATH/cp -a $VTOY_PATH/loop/endless/ventoy-inotifyd-start.sh /lib/dracut/hooks/pre-udev/01-ventoy-inotifyd-start.sh
+
--- /dev/null
+#!/ventoy/busybox/sh
+#************************************************************************************
+# Copyright (c) 2020, longpanda <admin@ventoy.net>
+#
+# This program 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.
+#
+# This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+#
+#************************************************************************************
+
+. /ventoy/hook/ventoy-hook-lib.sh
+
+if is_ventoy_hook_finished; then
+ exit 0
+fi
+
+VTPATH_OLD=$PATH; PATH=$PATH:$BUSYBOX_PATH:$VTOY_PATH/tool
+
+if is_inotify_ventoy_part $3; then
+ vtlog "##### INOTIFYD: $2/$3 is created (YES) ..."
+
+ ventoy_udev_disk_common_hook "$3" "noreplace"
+ set_ventoy_hook_finish
+else
+ vtlog "##### INOTIFYD: $2/$3 is created (NO) ..."
+fi
+
+PATH=$VTPATH_OLD
--- /dev/null
+#!/ventoy/busybox/sh
+#************************************************************************************
+# Copyright (c) 2020, longpanda <admin@ventoy.net>
+#
+# This program 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.
+#
+# This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+#
+#************************************************************************************
+
+. /ventoy/hook/ventoy-hook-lib.sh
+
+vtHook=$($CAT $VTOY_PATH/inotifyd-loop-script.txt)
+
+vtdisk=$(get_ventoy_disk_name)
+if [ "$vtdisk" = "unknown" ]; then
+ vtlog "... start inotifyd listen $vtHook ..."
+ $BUSYBOX_PATH/nohup $VTOY_PATH/tool/inotifyd $vtHook /dev:n 2>&- &
+else
+ vtlog "... $vtdisk already exist ..."
+ $BUSYBOX_PATH/sh $vtHook n /dev "${vtdisk#/dev/}2"
+fi
echo 'suse'; return
elif $GREP -q 'uruk' /etc/os-release; then
echo 'debian'; return
+ elif $GREP -q 'Solus' /etc/os-release; then
+ echo 'rhel7'; return
fi
fi
--- /dev/null
+#!/ventoy/busybox/sh
+#************************************************************************************
+# Copyright (c) 2020, longpanda <admin@ventoy.net>
+#
+# This program 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.
+#
+# This program 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 this program; if not, see <http://www.gnu.org/licenses/>.
+#
+#************************************************************************************
+
+####################################################################
+# #
+# Step 1 : Parse kernel parameter #
+# #
+####################################################################
+if ! [ -e /proc ]; then
+ $BUSYBOX_PATH/mkdir /proc
+ rmproc='Y'
+fi
+$BUSYBOX_PATH/mount -t proc proc /proc
+
+# vtinit=xxx to replace rdinit=xxx
+vtcmdline=$($CAT /proc/cmdline)
+for i in $vtcmdline; do
+ if echo $i | $GREP -q vtinit; then
+ user_rdinit=${i#vtinit=}
+ echo "user set user_rdinit=${user_rdinit}" >>$VTLOG
+ fi
+done
+
+
+####################################################################
+# #
+# Step 2 : Do OS specific hook #
+# #
+####################################################################
+ventoy_get_os_type() {
+ echo "kernel version" >> $VTLOG
+ $CAT /proc/version >> $VTLOG
+
+ # deepin-live
+ if $GREP -q 'deepin' /proc/version; then
+ echo 'deepin'; return
+ fi
+
+ if $GREP -q 'endless' /proc/version; then
+ echo 'endless'; return
+ fi
+
+ echo "default"
+}
+
+VTOS=$(ventoy_get_os_type)
+echo "OS=###${VTOS}###" >>$VTLOG
+if [ -e "$VTOY_PATH/loop/$VTOS/ventoy-hook.sh" ]; then
+ $BUSYBOX_PATH/sh "$VTOY_PATH/loop/$VTOS/ventoy-hook.sh"
+fi
+
+
+####################################################################
+# #
+# Step 3 : Check for debug break #
+# #
+####################################################################
+if [ "$VTOY_BREAK_LEVEL" = "03" ] || [ "$VTOY_BREAK_LEVEL" = "13" ]; then
+ $SLEEP 5
+ echo -e "\n\n\033[32m ################################################# \033[0m"
+ echo -e "\033[32m ################ VENTOY DEBUG ################### \033[0m"
+ echo -e "\033[32m ################################################# \033[0m \n"
+ if [ "$VTOY_BREAK_LEVEL" = "13" ]; then
+ $CAT $VTOY_PATH/log
+ fi
+ exec $BUSYBOX_PATH/sh
+fi
+
+
+####################################################################
+# #
+# Step 3 : Hand over to real init #
+# #
+####################################################################
+$BUSYBOX_PATH/umount /proc
+if [ "$rmproc" = "Y" ]; then
+ $BUSYBOX_PATH/rm -rf /proc
+fi
+
+cd /
+
+unset VTLOG FIND GREP EGREP CAT AWK SED SLEEP HEAD
+
+for vtinit in $user_rdinit /sbin/init /init /linuxrc; do
+ if [ -d /ventoy_rdroot ]; then
+ if [ -e "/ventoy_rdroot$vtinit" ]; then
+ # switch_root will check /init file, this is a cheat code
+ echo 'switch_root' > /init
+ exec $BUSYBOX_PATH/switch_root /ventoy_rdroot "$vtinit"
+ fi
+ else
+ if [ -e "$vtinit" ];then
+ exec "$vtinit"
+ fi
+ fi
+done
+
+# Should never reach here
+echo -e "\n\n\033[31m ############ INIT NOT FOUND ############### \033[0m \n"
+exec $BUSYBOX_PATH/sh
xz tool.cpio
rm -rf tool
-xz ventoy.sh
+xz ventoy_chain.sh
+xz ventoy_loop.sh
find ./hook | cpio -o -H newc>hook.cpio
xz hook.cpio
fi
# 00->ff avoid sparse file
-dd if=/dev/zero bs=1M count=$size | tr '\000' '\377' > persistence.img
+dd if=/dev/zero bs=1M count=$size | tr '\000' '\377' > persistence.dat
sync
freeloop=$(losetup -f)
-losetup $freeloop persistence.img
+losetup $freeloop persistence.dat
mkfs -t $fstype $fsopt -L $label $freeloop
#************************************************************************************
function ventoy_pause {
- if [ -n "${vtdebug_flag}" ]; then
- echo "press Enter to continue ......"
- read vtTmpPause
- fi
+ echo "press Enter to continue ......"
+ read vtTmpPause
}
function ventoy_debug_pause {
fi
}
-function ventoy_cli_console {
- if [ "$grub_platform" = "pc" ]; then
- #terminal_output vga_text
+function ventoy_cli_console {
+ if [ -z "$vtoy_display_mode" ]; then
+ terminal_output console
+ elif [ "$vtoy_display_mode" = "GUI" ]; then
terminal_output console
- else
- if [ "$vtoy_display_mode" != "CLI" ]; then
- terminal_output console
- fi
fi
}
function ventoy_gui_console {
- if [ "$grub_platform" = "pc" ]; then
- if [ "$vtoy_display_mode" = "CLI" ]; then
- terminal_output console
- else
- terminal_output gfxterm
- fi
- else
- if [ "$vtoy_display_mode" != "CLI" ]; then
- terminal_output gfxterm
- fi
- fi
+ if [ -z "$vtoy_display_mode" ]; then
+ terminal_output gfxterm
+ elif [ "$vtoy_display_mode" = "GUI" ]; then
+ terminal_output gfxterm
+ fi
}
function ventoy_power {
fi
vt_load_cpio ${vtoy_path}/ventoy.cpio $2 $1
-
+
vt_linux_clear_initrd
if [ -d (loop)/pmagic ]; then
unset LoadIsoEfiDriver
fi
- vt_chosen_img_path chosen_path
+ set chosen_path=$2
vt_select_auto_install ${chosen_path}
vt_select_persistence ${chosen_path}
vt_iso9660_nojoliet 0
fi
- loopback loop ${1}${chosen_path}
- vt_parse_iso_volume ${1}${chosen_path} vt_system_id vt_volume_id
+ loopback loop ${1}${chosen_path}
get_os_type (loop)
if [ -d (loop)/EFI ]; then
}
function uefi_iso_memdisk {
- vt_chosen_img_path chosen_path
-
echo 'Loading ISO file to memory ...'
- vt_load_iso_to_mem ${1}${chosen_path} vtoy_iso_buf
+ vt_load_img_memdisk ${1}${2} vtoy_iso_buf
ventoy_cli_console
chainloader ${vtoy_path}/ventoy_x64.efi memdisk env_param=${env_param} isoefi=${LoadIsoEfiDriver} ${vtdebug_flag} mem:${vtoy_iso_buf_addr}:size:${vtoy_iso_buf_size}
loopback -d loop
fi
- vt_chosen_img_path chosen_path
+ set chosen_path=$2
vt_select_auto_install ${chosen_path}
vt_select_persistence ${chosen_path}
fi
loopback loop ${1}${chosen_path}
- vt_parse_iso_volume ${1}${chosen_path} vt_system_id vt_volume_id
+
get_os_type (loop)
if [ -n "$vtcompat" ]; then
}
function legacy_iso_memdisk {
- vt_chosen_img_path chosen_path
linux16 $vtoy_path/memdisk iso raw
echo "Loading ISO file to memory ..."
- initrd16 ${1}${chosen_path}
+ initrd16 ${1}${2}
+ boot
+}
+
+function iso_deepin_live_proc {
+ if [ -d (loop)/ ]; then
+ loopback -d loop
+ fi
+
+ loopback loop ${1}${2}
+ vt_img_sector ${1}${2}
+
+ vt_load_cpio $vtoy_path/ventoy.cpio $2 $1
+ vt_trailer_cpio $1 $2 noinit
+
+ ventoy_debug_pause
+
+ vt_set_boot_opt rdinit=/ventoy/loop/deepin/ventoy-init.sh live-media=/dev/mapper/ventoy
+
+ set ventoy_loading_tip="Loading files ......"
+
+ linux (loop)/live/vmlinuz boot=live components locales=zh_CN.UTF-8 splash quiet
+ initrd (loop)/live/initrd.img
boot
+
+ unset ventoy_loading_tip
+
+ vt_unset_boot_opt
+}
+
+
+function iso_endless_os_proc {
+ if [ -d (loop)/ ]; then
+ loopback -d loop
+ fi
+
+ loopback loop ${1}${2}
+ vt_img_sector ${1}${2}
+
+ vt_load_cpio $vtoy_path/ventoy.cpio $2 $1
+ vt_trailer_cpio $1 $2 noinit
+
+ ventoy_debug_pause
+
+ vt_set_boot_opt '@kparams' rdinit=/vtoy/vtoy
+
+ set eosimage=loop
+ set ventoy_bls_bootdev=/boot
+ set ventoy_loading_tip="Loading files ......"
+
+ export eosimage
+ configfile (loop)/endless/grub/grub.cfg
+
+ unset eosimage
+ unset ventoy_bls_bootdev
+ unset ventoy_loading_tip
+
+ vt_unset_boot_opt
}
function iso_common_menuentry {
unset vt_system_id
unset vt_volume_id
+ vt_chosen_img_path vt_chosen_path vt_chosen_size
+ vt_parse_iso_volume ${vtoy_iso_part}${vt_chosen_path} vt_system_id vt_volume_id
+
+ #special process for deepin-live iso
+ if [ "$vt_chosen_size" = "403701760" ]; then
+ if vt_str_begin $vt_chosen_path "/deepin-live"; then
+ iso_deepin_live_proc $vtoy_iso_part $vt_chosen_path
+ fi
+ fi
+
+ #special process for Endless OS
+ if vt_str_begin $vt_volume_id "Endless-OS"; then
+ iso_endless_os_proc $vtoy_iso_part $vt_chosen_path
+ fi
+
if [ "$grub_platform" = "pc" ]; then
if vt_check_mode 0; then
- legacy_iso_memdisk $vtoy_iso_part
+ legacy_iso_memdisk $vtoy_iso_part $vt_chosen_path
else
- legacy_iso_menu_func $vtoy_iso_part
+ legacy_iso_menu_func $vtoy_iso_part $vt_chosen_path
fi
else
if vt_check_mode 0; then
- uefi_iso_memdisk $vtoy_iso_part
+ uefi_iso_memdisk $vtoy_iso_part $vt_chosen_path
else
- uefi_iso_menu_func $vtoy_iso_part
+ uefi_iso_menu_func $vtoy_iso_part $vt_chosen_path
fi
fi
}
}
function wim_common_menuentry {
- vt_chosen_img_path chosen_path
- vt_wim_chain_data ${vtoy_iso_part}${chosen_path}
+ vt_chosen_img_path vt_chosen_path vt_chosen_size
+ vt_wim_chain_data ${vtoy_iso_part}${vt_chosen_path}
ventoy_debug_pause
}
function efi_common_menuentry {
- vt_chosen_img_path chosen_path
+ vt_chosen_img_path vt_chosen_path vt_chosen_size
+
+ vt_concat_efi_iso ${vtoy_iso_part}${vt_chosen_path} vtoy_iso_buf
+
+ ventoy_debug_pause
ventoy_cli_console
- chainloader ${vtoy_iso_part}${chosen_path}
+ chainloader ${vtoy_path}/ventoy_x64.efi memdisk env_param=${env_param} isoefi=on ${vtdebug_flag} mem:${vtoy_iso_buf_addr}:size:${vtoy_iso_buf_size}
boot
ventoy_gui_console
}
+
+
+function img_common_menuentry {
+
+ echo "To be implement"
+}
+
+function img_unsupport_menuentry {
+ common_unsupport_menuentry
+}
+
#############################################################
#############################################################
#############################################################
if [ "$vtoy_display_mode" = "CLI" ]; then
terminal_output console
+elif [ "$vtoy_display_mode" = "serial" ]; then
+ if [ -n "$vtoy_serial_param" ]; then
+ serial $vtoy_serial_param
+ fi
+ terminal_input serial
+ terminal_output serial
+elif [ "$vtoy_display_mode" = "serial_console" ]; then
+ if [ -n "$vtoy_serial_param" ]; then
+ serial $vtoy_serial_param
+ fi
+ terminal_input serial console
+ terminal_output serial console
else
if [ -n "$vtoy_theme" ]; then
set theme=$vtoy_theme
*acpi: acpi
*all_functional_test: functional_test
*background_image: gfxterm_background
+*bls_import: blscfg
+*blscfg: blscfg
*cat: cat
*cpuid: cpuid
*crc: hashsum
hexdump_random: random
initrd16: linux16
initrd: linux
+initrdefi: linux
keymap: keylayouts
kfreebsd_loadenv: bsd
kfreebsd_module: bsd
legacy_source: legacycfg
linux16: linux16
linux: linux
+linuxefi: linux
list_trusted: pgp
loadfont: font
lsapm: lsapm
vbetest: videotest
videoinfo: videoinfo
videotest: videotest
+vt_set_boot_opt: linux
+vt_unset_boot_opt: linux
write_byte: memrw
write_dword: memrw
write_word: memrw
usbserial_ftdi: serial usb usbserial_common
legacy_password_test: functional_test legacycfg
cpuid: extcmd
+blscfg: extcmd normal
hdparm: extcmd hexdump
bfs: fshelp
gcry_blowfish: crypto
*acpi: acpi
*all_functional_test: functional_test
*background_image: gfxterm_background
+*bls_import: blscfg
+*blscfg: blscfg
*cat: cat
*cpuid: cpuid
*crc: hashsum
hexdump_random: random
initrd16: linux16
initrd: linux
+initrdefi: linux
keymap: keylayouts
kfreebsd_loadenv: bsd
kfreebsd_module: bsd
legacy_source: legacycfg
linux16: linux16
linux: linux
+linuxefi: linux
list_trusted: pgp
loadbios: loadbios
loadfont: font
usb: usbtest
videoinfo: videoinfo
videotest: videotest
+vt_set_boot_opt: linux
+vt_unset_boot_opt: linux
write_byte: memrw
write_dword: memrw
write_word: memrw
usbserial_ftdi: serial usb usbserial_common
legacy_password_test: functional_test legacycfg
cpuid: extcmd
+blscfg: extcmd normal
hdparm: extcmd hexdump
bfs: fshelp
gcry_blowfish: crypto