summaryrefslogtreecommitdiffstats
path: root/util/resolve.c
diff options
context:
space:
mode:
Diffstat (limited to 'util/resolve.c')
-rw-r--r--util/resolve.c287
1 files changed, 287 insertions, 0 deletions
diff --git a/util/resolve.c b/util/resolve.c
new file mode 100644
index 0000000..3e887d2
--- /dev/null
+++ b/util/resolve.c
@@ -0,0 +1,287 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2002,2007 Free Software Foundation, Inc.
+ *
+ * GRUB is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GRUB is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <grub/emu/misc.h>
+#include <grub/misc.h>
+#include <grub/util/misc.h>
+#include <grub/util/resolve.h>
+#include <grub/i18n.h>
+
+/* Module. */
+struct mod_list
+{
+ const char *name;
+ struct mod_list *next;
+};
+
+/* Dependency. */
+struct dep_list
+{
+ const char *name;
+ struct mod_list *list;
+ struct dep_list *next;
+};
+
+static char buf[1024];
+
+static void
+free_mod_list (struct mod_list *head)
+{
+ while (head)
+ {
+ struct mod_list *next;
+
+ next = head->next;
+ free ((void *) head->name);
+ free (head);
+ head = next;
+ }
+}
+
+static void
+free_dep_list (struct dep_list *head)
+{
+ while (head)
+ {
+ struct dep_list *next;
+
+ next = head->next;
+ free ((void *) head->name);
+ free_mod_list (head->list);
+ free (head);
+ head = next;
+ }
+}
+
+/* Read the list of dependencies. */
+static struct dep_list *
+read_dep_list (FILE *fp)
+{
+ struct dep_list *dep_list = 0;
+
+ while (fgets (buf, sizeof (buf), fp))
+ {
+ char *p;
+ struct dep_list *dep;
+
+ /* Get the target name. */
+ p = strchr (buf, ':');
+ if (! p)
+ grub_util_error (_("invalid line format: %s"), buf);
+
+ *p++ = '\0';
+
+ dep = xmalloc (sizeof (*dep));
+ dep->name = xstrdup (buf);
+ dep->list = 0;
+
+ dep->next = dep_list;
+ dep_list = dep;
+
+ /* Add dependencies. */
+ while (*p)
+ {
+ struct mod_list *mod;
+ char *name;
+
+ /* Skip whitespace. */
+ while (*p && grub_isspace (*p))
+ p++;
+
+ if (! *p)
+ break;
+
+ name = p;
+
+ /* Skip non-whitespace. */
+ while (*p && ! grub_isspace (*p))
+ p++;
+
+ *p++ = '\0';
+
+ mod = (struct mod_list *) xmalloc (sizeof (*mod));
+ mod->name = xstrdup (name);
+ mod->next = dep->list;
+ dep->list = mod;
+ }
+ }
+
+ return dep_list;
+}
+
+static char *
+get_module_name (const char *str)
+{
+ char *base;
+ char *ext;
+
+ base = strrchr (str, '/');
+ if (! base)
+ base = (char *) str;
+ else
+ base++;
+
+ ext = strrchr (base, '.');
+ if (ext && strcmp (ext, ".mod") == 0)
+ {
+ char *name;
+
+ name = xmalloc (ext - base + 1);
+ memcpy (name, base, ext - base);
+ name[ext - base] = '\0';
+ return name;
+ }
+
+ return xstrdup (base);
+}
+
+static char *
+get_module_path (const char *prefix, const char *str)
+{
+ char *dir;
+ char *base;
+ char *ext;
+ char *ret;
+
+ ext = strrchr (str, '.');
+ if (ext && strcmp (ext, ".mod") == 0)
+ base = xstrdup (str);
+ else
+ {
+ base = xmalloc (strlen (str) + 4 + 1);
+ sprintf (base, "%s.mod", str);
+ }
+
+ dir = strchr (str, '/');
+ if (dir)
+ return base;
+
+ ret = grub_util_get_path (prefix, base);
+ free (base);
+ return ret;
+}
+
+static void
+add_module (const char *dir,
+ struct dep_list *dep_list,
+ struct mod_list **mod_head,
+ struct grub_util_path_list **path_head,
+ const char *name)
+{
+ char *mod_name;
+ struct grub_util_path_list *path;
+ struct mod_list *mod;
+ struct dep_list *dep;
+
+ mod_name = get_module_name (name);
+
+ /* Check if the module has already been added. */
+ for (mod = *mod_head; mod; mod = mod->next)
+ if (strcmp (mod->name, mod_name) == 0)
+ {
+ free (mod_name);
+ return;
+ }
+
+ /* Resolve dependencies. */
+ for (dep = dep_list; dep; dep = dep->next)
+ if (strcmp (dep->name, mod_name) == 0)
+ {
+ for (mod = dep->list; mod; mod = mod->next)
+ add_module (dir, dep_list, mod_head, path_head, mod->name);
+
+ break;
+ }
+
+ /* Add this module. */
+ mod = (struct mod_list *) xmalloc (sizeof (*mod));
+ mod->name = mod_name;
+ mod->next = *mod_head;
+ *mod_head = mod;
+
+ /* Add this path. */
+ path = (struct grub_util_path_list *) xmalloc (sizeof (*path));
+ path->name = get_module_path (dir, name);
+ path->next = *path_head;
+ *path_head = path;
+}
+
+struct grub_util_path_list *
+grub_util_resolve_dependencies (const char *prefix,
+ const char *dep_list_file,
+ char *modules[])
+{
+ char *path;
+ FILE *fp;
+ struct dep_list *dep_list;
+ struct mod_list *mod_list = 0;
+ struct grub_util_path_list *path_list = 0;
+
+ path = grub_util_get_path (prefix, dep_list_file);
+ fp = grub_util_fopen (path, "r");
+ if (! fp)
+ grub_util_error (_("cannot open `%s': %s"), path, strerror (errno));
+
+ free (path);
+ dep_list = read_dep_list (fp);
+ fclose (fp);
+
+ while (*modules)
+ {
+ add_module (prefix, dep_list, &mod_list, &path_list, *modules);
+ modules++;
+ }
+
+ free_dep_list (dep_list);
+ free_mod_list (mod_list);
+
+ { /* Reverse the path_list */
+ struct grub_util_path_list *p, *prev, *next;
+
+ for (p = path_list, prev = NULL; p; p = next)
+ {
+ next = p->next;
+ p->next = prev;
+ prev = p;
+ }
+
+ return prev;
+ }
+}
+
+void
+grub_util_free_path_list (struct grub_util_path_list *path_list)
+{
+ struct grub_util_path_list *next;
+
+ while (path_list)
+ {
+ next = path_list->next;
+ free ((void *) path_list->name);
+ free (path_list);
+ path_list = next;
+ }
+}