#include #include #include #include #include "askrunlevel.h" #include #include #include #include #include #include #include "../paths.h" static HELP_FILE helpf (HELP_ASKRUN,"ksyms"); static CONFIG_FILE f_procsym ("/proc/ksyms",helpf ,CONFIGF_OPTIONAL|CONFIGF_PROBED); static HELP_FILE helpm (HELP_ASKRUN,"modules"); static CONFIG_FILE f_procmod ("/proc/modules",helpm ,CONFIGF_OPTIONAL|CONFIGF_PROBED); static CONFIG_FILE f_conf (ETC_MODULES_CONF,helpm ,CONFIGF_OPTIONAL|CONFIGF_MANAGED,subsys_hardware); class PARMVAL: public ARRAY_OBJ{ public: SSTRING parm; SSTRING val; bool single; // Is this a PARM=VAL or simply a PARM option /*~PROTOBEG~ PARMVAL */ public: PARMVAL (const char *_parm); PARMVAL (const char *_parm, const char *_line); /*~PROTOEND~ PARMVAL */ }; PUBLIC PARMVAL::PARMVAL (const char *_parm, const char *_line) { parm.setfrom (_parm); val.copyword (_line); single = false; } PUBLIC PARMVAL::PARMVAL (const char *_parm) { parm.copyword (_parm); single = true; } class PARMVALS: public ARRAY{ /*~PROTOBEG~ PARMVALS */ public: PARMVAL *getitem (int no)const; void setoption (const char *optname, const char *val); /*~PROTOEND~ PARMVALS */ }; PUBLIC PARMVAL *PARMVALS::getitem(int no) const { return (PARMVAL*)ARRAY::getitem(no); } PUBLIC void PARMVALS::setoption (const char *optname, const char *val) { int n = getnb(); int i; for (i=0; iparm.cmp(optname)==0){ if (*val == '\0'){ remove_del(i); }else{ p->val.setfrom (val); p->single = false; } break; } } if (i == n && *val != '\0') add (new PARMVAL(optname,val)); } enum USAGE_MODE { USAGE_KERNELD, // On demand loading USAGE_BOOT, // Load at boot time USAGE_MANUAL, // Don't load automaticly USAGE_KERNELD_STICK, // Load once with kerneld }; class MODULE_LINE: public ARRAY_OBJ{ public: SSTRING pre_comments; SSTRING end_comment; virtual void write_begin (FILE_CFG *fout)=0; /*~PROTOBEG~ MODULE_LINE */ public: MODULE_LINE (const SSTRING&pre_com, const char *end_com); MODULE_LINE (void); void write (FILE_CFG *fout); /*~PROTOEND~ MODULE_LINE */ }; PUBLIC MODULE_LINE::MODULE_LINE ( const SSTRING &pre_com, const char *end_com) { pre_comments.setfrom (pre_com); end_comment.setfrom (end_com); } PUBLIC MODULE_LINE::MODULE_LINE () { } PUBLIC void MODULE_LINE::write (FILE_CFG *fout) { comment_write (pre_comments,fout); write_begin (fout); if (!end_comment.is_empty()){ fprintf (fout,"# %s",end_comment.get()); } fputs ("\n",fout); } /* Contain configuration commands and options not managed by linuxconf */ class MODULE_LINE_IGNORE: public MODULE_LINE{ public: SSTRING begin; /*~PROTOBEG~ MODULE_LINE_IGNORE */ public: MODULE_LINE_IGNORE (const char *_begin, const SSTRING&pre_com, const char *end_com); void write_begin (FILE_CFG *fout); /*~PROTOEND~ MODULE_LINE_IGNORE */ }; PUBLIC MODULE_LINE_IGNORE::MODULE_LINE_IGNORE ( const char *_begin, const SSTRING &pre_com, const char *end_com) : MODULE_LINE (pre_com,end_com) { begin.setfrom (_begin); } PUBLIC void MODULE_LINE_IGNORE::write_begin(FILE_CFG *fout) { fprintf (fout,"%s ",begin.get()); } class MODULE_LINES: public ARRAY{ /*~PROTOBEG~ MODULE_LINES */ public: MODULE_LINE *getitem (int no)const; /*~PROTOEND~ MODULE_LINES */ }; PUBLIC MODULE_LINE* MODULE_LINES::getitem (int no) const { return (MODULE_LINE*)ARRAY::getitem(no); } class MODULE_CONF: public MODULE_LINE{ public: SSTRING name; PARMVALS parms; // Array of configurable parameter USAGE_MODE umode; /*~PROTOBEG~ MODULE_CONF */ public: MODULE_CONF (char *line, const SSTRING&pre_com, const char *end_com); MODULE_CONF (const char *_name); void write_begin (FILE_CFG *fout); /*~PROTOEND~ MODULE_CONF */ }; PUBLIC MODULE_CONF::MODULE_CONF( char *line, const SSTRING &pre_com, const char *end_com) : MODULE_LINE (pre_com,end_com) { line = name.copyword (line); while (1){ line = str_skip(line); if (line[0] == '\0') break; char *pt = strchr(line,'='); if (pt != NULL){ *pt++ = '\0'; strip_end (line); pt = str_skip (pt); parms.add (new PARMVAL (line,pt)); line = pt; }else{ parms.add (new PARMVAL (line)); } line = str_skipword(line); } } PUBLIC MODULE_CONF::MODULE_CONF(const char *_name) { name.setfrom (_name); } PUBLIC void MODULE_CONF::write_begin(FILE_CFG *fout) { int n = parms.getnb(); if (n > 0){ fprintf (fout,"options %s ",name.get()); for (int i=0; isingle){ fprintf (fout,"%s ",p->parm.get()); }else{ fprintf (fout,"%s=%s ",p->parm.get(),p->val.get()); } } } } class MODULE_CONFS: public ARRAY{ /*~PROTOBEG~ MODULE_CONFS */ public: MODULE_CONF *getitem (int no)const; /*~PROTOEND~ MODULE_CONFS */ }; PUBLIC MODULE_CONF* MODULE_CONFS::getitem(int no) const { return (MODULE_CONF*)ARRAY::getitem(no); } class MODULE_ALIAS: public MODULE_LINE{ public: SSTRING alias; SSTRING module; /*~PROTOBEG~ MODULE_ALIAS */ public: MODULE_ALIAS (const char *_alias, const char *_module); MODULE_ALIAS (const char *line, const SSTRING&pre_com, const char *end_com); void write_begin (FILE_CFG *fout); /*~PROTOEND~ MODULE_ALIAS */ }; PUBLIC MODULE_ALIAS::MODULE_ALIAS ( const char *line, const SSTRING &pre_com, const char *end_com) : MODULE_LINE(pre_com,end_com) { line = str_skip(line); line = alias.copyword (line); line = str_skip(line); module.setfrom(line); } PUBLIC MODULE_ALIAS::MODULE_ALIAS (const char *_alias, const char *_module) { alias.setfrom (_alias); module.setfrom (_module); } PUBLIC void MODULE_ALIAS::write_begin (FILE_CFG *fout) { fprintf (fout,"alias %s %s ",alias.get(),module.get()); } class MODULE_ALIASES: public ARRAY{ /*~PROTOBEG~ MODULE_ALIASES */ public: MODULE_ALIAS *getitem (int no)const; /*~PROTOEND~ MODULE_ALIASES */ }; PUBLIC MODULE_ALIAS *MODULE_ALIASES::getitem(int no) const { return (MODULE_ALIAS*)ARRAY::getitem(no); } class MODULES{ public: MODULE_LINES lines; MODULE_ALIASES aliases; MODULE_CONFS confs; SSTRING last_comment; /*~PROTOBEG~ MODULES */ public: MODULES (void); MODULE_ALIAS *getalias (const char *name); MODULE_CONF *getconf (const char *name); void setalias (const char *alias, const char *module); void setoption (const char *module, const char *option, const char *value); int write (void); /*~PROTOEND~ MODULES */ }; PUBLIC MODULES::MODULES() { /* We maintain a list of object and a list of lines. The aliases and confs tables contains the same pointers as the lines object. So they are not allowed to delete them. We do this to preserver comments in that file and the ordering of the file. This strategy should probably be generalised to other config files. */ aliases.neverdelete(); confs.neverdelete(); FILE_CFG *fin = f_conf.fopen ("r"); if (fin != NULL){ char buf[1000]; SSTRING comments; while (fgets_comments (buf,sizeof(buf)-1,fin,comments)!=NULL){ char *pt = str_skip(buf); char *endcom = strchr(pt,'#'); if (endcom != NULL){ *endcom++ = '\0'; strip_end (buf); } if (str_isword(pt,"options")){ pt += 7; MODULE_CONF *conf = new MODULE_CONF(pt,comments,endcom); confs.add (conf); lines.add (conf); }else if (str_isword(pt,"alias")){ pt += 5; MODULE_ALIAS *alias = new MODULE_ALIAS(pt,comments,endcom); aliases.add (alias); lines.add (alias); }else{ MODULE_LINE_IGNORE *line = new MODULE_LINE_IGNORE (pt,comments,endcom); lines.add (line); } comments.setfrom(""); } last_comment.setfrom (comments); fclose (fin); } } PUBLIC int MODULES::write () { int ret = -1; FILE_CFG *fout = f_conf.fopen ("w"); if (fout != NULL){ int n = lines.getnb(); for (int i=0; iwrite (fout); } comment_write (last_comment,fout); ret = fclose (fout); } return ret; } /* Get the configuration for a specific module */ PUBLIC MODULE_CONF *MODULES::getconf (const char *name) { MODULE_CONF *ret = NULL; int n = confs.getnb(); for (int i=0; iname.cmp(name)==0){ ret = a; break; } } return ret; } /* Get the module associate with an alias */ PUBLIC MODULE_ALIAS *MODULES::getalias(const char *name) { MODULE_ALIAS *ret = NULL; int n = aliases.getnb(); for (int i=0; ialias.cmp(name)==0){ ret = a; break; } } return ret; } PUBLIC void MODULES::setalias (const char *alias, const char *module) { MODULE_ALIAS *a = getalias (alias); if (a != NULL){ a->module.setfrom (module); }else{ a = new MODULE_ALIAS (alias,module); aliases.add (a); lines.add (a); } } PUBLIC void MODULES::setoption ( const char *module, const char *option, const char *value) { MODULE_CONF *c = getconf (module); if (c == NULL && *value != '\0'){ c = new MODULE_CONF (module); confs.add (c); lines.add (c); } if (c != NULL) c->parms.setoption (option,value); } class MODULE_VIRTDB: public VIRTDB{ /*~PROTOBEG~ MODULE_VIRTDB */ public: MODULE_VIRTDB (void); int docmd (VIRTDB_CMD cmd, int argc, char *argv[]); /*~PROTOEND~ MODULE_VIRTDB */ }; PUBLIC MODULE_VIRTDB::MODULE_VIRTDB() : VIRTDB ("modules.conf") { } PUBLIC int MODULE_VIRTDB::docmd (VIRTDB_CMD cmd, int argc, char *argv[]) { int ret = -1; if (argc < 2){ fprintf (stderr,"*** alias module\n options module\n"); }else{ MODULES mods; const char *verb = argv[0]; const char *module = argv[1]; #if 0 { printf ("-----------\n"); int n = mods.aliases.getnb(); for (int i=0; iwrite (stdout); } printf ("----confs----\n"); n = mods.confs.getnb(); for (i=0; iwrite (stdout); } printf ("-----------\n"); } printf ("command %d verb :%s: module :%s:\n",cmd,verb,module); #endif MODULE_ALIAS *a = mods.getalias (module); MODULE_CONF *c = mods.getconf (module); if (cmd == VIRTDB_GETALL){ if (strcmp(verb,"alias")==0){ if (a != NULL){ printf ("alias %s %s\n",module,a->module.get()); } }else if (strcmp(verb,"options")==0){ if (c != NULL){ //c->write_begin (stdout); assert(0); // Not done, anyway the virtdb will // be replaced by the vregistry puts("\n"); } } ret = 0; }else if (cmd == VIRTDB_REPLACE){ if (strcmp(verb,"alias")==0){ mods.setalias (module,argv[2]); }else if (strcmp(verb,"options")==0){ if (strlen(argv[2])<200){ char optname[200]; strcpy (optname,argv[2]); char *pt = strchr(optname,'='); if (pt != NULL){ *pt++ = '\0'; mods.setoption (module,optname,pt); } } } ret = mods.write(); } } return ret; } static MODULE_VIRTDB v; /* Make sure the modules are properly installed Return 0 if nothing at all, 1 if the directory exist, 2 if modules.dep exist. */ static int modules_installed() { int ret = 0; int v[3]; /* #Specification: modules / depmod linuxconf will call "depmod -a" if /lib/modules/kernel_version exist and /lib/modules/kernel_version/modules.dep do not exist and /proc/ksyms exist. */ if (kernel_version(v)!=-1 && f_procsym.exist()){ char path[PATH_MAX]; sprintf (path,"%s/%d.%d.%d",LIB_MODULES,v[0],v[1],v[2]); if (file_exist(path)){ ret = 1; sprintf (path,"%s/%d.%d.%d/modules.dep",LIB_MODULES,v[0],v[1],v[2]); if (file_exist(path)){ ret = 2; } } } return ret; } /* Make sure the modules are properly installed */ void modules_check() { if (modules_installed() == 1){ netconf_system_if ("depmod","-a"); } if (!distrib_isenhanced() && !kernel_newer (2,2,0)){ int avail = modules_avail(); if (avail != -1) netconf_startstop ("kerneld","kerneld",avail); } } /* Return 1 if there are some kernel modules available on this system, 0 if there are none or -1 if it can't be sure. */ int modules_avail () { int ret = -1; if (modules_installed()==2){ DAEMON_INTERNAL *dae = daemon_find ("modprobe"); if (dae != NULL && dae->is_managed()){ char cmd[200]; sprintf (cmd,"%s -l",dae->getpath()); POPEN pop (cmd); while (pop.wait(1000)>0){ char buf[300]; while (pop.readout(buf,sizeof(buf)-1)!=-1) ret = 1; } } } return ret; } /* Just to ease linking */ void modules_dummy() { } /* Return != 0 if a module is loaded */ int module_is_loaded (const char *name) { int ret = 0; FILE_CFG *fin = f_procmod.fopen ("r"); if (fin != NULL){ char buf[400]; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ char mod[100]; str_copyword (mod,buf,sizeof(mod)); if (strcmp(mod,name)==0){ ret = 1; break; } } fclose (fin); } return ret; } /* Set/replace one alias line in /etc/modules.conf */ int modules_setalias ( const char *device, // Pseudo module, such as eth0 const char *kmodule) // kernel module such as 3c509 { MODULES mods; mods.setalias (device,kmodule); return mods.write(); } /* Set/replace some options of a kernel module in /etc/modules.conf */ int modules_setoption ( const char *kmodule, // kernel module such as 3c509 const char *option, const char *value) { MODULES mods; mods.setoption (kmodule,option,value); return mods.write(); } void modules_getsetting ( const char *device, SSTRING &kmodule, SSTRING &modio, SSTRING &modirq) { kmodule.setfrom (""); modio.setfrom (""); modirq.setfrom (""); MODULES mods; MODULE_ALIAS *alias = mods.getalias(device); if (alias != NULL){ kmodule.setfrom (alias->module); MODULE_CONF *c = mods.getconf (kmodule.get()); if (c != NULL){ for (int i=0; iparms.getnb(); i++){ PARMVAL *p = c->parms.getitem(i); const char *parm = p->parm.get(); if (strcmp(parm,"io")==0){ modio.setfrom (p->val); }else if (strcmp(parm,"irq")==0){ modirq.setfrom (p->val); } } } } }