#include #include #include #include #include #include #include "askrunlevel.h" #include "internal.h" #include #include #include "../paths.h" #include "askrunlevel.m" #include #include #include static HELP_FILE help_default (HELP_ASKRUN,"default"); static HELP_FILE help_define (HELP_ASKRUN,"define"); // Some keys for /etc/conf.linuxconf static const char ASKRUNLEVEL[]="askrunlevel"; static const char TIMEOUT[]="timeout"; static const char ENABLED[]="enable"; static const char DIATIMEOUT[]="diatimeout"; static const char DEFMODE[]="defmode"; static const char K_RUNLEVEL[]="runlevel"; #define NB_RUNLEVEL 6 /* Write the configuration parameter into /etc/askrunlevel.conf */ static int askrunlevel_saveparm(ASK_PARM &parm) { linuxconf_setcursys (subsys_hardware); linuxconf_replace (ASKRUNLEVEL,ENABLED,parm.askrun); linuxconf_replace (ASKRUNLEVEL,TIMEOUT,parm.timeout); linuxconf_replace (ASKRUNLEVEL,DIATIMEOUT,parm.diatimeout); linuxconf_replace (ASKRUNLEVEL,DEFMODE,parm.defmode); return linuxconf_save(); } /* Read the configuration parameter from /etc/conf.linuxconf */ static void runlevels_readparm(ASK_PARM &parm) { parm.askrun = linuxconf_getvalnum(ASKRUNLEVEL,ENABLED,1); parm.timeout = linuxconf_getvalnum(ASKRUNLEVEL,TIMEOUT,20); parm.diatimeout = linuxconf_getvalnum(ASKRUNLEVEL,DIATIMEOUT,15); int default_defmode = 3; /* #Specification: askrunlevel / original default mode / inittab The default operation mode, when not configured in Linuxconf is set to the mode that match the default init runlevel. This requires the inittab Linuxconf module (and its inter-module API). If the API is not available, the original default mode is set to text mode and network. */ INITTAB_API *api = inittab_api_init ("runlevels"); if (api != NULL){ int level = api->getdefaultlevel (); inittab_api_end (api); if (level != -1){ RUNLEVELS runs(0,0); int defmode = runs.find_initlevel (level); if (defmode != -1) default_defmode = defmode; } } parm.defmode = linuxconf_getvalnum(ASKRUNLEVEL,DEFMODE,default_defmode); /* #Specification: askrunlevel / configuration file askrunlevel stores its default operation mode into /etc/conf.linuxconf. This file is optionnal. The default setup is: runlevel 5, netlevel 2 -> text mode, full networking A timeout of 20 seconds. Too many people forget to tell linuxconf about the default and the timeout and install linuxconf on server. They are sorry when the system reboots and linuxconf waits forever. This is why the default goes in the other direction (full service, long timeout). */ } /* Read the configuration parameter from /etc/conf.linuxconf. Patch them to fit the distribution */ void askrunlevel_readparm(ASK_PARM &parm) { runlevels_readparm (parm); if (distrib_isenhanced()){ /* #Specification: askrunlevel / default mode / distributions On linuxconf aware distributions, the concept of network level is not supported yet. On such distribution, the only choice available are either text + network or graphic + network. This correspond to choice 0 and 3 of the normal askrunlevel menu. For compatibility, this is the way the default selection is stored in /etc/conf.linuxconf. It is ajusted from 0 or 3 to 0 or 1 to make the askrunlevel menu more manageable. */ if (parm.defmode > 0) parm.defmode = 1; } } /* parse one line of /etc/conf.linuxconf */ PRIVATE void RUNLEVELS::parse (const char *str, RUNLEVEL *ptrun) { /* #Specification: askrunlevel / runlevel definition / /etc/conf.linuxconf The definitions of the different operation mode are stored in /etc/conf.linuxconf with the following format # askrunlevel.runlevel init net graphic_mode title ... Where, init (runlevel for /sbin/init) is one of 1,2,3,4,5,6,S net is 0 1 or 2 for no network, client network and server respectivly graphic is 0 1 or 2 for text mode, graphic mode (workstation) and X terminal respectivly. # */ str = str_skip(str); ptrun->init_runlevel = *str++; str = str_skip(str); ptrun->netconf_runlevel = atoi(str++); str = str_skip(str); ptrun->graphic_level = atoi(str++); ptrun->title.setfrom (str_skip(str)); } /* Definition of the different runlevels available */ PUBLIC RUNLEVELS::RUNLEVELS( int graphic_ok, int net_ok) { static struct { const char *mode; const char *title; }default_tbrun[]={ {"4 2 1",MSG_U(M_GR_NET,"Graphic & Network")}, {"4 0 1",MSG_U(M_GRONLY,"Graphic only")}, {"2 1 2",MSG_U(M_XTERMINAL,"X terminal")}, {"5 2 0",MSG_U(M_TX_NET,"Text mode & Network")}, {"3 0 0",MSG_U(M_TXONLY,"Text mode only")}, {"S 0 0",MSG_U(M_MAINTENANCE,"Maintenance mode")}, }; SSTRINGS lstdist; // Coming from the distribution specific directory { /* #Specification: distribution specific / runlevel definitions Each distribution may have a /usr/lib/linuxconf/DIST/runlevels file detailing the 6 linuxconf runlevel. This file allows linuxconf to match more closely the startup scripts and the inittab supply with the distribution.The file have 6 lines going like this (each line) # R N G title R: init run level (1-6) N: network run level (0,1,2) G: graphic runlevel (0,1,2) # */ char basepath[PATH_MAX],langpath[PATH_MAX]; linuxconf_fixdistdir(USR_LIB_CONF_RUNLEVELS,basepath); sprintf (langpath,"%s.%s",basepath,linuxconf_getlang()); if (!file_exist (langpath)) strcpy (langpath,basepath); FILE *fin = fopen (langpath,"r"); if (fin != NULL){ char buf[300]; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ strip_end (buf); if (buf[0] != '\0') lstdist.add (new SSTRING(buf)); } fclose (fin); } } SSTRINGS lst; /* #Specification: askrunlevel / operation mode / definition The definition of the six different operation mode are defined in /etc/conf.linuxconf */ linuxconf_getall (ASKRUNLEVEL,K_RUNLEVEL,lst,0); RUNLEVEL *ptrun = tbrun; for (int i=0; iget(),ptrun); }else if (iget(),ptrun); }else{ char buf[100]; sprintf (buf,"%s %s",default_tbrun[i].mode,default_tbrun[i].title); parse (buf,ptrun); } ptrun->graphic_err = ptrun->graphic_level > 0 && !graphic_ok; ptrun->net_err = ptrun->netconf_runlevel > 0 && !net_ok; char buf[80]; ptrun->title.copy(buf); if (ptrun->graphic_err || ptrun->net_err){ strcat (buf," "); strcat (buf,MSG_U(M_NOTCONF,"(Not configured)")); } tbmenu[i].setfrom (buf); } } PUBLIC RUNLEVELS::~RUNLEVELS() { } PUBLIC void RUNLEVELS::save() { linuxconf_setcursys (subsys_hardware); linuxconf_removeall (ASKRUNLEVEL,K_RUNLEVEL); RUNLEVEL *ptrun = tbrun; for (int i=0; iinit_runlevel ,ptrun->netconf_runlevel ,ptrun->graphic_level ,ptrun->title.get()); linuxconf_add (ASKRUNLEVEL,K_RUNLEVEL,buf); } linuxconf_save(); } /* Locate the askrunlevel mode that match one initlevel. */ PUBLIC int RUNLEVELS::find_initlevel(int initlevel) { int ret = -1; RUNLEVEL *ptrun = tbrun; initlevel += '0'; for (int i=0; iinit_runlevel == initlevel){ ret = i; break; } } return ret; } /* Build the askrunlevel menu based on distribution type */ PUBLIC int RUNLEVELS::setmenu ( const char *menuopt[]) { int ret = sizeof(tbrun)/sizeof(tbrun[0]); if (distrib_isenhanced()){ menuopt[1] = tbmenu[0].get(); menuopt[3] = tbmenu[3].get(); menuopt[5] = tbmenu[5].get(); ret = 3; }else{ int ii=1; for (int i=0; igraphic_err || ptrun->net_err){ xconf_notice(MSG_U(N_NOTCONF,"This runlevel is not yet" " configured")); } int mask = 0; for (unsigned m=0; msetdefaultlevel (ptrun->init_runlevel-'0'); inittab_api_end (api); } break; } } } } } /* Return the configured timeout for dialog (errors) at boot time */ int runlevels_getdiatimeout() { ASK_PARM parm; runlevels_readparm(parm); return parm.diatimeout; } /* Initialise one combo box field */ static void runlevels_setcombo ( DIALOG &dia, const char *title, SSTRING &s, int curval, const char *values[]) { s.setfrom (values[curval]); FIELD_COMBO *comb = dia.newf_combo (title,s); for (int i=0; values[i] != NULL; i++){ comb->addopt (values[i]); } } /* Get the index of a value in a table */ static int runlevels_locate ( const char *values[], SSTRING &s, int ¬found, // Will be set to id if not found // Will be left unchanged if found. int id) { const char *pt = s.get(); int ret = 0; int i; for (i=0; values[i] != NULL; i++){ if (stricmp(values[i],pt)==0){ ret = i; break; } } if (values[i] == NULL) notfound = id; return ret; } PUBLIC void RUNLEVELS::define() { /* #Specification: askrunlevel / runlevel definition askrunlevel let the user select one of six operation mode. It also let the user redefine (and rename) those operation mode. The user can change any of the six proposed mode. The name (title), the runlevel (for /sbin/init) and the network mode (for netconf) and the graphic mode (nographic, Workstation and X terminal) can be selected for each mode. */ DIALOG dia; struct TBSTR{ SSTRING init; SSTRING net; SSTRING graphic; }tbstr[NB_RUNLEVEL]; static const char *tbinit[] = { "1","2","3","4","5","6", "A","B","C","D","E","F", "Maintenance", NULL }; static const char *tbnet[]={ MSG_U(M_NONET,"No network"), MSG_U(M_CLIENT,"Client"), MSG_U(M_SERVER,"Server"), NULL }; static const char *tbgraphic[]={ MSG_U(M_TEXTMODE,"Text mode"), MSG_U(M_WORKSTATION,"Workstation"), MSG_U(M_XTERM,"X terminal"), NULL }; RUNLEVEL *ptrun = tbrun; TBSTR *ptstr = tbstr; for (int i=0; ititle); int init_r = ptrun->init_runlevel; if (init_r == 'S'){ init_r = 12; }else if (isdigit(init_r)){ init_r -= '1'; }else{ init_r = (init_r - 'A') + 6; } runlevels_setcombo (dia,MSG_U(F_RUNLEVEL,"init runlevel") ,ptstr->init ,init_r ,tbinit); runlevels_setcombo (dia,MSG_U(F_NETMODE,"Network mode") ,ptstr->net ,ptrun->netconf_runlevel ,tbnet); runlevels_setcombo (dia,MSG_U(F_GRMODE,"Graphic mode") ,ptstr->graphic ,ptrun->graphic_level ,tbgraphic); } int pos = 1; while (1){ if (dia.edit (MSG_U(T_RUNDEF,"Runlevels definition") ,MSG_U(I_RUNDEF,"You are allowed to name\n" "the different runlevel for this machine\n") ,help_define ,pos) != MENU_ACCEPT){ dia.restore(); break; }else{ ptrun = tbrun; ptstr = tbstr; int notfound = 0; for (int j=0; jinit ,notfound_one,2); if (init_r == 12){ init_r = 'S'; }else if (init_r >= 6){ init_r += 'A' - 6; }else{ init_r += '1'; } ptrun->init_runlevel = init_r; ptrun->netconf_runlevel = runlevels_locate ( tbnet,ptstr->net,notfound_one,3); ptrun->graphic_level = runlevels_locate ( tbgraphic,ptstr->graphic ,notfound_one,4); if (notfound_one){ notfound = 1; xconf_error (MSG_U(E_IVLDEF,"Invalid definition")); pos = j * 5 + notfound_one; break; } } if (!notfound){ save(); break; } } } }