#include #include #include "grubconf.h" #include "grubconf.m" #include "grubconf.p" #include "popen.h" static HELP_FILE help_file_edit ("grubconf","edit"); void grubconf_edit() { GRUBCONFFILE gcf; DIALOG_MENU dia; static const char *m_options = MSG_U(M_OPTIONS,"General options"); static const char *m_entries = MSG_U(M_ENTRIES,"Menu entries"); static const char *m_default = MSG_U(M_DEFAULT,"Default entry"); static const char *m_fallbak = MSG_U(M_FALLBAK,"Fallback entry"); static const char *m_install = MSG_U(M_INSTALL,"Install"); static const char *menuopt[]={ "", m_options, "", m_entries, "", m_default, "", m_fallbak, "", m_install, NULL }; dia.new_menuitems (menuopt); int nb = 0; while (1){ MENU_STATUS code = dia.editmenu (MSG_U(T_GRUBCONF,"Grub configuration") ,MSG_U(I_GRUBCONF,"This menu allows you to configure\nthe Grub boot loader.") ,help_nil,nb,0); if (code == MENU_QUIT || code == MENU_ESCAPE){ break; }else if (code == MENU_OK){ const char *key = menuopt[nb*2+1]; if (key == m_options){ grubconf_options(gcf); }else if (key == m_entries){ grubconf_entries(gcf); }else if (key == m_default){ grubconf_default(gcf); }else if (key == m_fallbak){ grubconf_fallbak(gcf); }else if (key == m_install){ grubconf_install(gcf); } } } } void grubconf_options(GRUBCONFFILE &gcf) { DIALOG dia; SSTRING timeout(gcf.locate(-1,"timeout")); dia.newf_str(MSG_U(L_TIMEOUT,"Menu timeout"),timeout); SSTRING color(gcf.locate(-1,"color")); dia.newf_str(MSG_U(L_COLORS,"Colors"),color); SSTRING password(gcf.locate(-1,"password")); dia.newf_str(MSG_U(L_PASSWORD,"Password"),password); int nb = 0; while(1){ MENU_STATUS code = dia.edit( MSG_U(T_GENOPT,"General options") ,MSG_U(I_GENOPT, "Here you can edit the general Grub options") ,help_nil,nb,MENUBUT_ACCEPT|MENUBUT_CANCEL); if (code == MENU_QUIT || code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (code == MENU_ACCEPT){ gcf.update(-1,"timeout",timeout.get()); gcf.update(-1,"color",color.get()); if (password.getlen() == 0){ gcf.erase(-1,"password"); }else{ gcf.update(-1,"password",password.get()); } break; } } } void grubconf_default(GRUBCONFFILE &gcf) { DIALOG dia; int nb = 0; const char *defstr = gcf.locate(-1,"default"); char var = (defstr==NULL)?0:atoi(defstr)+1; dia.newf_radio("", var, 0, MSG_U(X_FIRSTENTRY,"First menu entry")); for (int i = 1; i <= gcf.count_titles(); i++){ dia.newf_radio("", var, i, gcf.locate(i-1,"title")); } while(1){ MENU_STATUS code = dia.edit( MSG_U(T_EDDEFAULT,"Default entry") ,MSG_U(I_EDDEFAULT, "Here you can select the entry that will\n" "be choosen when the timeout expires") ,help_nil,nb,MENUBUT_ACCEPT|MENUBUT_CANCEL); if (code == MENU_QUIT || code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (code == MENU_ACCEPT){ SSTRING tmp; if (var != 0){ tmp.setfrom(var-1); } gcf.update(-1,"default",tmp.get()); break; } } } void grubconf_fallbak(GRUBCONFFILE &gcf) { DIALOG dia; int nb = 0; const char *defstr = gcf.locate(-1,"fallback"); char var = (defstr==NULL)?0:atoi(defstr)+1; dia.newf_radio("", var, 0, MSG_U(X_DISFALLBACK,"Disable fallback")); for (int i = 1; i <= gcf.count_titles(); i++){ dia.newf_radio("", var, i, gcf.locate(i-1,"title")); } while(1){ MENU_STATUS code = dia.edit( MSG_U(T_EDFALLBACK,"Fallback entry") ,MSG_U(I_EDFALLBACK, "Here you can select the entry that will\n" "be choosen when the default entry fails") ,help_nil,nb,MENUBUT_ACCEPT|MENUBUT_CANCEL); if (code == MENU_QUIT || code == MENU_CANCEL || code == MENU_ESCAPE){ break; }else if (code == MENU_ACCEPT){ SSTRING tmp; if (var != 0){ tmp.setfrom(var-1); } gcf.update(-1,"fallback",tmp.get()); break; } } } void grubconf_entries(GRUBCONFFILE &gcf) { DIALOG_LISTE dia; dia.newf_head("",MSG_U(X_TITLE,"Title")); int nb = 0; while (1){ int total_titles = gcf.count_titles(); for (int i = 0; i < total_titles; i++){ dia.set_menuitem(i,gcf.locate(i,"title"),""); } dia.remove_last(total_titles+1); MENU_STATUS code = dia.editmenu ( MSG_U(T_ENTRIES,"Menu entries") ,MSG_U(I_ENTRIES, "This menu allows you to change and create\n" "Grub menu entries") ,help_nil,nb,MENUBUT_ADD); if (code == MENU_QUIT || code == MENU_ESCAPE){ break; }else if (code == MENU_OK){ if (gcf.check_script(nb)){ edit_menu_entry(gcf,nb); }else{ xconf_notice(MSG_U(N_UNSUPPORTED,"Unsupported script. You'll have to edit it by hand.")); } }else if (code == MENU_ADD){ edit_menu_entry(gcf,gcf.count_titles()); } } } void edit_menu_entry(GRUBCONFFILE &gcf, int number) { DIALOG dia; SSTRING title(gcf.locate(number,"title")); dia.newf_str(MSG_R(X_TITLE),title); SSTRING root_media_type; SSTRING root_media_number; SSTRING root_part_number; SSTRING root_freebsd_part; char verify = 1; const char *p = gcf.locate(number,"root"); if (p == NULL){ p = gcf.locate(number,"rootnoverify"); if (p != NULL){ verify = 0; } } if (p == NULL || *p == 0){ root_media_type.setfrom(MSG_U(X_NOROOT,"Don't use root option")); }else{ bool root_error = true; if (strlen(p) >= 7) { if (*p == '('){ p++; if (strncmp(p,"hd",2)==0){ root_media_type.setfrom(MSG_U(X_HD,"Hard disk")); }else if (strncmp(p,"fd",2)==0){ root_media_type.setfrom(MSG_U(X_FD,"Floppy disk")); } p += 2; if (*p >= '0' && *p <= '9'){ int hfdn = 0; for (;*p >= '0' && *p <= '9'; p++){ hfdn = (hfdn*10)+(*p-'0'); } root_media_number.setfrom(hfdn); if (*p == ',' && *(p+1) >= '0' && *(p+1) <= '9'){ p++; int pn = 0; for (;*p >= '0' && *p <= '9'; p++){ pn = (pn*10)+(*p-'0'); } root_part_number.setfrom(pn); if (*p == ','){ p++; if (*p >= 'a' && *p <= 'h'){ root_freebsd_part.setfrom(p,1); p++; if (*p == ')'){ root_error = false; } } }else if (*p == ')'){ root_error = false; } } } } } if (root_error == true){ xconf_notice(MSG_U(N_BADROOT,"Bad root option!")); } } // root options dia.newf_title (MSG_U(T_ROOT,"Root"),1,"",MSG_R(T_ROOT)); FIELD_COMBO *rmt = dia.newf_combo(MSG_U(L_MEDIATYPE,"Root media type"),root_media_type); rmt->addopt(MSG_R(X_NOROOT),""); rmt->addopt(MSG_R(X_HD),""); rmt->addopt(MSG_R(X_FD),""); dia.newf_str(MSG_U(L_HDFDNUMBER,"Root HD/FD number"),root_media_number); dia.newf_str(MSG_U(L_PARTNUMBER,"Root partition number"),root_part_number); dia.newf_str(MSG_U(L_FREEBSDPART,"Root FreeBSD partition"),root_freebsd_part); dia.newf_chk("",verify,MSG_U(X_VRFYROOT,"Verify root")); // kernel options const char *ks = gcf.locate(number,"kernel"); const char *ke = ks; char netbsd = 0; SSTRING kernel, kernel_param; if (ks != NULL) { if (strncmp(ks,"--type=",7)==0){ ke += 7; const char *ts = ke; while (*ke != ' ' && *ke != '\t' && *ke != 0) ke++; while (*ke == ' ' || *ke == '\t') ke++; if (strncmp(ts,"netbsd",6)==0){ netbsd = 1; ks = ke; } } while (*ke != ' ' && *ke != '\t' && *ke != 0) ke++; kernel.setfrom(ks,ke-ks); while (*ke == ' ' || *ke == '\t') ke++; kernel_param.setfrom(ke); } dia.newf_title (MSG_U(T_KERNEL,"Kernel"),1,"",MSG_R(T_KERNEL)); dia.newf_str(MSG_U(L_KERNFILE,"Kernel file"),kernel); dia.newf_str(MSG_U(L_KERNPARM,"Kernel parameters"),kernel_param); SSTRING module(gcf.locate(number,"module")); dia.newf_str(MSG_U(L_KERNMOD,"Kernel module"),module); SSTRING initrd(gcf.locate(number,"initrd")); dia.newf_str(MSG_U(L_INITRD,"Initial ramdisk file"),initrd); dia.newf_chk("",netbsd,MSG_U(X_NETBSDELF,"NetBSD ELF kernel")); // other options const char *cl = gcf.locate(number,"chainloader"); char cl_var = 0; SSTRING clfile; if (cl != NULL){ if (*cl == '+' && *(cl+1) == '1'){ cl_var = 1; }else if (*cl != 0){ clfile.setfrom(cl); cl_var = 2; } } dia.newf_title (MSG_U(T_OTHEROPTIONS,"Other options"),1,"",MSG_R(T_OTHEROPTIONS)); const char *cl_opt[] = {MSG_U(X_CLNONE,"None"),MSG_U(X_CLFIRSTSECT,"First sector"),MSG_U(X_CLFILE,"File"),NULL}; dia.newf_chkm(MSG_U(L_CHAINLOAD,"Chainload"),cl_var,cl_opt); dia.newf_str(MSG_U(L_CLFILE,"Chainload file"),clfile); char makeactive = 0; if (gcf.locate(number,"makeactive") != NULL){ makeactive = 1; } dia.newf_chk("",makeactive,MSG_U(X_MAKEACTIVE,"Make partition active")); int nb = 0; while (1){ MENU_STATUS code = dia.edit ( MSG_U(T_EDIT,"Edit entry") ,MSG_U(I_EDIT, "This menu allows you to change a Grub menu entry.") ,help_file_edit,nb,MENUBUT_ACCEPT|MENUBUT_CANCEL|MENUBUT_DEL); if (code == MENU_QUIT || code == MENU_ESCAPE || code == MENU_CANCEL){ break; }else if (code == MENU_ACCEPT){ gcf.update(number,"title",title.get()); if (module.getlen() == 0){ gcf.erase(number,"module"); }else{ gcf.update(number,"module",module.get()); } // update "root" variable if (strcmp(MSG_R(X_HD),root_media_type.get())==0){ root_media_type.setfrom("hd"); }else if (strcmp(MSG_R(X_FD),root_media_type.get())==0){ root_media_type.setfrom("fd"); } if (strcmp(MSG_R(X_NOROOT),root_media_type.get())!=0){ SSTRING root; if (root_freebsd_part.getlen() == 0){ root.setfromf("(%s%s,%s)",root_media_type.get() ,root_media_number.get(),root_part_number.get()); }else{ root.setfromf("(%s%s,%s,%s)" ,root_media_type.get() ,root_media_number.get() ,root_part_number.get() ,root_freebsd_part.get()); } if (verify != 0){ gcf.erase(number,"rootnoverify"); gcf.update(number,"root",root.get()); }else{ gcf.erase(number,"root"); gcf.update(number,"rootnoverify",root.get()); } }else{ gcf.erase(number,"rootnoverify"); gcf.erase(number,"root"); } // update "kernel" variable if (kernel.getlen() == 0){ gcf.erase(number,"kernel"); }else{ if (netbsd && !(strncmp(str_skip(kernel.get()),"--type=",7)==0)){ kernel.setfromf("--type=netbsd %s %s",kernel.get(),kernel_param.get()); }else{ kernel.setfromf("%s %s",kernel.get(),kernel_param.get()); } gcf.update(number,"kernel",kernel.get()); } // update "initrd" variable if (initrd.getlen() == 0){ gcf.erase(number,"initrd"); }else{ gcf.update(number,"initrd",initrd.get()); } // update "chainloader" variable if (cl_var == 0){ gcf.erase(number,"chainloader"); }else if (cl_var == 1){ gcf.update(number,"chainloader","+1"); }else{ gcf.update(number,"chainloader",clfile.get()); } // update "makeactive" variable if (makeactive == 0){ gcf.erase(number,"makeactive"); }else{ gcf.update(number,"makeactive",""); } break; }else if (code == MENU_DEL){ for (int i = 0; i < total_commands; i++){ gcf.erase(number,command_order[i]); } gcf.erase(number,"title"); break; } } } void grubconf_install(GRUBCONFFILE &gcf) { DIALOG dia; SSTRING device; SSTRING rootdir("/boot/grub"); char forcelba = 0; dia.newf_str(MSG_U(L_DEVICE,"Device"),device); dia.newf_str(MSG_U(L_IMAGESDIR,"Images directory"), rootdir); dia.newf_chk("",forcelba,MSG_U(X_FORCELBA,"Force lba mode")); int nb = 0; while (1){ MENU_STATUS code = dia.edit (MSG_U(T_INSTALL,"Install Grub") ,MSG_U(I_INSTALL, "This menu allows you to install the Grub boot loader\n" "in your hard disk or floppy disk. Note that, unlike\n" "other boot loaders, Grub doesn't need to be installed\n" "everytime a setup option changes. You will probably\n" "need to install Grub in your hard disk just once." ) ,help_nil,nb,MENUBUT_ACCEPT|MENUBUT_CANCEL); if (code == MENU_QUIT || code == MENU_ESCAPE || code == MENU_CANCEL){ break; }else if (code == MENU_ACCEPT){ SSTRING args; if (rootdir.getlen() > 0){ args.setfromf("--root-directory=%s ",rootdir.get()); } if (forcelba){ args.append(" --force-lba "); } args.append(device.get()); POPEN grub_install("grub-install",args.get()); int ret = grub_install.wait(10); if (ret == 0){ grub_install.kill(); xconf_error(MSG_U(E_NOANSWER,"No answer from install program!")); }else if (ret != -1){ int status = grub_install.close(); if (status == 0){ xconf_notice(MSG_U(N_INSTALLED,"Grub installed successfully!")); }else{ SSTRING error(MSG_U(E_MSGFROMINST,"Error message received from install program:\n\n")); char line[128]; while (grub_install.readerr(line,128)!=EOF){ error.append(line); } xconf_error(error.get()); } } } } }