home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <stdarg.h>
- #include <string.h>
- #include <errno.h>
- #include <stdlib.h>
- #include <ctype.h>
- #include <sys/param.h>
- #include "link.h"
- #include "kernelsyms.h"
-
- static char verbose_flag = 0;
- static int from_kerneld = 0;
-
-
- static void verbose (const char *ctl, ...)
- {
- if (verbose_flag){
- va_list list;
- va_start (list,ctl);
- vprintf (ctl,list);
- va_end (list)
- fflush (stdout);
- }
- }
-
- /*
- Strip the extension of a file name
- Return a pointer to a static buffer
- */
- const char *stripo(const char *fname)
- {
- #if 0
- static char buf[300];
- strcpy (buf,fname);
- char *pt = buf + strlen(buf)-1;
- while (pt > buf){
- if (*pt == '.'){
- *pt = '\0';
- break;
- }
- pt--;
- }
- return buf;
- #else
- const char *pt = fname;
- while ((pt=strchr(fname,'/'))!=NULL) fname = pt+1;
- if ((pt = strrchr(fname, '.'))
- && ((strcmp(pt, ".o") == 0) || (strcmp(pt, ".mod") == 0))) {
- char *leak = (char *)malloc(pt - fname + 1);
- strncpy(leak, fname, pt - fname);
- leak[pt - fname] = '\0';
- fname = leak;
- }
- return fname;
- #endif
- }
-
- /*
- Return the options associated with a module.
- Return NULL if there is none.
- */
- static char *any_options(const char *mod)
- {
- const char *modname = stripo(mod);
- int len = strlen(modname);
-
- for (int i = 0; optlist[i]; ++i) {
- if (strncmp(optlist[i], modname, len) == 0
- && isspace (optlist[i][len])) {
- return str_skip(&(optlist[i][len]));
- }
- }
- return NULL;
- }
-
- class NODE{
- public:
- NODE *next;
- NODE *info;
- char *str;
- /*~PROTOBEG~ NODE */
- public:
- NODE (const char *_str, NODE *_next);
- NODE *lookup (const char *name);
- ~NODE (void);
- /*~PROTOEND~ NODE */
- };
-
- PUBLIC NODE::NODE(const char *_str, NODE *_next)
- {
- next = _next;
- info = NULL;
- str = strdup_err (_str);
- }
-
- PUBLIC NODE::~NODE()
- {
- delete info;
- delete next;
- free (str);
- }
-
- PUBLIC NODE * NODE::lookup (const char *name)
- {
- NODE *ret = NULL;
- if (strcmp(name,str)==0){
- ret = this;
- }else if (next != NULL){
- ret = next->lookup(name);
- }
- return ret;
- }
-
- class DEPEND{
- NODE *in_kernel;
- NODE *dep_file;
- /*~PROTOBEG~ DEPEND */
- public:
- DEPEND (void);
- int insmod (const char *mod,
- NODE **newin_kernel,
- char *options[]);
- int read (const char *cfgfile);
- int readcur (void);
- int unload (const char *mod);
- ~DEPEND (void);
- /*~PROTOEND~ DEPEND */
- };
-
- PUBLIC DEPEND::DEPEND()
- {
- in_kernel = NULL;
- dep_file = NULL;
- }
- PUBLIC DEPEND::~DEPEND()
- {
- delete in_kernel;
- delete dep_file;
- }
- /*
- Read the liste of module already loaded in the kernel
- */
- PUBLIC int DEPEND::readcur ()
- {
- #if 0
- int ret = -1;
- FILE *fin = fopen ("/proc/modules","r");
- delete in_kernel;
- in_kernel = NULL;
- if (fin != NULL){
- char buf[300];
- char mod[300];
- while(fgets(buf,sizeof(buf)-1,fin)!=NULL
- && sscanf(buf,"%s",mod)==1){
- in_kernel = new NODE(stripo(mod),in_kernel);
- }
- fclose (fin);
- ret = 0;
- }
- #else
- int ret = 0;
- delete in_kernel;
- in_kernel = NULL;
- struct kernel_sym *ksym;
- int so_far = 0;
-
- load_kernel_symbols();
-
- for (ksym = ksymtab; so_far < nksyms ; ++so_far, ksym++) {
- if (ksym->name[0] == '#') {
- if (ksym->name[1]) {
- in_kernel = new NODE(ksym->name + 1,in_kernel);
- }
- else
- break;
- }
- }
- #endif
- return ret;
- }
- /*
- Read the dependancy file.
- The format is like a makefile.
- */
- PUBLIC int DEPEND::read (const char *cfgfile)
- {
- int ret = -1;
- FILE *fin = fopen (cfgfile,"r");
- if (fin == NULL){
- depmod_error ("Can't open dependancies file %s (%s)"
- ,cfgfile,strerror(errno));
- }else{
- char buf[300];
- ret = 0;
- while(fgets(buf,sizeof(buf)-1,fin)!=NULL){
- char line[300];
- str_strip (buf,line);
- if (line[0] != '\0'){
- char *pt = line;
- while (isspace(*pt)) pt++;
- char *modname = pt;
- while (*pt != ':' && *pt != '\0' && !isspace(*pt)) pt++;
- if (*pt != ':'){
- depmod_error ("Invalid dependancy\n\t%s",line);
- ret = -1;
- }else{
- *pt++ = '\0';
- dep_file = new NODE (modname,dep_file);
- // Parse the list of modules
- while (*pt != '\0'){
- while (isspace (*pt)) pt++;
- if (*pt > ' '){
- char *depname = pt;
- while (*pt > ' ') pt++;
- if (*pt != '\0') *pt++ = '\0';
- dep_file->info = new NODE (depname
- ,dep_file->info);
- }
- }
- }
- }
- }
- fclose (fin);
- ret = 0;
- }
- return ret;
- }
- static int call_rmmod(const char *mod)
- {
- char cmd[300];
- mod = stripo(mod);
- sprintf (cmd,"/sbin/rmmod %s %s",(depmod_syslog ? "-s" : ""),mod);
- // This special sequence is there so error message generated
- // by rmmod are indented.
- verbose ("\r\t%s\n\t\t",cmd);
- int ret = system(cmd);
- return ret;
- }
- /*
- Unload all submodule in reverse order they were loaded.
- Return -1 if any error.
- */
- static int rmmod (NODE *nod)
- {
- int ret = 0;
- if (nod != NULL){
- ret = rmmod (nod->next);
- if (ret == 0){
- ret = call_rmmod(nod->str);
- }
- }
- return ret;
- }
- static NODE *lookup (NODE *nod, const char *str)
- {
- NODE *ret = NULL;
- if (nod != NULL){
- ret = nod->lookup (str);
- }
- return ret;
- }
- /*
- Try to load a module and the sub-module needed.
- Return -1 if any error.
-
- If the module can't ne loaded, undo everything.
- */
- PUBLIC int DEPEND::insmod (
- const char *mod,
- NODE **newin_kernel, // modules added by this session
- char *options[])
- {
- int ret = 0;
- if (mod != NULL
- && lookup (in_kernel,stripo(mod))==NULL
- && lookup (*newin_kernel,mod)==NULL){
- NODE *nod = lookup (dep_file,mod);
- if (nod == NULL){
- depmod_error ("No dependancy information for module %s",mod);
- ret = -1;
- }else{
- NODE *dep = nod->info;
- while (dep != NULL && ret == 0){
- ret = insmod (dep->str,newin_kernel,NULL);
- dep = dep->next;
- }
- if (ret == 0){
- char cmd[300];
- sprintf (cmd,"/sbin/insmod %s %s %s"
- ,from_kerneld ? "-k" : ""
- ,depmod_syslog ? "-s" : ""
- ,mod);
- char *op;
- if (options && options[0] &&
- strchr(options[0], '=')) {
- for (int nopt = 0; options[nopt]; ++nopt) {
- if (strchr(options[nopt], '=')){
- strcat(cmd, " ");
- strcat(cmd, options[nopt]);
- }
- else
- break;
- }
- }
- else if (op = any_options(mod)) {
- strcat(cmd, " ");
- strcat(cmd, op);
- }
- verbose ("\r\t%s\n\t\t",cmd);
- /* For now, seems like insmod is not reporting */
- /* success or failure correctly, so we read */
- /* /proc/modules each time */
- ret = system(cmd);
- //readcur();
- //ret = lookup (in_kernel,stripo(mod))==NULL ? -1 : 0;
- //verbose (" -> %s\n",ret==0 ? "OK" : "Error");
- if (ret != 0){
- // Must unload all the sub-module
- rmmod (nod->info);
- }else{
- *newin_kernel = new NODE (mod,*newin_kernel);
- }
- }else{
- rmmod (nod->info);
- readcur();
- }
- }
- }
- return ret;
- }
- /*
- Unload a module and whatever modules was requiered by this module.
- We blindly remove everything in order, even if a module is needed
- by another module. The idea is that this module will refuse to
- unload.
-
- Return -1 if the first module cound not be unloaded.
- */
- PUBLIC int DEPEND::unload (
- const char *mod)
- {
- int ret = 0;
- if (mod != NULL){
- char *tbpath[1000];
- int nbl = config_locate (mod,tbpath,NULL);
- if (nbl == 0){
- /* #Specification: modprobe -r / unknown module
- If there is no information about a module in
- the dependancy file, we simply call /sbin/rmmod
- on the module without further checking.
- */
- ret = call_rmmod(mod);
- }else{
- for (int m=0; m<nbl; m++){
- char *path = tbpath[m];
- if(lookup (in_kernel,stripo(path))!=NULL){
- NODE *nod = lookup (dep_file,path);
- if (nod == NULL){
- depmod_error (
- "No dependancy information for module %s"
- ,mod);
- }else{
- ret = call_rmmod (path);
- /* We don't care if we succeed */
- /* to unload sub-modules. */
- NODE *dep = nod->info;
- while (dep != NULL){
- unload (dep->str);
- dep = dep->next;
- }
- }
- }
- }
- tbstr_free (tbpath,nbl);
- }
- }
- return ret;
- }
-
-
-
- static int modprobe_fromlist (
- DEPEND &dep,
- char *list[],
- int nb,
- const char *type,
- int loadall)
- {
- int ret = -1;
- for (int i=0; i<nb; i++){
- NODE *newin_kernel = NULL;
- char *tbpath[1000];
- /* #Specification: modprobe / module option
- We can pass option to module in the modprobe's command line.
- It goes like this:
- #
- /sbin/modprobe module opt1=value opt2=value [ othermodule ...]
- #
- An option is a keyword followed by an equal sign and a value.
- No space are allowed in the sequence, unless it is quoted.
-
- The option list end at the end of the list or at the
- first non-option argument (a module).
- */
- if (strchr(list[i], '=') == NULL) {
- int nbl = config_locate (list[i],tbpath,type);
- if (nbl == 0){
- depmod_error ("Can't locate module %s",list[i]);
- }else{
- for (int m=0; m<nbl; m++){
- if (dep.insmod (tbpath[m],&newin_kernel,&list[i+1])
- != -1){
- ret = 0;
- if (!loadall) break;
- }
- }
- tbstr_free (tbpath,nbl);
- }
- }
- delete newin_kernel;
- if (ret == 0 && !loadall) break;
- }
- return ret;
- }
- /*
- Print all available module matching "pattern" and of a certain type.
- type may be NULL.
- */
- static void modprobe_printlist (
- const char *pattern,
- const char *type)
- {
- char *lst[1000];
- int nb = config_lstmod (pattern,type,lst,1);
- for (int i=0; i<nb; i++) printf ("%s\n",lst[i]);
- tbstr_free (lst,nb);
- }
-
- static void modprobe_nothing(const char *str)
- {
- depmod_error (
- "Nothing to %s ???\n"
- "Specify at least a module or a wildcard like \\*",str);
- }
-
- int modprobe_main (int argc, char *argv[])
- {
- int ret = -1;
- if (argc == 1){
- fprintf (stderr,
- "modprobe " DEPMOD_RELEASE "\n"
- "Load/Unload modules with dependancies\n"
- "\n"
- "modprobe [-a] [ -t type ] module1 module2 ...\n"
- "modprobe -c\n"
- "\n"
- " modprobe will try to load one of module1 module2 and will\n"
- " automaticly load the modules needed by module1 or module2\n"
- " using the dependancy file (see " ETC_CONF_MODULES ").\n"
- " If type is specified, the modules will be search only\n"
- " in the corresponding directory (See path[type]=... in\n"
- " " ETC_CONF_MODULES "). Note that modprobe can expand\n"
- " wildcards, so\n"
- "\n"
- " modprobe -t net \\* \n"
- " will load one of the ethernet driver.\n"
- "\n"
- " Unless -a option is provided, modprobe will\n"
- " stop loading as soon as one module load sucessfully\n"
- "\n"
- " modprobe -a -t boot \\*\n"
- " will load all module of type boot.\n"
- "\n"
- "modprobe -r module\n"
- " remove a module and all sub-modules it depends on\n"
- "\n"
- "modprobe -l [ -t type ] [ pattern ]\n"
- " will list all modules available. With option -t, it will\n"
- " shows only those of a certain type. A pattern may be used\n"
- " to limit the output.\n"
- "\n"
- "modprobe -c\n"
- " will display the current configuration\n"
- "\n"
- "It is calling /sbin/insmod and /sbin/rmmod to achieve its goal.\n"
- );
- }else if (config_read()!=-1){
- DEPEND dep;
- if (dep.read(config_getdepfile())!=-1
- && dep.readcur()!=-1){
- ret = 0;
- int loadall = 0; // Load only one module out of a list
- char *type = NULL; // Search in all path[]
- int remove = 0;
- int showconfig = 0;
- int list = 0;
- int noarg = 1;
- while (1){
- char *arg = argv[noarg];
- if (arg == NULL || arg[0] != '-'){
- break;
- }else if (!isalpha(arg[1])){
- depmod_error ("Invalid option %s",arg);
- ret = -1;
- }else{
- char *opt = arg + 2;
- if (arg[1] == 't'){
- if (opt[0] != '\0'){
- type = opt;
- }else if (noarg < argc-1){
- type = argv[++noarg];
- }else{
- depmod_error ("Missing value for option -t");
- ret = -1;
- }
- }else if (arg[1] == 'a'){
- loadall = 1;
- }else if (arg[1] == 'c'){
- showconfig = 1;
- }else if (arg[1] == 'd'){
- debugmode = 1;
- }else if (arg[1] == 'l'){
- list = 1;
- }else if (arg[1] == 'r'){
- remove = 1;
- }else if (arg[1] == 'v'){
- verbose_flag = 1;
- }else if (arg[1] == 'k'){
- from_kerneld = 1;
- }else if (arg[1] == 's'){
- depmod_setsyslog ("modprobe");
- }else{
- depmod_error ("Invalid option %s",arg);
- ret = -1;
- }
- }
- noarg++;
- }
- if (ret != -1){
- int left = argc - noarg;
- char **lst = argv + noarg;
- if (showconfig){
- config_show();
- }else if (remove){
- if (left == 0){
- modprobe_nothing ("remove");
- }else{
- for (int i=0; i<left && ret == 0; i++){
- ret = dep.unload (lst[i]);
- }
- }
- }else if (list){
- if (left > 0){
- for (int i=0; i<left && ret == 0; i++){
- modprobe_printlist (lst[i],type);
- }
- }else{
- modprobe_printlist ("*",type);
- }
- ret = 0;
- }else{
- if (left == 0){
- modprobe_nothing ("load");
- }else{
- ret = modprobe_fromlist (dep,lst,left,type,loadall);
- }
- }
- }
- }
- }
- verbose ("\n");
- return ret;
- }
-
-