diff --git a/Makefile.in b/Makefile.in
index b24ee2e..06478af 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -139,11 +139,9 @@ include $(srcdir)/conf/$(target_cpu)-$(platform).mk
### General targets.
CLEANFILES += $(pkglib_DATA) $(pkgdata_DATA)
-pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst handler.lst
-moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep.awk
- cat $(DEFSYMFILES) /dev/null \
- | $(AWK) -f $(srcdir)/genmoddep.awk $(UNDSYMFILES) > $@ \
- || (rm -f $@; exit 1)
+pkglib_DATA += modsym.lst command.lst fs.lst partmap.lst handler.lst
+modsym.lst: $(MODFILES) grub-symdb
+ ./grub-symdb -d . update $?
command.lst: $(COMMANDFILES)
cat $^ /dev/null | sort > $@
diff --git a/conf/common.rmk b/conf/common.rmk
index 0e63da6..20a1b89 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -23,6 +23,10 @@ grub_probe_SOURCES = util/grub-probe.c \
kern/fs.c kern/env.c fs/fshelp.c \
disk/raid.c disk/mdraid_linux.c disk/lvm.c grub_probe_init.c
+# For grub-symdb
+bin_UTILITIES += grub-symdb
+grub_symdb_SOURCES = util/grub-symdb.c util/misc.c util/resolve.c
+
ifeq ($(enable_grub_fstest), yes)
bin_UTILITIES += grub-fstest
endif
diff --git a/genmk.rb b/genmk.rb
index b619421..c119fad 100644
--- a/genmk.rb
+++ b/genmk.rb
@@ -99,18 +99,10 @@ class PModule
pre_obj = 'pre-' + @name.suffix('o')
mod_src = 'mod-' + @name.suffix('c')
mod_obj = mod_src.suffix('o')
- defsym = 'def-' + @name.suffix('lst')
- undsym = 'und-' + @name.suffix('lst')
mod_name = File.basename(@name, '.mod')
symbolic_name = mod_name.sub(/\.[^\.]*$/, '')
- "CLEANFILES += address@hidden #{mod_obj} #{mod_src} #{pre_obj} #{objs_str} #{undsym}
-ifneq ($(#{prefix}_EXPORTS),no)
-CLEANFILES += #{defsym}
-DEFSYMFILES += #{defsym}
-endif
-MOSTLYCLEANFILES += #{deps_str}
-UNDSYMFILES += #{undsym}
+ "CLEANFILES += address@hidden #{mod_obj} #{mod_src} #{pre_obj} #{objs_str}
address@hidden: #{pre_obj} #{mod_obj} $(TARGET_OBJ2ELF)
-rm -f $@
@@ -125,17 +117,10 @@ UNDSYMFILES += #{undsym}
#{mod_obj}: #{mod_src}
$(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(#{prefix}_CFLAGS) -c -o $@ $<
-#{mod_src}: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
- sh $(srcdir)/genmodsrc.sh '#{mod_name}' $< > $@ || (rm -f $@; exit 1)
-
-ifneq ($(#{prefix}_EXPORTS),no)
-#{defsym}: #{pre_obj}
- $(NM) -g --defined-only -P -p $< | sed 's/^\\([^ ]*\\).*/\\1 #{mod_name}/' > $@
-endif
+#{mod_src}: $(srcdir)/genmodsrc.sh
+ sh $(srcdir)/genmodsrc.sh '#{mod_name}' > $@ || (rm -f $@; exit 1)
-#{undsym}: #{pre_obj}
- echo '#{mod_name}' > $@
- $(NM) -u -P -p $< | cut -f1 -d' ' >> $@
+MODFILES += address@hidden
" + objs.collect_with_index do |obj, i|
src = sources[i]
diff --git a/genmodsrc.sh b/genmodsrc.sh
index 2d42055..b334c7e 100644
--- a/genmodsrc.sh
+++ b/genmodsrc.sh
@@ -41,7 +41,4 @@ cat <.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#define _GNU_SOURCE 1
+#include
+
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
+
+typedef Elf32_Word Elf_Word;
+typedef Elf32_Addr Elf_Addr;
+typedef Elf32_Ehdr Elf_Ehdr;
+typedef Elf32_Shdr Elf_Shdr;
+typedef Elf32_Sym Elf_Sym;
+typedef Elf32_Half Elf_Half;
+typedef Elf32_Off Elf_Off;
+typedef Elf32_Section Elf_Section;
+
+#define ELF_ST_BIND ELF32_ST_BIND
+#define grub_target_to_host grub_target_to_host32
+#define grub_host_to_target grub_host_to_target32
+
+#elif GRUB_TARGET_SIZEOF_VOID_P == 8
+
+typedef Elf64_Word Elf_Word;
+typedef Elf64_Addr Elf_Addr;
+typedef Elf64_Ehdr Elf_Ehdr;
+typedef Elf64_Shdr Elf_Shdr;
+typedef Elf64_Sym Elf_Sym;
+typedef Elf64_Half Elf_Half;
+typedef Elf64_Off Elf_Off;
+typedef Elf64_Section Elf_Section;
+
+#define ELF_ST_BIND ELF64_ST_BIND
+#define grub_target_to_host grub_target_to_host64
+#define grub_host_to_target grub_host_to_target64
+
+#endif
+
+struct grub_symbol_list
+{
+ struct grub_symbol_list *next;
+ char *name;
+ struct grub_named_list *defs;
+ struct grub_named_list *unds;
+};
+
+static struct grub_symbol_list *symbol_list;
+
+struct grub_update_list
+{
+ struct grub_update_list *next;
+ char *name;
+ struct grub_named_list *add_mods;
+ struct grub_named_list *del_mods;
+ struct grub_named_list *cur_mods;
+};
+
+static struct grub_update_list *update_list;
+
+struct grub_mod_syms
+{
+ struct grub_named_list *defs;
+ struct grub_named_list *unds;
+};
+
+static void *
+insert_named_list (grub_named_list_t *head, grub_named_list_t item)
+{
+ grub_named_list_t *p, q;
+
+ for (p = head, q = *p; q; p = &(q->next), q = q->next)
+ {
+ int r;
+
+ r = strcmp (item->name, q->name);
+ if (! r)
+ return q;
+
+ if (r < 0)
+ break;
+ }
+
+ *p = item;
+ item->next = q;
+
+ return item;
+}
+
+static void
+free_named_list (grub_named_list_t *head)
+{
+ grub_named_list_t cur = *head;
+
+ while (cur)
+ {
+ grub_named_list_t tmp;
+
+ tmp = cur;
+ cur = cur->next;
+ free ((char *) tmp->name);
+ free (tmp);
+ }
+
+ *head = 0;
+}
+
+static int
+remove_string (grub_named_list_t *head, char *name)
+{
+ grub_named_list_t *p, q;
+
+ for (p = head, q = *p; q; p = &(q->next), q = q->next)
+ {
+ int r;
+
+ r = strcmp (name, q->name);
+ if (! r)
+ {
+ *p = q->next;
+ free ((char *) q->name);
+ free (q);
+
+ return 1;
+ }
+
+ if (r < 0)
+ break;
+ }
+
+ return 0;
+}
+
+static int
+insert_string (grub_named_list_t *head, char *name)
+{
+ struct grub_named_list *item, *n;
+
+ item = xmalloc (sizeof (struct grub_named_list));
+ item->name = xstrdup (name);
+
+ n = insert_named_list (head, item);
+ if (n != item)
+ {
+ free ((char *) item->name);
+ free (item);
+
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct grub_symbol_list *
+insert_symbol (char *name)
+{
+ struct grub_symbol_list *s, *n;
+
+ s = xmalloc (sizeof (struct grub_symbol_list));
+ s->name = xstrdup (name);
+ s->defs = 0;
+ s->unds = 0;
+
+ n = insert_named_list (GRUB_AS_NAMED_LIST_P (&symbol_list),
+ GRUB_AS_NAMED_LIST (s));
+
+ if (n != s)
+ {
+ free (s->name);
+ free (s);
+ }
+
+ return n;
+}
+
+static struct grub_update_list *
+insert_update (char *name)
+{
+ struct grub_update_list *u, *n;
+
+ u = xmalloc (sizeof (struct grub_update_list));
+ u->name = xstrdup (name);
+ u->add_mods = 0;
+ u->del_mods = 0;
+ u->cur_mods = 0;
+
+ n = insert_named_list (GRUB_AS_NAMED_LIST_P (&update_list),
+ GRUB_AS_NAMED_LIST (u));
+
+ if (n != u)
+ {
+ free (u->name);
+ free (u);
+ }
+
+ return n;
+}
+
+static void
+add_update (char *m1, char *m2, int is_add)
+{
+ struct grub_update_list *u;
+
+ u = insert_update (m2);
+ if (is_add)
+ {
+ remove_string (&u->del_mods, m1);
+ insert_string (&u->add_mods, m1);
+ }
+ else
+ insert_string (&u->del_mods, m1);
+}
+
+static void
+read_symdb (char *path)
+{
+ FILE *fp;
+ char line[512];
+ struct grub_symbol_list *sym = 0;
+
+ fp = fopen (path, "r");
+ if (! fp)
+ return;
+
+ while (fgets (line, sizeof (line), fp))
+ {
+ char *p;
+
+ p = line + strlen (line) - 1;
+ while ((p >= line) && ((*p == '\r') || (*p == '\n') || (*p == ' ')))
+ p--;
+
+ if (p < line)
+ continue;
+
+ *(p + 1) = 0;
+
+ p = line;
+ while (*p == ' ')
+ p++;
+
+ if (*p == '#')
+ continue;
+
+ if ((*p == '+') || (*p == '-'))
+ {
+ if (! sym)
+ grub_util_error ("No current symbol.");
+
+ insert_string ((*p == '+') ? &sym->defs : &sym->unds, p + 1);
+ }
+ else
+ sym = insert_symbol (p);
+ }
+
+ fclose (fp);
+}
+
+static void
+write_symdb (char *path)
+{
+ FILE *fp;
+ struct grub_symbol_list *sym;
+
+ fp = fopen (path, "w");
+ if (! fp)
+ grub_util_error ("Can\'t write to ", path);
+
+ sym = symbol_list;
+ while (sym)
+ {
+ struct grub_named_list *mod;
+
+ fprintf (fp, "%s\n", sym->name);
+ mod = sym->defs;
+ while (mod)
+ {
+ fprintf (fp, "+%s\n", mod->name);
+ mod = mod->next;
+ }
+ mod = sym->unds;
+ while (mod)
+ {
+ fprintf (fp, "-%s\n", mod->name);
+ mod = mod->next;
+ }
+
+ sym = sym->next;
+ }
+
+ fclose (fp);
+}
+
+static void
+check_symdb (void)
+{
+ struct grub_symbol_list *sym;
+
+ sym = symbol_list;
+ while (sym)
+ {
+ if (! sym->defs)
+ printf ("undefined: %s\n", sym->name);
+ else if (sym->defs->next)
+ printf ("duplicate: %s\n", sym->name);
+
+ sym = sym->next;
+ }
+}
+
+/* Return if the ELF header is valid. */
+static int
+check_elf_header (Elf_Ehdr *e, size_t size)
+{
+ if (size < sizeof (*e)
+ || e->e_ident[EI_MAG0] != ELFMAG0
+ || e->e_ident[EI_MAG1] != ELFMAG1
+ || e->e_ident[EI_MAG2] != ELFMAG2
+ || e->e_ident[EI_MAG3] != ELFMAG3
+ || e->e_ident[EI_VERSION] != EV_CURRENT
+ || e->e_version != EV_CURRENT)
+ return 0;
+
+ return 1;
+}
+
+/* Return the symbol table section, if any. */
+static Elf_Shdr *
+find_symtab_section (Elf_Shdr *sections,
+ Elf_Half section_entsize, Elf_Half num_sections)
+{
+ int i;
+ Elf_Shdr *s;
+
+ for (i = 0, s = sections;
+ i < num_sections;
+ i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+ if (s->sh_type == grub_target_to_host32 (SHT_SYMTAB))
+ return s;
+
+ return 0;
+}
+
+/* Return the address of the string table. */
+static char *
+find_strtab (Elf_Ehdr *e, Elf_Shdr *sections, Elf_Half section_entsize)
+{
+ Elf_Shdr *s;
+ char *strtab;
+
+ s = (Elf_Shdr *) ((char *) sections
+ + grub_target_to_host16 (e->e_shstrndx) * section_entsize);
+ strtab = (char *) e + grub_target_to_host (s->sh_offset);
+ return strtab;
+}
+
+static Elf_Shdr *
+find_moddep_section (Elf_Shdr *sections,
+ Elf_Half section_entsize, Elf_Half num_sections,
+ char *strtab)
+{
+ int i;
+ Elf_Shdr *s;
+
+ for (i = 0, s = sections;
+ i < num_sections;
+ i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+ {
+ char *name = strtab + grub_target_to_host32 (s->sh_name);
+
+ if (! strcmp (name, ".moddeps"))
+ return s;
+ }
+
+ return 0;
+}
+
+static void
+read_elf_symbols (struct grub_mod_syms *mod_syms,
+ Elf_Ehdr *e, Elf_Shdr *sections,
+ Elf_Shdr *symtab_section, Elf_Half section_entsize,
+ Elf_Half num_sections)
+{
+ Elf_Word symtab_size, sym_size, num_syms;
+ Elf_Off symtab_offset;
+ Elf_Word i;
+ Elf_Sym *sym;
+ Elf_Shdr *strtab_section;
+ const char *strtab;
+
+ strtab_section
+ = (Elf_Shdr *) ((char *) sections
+ + (grub_target_to_host32 (symtab_section->sh_link)
+ * section_entsize));
+ strtab = (char *) e + grub_target_to_host32 (strtab_section->sh_offset);
+
+ symtab_size = grub_target_to_host32 (symtab_section->sh_size);
+ sym_size = grub_target_to_host32 (symtab_section->sh_entsize);
+ symtab_offset = grub_target_to_host (symtab_section->sh_offset);
+ num_syms = symtab_size / sym_size;
+
+ for (i = 0, sym = (Elf_Sym *) ((char *) e + symtab_offset);
+ i < num_syms;
+ i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
+ {
+ Elf_Section index;
+ struct grub_named_list **p = &mod_syms->defs;
+
+ if (ELF_ST_BIND (sym->st_info) == STB_LOCAL)
+ continue;
+
+ index = grub_target_to_host16 (sym->st_shndx);
+ if (index == STN_ABS)
+ {
+ continue;
+ }
+ else if (index == STN_UNDEF)
+ {
+ p = &mod_syms->unds;
+ }
+ else if (index >= num_sections)
+ grub_util_error ("section %d does not exist", index);
+
+ insert_string (p,
+ (char *) (strtab + grub_target_to_host32 (sym->st_name)));
+ }
+}
+
+static void
+read_mod_syms (struct grub_mod_syms *mod_syms, char *path)
+{
+ size_t size;
+ char *image;
+ Elf_Ehdr *e;
+ Elf_Off section_offset;
+ Elf_Half section_entsize;
+ Elf_Half num_sections;
+ Elf_Shdr *sections;
+ Elf_Shdr *symtab_section;
+
+ mod_syms->defs = 0;
+ mod_syms->unds = 0;
+
+ size = grub_util_get_image_size (path);
+ image = grub_util_read_image (path);
+
+ e = (Elf_Ehdr *) image;
+ if (! check_elf_header (e, size))
+ grub_util_error ("invalid ELF header");
+
+ section_offset = grub_target_to_host (e->e_shoff);
+ section_entsize = grub_target_to_host16 (e->e_shentsize);
+ num_sections = grub_target_to_host16 (e->e_shnum);
+
+ if (size < section_offset + section_entsize * num_sections)
+ grub_util_error ("invalid ELF format");
+
+ sections = (Elf_Shdr *) (image + section_offset);
+ symtab_section = find_symtab_section (sections,
+ section_entsize, num_sections);
+ if (! symtab_section)
+ grub_util_error ("no symbol table");
+
+ read_elf_symbols (mod_syms, e, sections, symtab_section, section_entsize,
+ num_sections);
+
+ free (image);
+}
+
+static void
+update_mods (char *mods[], const char *dir)
+{
+ for (; mods[0]; mods++)
+ {
+ char *mod_name, *mod_path;
+ struct grub_mod_syms mod_syms;
+ struct grub_named_list *m;
+
+ mod_name = grub_util_get_module_name (mods[0]);
+ mod_path = grub_util_get_module_path (dir, mod_name);
+
+ if (! strcmp (mod_name, "grub-symdb"))
+ {
+ free (mod_name);
+ free (mod_path);
+ continue;
+ }
+
+ read_mod_syms (&mod_syms, mod_path);
+
+ m = mod_syms.defs;
+ while (m)
+ {
+ struct grub_symbol_list *sym;
+ struct grub_named_list *n;
+
+ sym = insert_symbol ((char *) m->name);
+ insert_string (&sym->defs, mod_name);
+
+ n = sym->unds;
+ while (n)
+ {
+ add_update ((char *) mod_name, (char *) n->name, 1);
+ n = n->next;
+ }
+
+ m = m->next;
+ }
+
+ m = mod_syms.unds;
+ while (m)
+ {
+ struct grub_symbol_list *sym;
+ struct grub_named_list *n;
+
+ sym = insert_symbol ((char *) m->name);
+ insert_string (&sym->unds, mod_name);
+
+ n = sym->defs;
+ while (n)
+ {
+ add_update ((char *) n->name, (char *) mod_name, 1);
+ n = n->next;
+ }
+
+ m = m->next;
+ }
+
+ free (mod_name);
+ free (mod_path);
+ }
+}
+
+static void
+remove_mods (char *mods[])
+{
+ for (; mods[0]; mods++)
+ {
+ char *mod_name;
+ struct grub_symbol_list *sym;
+
+ mod_name = grub_util_get_module_name (mods[0]);
+
+ sym = symbol_list;
+ while (sym)
+ {
+ struct grub_named_list *m, *n;
+
+ m = sym->defs;
+ while (m)
+ {
+ int r;
+
+ r = strcmp (mod_name, m->name);
+ if (! r)
+ break;
+
+ if (r < 0)
+ {
+ m = 0;
+ break;
+ }
+
+ m = m->next;
+ }
+
+ n = sym->unds;
+ while (n)
+ {
+ if (m)
+ {
+ add_update ((char *) m->name, (char *) n->name, 0);
+ }
+ else
+ {
+ int r;
+
+ r = strcmp (mod_name, n->name);
+ if (! r)
+ {
+ m = sym->defs;
+ while (m)
+ {
+ add_update ((char *) m->name, (char *) n->name, 0);
+ m = m->next;
+ }
+
+ break;
+ }
+
+ if (r < 0)
+ break;
+ }
+
+ n = n->next;
+ }
+
+ sym = sym->next;
+ }
+
+ free (mod_name);
+ }
+}
+
+static void
+dump_update (void)
+{
+ struct grub_update_list *u;
+
+ u = update_list;
+ while (u)
+ {
+ struct grub_named_list *n;
+
+ printf ("%s:" , u->name);
+ n = u->add_mods;
+ while (n)
+ {
+ printf (" +%s", n->name);
+ n = n->next;
+ }
+
+ n = u->del_mods;
+ while (n)
+ {
+ printf (" -%s", n->name);
+ n = n->next;
+ }
+
+ printf ("\n");
+ u = u->next;
+ }
+}
+
+static void
+update_deps (struct grub_update_list *u, char *path)
+{
+ size_t size;
+ char *image;
+ Elf_Ehdr *e;
+ Elf_Off section_offset;
+ Elf_Half section_entsize;
+ Elf_Half num_sections;
+ Elf_Shdr *sections;
+ Elf_Shdr *moddep_section;
+ char *strtab, *pb, *pe;
+ struct grub_named_list *n;
+ int modified;
+
+ size = grub_util_get_image_size (path);
+ image = grub_util_read_image (path);
+
+ e = (Elf_Ehdr *) image;
+ if (! check_elf_header (e, size))
+ grub_util_error ("invalid ELF header");
+
+ section_offset = grub_target_to_host (e->e_shoff);
+ section_entsize = grub_target_to_host16 (e->e_shentsize);
+ num_sections = grub_target_to_host16 (e->e_shnum);
+
+ if (size < section_offset + section_entsize * num_sections)
+ grub_util_error ("invalid ELF format");
+
+ sections = (Elf_Shdr *) (image + section_offset);
+ strtab = find_strtab (e, sections, section_entsize);
+
+ moddep_section = find_moddep_section (sections, section_entsize,
+ num_sections, strtab);
+ if (! moddep_section)
+ grub_util_error ("no .moddeps section");
+
+ pb = (char *) e + grub_target_to_host (moddep_section->sh_offset);
+ pe = pb + grub_target_to_host32 (moddep_section->sh_size);
+ while (pb < pe)
+ {
+ if (! *pb)
+ break;
+
+ insert_string (&u->cur_mods, pb);
+ pb += strlen (pb) + 1;
+ }
+
+ modified = 0;
+ n = u->del_mods;
+ while (n)
+ {
+ modified += remove_string (&u->cur_mods, (char *) n->name);
+ n = n->next;
+ }
+ n = u->add_mods;
+ while (n)
+ {
+ modified += insert_string (&u->cur_mods, (char *) n->name);
+ n = n->next;
+ }
+
+ if (modified)
+ {
+ char *new_image, *p;
+ int old_size, new_size, delta, ofs;
+ Elf_Shdr *s;
+ int i;
+ FILE *fp;
+
+ new_size = 0;
+ n = u->cur_mods;
+ while (n)
+ {
+ new_size += strlen (n->name) + 1;
+ n = n->next;
+ }
+
+ old_size = (int) grub_target_to_host32 (moddep_section->sh_size);
+ delta = new_size - old_size ;
+
+ ofs = grub_target_to_host (moddep_section->sh_offset);
+ new_image = xmalloc ((int) size + delta);
+ e = (Elf_Ehdr *) new_image;
+
+ memcpy (new_image, image, ofs);
+
+ p = new_image + ofs;
+ n = u->cur_mods;
+ while (n)
+ {
+ strcpy (p, n->name);
+ p += strlen (p) + 1;
+ n = n->next;
+ }
+
+ if (ofs + old_size < (int) size)
+ memcpy (p, image + ofs + old_size, (int) size - ofs - old_size);
+
+ if ((int) section_offset > ofs)
+ {
+ section_offset = (int) section_offset + delta;
+ e->e_shoff = grub_host_to_target (section_offset);
+ }
+
+ sections = (Elf_Shdr *) (new_image + section_offset);
+ moddep_section = find_moddep_section (sections, section_entsize,
+ num_sections, strtab);
+ if (! moddep_section)
+ grub_util_error ("no .moddeps section");
+
+ moddep_section->sh_size = grub_host_to_target32 (new_size);
+
+ for (i = 0, s = sections;
+ i < num_sections;
+ i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+ {
+ Elf_Off off;
+
+ off = grub_target_to_host (s->sh_offset);
+ if ((int) off > ofs)
+ {
+ off = (int) off + delta;
+ s->sh_offset = grub_host_to_target (off);
+ }
+ }
+
+ fp = fopen (path, "wb");
+ if (! fp)
+ grub_util_error ("Can\'t write to %s", path);
+
+ grub_util_write_image (new_image, (int) size + delta, fp);
+
+ fclose (fp);
+
+ free (new_image);
+ }
+
+ free (image);
+}
+
+static void
+write_moddep (struct grub_update_list *u, FILE *fp)
+{
+ struct grub_named_list *n;
+
+ if (! u->cur_mods)
+ return;
+
+ fprintf (fp, "%s:", u->name);
+ n = u->cur_mods;
+ while (n)
+ {
+ fprintf (fp, " %s", n->name);
+ n = n->next;
+ }
+
+ fprintf (fp, "\n");
+ free_named_list (&u->cur_mods);
+}
+
+static void
+update_moddep (char *dir)
+{
+ FILE *fp;
+ struct stat st;
+ char *path, *image;
+ struct grub_update_list *u;
+
+ path = grub_util_get_path (dir, "moddep.lst");
+ image = (stat (path, &st) == 0) ? grub_util_read_image (path) : 0;
+
+ fp = fopen (path, "w");
+ if (! fp)
+ grub_util_error ("Can\'t write to ", path);
+
+ if (image)
+ {
+ char *line;
+
+ line = image;
+ while (*line)
+ {
+ char *p, *c;
+ int n;
+
+ n = strcspn (line, "\r\n");
+ p = line;
+
+ line += n;
+ while ((*line == '\r') || (*line == '\n'))
+ line++;
+
+ *(p + n) = 0;
+
+ c = strchr (p, ':');
+ if (! c)
+ continue;
+
+ *c = 0;
+ u = update_list;
+ while (u)
+ {
+ int r;
+
+ r = strcmp (p, u->name);
+ if (! r)
+ break;
+
+ if (r < 0)
+ {
+ u = 0;
+ break;
+ }
+
+ u = u->next;
+ }
+ *c = ':';
+
+ if (u)
+ write_moddep (u, fp);
+ else
+ fprintf (fp, "%s\n", p);
+ }
+ }
+
+
+ u = update_list;
+ while (u)
+ {
+ write_moddep (u, fp);
+ u = u->next;
+ }
+
+ fclose (fp);
+ free (path);
+ free (image);
+}
+
+static void
+apply_update (char *dir)
+{
+ struct grub_update_list *u;
+
+ u = update_list;
+ while (u)
+ {
+ char *mod_path;
+
+ mod_path = grub_util_get_module_path (dir, u->name);
+ update_deps (u, mod_path);
+ free (mod_path);
+ u = u->next;
+ }
+
+ update_moddep (dir);
+}
+
+static struct option options[] =
+ {
+ {"directory", required_argument, 0, 'd'},
+ {"test", no_argument, 0, 't'},
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"verbose", no_argument, 0, 'v'},
+ {0, 0, 0, 0}
+ };
+
+static void
+usage (int status)
+{
+ if (status)
+ fprintf (stderr, "Try ``grub-symdb --help'' for more information.\n");
+ else
+ printf ("\
+Usage: grub-symdb [OPTION]... COMMAND\n\
+\n\
+Manage the symbol database of GRUB.\n\
+\nCommands:\n\
+ update MODULES add/update modules to the symbol database\n\
+ remove MODULES remove modules from the symbol databsae\n\
+ check check for duplicate and unresolved symbols\n\
+\n\
+ -d, --directory=DIR use images and modules under DIR [default=%s]\n\
+ -t, --test test mode\n\
+ -h, --help display this message and exit\n\
+ -V, --version print version information and exit\n\
+ -v, --verbose print verbose messages\n\
+\n\
+Report bugs to <%s>.\n\
+", GRUB_LIBDIR, PACKAGE_BUGREPORT);
+
+ exit (status);
+}
+
+int
+main (int argc, char *argv[])
+{
+ char *dir = NULL;
+ char *path;
+ int test_mode = 0;
+
+ progname = "grub-symdb";
+
+ while (1)
+ {
+ int c = getopt_long (argc, argv, "d:thVv", options, 0);
+
+ if (c == -1)
+ break;
+ else
+ switch (c)
+ {
+ case 'd':
+ if (dir)
+ free (dir);
+
+ dir = xstrdup (optarg);
+ break;
+
+ case 't':
+ test_mode++;
+ break;
+
+ case 'h':
+ usage (0);
+ break;
+
+ case 'V':
+ printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ return 0;
+
+ case 'v':
+ verbosity++;
+ break;
+
+ default:
+ usage (1);
+ break;
+ }
+ }
+
+ if (! dir)
+ dir = xstrdup (GRUB_LIBDIR);
+
+ path = grub_util_get_path (dir, "modsym.lst");
+
+ argv += optind;
+ argc -= optind;
+ if (argc == 0)
+ grub_util_error ("No command specified.");
+
+ read_symdb (path);
+ if (! strcmp (argv[0], "update"))
+ {
+ remove_mods (argv + 1);
+ update_mods (argv + 1, dir);
+ if (test_mode)
+ dump_update ();
+ else
+ {
+ apply_update (dir);
+ write_symdb (path);
+ }
+ }
+ else if (! strcmp (argv[0], "remove"))
+ {
+ remove_mods (argv + 1);
+ if (test_mode)
+ dump_update ();
+ else
+ {
+ apply_update (dir);
+ write_symdb (path);
+ }
+ }
+ else if (! strcmp (argv[0], "check"))
+ {
+ check_symdb ();
+ }
+ else
+ grub_util_error ("Unkown command %s.", argv[0]);
+
+ free (path);
+ free (dir);
+
+ return 0;
+}
diff --git a/util/resolve.c b/util/resolve.c
index 85aec72..37ee020 100644
--- a/util/resolve.c
+++ b/util/resolve.c
@@ -126,8 +126,8 @@ read_dep_list (FILE *fp)
return dep_list;
}
-static char *
-get_module_name (const char *str)
+char *
+grub_util_get_module_name (const char *str)
{
char *base;
char *ext;
@@ -152,8 +152,8 @@ get_module_name (const char *str)
return xstrdup (base);
}
-static char *
-get_module_path (const char *prefix, const char *str)
+char *
+grub_util_get_module_path (const char *prefix, const char *str)
{
char *dir;
char *base;
@@ -190,7 +190,7 @@ add_module (const char *dir,
struct mod_list *mod;
struct dep_list *dep;
- mod_name = get_module_name (name);
+ mod_name = grub_util_get_module_name (name);
/* Check if the module has already been added. */
for (mod = *mod_head; mod; mod = mod->next)
@@ -218,7 +218,7 @@ add_module (const char *dir,
/* Add this path. */
path = (struct grub_util_path_list *) xmalloc (sizeof (*path));
- path->name = get_module_path (dir, name);
+ path->name = grub_util_get_module_path (dir, name);
path->next = *path_head;
*path_head = path;
}