#include #include #include #include #include "shellmod.h" #include #include "protocol.h" #include "shellmod.m" static HELP_FILE help_config ("shellmod","config"); /* #Specification: SHELLMOD / preload information / principles Shell scripts are somewhat slow to start. shellmod tries to cache some information about those modules to avoid starting them everytime Linuxconf is started. For each shell module, we remember The various menu entries provided by the modules. We record for each the MENU_CONTEXT where those entries register. The various dialog where it acts as a co-manager. */ PUBLIC MENUENTRY::MENUENTRY ( const char *_func, const char *_context, const char *_title) { func.setfrom (_func); context.setfrom (_context); title.setfrom (_title); } PUBLIC MENUENTRY *MENUENTRIES::getitem(int no) const { return (MENUENTRY*)ARRAY::getitem(no); } PUBLIC COMANAGER::COMANAGER(const char *_func, const char *_dialog) { func.setfrom (_func); dialog.setfrom (_dialog); } PUBLIC COMANAGER *COMANAGERS::getitem(int no) const { return (COMANAGER*)ARRAY::getitem(no); } static const char K_SHELLMOD[]="shellmod"; static const char K_REGMENU[]="regmenu"; static const char K_COMANAGER[]="comanager"; static const char K_INDEX[]="index"; static const char K_DEBUG[]="debug"; /* Set the debug mode for the current Linuxconf session */ void shellmod_setdebug() { protocol_setdebug (linuxconf_getvalnum(K_SHELLMOD,K_DEBUG,0) != 0); } static HELP_FILE help_add ("shellmod","addmodule"); /* Edit shell modules */ void shellmod_edit() { DIALOG_LISTE dia; dia.newf_head ("",MSG_U(H_MODULEMENU,"Modules")); SSTRINGS tb; int choice = 0; while(1){ tb.remove_all(); int nb = modules_getpathlist (tb); tb.sort(); for (int i=0; iget(),""); } dia.remove_last (nb+1); MENU_STATUS code = dia.editmenu (MSG_U(T_MODULEMENU,"Shell modules") ,MSG_U(I_MODULEMENU,"You can edit, add, or delete modules\n" "Press [Add] to add a new module") ,help_nil ,choice,MENUBUT_ADD); if (code == MENU_OK){ DIALOG editdia; SSTRING path (*(tb.getitem(choice))); int nof = 0; editdia.newf_str (MSG_U(F_MODNAME,"Path"),path); editdia.setbutinfo(MENU_USR1,MSG_U(B_RELOAD,"Reload"),MSG_R(B_RELOAD)); while (1){ MENU_STATUS code = editdia.edit (MSG_U(T_MODULE,"Shell module") ,MSG_U(I_MODULE,"Module properties") ,help_nil ,nof ,MENUBUT_ACCEPT|MENUBUT_CANCEL|MENUBUT_DEL|MENUBUT_USR1); if (code == MENU_ACCEPT){ modules_unsetmod(tb.getitem(choice)->get()); modules_setmod(path.get(),true); break; }else if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (code == MENU_DEL){ modules_unsetmod (path.get()); break; }else if (code == MENU_USR1){ modules_unsetmod (path.get()); modules_setmod (path.get(),true); xconf_notice (MSG_U(I_RELOADED,"Module reloaded!")); } } }else if (code == MENU_QUIT || code == MENU_ESCAPE){ break; }else if (code == MENU_ADD){ SSTRING path; while (1){ MENU_STATUS code = dialog_inputbox (MSG_U(T_NEWMODULE,"New module") ,MSG_U(F_MODPATH,"Path of the script") ,help_add ,path); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else{ modules_setmod (path.get(),true); break; } } } } } /* Main setting configuration for shellmod */ void shellmod_config () { DIALOG dia; char debugmode = linuxconf_getvalnum(K_SHELLMOD,K_DEBUG,0) != 0; dia.newf_chk ("",debugmode,MSG_U(F_DEBUG,"Debug mode")); int nof = 0; while (1){ MENU_STATUS code = dia.edit (MSG_U(T_SHELLMODCONF ,"Shellmod configuration") ,"",help_config ,nof); if (code == MENU_CANCEL || code == MENU_ESCAPE){ dia.restore(); break; }else{ linuxconf_replace (K_SHELLMOD,K_DEBUG,debugmode); linuxconf_save(); protocol_setdebug (debugmode != 0); break; } } } PUBLIC SHELLMOD::SHELLMOD (const char *_path) { instance = NULL; path.setfrom (_path); SSTRINGS tb; char key[PATH_MAX]; snprintf (key,sizeof(key)-1,"%s.%s",K_REGMENU,_path); linuxconf_getall (K_SHELLMOD,key,tb,false); for (int i=0; iget(); SSTRING func,context,title; s = str_extract (s,func); s = str_extract (s,context); str_extract (s,title); entries.add (new MENUENTRY(func.get(),context.get(),title.get())); } tb.remove_all(); snprintf (key,sizeof(key)-1,"%s.%s",K_COMANAGER,_path); linuxconf_getall (K_SHELLMOD,key,tb,false); for (int i=0; iget(); SSTRING func,dialog; s = str_extract (s,func); str_extract (s,dialog); managers.add (new COMANAGER(func.get(),dialog.get())); } } PUBLIC void SHELLMOD::write() { linuxconf_add (K_SHELLMOD,K_INDEX,path.get()); char key[PATH_MAX]; snprintf (key,sizeof(key)-1,"%s.%s",K_REGMENU,path.get()); linuxconf_removeall (K_SHELLMOD,key); for (int i=0; ifunc.get(),e->context.get() ,e->title.get()); linuxconf_add (K_SHELLMOD,key,tmp); } snprintf (key,sizeof(key)-1,"%s.%s",K_COMANAGER,path.get()); linuxconf_removeall (K_SHELLMOD,key); for (int i=0; ifunc.get(),e->dialog.get()); linuxconf_add (K_SHELLMOD,key,tmp); } } PRIVATE SHELL_INSTANCE* SHELLMOD::newinst () { //fprintf (stderr,"Starting :%s:\n",path.get()); const char *command = "/bin/sh"; FILE *fin = fopen (path.get(),"r"); if (fin != NULL){ char line[100]; if (fgets(line,sizeof(line)-1,fin)!=NULL && strstr(line,"--perl")!=NULL) command = "/usr/bin/perl"; fclose (fin); } char cmd[PATH_MAX]; snprintf (cmd,sizeof(cmd)-1,"%s %s",command,path.get()); return new SHELL_INSTANCE (cmd); } PUBLIC void SHELLMOD::exec (const char *func) { if (instance == NULL) instance = newinst(); instance->runfunc (func); if (!instance->isalive()){ delete instance; instance = NULL; } } /* Execute the module and record the registration information by executing its register function Return -1 if any error */ PUBLIC int SHELLMOD::collect () { int ret = -1; entries.remove_all(); managers.remove_all(); revdate = file_date (path.get()); if (revdate == -1){ xconf_error (MSG_U(E_NOMODULE,"Module %s does not exist"),path.get()); }else{ SHELL_INSTANCE *inst = newinst(); ret = inst->collect (entries,managers); delete inst; } return ret; } PUBLIC SHELLMOD *SHELLMODS::getitem(int no) const { return (SHELLMOD*)ARRAY::getitem(no); } /* Get the list of module currently registered */ void modules_getlist (SSTRINGS &tb) { linuxconf_getall (K_SHELLMOD,K_INDEX,tb,false); } /* Get a bunch of string describing the contribution of the shellmod module to the treemenu layout. We are adding in tb[] the list of module, then the list of menus for each modules and the list of co-managers. */ int modules_getmenudepend (SSTRINGS &tb) { int start = tb.getnb(); modules_getlist (tb); int last = tb.getnb(); for (int i=start; iget(); char key[PATH_MAX]; snprintf (key,sizeof(key)-1,"%s.%s",K_REGMENU,path); linuxconf_getall (K_SHELLMOD,key,tb,false); snprintf (key,sizeof(key)-1,"%s.%s",K_COMANAGER,path); linuxconf_getall (K_SHELLMOD,key,tb,false); } return tb.getnb()-start; } PUBLIC SHELLMODS::SHELLMODS() { SSTRINGS tb; modules_getlist(tb); for (int i=0; iget())); } } PUBLIC int SHELLMODS::write() { // First, erase all definition in conf.linuxconf SSTRINGS tb; modules_getlist(tb); for (int i=0; iget(); char key[PATH_MAX]; snprintf (key,sizeof(key)-1,"%s.%s",K_REGMENU,path); linuxconf_removeall (K_SHELLMOD,key); snprintf (key,sizeof(key)-1,"%s.%s",K_COMANAGER,path); linuxconf_removeall (K_SHELLMOD,key); } linuxconf_removeall (K_SHELLMOD,K_INDEX); // Now save each module one by one for (int i=0; iwrite(); } return linuxconf_save(); } SHELLMODS *cur; static void modules_delcur() { delete cur; } void modules_loadcur() { if (cur == NULL){ cur = new SHELLMODS; atexit(modules_delcur); } } void modules_setmenu ( DIALOG &dia, const char *menuid) { modules_loadcur(); for (int i=0; igetnb(); i++){ SHELLMOD *mod = cur->getitem(i); for (int j=0; jentries.getnb(); j++){ MENUENTRY *menu = mod->entries.getitem(j); if (menu->context.cmp(menuid)==0){ dia.new_menuitem ("",menu->title.get()); } } } } // Translate the menu context into string, the way they are stored // in the MENUENTRY extern const char *tbmenu_ctx[]; extern int tbmenu_nbitem; void modules_setmenu ( DIALOG &dia, MENU_CONTEXT context) { if (context < tbmenu_nbitem){ modules_setmenu (dia,tbmenu_ctx[context]); } }; int modules_domenu ( const char *context, const char *key) { modules_loadcur(); bool found = false; for (int i=0; igetnb() && !found; i++){ SHELLMOD *mod = cur->getitem(i); for (int j=0; jentries.getnb(); j++){ MENUENTRY *menu = mod->entries.getitem(j); if (menu->context.cmp(context)==0 && menu->title.get()==key){ if (shellmod_haspriv (mod->path.get())){ mod->exec (menu->func.get()); } found = true; break; } } } return 0; } int modules_domenu ( MENU_CONTEXT context, const char *key) { return modules_domenu (tbmenu_ctx[context],key); } static void modules_setabs ( const char *path, char abspath[PATH_MAX]) { if (path[0] == '/'){ strcpy (abspath,path); }else{ char tmp[PATH_MAX]; const char *cwd = getcwd(tmp,sizeof(tmp)); if (cwd == NULL){ fprintf (stderr,MSG_R(E_CWD)); }else{ snprintf (abspath,PATH_MAX-1,"%s/%s",cwd,path); } } } int modules_setmod(const char *path, bool uimode) { int ret = -1; char abspath[PATH_MAX]; modules_setabs (path,abspath); if (file_exist (abspath)){ modules_loadcur(); SHELLMOD *found = NULL; for (int i=0; igetnb() && !found; i++){ SHELLMOD *mod = cur->getitem(i); if (mod->path.cmp(abspath)==0){ found = mod; break; } } if (found == NULL){ found = new SHELLMOD (abspath); cur->add (found); } if (found->collect() != -1) ret = cur->write(); }else if (uimode){ xconf_error (MSG_U(E_NOFILE,"File %s does not exist\n"),path); }else{ fprintf (stderr,MSG_R(E_NOFILE),path); } return ret; } int modules_unsetmod(const char *path) { int ret = -1; char abspath[PATH_MAX]; modules_setabs (path,abspath); modules_loadcur(); for (int i=0; igetnb(); i++){ SHELLMOD *mod = cur->getitem(i); if (mod->path.cmp(abspath)==0){ cur->remove_del (mod); ret = cur->write(); break; } } return ret; } int modules_getpathlist(SSTRINGS &tb) { for (int i=0; igetnb(); i++){ tb.add (new SSTRING(cur->getitem(i)->path)); } return cur->getnb(); } PUBLIC void SHELLMOD::setupdia( DICTIONARY &dict, const char *func_prefix, DIALOG &dia) { if (instance == NULL) instance = newinst(); instance->comanage (&dia,dict,func_prefix,"setupdia",NULL); } PUBLIC int SHELLMOD::save (DICTIONARY &dict, const char *func_prefix) { return instance->comanage (NULL,dict,func_prefix,"save",NULL); } PUBLIC int SHELLMOD::deluser (DICTIONARY &dict, const char *func_prefix) { return instance->comanage (NULL,dict,func_prefix,"deluser",NULL); } PUBLIC int SHELLMOD::validate (DICTIONARY &dict, const char *func_prefix, int &nof) { return instance->comanage (NULL,dict,func_prefix,"validate",&nof); }