#include #include #include #include #include #include #include #include #include #include "../../paths.h" #include "liloconf.h" #include "liloconf.m" #include static const char K_RAMDISK[]="ramdisk"; static const char K_IMAGE[]="image"; static const char K_INITRD[]="initrd"; static const char K_PASSWORD[]="password"; static const char K_DELAY[]="delay"; static const char K_TIMEOUT[]="timeout"; static const char K_BOOT[]="boot"; static const char K_VGA[]="vga"; static const char K_MESSAGE[]="message"; static const char K_DEFAULT[]="default"; static const char K_APPEND[]="append"; static const char K_LABEL[]="label"; static const char K_OTHER[]="other"; static const char K_MAP[]="map"; static const char K_COMPACT[]="compact"; static const char K_LINEAR[]="linear"; static const char K_PROMPT[]="prompt"; static const char K_READ_ONLY[]="read-only"; static const char K_READ_WRITE[]="read-write"; static const char K_RESTRICTED[]="restricted"; static const char K_ROOT[]="root"; HELP_FILE help_lilo ("liloconf","lilo"); static CONFIG_FILE f_lilo (ETC_LILO_CONF,help_lilo ,CONFIGF_MANAGED|CONFIGF_OPTIONAL ,"root","root",0600 ,subsys_hardware); static CONFIG_FILE f_makefile (USR_SRC_LINUX_MAKEFILE,help_lilo ,CONFIGF_PROBED|CONFIGF_NOARCH); /* One configuration */ class LILO_PARM{ public: SSTRING ramdisk; // Size of the ramdisk or no ramdisk char read_only; char restricted; SSTRING vga; SSTRING root; SSTRING append; SSTRING initrd; SSTRING password; /*~PROTOBEG~ LILO_PARM */ public: LILO_PARM (void); void setupdia (DIALOG&dia); /*~PROTOEND~ LILO_PARM */ }; PUBLIC LILO_PARM::LILO_PARM() { read_only = 1; restricted = 0; } class LILO; /* This represent one bootable linux configyration */ class LILO_CONF: public ARRAY_OBJ{ public: LILO_PARM parm; SSTRING image; SSTRING label; SSTRINGS unknown; // Unmanaged lilo commands /*~PROTOBEG~ LILO_CONF */ public: LILO_CONF (void); int edit (bool no_empty_root, LILO&lilo); /*~PROTOEND~ LILO_CONF */ }; PUBLIC LILO_CONF::LILO_CONF() { } class LILO_CONFS: public ARRAY{ /*~PROTOBEG~ LILO_CONFS */ public: LILO_CONF *getitem (int no); /*~PROTOEND~ LILO_CONFS */ }; PUBLIC LILO_CONF *LILO_CONFS::getitem(int no) { return (LILO_CONF*)ARRAY::getitem(no); } class LILO_OTHER: public ARRAY_OBJ{ public: SSTRING label; SSTRING partition; SSTRINGS unknown; // Unmanaged lilo commands /*~PROTOBEG~ LILO_OTHER */ public: int edit (LILO&lilo); /*~PROTOEND~ LILO_OTHER */ }; class LILO_OTHERS: public ARRAY{ /*~PROTOBEG~ LILO_OTHERS */ public: LILO_OTHER *getitem (int no); /*~PROTOEND~ LILO_OTHERS */ }; PUBLIC LILO_OTHER *LILO_OTHERS::getitem(int no) { return (LILO_OTHER*)ARRAY::getitem(no); } /* #Specification: lilo.conf / how it works The lilo.conf file is splitted in two sections. The first contain the global or default setting. This section act as a default for the rest of the file. This section ends with the first "image = " or "other = " statement. Global settings are: # compact delay boot = ... # Default setting that can be overriden in the followings image= are # ramdisk = x read-only read-write root = ... vga = ... # */ // This allows for positionning the cursor // properly when there is an error. struct FIELD_POS_INFO{ int start_first_parm; // Start of the first parameter section int start_conf; // Start of the fields for the configurations int size_conf; // Number of fields in each configurations int prefix_conf; // Number of field prior to the parameters // of each sections }; struct LILO_CUR{ LILO_CONF *conf; LILO_PARM *parm; LILO_OTHER *other; int noline; }; class LILO { SSTRING boot; // On which device to place the boot code char compact; //Special boot mode char linear; int delay; // Delay in seconds or 0 for no delay int timeout; // Delay in seconds or 0 for no timeout char prompt; LILO_PARM def; // Default value SSTRING message; // Path of the message file LILO_CONFS confs; LILO_OTHERS others; char prefix[PATH_MAX]; SSTRINGS unknown; SSTRING defconf; SSTRING map; public: char isvalid; // Tell if the configuration is usable or present char isused; // Is LILO used on this computer /*~PROTOBEG~ LILO */ public: LILO (void); void addkernel (const char *def_src, const char *def_name); private: void addunknown (LILO_CUR&cur, const char *line); void compute_prefix (void); public: int editdefaults (void); int editlinux (void); int editothers (void); LILO_CONF *getconffromlabel (const char *lab); LILO_CONF *getdefaultlinux (void); bool is_duplicate (const SSTRING&label, LILO_CONF *conf, LILO_OTHER *other); private: void makecfgpath (const char *path, char *realpath); void parse_eq (const char *keyw, const char *vals, LILO_CUR&cur); void parse_single (const char *pt, LILO_CUR&cur); public: int save (void); void setdefault (void); int updateif (void); protected: void writeparm (FILE_CFG *fout, LILO_PARM&p, int global_parm); public: /*~PROTOEND~ LILO */ }; /* Add a command which is unknown to linuxconf. It will be write back in lilo.conf without further processing */ PRIVATE void LILO::addunknown (LILO_CUR &cur, const char *line) { if (cur.other != NULL){ cur.other->unknown.add (new SSTRING(line)); }else if (cur.conf != NULL){ cur.conf->unknown.add (new SSTRING(line)); }else{ unknown.add (new SSTRING(line)); } } /* Parse keyword with a value */ PRIVATE void LILO::parse_eq( const char *keyw, const char *vals, LILO_CUR &cur) { vals = str_skip (vals); char word[200]; str_copyword (word,keyw,sizeof(word)); int numval = atoi(vals); if (stricmp(word,K_RAMDISK)==0){ cur.parm->ramdisk.setfrom(vals); }else if (stricmp(word,K_PASSWORD)==0){ cur.parm->password.setfrom(vals); }else if (stricmp(word,K_DELAY)==0){ delay = numval/10; }else if (stricmp(word,K_TIMEOUT)==0){ timeout = numval/10; }else if (stricmp(word,K_BOOT)==0){ boot.setfrom (vals); }else if (stricmp(word,K_VGA)==0){ cur.parm->vga.setfrom (vals); }else if (stricmp(word,K_MESSAGE)==0){ message.setfrom (vals); }else if (stricmp(word,K_DEFAULT)==0){ defconf.setfrom (vals); }else if (stricmp(word,K_ROOT)==0){ cur.parm->root.setfrom (vals); }else if (stricmp(word,K_APPEND)==0){ char vals_unq[strlen(vals)+1]; if (vals[0] == '"'){ str_copyquote (vals_unq,vals); }else{ strcpy (vals_unq,vals); } cur.parm->append.setfrom (vals_unq); }else if (stricmp(word,K_INITRD)==0){ cur.parm->initrd.setfrom (vals); }else if (stricmp(word,K_LABEL)==0){ if (cur.conf != NULL){ cur.conf->label.setfrom (vals); }else if (cur.other != NULL){ cur.other->label.setfrom (vals); }else{ xconf_error ("Misplaced \"label\" statement\n" "in file %s, line %d",f_lilo.getpath() ,cur.noline); } }else if (stricmp(word,K_IMAGE)==0){ cur.conf = new LILO_CONF; cur.other = NULL; confs.add (cur.conf); cur.conf->image.setfrom (vals); cur.parm = &cur.conf->parm; cur.parm->read_only = def.read_only; cur.parm->restricted = def.restricted; }else if (stricmp(word,K_OTHER)==0){ cur.other = new LILO_OTHER; cur.conf = NULL; others.add (cur.other); cur.other->partition.setfrom (vals); }else if (stricmp(word,K_MAP)==0){ map.setfrom (vals); }else{ char str[strlen(keyw)+1+strlen(vals)+1]; sprintf (str,"%s=%s",keyw,vals); addunknown (cur,str); } } /* Interpret single word parameter line */ PRIVATE void LILO::parse_single(const char *pt, LILO_CUR &cur) { char word[100]; str_copyword (word,pt,sizeof(word)); if (stricmp(word,K_COMPACT)==0){ compact = 1; }else if (stricmp(word,K_LINEAR)==0){ linear = 1; }else if (stricmp(word,K_PROMPT)==0){ prompt = 1; }else if (stricmp(word,K_READ_ONLY)==0){ cur.parm->read_only = 1; }else if (stricmp(word,K_READ_WRITE)==0){ cur.parm->read_only = 0; }else if (stricmp(word,K_RESTRICTED)==0){ cur.parm->restricted = 1; }else{ addunknown (cur,pt); } } PRIVATE void LILO::compute_prefix() { /* #Specification: lilo / moving lilo.conf Linuxconf check carefully the path of the configuration file (normally /etc/lilo.conf but changeable by the user). We assume that the path of the /boot/map is fairly fixed. The only option used with lilo is -r (by linuxconf at least), so lilo.conf is somewhere in a "etc" directory and the file "map" is somewhere in a "boot" directory right near this "etc". */ const char *path = f_lilo.getpath(); static char stdconf[]= ETC_LILO_CONF; if (strcmp (path,stdconf)==0){ prefix[0] = '\0'; }else{ int len = strlen(stdconf); int newlen = strlen(path); int offset = newlen - len; if (newlen < len || strcmp(path+offset,stdconf)!=0){ xconf_error (MSG_U(E_IVLDPATH ,"Invalid path of lilo.conf: %s\n" "expected something at least as long\n" "as %s\n" "and ending with %s") ,path,stdconf,stdconf); isvalid = 0; }else{ strncpy (prefix,path,offset); prefix[offset] = '\0'; } } } static char LILOCFG[]="lilo"; static char ISUSED[]="isused"; /* Load and parse the /etc/lilo.conf configuration file */ PUBLIC LILO::LILO() { isvalid = 0; compact = 0; linear = 0; prompt = 0; delay = 0; timeout = 50; map.setfrom ("/boot/map"); /* #Specification: lilo / disabling allowed As a default, linuxconf assume lilo is used to boot this computer. A check box allows the admin to turn lilo off. Linuxconf won't bother the check lilo further. */ isused = linuxconf_getvalnum (LILOCFG,ISUSED,1); FILE_CFG *fin = f_lilo.fopen ("r"); if (fin != NULL){ char buf[1000]; LILO_CUR cur; cur.parm = &def; cur.conf = NULL; cur.other = NULL; cur.noline = 0; /* #Specification: /etc/lilo.conf / comments Comments are not preserved when editing lilo.conf */ isvalid = 1; while (fgets_strip(buf,sizeof(buf)-1,fin,&cur.noline)!=NULL){ strip_end (buf); char *pt = str_skip (buf); if (*pt != '#' && *pt != '\0'){ char *pteq = strchr(pt,'='); if (pteq != NULL){ *pteq++ = '\0'; parse_eq (pt,pteq,cur); }else{ parse_single(pt,cur); } } } fclose (fin); } compute_prefix(); } /* Locate one setup from its label */ PUBLIC LILO_CONF *LILO::getconffromlabel (const char *lab) { LILO_CONF *ret = NULL; for (int i=0; ilabel.cmp(lab)==0){ ret = c; break; } } return ret; } /* Build a path using a path relative to the /etc/lilo.conf file. */ PRIVATE void LILO::makecfgpath(const char *path, char *realpath) { if (prefix[0] == '\0'){ strcpy (realpath,path); }else{ strcpy (realpath,prefix); strcat (realpath,path); } } static void writeif (FILE_CFG *fout, SSTRING &s, const char *keyw) { if (!s.is_empty()) fprintf (fout," %s = %s\n",keyw,s.get()); } PROTECTED void LILO::writeparm( FILE_CFG *fout, LILO_PARM &p, int global_parm) // Is p LILO::parm or // one of the LILO_CONF::parm ? { /* #Specification: lilo / writing lilo.conf / normalising linuxconf is not writing back lilo.conf in the same way it was read. It is somewhat normalising it. If for example, one setup has the same definitions than the default setup, the definition are not repeated. This feature is transparent to the user though. It make the file lilo.conf smaller and easier to read manually. */ if (!p.ramdisk.is_empty() && (global_parm || p.ramdisk.cmp(def.ramdisk) != 0)){ fprintf (fout," %s = %s\n",K_RAMDISK,p.ramdisk.get()); } if (p.vga.is_empty()){ if (global_parm) fprintf (fout," %s = normal\n",K_VGA); }else{ fprintf (fout," %s = %s\n",K_VGA,p.vga.get()); } writeif (fout,p.password,K_PASSWORD); if (global_parm || p.restricted != def.restricted){ if (p.restricted) fprintf (fout," %s\n",K_RESTRICTED); } if (!p.append.is_empty()){ fprintf (fout," %s = \"%s\"\n",K_APPEND,p.append.get()); } writeif (fout,p.initrd,K_INITRD); if (global_parm || def.root.is_empty()){ writeif (fout,p.root,K_ROOT); }else if (!p.root.is_empty() && p.root.cmp(def.root)!=0){ writeif (fout,p.root,K_ROOT); } if (global_parm || p.read_only != def.read_only){ fprintf (fout," %s\n",p.read_only ? K_READ_ONLY : K_READ_WRITE); } } static void lilo_writeunknown (FILE_CFG *fout, const char *prefix, SSTRINGS &tb) { for (int i=0; iget()); } } /* Write back the /etc/lilo.conf file. Return -1 if any error. */ PUBLIC int LILO::save() { int ret = -1; FILE_CFG *fout = f_lilo.fopen ("w"); if (fout != NULL){ linuxconf_setcursys (subsys_hardware); fprintf (fout,"%s = %s\n",K_BOOT,boot.get()); fprintf (fout,"%s = %s\n",K_MAP,map.get()); if (delay != 0) fprintf (fout,"%s = %d\n",K_DELAY,delay*10); if (timeout != 0) fprintf (fout,"%s = %d\n",K_TIMEOUT,timeout*10); if (compact) fprintf (fout,"%s\n",K_COMPACT); if (linear) fprintf (fout,"%s\n",K_LINEAR); if (prompt) fprintf (fout,"%s\n",K_PROMPT); writeif (fout,message,K_MESSAGE); writeif (fout,defconf,K_DEFAULT); writeparm (fout,def,1); lilo_writeunknown (fout,"",unknown); int i; for (i=0; iimage.get()); fprintf (fout," %s = %s\n",K_LABEL,c->label.get()); writeparm (fout,c->parm,0); lilo_writeunknown (fout," ",c->unknown); } for (i=0; ipartition.is_empty()){ fprintf (fout,"%s = %s\n",K_OTHER ,c->partition.get()); fprintf (fout," %s = %s\n",K_LABEL ,c->label.get()); lilo_writeunknown (fout," ",c->unknown); } } ret = fclose (fout); linuxconf_replace (LILOCFG,ISUSED,isused); linuxconf_save(); } return ret; } static void lilo_setpart (FIELD_COMBO *comb) { PARTITIONS *parts = partition_load(); for (int i=0; igetnb(); i++){ PARTITION *p = parts->getitem(i); SSTRING str; p->formatinfo (str,true); comb->addopt(p->getdevice(),str.get()); } } /* Dispose the parameter of a configuration or the default ones. */ PUBLIC void LILO_PARM::setupdia (DIALOG &dia) { FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_ROOTPART,"root partition") ,root); lilo_setpart (comb); dia.newf_str (MSG_U(F_RAMSIZE,"Ramdisk size (opt)"),ramdisk); dia.newf_chk (MSG_U(F_BOOTMODE,"boot mode"),read_only ,MSG_U(I_READONLY,"Read only")); comb = dia.newf_combo (MSG_U(F_VGA,"VGA mode"),vga); comb->addopt (MSG_U(F_NORMAL,"normal"),MSG_U(F_STD8025,"standard 80x25")); comb->addopt (MSG_U(F_EXTENDED,"extended"),""); comb->addopt (MSG_U(F_ASK,"ask"),MSG_U(I_ASK,"Query the user")); dia.newf_str (MSG_U(F_BOOTOPT,"Boot options"),append); dia.newf_str (MSG_U(F_INITRD,"Initial ramdisk(opt)"),initrd); dia.newf_str (MSG_U(F_PASSWORD,"Password (opt)"),password); dia.newf_chk ("",restricted,MSG_U(F_RESTRICTED,"Restricted access")); } static int validate_parm( LILO_PARM &p, bool complain_if_empty, int &nof) // No of the offending field { PARTITIONS *parts = partition_load(); int ret = 0; if (!p.root.is_empty()){ const char *pr = p.root.get(); if (strncmp(pr,"/dev/fd",7)!=0 && strncmp(pr,"/dev/md",7)!=0){ PARTITION *e = parts->getitem(pr); if (e == NULL || !e->islinux()){ xconf_error (MSG_U(E_IVLDPART,"Partition %s is either invalid\n" "or not a linux partition\n"),pr); nof = 0; ret = -1; } } }else if(complain_if_empty){ xconf_error (MSG_U(E_ROOTPNEED ,"You must specify the root partition")); ret = -1; nof = 0; } if (ret == 0){ if (!p.ramdisk.is_empty()){ const char *pt = p.ramdisk.get(); while (*pt != '\0'){ if (!isdigit(*pt)){ xconf_error (MSG_U(E_IVLDRMDSKSIZE,"Invalid ramdisk size")); nof = 1; ret = -1; break; } pt++; } } } return ret; } PUBLIC int LILO::editdefaults() { DIALOG dia; dia.newf_title (MSG_U(T_BASE,"Base options"),1,"",MSG_R(T_BASE)); dia.newf_chk ("",isused,MSG_U(F_LILOUSED ,"LILO is used to boot this system")); FSTAB fstab; FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_INSTBOOT ,"Install boot sector on"),boot); comb->addopt (fstab.getrootdev(),MSG_U(F_BOOTREC ,"boot record of the current root partition")); comb->addopt ("/dev/hda",MSG_U(F_MASTERIDE ,"Master boot record on IDE systems")); comb->addopt ("/dev/sda",MSG_U(F_MASTERSCSI ,"Master boot record on SCSI systems")); comb->addopt (MSG_U(F_FD0,"/dev/fd0"),""); lilo_setpart (comb); dia.newf_chk (MSG_U(F_BIOSMODE,"Bios boot mode"),compact,"Compact"); dia.newf_chk (MSG_U(F_LINEAR,"Boot table encoding"),linear,"Linear"); dia.newf_num (MSG_U(F_BOOTDELAY,"Boot delay in seconds"),delay); dia.newf_chk ("",prompt,MSG_U(I_PROMPT,"Present the LILO boot: prompt")); dia.newf_num (MSG_U(F_PROMPTTIMEOUT,"Prompt timeout in seconds"),timeout); dia.newf_str (MSG_U(F_MSGFILE,"Message file(opt)"),message); dia.newf_title (MSG_U(T_EXTRALILO,"Extra options"),1,"",MSG_R(T_EXTRALILO)); int first_parm = dia.getnb(); def.setupdia (dia); int ret = -1; int nof = 0; PARTITIONS *parts = partition_load(); // Check if the default root partition may be omitted bool no_empty_root = false; for (int i=0; iparm.root.is_empty()){ no_empty_root = true; } } while (1){ MENU_STATUS code = dia.edit (MSG_U(T_DEFAULTS,"Lilo defaults") ,"" ,help_lilo ,nof); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (validate_parm(def,no_empty_root,nof) == -1){ nof += first_parm; }else{ if (boot.cmp("/dev/fd0")!=0 && boot.cmp("/dev/hda")!=0 && boot.cmp("/dev/sda")!=0 && parts->getitem(boot.get())==NULL){ xconf_notice (MSG_U(E_IVLSECTOR ,"Unusual partition or device for boot sector\n" "installation. This will probably yield a non\n" "bootable system.")); } ret = save(); break; } } return ret; } /* Check if this label is currently in used by a configuration different from either conf and other */ PUBLIC bool LILO::is_duplicate( const SSTRING &label, LILO_CONF *conf, LILO_OTHER *other) { bool ret = false; for (int i=0; ilabel.cmp(label)==0){ ret = true; } } if (!ret){ for (int j=0; jlabel.cmp(label)==0){ ret = true; } } } if (ret){ xconf_error (MSG_U(E_DUPLILOLABEL,"Duplicate LILO label: %s") ,label.get()); } return ret; } /* Dispose the dialog */ PUBLIC int LILO_CONF::edit (bool no_empty_root, LILO &lilo) { DIALOG dia; dia.newf_str (MSG_U(F_LABEL,"Label"),label); dia.last_noempty(); dia.newf_str (MSG_U(F_KERNELIMAGE,"Kernel image file"),image); dia.last_noempty(); int prefix_conf = dia.getnb(); parm.setupdia (dia); int nof = 0; int ret = -1; while (1){ MENU_STATUS code = dia.edit (MSG_U(T_LINUX,"Linux boot configuration") ,MSG_U(I_LINUXOS,"You control how to boot one Linux\n" "configuration") ,help_lilo ,nof,MENUBUT_CANCEL|MENUBUT_ACCEPT|MENUBUT_DEL); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (code == MENU_DEL){ if (xconf_delok()){ ret = 1; break; } }else if (lilo.is_duplicate(label,this,NULL)){ nof = 0; }else if (!file_exist (image.get())){ xconf_error (MSG_U(E_IMAGE,"Kernel file %s is missing") ,image.get()); nof = 1; }else if (validate_parm(parm,no_empty_root,nof) == -1){ nof += prefix_conf; }else{ ret = 0; break; } } return ret; } PUBLIC int LILO_OTHER::edit (LILO &lilo) { DIALOG dia; dia.newf_str (MSG_R(F_LABEL),label); dia.last_noempty(); FIELD_COMBO *comb = dia.newf_combo (MSG_U(F_PARTBOOT ,"partition to boot") ,partition); dia.last_noempty(); lilo_setpart (comb); int nof = 0; int ret = -1; while (1){ MENU_STATUS code = dia.edit (MSG_U(T_OTHEROS,"Other operating system setup") ,MSG_U(I_OTHEROS,"You control how to boot another operating\n" "system on one partition of your harddrive(s)") ,help_lilo ,nof,MENUBUT_CANCEL|MENUBUT_DEL|MENUBUT_ACCEPT); if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (code == MENU_DEL){ if (xconf_delok()){ ret = 1; break; } }else if (lilo.is_duplicate(label,NULL,this)){ nof = 0; }else{ ret = 0; break; } } return ret; } PUBLIC int LILO::editlinux () { DIALOG_LISTE *dia = NULL; int nof = 0; int ret = -1; bool no_empty_root = def.root.is_empty(); while (1){ if (dia == NULL){ dia = new DIALOG_LISTE; dia->newf_head ("",MSG_U(H_LILOCONFS ,"Label\tPartition\tKernel")); for (int i=0; iparm.root.get() ,conf->image.get()); dia->new_menuitem (conf->label.get(),tmp); } } MENU_STATUS code = dia->editmenu (MSG_U(T_LILOCONFS,"Lilo linux configurations") ,"" ,help_lilo ,nof,MENUBUT_QUIT|MENUBUT_ADD); bool must_delete = false; if(code == MENU_QUIT || code == MENU_ESCAPE){ break; }else if (code == MENU_ADD){ LILO_CONF *conf = new LILO_CONF; int ok = conf->edit(no_empty_root,*this); if (ok == 0){ confs.add (conf); ret = 0; must_delete = true; }else{ delete conf; } }else if (nof >= 0 && nof edit (no_empty_root,*this); if (ok == 1){ confs.remove_del (nof); must_delete = true; ret = 0; }else if (ok == 0){ must_delete = true; ret = 0; } } if (must_delete){ if(save() != -1) lilo_update(); delete dia; dia = NULL; } } delete dia; return ret; } PUBLIC int LILO::editothers () { DIALOG_LISTE *dia = NULL; int nof = 0; int ret = -1; while (1){ if (dia == NULL){ dia = new DIALOG_LISTE; dia->newf_head ("",MSG_U(H_LILOOTHERS ,"Label\tPartition")); for (int i=0; inew_menuitem (conf->label.get(),conf->partition.get()); } } MENU_STATUS code = dia->editmenu (MSG_U(T_LILOOTHERS ,"Lilo other OSs configurations") ,"" ,help_lilo ,nof,MENUBUT_QUIT|MENUBUT_ADD); bool must_delete = false; if(code == MENU_QUIT || code == MENU_ESCAPE){ break; }else if (code == MENU_ADD){ LILO_OTHER *conf = new LILO_OTHER; int ok = conf->edit(*this); if (ok == 0){ others.add (conf); ret = 0; must_delete = true; }else{ delete conf; } }else if (nof >= 0 && nof edit (*this); if (ok == 1){ others.remove_del (nof); must_delete = true; ret = 0; }else if (ok == 0){ must_delete = true; ret = 0; } } if (must_delete){ if (save() != -1) lilo_update(); delete dia; dia = NULL; } } delete dia; return ret; } int lilo_editdefaults () { LILO lilo; int ret = lilo.editdefaults(); if (ret == 0) lilo_update(); return ret; } int lilo_editlinux () { LILO lilo; int ret = lilo.editlinux(); return ret; } int lilo_editothers () { LILO lilo; int ret = lilo.editothers(); return ret; } /* Exec /sbin/lilo if needed. Return 0 if not need, or -1 if any error. */ PUBLIC int LILO::updateif() { char mappath[PATH_MAX]; makecfgpath (map.get(),mappath); long confdate = f_lilo.getdate (); long mapdate = file_date (mappath); int ret = 0; /* #Specification: lilo / update needed if If the file /etc/lilo.conf is newer than /boot/map then the command lilo must be executed. kernel files are also checked. If they are newer than /boot/map, lilo has to be executed as this situation may yield a non bootable system. Simply copying over a kernel image may create a mismatch in /boot/map and the actual layout of the kernel on the disk We refer to /boot/map, but we check the map directive. */ bool needed = false; SSTRINGS tb; // File newer than /boot/map if (confdate > mapdate){ tb.add (new SSTRING(f_lilo.getpath())); needed = true; }else{ // Check all kernel to see if they are newer // Failing for (int i=0; iimage.get(),path); long image_date = file_date (path); if (image_date > mapdate){ tb.add (new SSTRING(path)); needed = true; break; } if (!c->parm.initrd.is_empty()){ makecfgpath (c->parm.initrd.get(),path); long initrd_date = file_date(path); if (initrd_date > mapdate){ tb.add (new SSTRING(path)); needed = true; break; } } } } if (needed){ char buf[PATH_MAX]; buf[0] = '\0'; if (prefix[0] != '\0') sprintf (buf,"-r %s",prefix); if (simul_ison() || dialog_yesno(MSG_U(T_ACTLILO,"Activating LILO configuration") ,MSG_U(Q_ACTLILO,"Activating LILO change the way your\n" "machine is booting.\n" "Do I activate the configuration ?") ,help_lilo)==MENU_YES){ for (int i=0; iget(); net_prtlog (NETLOG_WHY,MSG_U(I_FILENEWER,"File %s is newer than %s\n") ,fname,mappath); } ret = netconf_system_if ("lilo",buf); }else{ ret = 0; } } return ret; } /* Check if the lilo command must be executed */ int lilo_update () { int ret = 0; if (f_lilo.exist()){ DAEMON_INTERNAL *dae = daemon_find("lilo"); if (dae != NULL && dae->is_managed()){ LILO lilo; if (lilo.isvalid && lilo.isused) ret = lilo.updateif(); } } return ret; } /* Return the default configuration. Only check in the linux configuration (not in other OS configuration) */ PUBLIC LILO_CONF *LILO::getdefaultlinux() { LILO_CONF *ret = confs.getitem(0); if (!defconf.is_empty()){ ret = NULL; for (int i=0; ilabel.cmp(defconf)==0){ ret = c; break; } } } return ret; } /* Add a new kernel to the current configuration */ PUBLIC void LILO::addkernel( const char *def_src, // Default path for the kernel const char *def_name) // Default name for kernel file { DIALOG dia; SSTRING kernel_src (def_src); SSTRING kernel_dst; SSTRING label; char install = 0; dia.newf_str (MSG_R(F_KERNELIMAGE),kernel_src); dia.newf_radio (MSG_U(F_HOWBOOT,"How it boots"),install,0 ,MSG_U(F_NEWDEFAULT,"new default bootable setup")); dia.newf_radio (" ",install,1 ,MSG_U(F_REPLCUR,"replace the current bootable setup")); dia.newf_radio (" ",install,2,MSG_U(F_SELSETUP,"selectable setup")); dia.newf_str (MSG_R(F_LABEL),label); if (prefix != '\0' ){ kernel_dst.setfrom (prefix); kernel_dst.append ("/"); } kernel_dst.append (def_name); dia.newf_str (MSG_U(F_WHERETOCOPY,"Where to copy the kernel file") ,kernel_dst); LILO_PARM newparm = def; dia.newf_title ("",MSG_U(F_OPTIONS,"Options")); newparm.setupdia (dia); int nof = 0; while (1){ int len_prefix = strlen(prefix); MENU_STATUS code = dia.edit ( MSG_U(T_ADDINGKERN,"Adding a new kernel to LILO") ,MSG_U(I_ADDINGKERN ,"You have already a working LILO\n" "and you want to upgrade your kernel") ,help_lilo ,nof); int local_nof; if (code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (kernel_src.is_empty()){ xconf_error (MSG_U(E_KERNNEEDED,"You must specify a kernel file")); nof = 0; }else if (install != 1 && label.is_empty()){ xconf_error (MSG_U(E_LABELNEEDED,"You must specify a label")); nof = 4; }else if (install != 1 && getconffromlabel(label.get())!=NULL){ xconf_error (MSG_U(E_LABELEXIST,"The label is already used")); nof = 4; }else if (!file_exist(kernel_src.get())){ xconf_error (MSG_U(E_ENOENT,"File %s does not exist") ,kernel_src.get()); nof = 0; }else if (file_type(kernel_src.get())!=0){ xconf_error (MSG_U(E_KERNBAD,"%s is not a file") ,kernel_src.get()); nof = 0; }else if (kernel_dst.getlen() <= len_prefix || kernel_dst.ncmp(prefix,len_prefix)!=0 || kernel_dst.get()[len_prefix] != '/'){ xconf_error (MSG_U(E_BADPATH,"Bad path, must be under %s/") ,prefix); nof = 5; }else if (validate_parm(newparm,def.root.is_empty(),local_nof)==-1){ nof = 7 + local_nof; }else{ if (file_type(kernel_dst.get())==1){ // We must add the name of the source to the destination // This is a convenience const char *name = kernel_src.strrchr('/'); if (name == NULL){ name = kernel_src.get(); }else{ name++; } const char *dst = kernel_dst.get(); char last = dst[strlen(dst)-1]; if (last != '/') kernel_dst.append ("/"); kernel_dst.append (name); } if (kernel_dst.cmp(kernel_src)==0 || !file_exist(kernel_dst.get()) || dialog_yesno(MSG_U(T_REPLACE,"Replacing existing kernel file") ,MSG_U(I_REPLACE,"ok to overwrite it ?") ,help_lilo)==MENU_YES){ file_copy (kernel_src.get(),kernel_dst.get()); LILO_CONF *conf = getdefaultlinux(); if (install != 1 || conf == NULL){ conf = new LILO_CONF; if (install == 0){ confs.insert (0,conf); }else{ confs.add (conf); } } conf->parm = newparm; conf->label.setfrom(label); conf->image.setfrom(kernel_dst.get()+len_prefix); if (install != 2){ defconf.setfrom (conf->label); } if (save() != -1) lilo_update(); break; } } } } static bool lilo_imageexist (const char *name, char path[PATH_MAX]) { static char std_path[]="/usr/src/linux/arch/i386/boot"; snprintf (path,PATH_MAX-1,"%s/%s",std_path,name); return file_exist (path)!=0; } /* Let the user install a new kernel he just compiled */ void lilo_addcompil() { char image[PATH_MAX]; if (!lilo_imageexist ("zImage",image) && !lilo_imageexist ("bzImage",image)){ xconf_error (MSG_U(E_NOCOMPILED ,"No kernel recently compiled available")); }else{ FILE_CFG *fin = f_makefile.fopen ("r"); if (fin != NULL){ char name[30]; name[0] = '\0'; char buf[300]; int version = -1; int patchlevel = -1; int sublevel = -1; SSTRING extra; bool extra_seen=false; while (fgets(buf,sizeof(buf)-1,fin)!=NULL){ char *pt = strchr (buf,'='); /* #Specification: lilo / /usr/src/linux/Makefile / assumption To help lilo admin set a proper name for his kernel file, we read /usr/src/linux/Makefile to grab PATCHLEVEL and SUBLEVEL. We assume that the Makefile has the following lines at the beginning. # VERSION = x PATCHLEVEL = y SUBLEVEL = z # The order is not important. */ if (pt != NULL){ pt = str_skip(pt+1); if (strncmp(buf,"VERSION",7)==0){ version = atoi(pt); }else if (strncmp(buf,"PATCHLEVEL",10)==0){ patchlevel = atoi(pt); }else if (strncmp(buf,"SUBLEVEL",8)==0){ sublevel = atoi(pt); }else if (strncmp(buf,"EXTRAVERSION",12)==0){ extra.setfrom(pt); extra.strip_end(); extra_seen = true; } if (version != -1 && patchlevel != -1 && sublevel != -1 && extra_seen){ sprintf (name,"boot/kernel-%d.%d.%d%s" ,version,patchlevel,sublevel,extra.get()); break; } } } fclose (fin); LILO lilo; lilo.addkernel(image,name); } } } /* Let the user install a new kernel he got from anywhere */ void lilo_addany() { LILO lilo; lilo.addkernel("",""); } /* Let the user pick a different default boot configuration */ PUBLIC void LILO::setdefault() { DIALOG dia; char sel = 0; if (!defconf.is_empty()){ bool found = false; for (int i=0; ilabel.cmp(defconf)==0){ sel = i; found = true; break; } } if (!found){ for (int j=0; jlabel.cmp(defconf)==0){ sel = j + confs.getnb(); break; } } } } char old_sel = sel; for (int i=0; iparm.root.get(); if (root[0] == '\0'){ root = def.root.get(); } sprintf (buf,"%s %s %s",c->label.get(),root,c->image.get()); dia.newf_radio ("",sel,i,buf); } for (int j=0; jlabel.get(),c->partition.get()); dia.newf_radio ("",sel,j+confs.getnb(),buf); } int choice = 0; while (1){ MENU_STATUS code = dia.edit( MSG_U(T_DEFKERN,"Default boot configuration") ,MSG_U(I_DEFKERN,"Pick the configuration which will become\n" "the default LILO configuration") ,help_lilo ,choice); if (code == MENU_QUIT || code == MENU_ESCAPE){ break; }else if (sel < confs.getnb() + others.getnb()){ if (sel != old_sel){ if (sel < confs.getnb()){ defconf.setfrom (confs.getitem(sel)->label); }else{ int n = sel - confs.getnb(); defconf.setfrom (others.getitem(n)->label); } if (save() != -1) lilo_update(); } break; } } } void lilo_setdefault() { LILO lilo; lilo.setdefault(); }