home *** CD-ROM | disk | FTP | other *** search
- /* Copyright 1997 Free Software Foundation, Inc.
- Contributed by Marcin Dalecki <dalecki@sub994.sub.uni-goettingen.de>
-
- This file is part of the Linux modutils.
-
- 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 2 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, write to the Free Software Foundation,
- Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
- #ident "$Id: depmod.c,v 1.1.1.1 1998/01/06 20:51:07 ewt Exp $"
-
- #include <stdio.h>
- #include <assert.h>
- #include <string.h>
- #include <stdlib.h>
- #include <unistd.h>
- #include <getopt.h>
- #include <errno.h>
- #include <elf.h>
- #include ELF_MACHINE_H
-
- #include "util.h"
- #include "obj.h"
- #include "misc.h"
- #include "conf_file.h"
-
- int n_objs = 0;
- int max_objs = 0;
- struct obj_file **objs;
- char **names;
-
- /*======================================================================*/
-
- static int flag_show_error = 0;
- static int flag_verbose = 0;
-
- #ifndef NO_COMPAT
- static int flag_new_syscalls = 0;
- #endif
-
- struct new_module_symbol *ksyms;
- size_t nksyms;
-
- /*======================================================================*/
-
- static void
- new_read_kernel_syms (void)
- {
- struct new_module_symbol *syms, *s;
- size_t ret, bufsize, nsyms, j;
-
- /* Collect the kernel's symbols. */
-
- syms = xmalloc (bufsize = 16 * 1024);
- retry_kern_sym_load:
- if (query_module (NULL, QM_SYMBOLS, syms, bufsize, &ret))
- {
- if (errno == ENOSPC)
- {
- syms = xrealloc (syms, bufsize = ret);
- goto retry_kern_sym_load;
- }
- error ("kernel: QM_SYMBOLS: %m");
- exit (1);
- }
- nksyms = nsyms = ret;
- ksyms = syms;
-
- for (j = 0, s = syms; j < nsyms; ++j, ++s)
- s->name += (unsigned long) syms;
- }
-
- #ifndef NO_COMPAT
-
- static void
- old_read_kernel_syms (void)
- {
- struct old_kernel_sym *ks, *k;
- struct new_module_symbol *s;
- int nks, nms, i;
-
- nks = get_kernel_syms(NULL);
- if (nks < 0)
- {
- error("get_kernel_syms: %m");
- return;
- }
-
- ks = k = xmalloc(nks * sizeof(*ks));
- if (get_kernel_syms(ks) != nks)
- {
- error("inconsistency with get_kernel_syms -- is someone else "
- "playing with modules?");
- free(ks);
- return;
- }
-
- /* Collect the module information. */
-
- while (k->name[0] != '#' || k->name[1])
- ++k;
- ++k;
-
- nksyms = nms = nks - (k - ks);
- ksyms = s = (nms ? xmalloc(nms * sizeof(*s)) : NULL);
-
- for (i = 0; i < nms; ++i, ++s, ++k)
- {
- s->name = (unsigned long)k->name;
- s->value = k->value;
- }
- }
-
- #endif
-
- /*
- * Format the dependency list of a module into a simple makefile
- */
- static void
- print_deps_file (const char *depfile)
- {
- FILE *fout = stdout;
- char **deps;
- int max_deps = 64;
- int o;
-
- deps = (char **) xmalloc (max_deps * sizeof (char *));
-
- if (depfile && !(fout = fopen (depfile, "w")))
- {
- lprintf ("can't open %s", depfile);
- exit (1);
- }
-
- /*
- * Loop through all modules we visited and construct the dependencies.
- */
- for (o = 0; o < n_objs; ++o)
- {
- int errs = 0;
- int n_deps = 0;
- int i;
-
- /*
- * Loop throught all undefined symbols of this object
- */
- for (i = 0; i < HASH_BUCKETS; ++i)
- {
- struct obj_symbol *sym;
- for (sym = objs[o]->symtab[i]; sym; sym = sym->next)
- {
- int j;
- int k;
-
- if (sym->secidx != SHN_UNDEF
- || ELFW (ST_BIND) (sym->info) == STB_WEAK)
- continue;
-
- /*
- * Traverse all modules and search for one, where it may be
- * defined.
- */
- for (j = 0; j < n_objs; ++j)
- {
- struct obj_symbol *tmp;
- if (j == o)
- continue;
-
- tmp = obj_find_symbol (objs[j], sym->name);
- if (tmp && tmp->secidx != SHN_UNDEF)
- break;
- }
- if (j == n_objs)
- {
- if (errs == 0)
- lprintf ("%s: unresolved symbol(s)"
- ,names[o]);
- if (flag_show_error)
- lprintf ("\t%s", sym->name);
- errs++;
- continue;
- }
-
- /*
- * Look if it's allready there
- */
- for (k = 0; k < n_deps; ++k)
- if (deps[k] == names[j])
- break;
- /*
- * And add the dep info if neccessary.
- */
- if (k != n_deps)
- continue;
-
- if (k == max_deps)
- {
- max_deps <<= 1;
- deps = (char **)
- xrealloc (deps, max_deps * sizeof (char *));
- }
- deps[k] = names[j];
- ++n_deps;
- }
- }
-
- if (errs == 0 && flag_verbose)
- printf ("%s\n", names[o]);
- fprintf (fout, "%s:", names[o]);
-
- /*
- * Print the dependencies for this module.
- */
- #if 1
- while (n_deps--)
- fprintf (fout, " %s", deps[n_deps]);
- #else
- for (i = 0; i < n_deps; ++i)
- fprintf (fout, " %s", deps[i]);
- #endif
- fprintf (fout, "\n\n");
- }
- if (fout != stdout)
- fclose (fout);
- free (deps);
- }
-
- /*
- * Load an object file and resolve all the symbols contained therein.
- */
- static int
- load_obj_file (const char *module)
- {
- FILE *fp;
- struct obj_file *file;
- struct obj_symbol *sym;
- int i;
-
- if (!(fp = fopen (module, "r")))
- {
- error("%s: open: %m", module);
- return 1;
- }
-
- file = obj_load (fp);
- fclose (fp);
-
- if (!file)
- {
- /* obj_load will already have printed an error message. */
- return 1;
- }
-
- if (n_objs == max_objs)
- {
- max_objs <<= 2;
- objs = (struct obj_file **)
- xrealloc (objs, max_objs * sizeof (struct obj_file *));
- names = (char **) xrealloc (names, max_objs * sizeof (char *));
- }
- objs[n_objs] = file;
- names[n_objs] = xstrdup (module);
-
- /*
- * Hide the kernel symbols...
- */
- for (i = 0; i < nksyms; ++i)
- if ((sym = obj_find_symbol (file, (char *) ksyms[i].name)) != NULL)
- sym->secidx = SHN_HIRESERVE + 1;
-
- /*
- * Hide them they are used by insmod internally.
- */
- if ((sym = obj_find_symbol (file, "__this_module")) != NULL)
- sym->secidx = SHN_HIRESERVE + 1;
- if ((sym = obj_find_symbol (file, "mod_use_count_")) != NULL)
- sym->secidx = SHN_HIRESERVE + 1;
- ++n_objs;
-
- return 0;
- }
-
- /*
- * Print usage information ans exit.
- */
- static void
- usage (void)
- {
- puts(
- "Usage: depmod [-e -s -v ] -a [FORCED_KERNEL_VER]\n"
- " depmod [-e -s -v ] MODULE_1.o MODULE_2.o ...\n"
- "Create module-dependency information for modprobe.\n\n"
- " -a, --all visit all modules\n"
- " -d, --debug run in debug mode\n"
- " -e output unresolved symbols\n"
- " -s, --system-log use the system log for error reporting\n"
- " --help display this help and exit\n"
- " -v, --verbose run in verbose mode\n"
- " -V, --version output version information and exit"
- );
- }
-
- int
- main (int argc, char *argv[])
- {
- int ret = 1;
- int flag_stdmode = 0;
-
- int opt_tag;
-
- if (argc == 1)
- {
- usage ();
- return 1;
- }
-
- #ifndef NO_COMPAT
- flag_new_syscalls = !query_module (NULL, 0, NULL, 0, NULL);
- if (!flag_new_syscalls)
- old_read_kernel_syms ();
- else
- #endif
- new_read_kernel_syms ();
-
- /*
- * Yes we are using getopts!
- */
- while (1)
- {
- static struct option long_opts[] =
- {
- {"all", 0, 0, 'a'},
- {"debug", 0, 0, 'd'},
- {"system-log", 0, 0, 's'},
- {"verbose", 0, 0, 'v'},
- {"version", 0, 0, 'V'},
- {"help", 0, 0, 'h'},
- {0, 0, 0, 0} /* Table end tag */
- };
- int opt_ind = 0;
-
- opt_tag = getopt_long (argc, argv, "adesvV", long_opts,
- &opt_ind);
- if (opt_tag == -1)
- break;
-
- switch (opt_tag)
- {
- case 'a':
- flag_stdmode = 1;
- break;
-
- case 'd':
- flag_debug = 1;
- break;
-
- case 'e':
- flag_show_error = 1;
- break;
-
- case 's':
- setsyslog ("depmod"); /* use the syslog for reporting */
- break;
-
- case 'v':
- flag_verbose = 1; /* give terse informations during run */
- break;
-
- case '?':
- case 'h':
- usage ();
- exit (opt_tag == 'h' ? 0 : 1);
- break;
-
- case 'V':
- puts ("depmod (Linux modutils) " MODUTILS_VERSION);
- if (argc != 2)
- putchar ('\n');
- break;
-
- default:
- abort ();
- }
- }
-
- /*
- * Skip all automatically processed options.
- */
- argc -= optind;
- argv += optind;
-
- /*
- * argv now points to the first non-option argument
- * argc is the remaining argument count
- */
-
- n_objs = 0;
- max_objs = 64;
- objs = (struct obj_file **) xmalloc (max_objs * sizeof (struct obj_file *));
- names = (char **) xmalloc (max_objs * sizeof (char *));
-
- if (flag_stdmode)
- {
- struct mod_path *mods = NULL;
- struct mod_path *tmp;
-
- if (argc > 0)
- {
- if (read_config_file (*argv))
- {
- lprintf ("%s does not exist", depfile);
- return 1;
- }
- }
- else
- {
- /* Read the default config file and don't complain if there
- isn't one. */
- read_config_file (NULL);
- }
-
- mods = find_matching_mods ("*", NULL, 1);
- ret = 0;
- while ((tmp = mods))
- {
- ret |= load_obj_file (mods->path);
- mods = mods->next;
- free (tmp->path);
- free (tmp);
- }
- while ((tmp = mods))
- {
- mods = mods->next;
- free (tmp->path);
- free (tmp);
- }
-
- if (!ret)
- print_deps_file (depfile);
- }
- else
- {
- /*
- * Process all modules which are explicitly specified on the command line
- */
-
- for (ret = 0; argc > 0 && !ret; ++argv, --argc)
- ret = load_obj_file (*argv);
- if (!ret)
- print_deps_file (NULL);
- }
-
- return ret;
- }
-