home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / boot / i386 / root / usr / share / YaST2 / modules / VM_Common.ycp < prev    next >
Text File  |  2006-11-29  |  32KB  |  1,046 lines

  1. /**
  2.  * File:    modules/VM_Common.ycp
  3.  * Package:    VM configuration - common function for all virtualization architectures
  4.  * Authors:    Ladislav Slezak <lslezak@suse.cz>
  5.  *        Michael G. Fritch <mgfritch@novell.com>
  6.  *
  7.  * $Id: VM_Common.ycp 34434 2006-11-16 21:34:28Z mgfritch $
  8.  */
  9. {
  10.     module "VM_Common";
  11.  
  12.     import "Report";
  13.     import "Popup";
  14.     import "Label";
  15.     import "Pkg";
  16.     import "Package";
  17.     import "Arch";
  18.     import "ProductControl";
  19.     import "HTML";
  20.     import "PackageCallbacksInit";
  21.     import "String";
  22.  
  23.     textdomain "vm";
  24.  
  25.     global integer source_id = 0;
  26.  
  27.     global symbol inst_type = `cdrom;
  28.  
  29.     global string custom_source = "";
  30.  
  31.     global integer default_memory_size = 256;
  32.  
  33.     global integer memory_size = default_memory_size;
  34.  
  35.     global integer default_number_of_cpus = 1;
  36.  
  37.     global integer number_of_cpus = default_number_of_cpus;
  38.  
  39.     global string default_start_mode = "manual";
  40.  
  41.     global string start_mode = default_start_mode;
  42.  
  43.     global string on_poweroff = "destroy";
  44.  
  45.     global string on_reboot = "restart";
  46.  
  47.     global string on_crash = "restart";
  48.  
  49.     global integer default_ne2000 = 0;  // if virtual network card is AMD PCnet, then 0, else 1(NE2000)
  50.  
  51.     global integer ne2000 = default_ne2000;
  52.  
  53.     global integer default_stdvga = 0;  // if graphics card is Cirrus Logic, then 0, else 1(Standard VGA)
  54.  
  55.     global integer stdvga = default_stdvga;
  56.  
  57.     global integer default_sdl = 1; // if graphics view is DirectMedia Layer(SDL) then 1, else 0 (VNC)
  58.  
  59.     global integer sdl = default_sdl;
  60.  
  61.     global integer default_localtime = 0;  // if hardware clock is set to local time then 1, else 0 (UTC)
  62.  
  63.     global integer localtime = default_localtime;
  64.  
  65.     global string default_MAC = "";
  66.  
  67.     global string MAC_address = default_MAC;
  68.  
  69.     global boolean random_MAC = true;
  70.  
  71.     global string config_name = "";
  72.  
  73.     // activation mode - in virtual machine installation proposal
  74.     global map start_mode_names = $[ "manual" : _("Manually"), "onboot" : _("Automatically") ];
  75.  
  76. // virtual network card - in virtual machine installation proposal
  77.     global map ne2000_names = $[ 0 : _("AMD PCnet"), 1 : _("NE2000") ];
  78.  
  79. // virtual graphics card - in virtual machine installation proposal
  80.     global map stdvga_names = $[ 0 : _("Cirrus Logic"), 1 : _("Standard VGA") ];
  81.  
  82. // graphics viewer - in virtual machine installation proposal
  83.     global map sdl_names = $[ 0 : _("VNC"), 1 : _("SDL") ];
  84.  
  85. // hardware clock - in virtual machine installation proposal
  86.     global map localtime_names = $[ 0 : _("UTC"), 1 : _("Local Time") ];
  87.  
  88.     global string extra_args = "";
  89.  
  90.     global string hidden_args = "";
  91.  
  92.     global string root_device = "";
  93.  
  94.     global string autoyast_profile = "";
  95.     global map autoyast_profile_settings = $[];
  96.  
  97.     global boolean default_use_dhcp = false;
  98.     global boolean use_dhcp = default_use_dhcp;
  99.     global boolean default_use_static = false;
  100.     global boolean use_static = default_use_static;
  101.     global string ip = "";
  102.     global string netmask = "";
  103.     global string gateway = "";
  104.  
  105.     global string proposal_type = "install";
  106.  
  107.     string custom_kernel = "";
  108.     string custom_initrd = "";
  109.     boolean use_custom_kernel = false;
  110.  
  111.     boolean modified = false;
  112.  
  113.     string default_type = "para";
  114.     string virtualization_type = default_type; // currently "para" or "full"
  115.  
  116.     string yast_tmp_dir = "";
  117.  
  118.     global define list<string> CPUflags()
  119.     {
  120.     // check only the first processor (assume the same processors)
  121.     string cpuinfo_flags = (string) SCR::Read(.proc.cpuinfo.value."0"."flags");
  122.     list<string> cpuflags = (size(cpuinfo_flags) > 0) ? splitstring(cpuinfo_flags, " ") : [];
  123.  
  124.     y2milestone("Detected CPU flags: %1", cpuflags);
  125.     return cpuflags;
  126.     }
  127.  
  128.     global define boolean VirtualizationCPU()
  129.     {
  130.     list<string> cpuflags = CPUflags();
  131.  
  132.     // vmx = Intel VT-x, svm = AMD Pacifica
  133.     return contains(cpuflags, "vmx") || contains(cpuflags, "svm");
  134.     }
  135.  
  136.     global define string GetVirtualizationType()
  137.     {
  138.     return virtualization_type;
  139.     }
  140.  
  141.     global define boolean SetVirtualizationType(string type)
  142.     {
  143.     if (!contains(["para", "full"], type))
  144.     {
  145.         y2warning("Unknown virtualization type: %1", type);
  146.         return false;
  147.     }
  148.  
  149.     modified = virtualization_type != type;
  150.     virtualization_type = type;
  151.     return true;
  152.     }
  153.  
  154.     global boolean ResetVirtualizationType()
  155.     {
  156.     string virt_type = default_type;
  157.     // FIXME: when full virt hardware is supported the following line should be uncommented.
  158.     // if (VirtualizationCPU()) virt_type = "full"; // full virt hardware detected, default all vm's to full virtualization
  159.     return SetVirtualizationType(virt_type);
  160.     }
  161.  
  162.     global string GetVirtualizationProposal()
  163.     {
  164.     string val = (virtualization_type == "para") ? _("Paravirtualization") : _("Full Virtualization");
  165.     return HTML::List([val]);
  166.     }
  167.  
  168.  
  169.     global boolean GetModified() {
  170.     return modified;
  171.     }
  172.  
  173.     global void SetModified(boolean modif) {
  174.     modified = modif;
  175.     }
  176.  
  177.  
  178.     global map Export() {
  179.  
  180.     map ret = $[
  181.         "source_id"        : source_id,
  182.         "inst_type"        : inst_type,
  183.         "custom_source"        : custom_source,
  184.         "memory_size"        : memory_size,
  185.         "number_of_cpus"    : number_of_cpus,
  186.         "start_mode"        : start_mode,
  187.         "on_poweroff"        : on_poweroff,
  188.         "on_reboot"        : on_reboot,
  189.         "on_crash"        : on_crash,
  190.         "ne2000"        : ne2000,
  191.         "stdvga"        : stdvga,
  192.         "sdl"            : sdl,
  193.         "localtime"        : localtime,
  194.         "MAC_address"        : MAC_address,
  195.         "random_MAC"        : random_MAC,
  196.         "config_name"        : config_name,
  197.         "extra_args"        : extra_args,
  198.         "hidden_args"        : hidden_args,
  199.         "root_device"        : root_device,
  200.         "use_dhcp"        : use_dhcp,
  201.         "use_static"        : use_static,
  202.         "ip"            : ip,
  203.         "netmask"        : netmask,
  204.         "gateway"        : gateway,
  205.         "custom_kernel"        : custom_kernel,
  206.         "custom_initrd"        : custom_initrd,
  207.         "use_custom_kernel"    : use_custom_kernel,
  208.         "virtualization_type"    : virtualization_type
  209.     ];
  210.  
  211.     // export configured source as custom (source index may point later to another source)
  212.     if (inst_type == `network_configured && source_id != nil && source_id > 0)
  213.     {
  214.         map general_data = Pkg::SourceGeneralData (source_id);
  215.         string url = general_data["url"]:"";
  216.     
  217.         y2milestone("Exporting source config: %1", url);
  218.     
  219.         ret["custom_source"] = url;
  220.         ret["inst_type"] = `network_custom;
  221.     }
  222.  
  223.     y2debug("VM_Common::Export() returned: %1", ret);
  224.  
  225.     return ret;
  226.     }
  227.  
  228.  
  229.     global void Import(map input) {
  230.  
  231.     y2debug("VM_Common::Import(%1)", input);
  232.  
  233.     source_id =        input["source_id"]:source_id;
  234.     inst_type =        input["inst_type"]:inst_type;
  235.     custom_source =        input["custom_source"]:custom_source;
  236.     memory_size =        input["memory_size"]:memory_size;
  237.     number_of_cpus =    input["number_of_cpus"]:number_of_cpus;
  238.     start_mode =        input["start_mode"]:start_mode;
  239.     on_poweroff =        input["on_poweroff"]:on_poweroff;
  240.     on_reboot =        input["on_reboot"]:on_reboot;
  241.     on_crash =        input["on_crash"]:on_crash;
  242.     ne2000 =        input["ne2000"]:ne2000;
  243.     stdvga =        input["stdvga"]:stdvga;
  244.     sdl =            input["sdl"]:sdl;
  245.     localtime =        input["localtime"]:localtime;
  246.     MAC_address =        input["MAC_address"]:MAC_address;
  247.     random_MAC =        input["random_MAC"]:random_MAC;
  248.     config_name =        input["config_name"]:config_name;
  249.     extra_args =        input["extra_args"]:extra_args;
  250.     hidden_args =        input["hidden_args"]:hidden_args;
  251.     root_device =        input["root_device"]:root_device;
  252.     use_dhcp =        input["use_dhcp"]:use_dhcp;
  253.     use_static =        input["use_static"]:use_static;
  254.     ip =            input["ip"]:ip;
  255.     netmask =        input["netmask"]:netmask;
  256.     gateway =        input["gateway"]:gateway;
  257.     custom_kernel =        input["custom_kernel"]:custom_kernel;
  258.     custom_initrd =        input["custom_initrd"]:custom_initrd;
  259.     use_custom_kernel =    input["use_custom_kernel"]:use_custom_kernel;
  260.     virtualization_type =    input["virtualization_type"]:virtualization_type;
  261.  
  262.     }
  263.  
  264.  
  265.     /**
  266.     * Displays a formatted popup error message, with a details button.
  267.     * @param errorMessage string - a simple message describing the error
  268.     * @param out map - output of the executed command
  269.     * @param cmd string - the executed command
  270.     * @return void
  271.     */
  272.     global void PopupErrorDetails(string errorMessage, map out, string cmd) ``{
  273.         string message = _("Undefined Error");
  274.         if (errorMessage != nil && errorMessage != "") message = errorMessage;
  275.         Popup::ClearFeedback();
  276.     // Details button on a popup error message
  277.         if (!Popup::AnyQuestion( Label::ErrorMsg(), message, Label::OKButton(), _("&Details..."), `focus )) {
  278.                 string description = sformat("<pre>command: %1 return \n %2 %3</pre>", cmd, out["stderr"]:"", out["stdout"]:"");
  279.                 UI::OpenDialog (`opt(`decorated ),
  280.                         `HBox( `VSpacing(16),
  281.                                 `VBox (
  282.                                         `HSpacing (100),
  283.                                         // popup window header
  284.                                         `Heading (message),
  285.                                         `VSpacing (0.5),
  286.                                         `RichText (description),
  287.                                         `VSpacing (1.0),
  288.                                         // push button label
  289.                                         `PushButton (`id(`ok), `opt(`default, `key_F10), Label::OKButton())
  290.                                 )
  291.                         )
  292.                 );
  293.  
  294.                 UI::SetFocus (`id(`ok));
  295.                 UI::UserInput ();
  296.                 UI::CloseDialog ();
  297.         }
  298.     }
  299.  
  300.  
  301.     global string GetAutoYastProposal() {
  302.     // proposal items
  303.     // %1 = an absolute filename path to the AutoYaST profile.
  304.     return HTML::List([ sformat(_("AutoYaST Profile: %1"), (autoyast_profile != "") ?
  305.         // none AutoYast profile has been selected
  306.         autoyast_profile : _("<I>none</I>"))]);
  307.     }
  308.  
  309.     global map<string,any> GetAutoYastProposalWarning() {
  310.     map<string,any> ret = $[];
  311.  
  312.     if (GetVirtualizationType() == "full" && autoyast_profile != "")
  313.     {
  314.         // error in the installation proposal - do not allow to continue
  315.         ret = $[
  316.         // warning text in proposal dialog
  317.         "warning" : _("The AutoYaST profile for VM cannot be configured here in full virtualization mode.<BR>Configure it inside the VM after boot."),
  318.         "warning_level" : `warning
  319.         ];
  320.     }
  321.  
  322.     return ret;
  323.     }
  324.  
  325.     global boolean SetAutoYastProfile(string profile) {
  326.     modified = (profile != autoyast_profile);
  327.     autoyast_profile = profile;
  328.     return true;
  329.     }
  330.  
  331.     global string GetAutoYastProfile() {
  332.     return autoyast_profile;
  333.     }
  334.  
  335.     global map<string, string> restart_mapping = $[
  336.      // combobox item
  337.      // restart mode - when the virtual machine is restarted
  338.      "always" : _("Always"),
  339.      // combobox item
  340.      // restart mode - when the virtual machine is restarted
  341.      "never" : _("Never"),
  342.      // combobox item
  343.      // restart mode - when the virtual machine is restarted
  344.      "onreboot" : _("On Reboot")
  345.     ];
  346.  
  347.     // used for values on_poweroff, on_reboot, on_crash
  348.     global map<string, string> lifecycle_event_mapping = $[
  349.      // combobox item
  350.      // lifecycle_event mode (on_poweroff, on_reboot, on_crash) - destroy virtual machine
  351.      "destroy" : _("Destroy"),
  352.      // combobox item
  353.      // lifecycle_event mode (on_poweroff, on_reboot, on_crash) - restart virtual machine
  354.      "restart" : _("Restart"),
  355.      // combobox item
  356.      // lifecycle_event mode (on_poweroff, on_reboot, on_crash) - preserve virtual machine
  357.      "preserve" : _("Preserve"),
  358.      // combobox item
  359.      // lifecycle_event mode (on_poweroff, on_reboot, on_crash) - rename and restart virtual machine
  360.      "rename-restart" : _("Rename and restart"),
  361.     ];
  362.  
  363.  
  364.     global define string GetKernelImage() {
  365.     return custom_kernel;
  366.     }
  367.  
  368.     global define boolean SetKernelImage(string im) {
  369.     custom_kernel = im;
  370.     return true;
  371.     }
  372.  
  373.     global define string GetInitrdImage() {
  374.     return custom_initrd;
  375.     }
  376.  
  377.     global define boolean SetInitrdImage(string im) {
  378.     custom_initrd = im;
  379.     return true;
  380.     }
  381.  
  382.     global define boolean SetCustomKernel(boolean use_custom)
  383.     {
  384.     use_custom_kernel = use_custom;
  385.     return true;
  386.     }
  387.  
  388.     global define boolean GetCustomKernel()
  389.     {
  390.     return use_custom_kernel;
  391.     }
  392.  
  393.     global integer ProposeSelection () ``{
  394.     list <integer> sources = Pkg::SourceGetCurrent (false);
  395.     y2milestone("sources: %1", sources);
  396.     integer sid = nil;
  397.  
  398.     foreach(integer src, sources, ``{
  399.         map general_data = Pkg::SourceGeneralData(src);
  400.         y2milestone("general_data: %1", general_data);
  401.  
  402.         string srcurl = general_data["url"]:"";
  403.  
  404.         // use only network sources in proposal
  405.         if (regexpmatch(srcurl, "^(ftp)|(nfs)|(smb)|(http)://"))
  406.         {
  407.             y2milestone("Found network source: %1", src);
  408.             sid = src;
  409.         }
  410.         }
  411.     );
  412.  
  413.     return sid;
  414.     }
  415.  
  416.  
  417.     global string GetDefaultRouteInterface() {
  418.     // grab the default route from the route table
  419.     string cmd = "/sbin/route | /usr/bin/grep -E '^default'";
  420.     y2milestone("Executing: %1", cmd);
  421.     map out = (map)SCR::Execute(.target.bash_output, cmd);
  422.     y2milestone("route output: %1", out);
  423.     
  424.     // get the interface assigned to the default route
  425.     list<string> output = splitstring(out["stdout"]:"", " \t\n");
  426.     output = filter(string tmpstr, output, ``(tmpstr != nil && tmpstr != ""));
  427.     y2milestone("output=%1", output);
  428.     string default_interface = output[size(output)-1]:"";
  429.     default_interface = String::CutBlanks(default_interface);
  430.     y2milestone("default_interface=%1", default_interface);
  431.  
  432.     // default to eth0 if an error occurs
  433.     if (default_interface == nil || default_interface == "")
  434.         default_interface = "eth0";
  435.  
  436.     y2milestone("GetDefaultRouteInterface returned '%1'", default_interface);
  437.     return default_interface;
  438.     }
  439.  
  440.     global boolean IsNetWareKernel(string kernel)
  441.     {
  442.         list<string> names = splitstring(kernel, "/");
  443.         string name = names[size(names) - 1]:"";
  444.         return (tolower(name) == "xnloader.sys");
  445.     }
  446.  
  447.     global void SetNetWareHiddenArgs()
  448.     {
  449.         string args = "";
  450.  
  451.     // Set the display
  452.     string cmd = "set | grep 'DISPLAY' | grep -v 'BASH_EXECUTION_STRING'";
  453.     y2milestone("Executing: %1", cmd);
  454.     map retmap = (map) SCR::Execute(.target.bash_output, cmd);
  455.     y2milestone("retmap=%1", retmap);
  456.     string display_value = deletechars(retmap["stdout"]:"", "\n"); // remove all newlines
  457.     display_value = String::CutBlanks(display_value);
  458.     list<string> display_list = (list<string>)splitstring(display_value, "=:");
  459.     y2milestone("display_list=%1", display_list);
  460.     // Add display=
  461.     if (display_list[1]:"" == nil || display_list[1]:"" == "" || display_list[1]:"" == "localhost" || display_list[1]:"" == "127.0.0.1") {
  462.  
  463.         // get the inferface assigned to the default route
  464.         string default_interface = GetDefaultRouteInterface();
  465.  
  466.         // get the IP address of the interface used in the default route
  467.         import "IP";
  468.         list<map> ifconfig =(list<map>)SCR::Read(.run.ifconfig);
  469.         ifconfig = filter(map iface, ifconfig, ``( iface["name"]:"" == default_interface));
  470.         integer ipint = ifconfig[0,"value", "inet", "addr"]:0;
  471.         if (ipint != nil && ipint > 0) {
  472.             args = args + sformat(" DISPLAY=%1:%2", IP::ToString(ipint), display_list[2]:"0");
  473.         }
  474.         else {
  475.             // use the display value as is...
  476.             args = args + display_value;
  477.         }
  478.  
  479.     }
  480.     else {
  481.         // use the display value as is...
  482.         args = args + display_value;
  483.     }
  484.  
  485.         VM_Common::hidden_args = args;
  486.     y2milestone("hidden_args=%1", hidden_args);
  487.     }
  488.  
  489.     global void SetLinuxHiddenArgs()
  490.     {
  491.         string arg = (VM_Common::proposal_type == "install") ? "install=$URL_INSTALL" : "";
  492.         VM_Common::hidden_args = arg;
  493.     }
  494.  
  495.     global void SetHiddenArgs(string kernel)
  496.     {
  497.         if (IsNetWareKernel(kernel))
  498.             SetNetWareHiddenArgs();
  499.         else
  500.             SetLinuxHiddenArgs();
  501.     }
  502.  
  503.     global list<string> CreateSourceProposal(symbol inst_type, integer source_id, string custom)
  504.     {
  505.     list<string> ret = [];
  506.  
  507.     if (inst_type == `cdrom || inst_type == `iso)
  508.     {
  509.         if (inst_type == `iso) {
  510.         // installation proposal item
  511.         ret = add(ret, sformat("%1 (%2)", _("Installation Device: ISO Image File"), custom));
  512.         }
  513.         else if (inst_type == `cdrom) {
  514.         // installation proposal item
  515.         ret = add(ret, sformat("%1 (%2)", _("Installation Device: CD/DVD Device"), custom));
  516.         }
  517.         if (use_custom_kernel) {
  518.         // installation proposal item
  519.         // %1 = absolute pathname the to a Xen-Enabled kernel
  520.         ret = add(ret, sformat(_("Kernel: %1"), custom_kernel));
  521.     
  522.         if (custom_initrd != "")
  523.             // installation proposal item
  524.             // %1 = absolute pathname to a Xen-Enabled initrd (ramdisk)
  525.             ret = add(ret, sformat(_("RAM Disk Image: %1"), custom_initrd));
  526.     
  527.         SetHiddenArgs(custom_kernel);
  528.         }
  529.         else { // SUSE installation source
  530.         SetLinuxHiddenArgs();
  531.         }
  532.     }
  533.     else { // network install (SUSE instsources only!)
  534.         string desc = "";
  535.  
  536.             SetLinuxHiddenArgs();
  537.  
  538.         y2milestone("inst_type: %1, source_id: %2", inst_type, source_id);
  539.  
  540.         if (inst_type == `network_configured && source_id != nil && source_id >= 0)
  541.         {
  542.         map product_data = Pkg::SourceProductData (source_id);
  543.         map general_data = Pkg::SourceGeneralData (source_id);
  544.         desc = product_data["label"]:"unknown" + " (" + general_data["url"]:"" + ")";
  545.         }
  546.         else if (inst_type == `network_custom || inst_type == `cdrom || inst_type == `iso)
  547.         {
  548.         // installation proposal header
  549.         desc =  _("Custom Installation Source") + " (" + custom_source + ")";
  550.         }
  551.         else if (inst_type == `slp)
  552.         {
  553.         // installation proposal header
  554.         desc = _("SLP Installation Source");
  555.         }
  556.  
  557.         // %1 = installation source description or URL
  558.         ret = [ sformat(_("SUSE Installation Source: %1"), desc) ];
  559.     }
  560.  
  561.     return ret;
  562.     }
  563.  
  564.     global map CreateSourceProposalWarning(symbol inst_type, integer source_id, string custom) {
  565.  
  566.     map ret = $[];
  567.  
  568.     if (inst_type == `network_configured && (source_id == nil || source_id < 0) && virtualization_type == "para") {
  569.         ret = $[ "warning" :
  570.             // error message in proposal
  571.             _("OS installation source is not configured"),
  572.              "warning_level" : `blocker
  573.         ];
  574.     }
  575.     else if ((inst_type == `network_custom || inst_type == `cdrom || inst_type == `iso) && (custom == nil || custom == "") && virtualization_type == "para") {
  576.         ret = $[ "warning" :
  577.             // error message in proposal
  578.             _("OS installation source is not configured"),
  579.              "warning_level" : `blocker
  580.         ];
  581.     }
  582. // TODO: check custom installation source - parse URL, try to open it...
  583. /*    else if (inst_type == `network_custom)
  584.     {
  585.         // installation proposal header
  586.         ret = _("Custom Installation Source") + " (" + custom_source + ")";
  587.     }
  588. */
  589.     return ret;
  590.     }
  591.  
  592.     global define boolean CreateDiskImage(string file, integer image_mb, boolean sparse) ``{
  593.     boolean ret = true;
  594.  
  595.     if ( ! sparse ) {
  596.         // non-sparse images might take a long time to create (Bugzilla #167145)
  597.         // Popup Feedback message
  598.         Popup::ShowFeedback(_("Preparing Disk Image"), sformat("%1 (%2 MB)\n\n%3", file, image_mb, _("This might take a while.")));
  599.     }
  600.  
  601.     string dd_options = (sparse) ? (" bs=1 count=1 " + sformat ("seek=%1", (image_mb*1024*1024)-1)) : (" bs=1M " + sformat ("count=%1", image_mb));
  602.     string cmd = "/bin/dd if=/dev/zero of='" + file + "'" + dd_options;
  603.  
  604.     y2milestone("Creating disk image %1 (%2MB)", file, image_mb);
  605.     y2debug("dd command: %1", cmd);
  606.     map result = (map) SCR::Execute (.target.bash_output, cmd);
  607.     y2debug("result=%1", result);
  608.  
  609.     Popup::ClearFeedback();
  610.  
  611.     if (result["exit"]:-1 != 0)
  612.     {
  613.         //PopupErrorDetails(sformat(_("Cannot create disk image %1"), file), result, cmd);  // FIXME: somehow the output from the dd command is not captured by .target.bash_output
  614.         y2error("Cannot create disk image %1", file);
  615.         // Popup error message
  616.         // %1 = absolute pathname to a loopback disk image (i.e '/var/lib/xen/images/vm1/hda')
  617.         Report::Error(sformat(_("Cannot create the following disk image:
  618. %1
  619.  
  620. Please, ensure there is enough free disk space
  621. to create the specified disk image.
  622.  
  623. "), file));
  624.  
  625.         // try to remove part of the image if it exists
  626.         SCR::Execute (.target.bash, "/bin/rm -- '" + file + "'");
  627.         ret = false;
  628.     }
  629.  
  630.     return ret;
  631.     }
  632.  
  633.     global define boolean CreateExt2Image(string image, integer image_mb) {
  634.     // create sparse image file
  635.     if (!VM_Common::CreateDiskImage(image, image_mb, true))
  636.     {
  637.         return false;
  638.     }
  639.  
  640.     // create Ext2 file system (built in FS, no kernel module required)
  641.     // reserve 0% percent for root
  642.     string command = "/sbin/mkfs.ext2 -F -m 0 -- '" + image + "'";
  643.     y2milestone("executing: %1", command);
  644.  
  645.     integer out = (integer)SCR::Execute(.target.bash, command);
  646.     y2milestone("mkfs.ext2 result: %1", out);
  647.     if (out != 0)
  648.     {
  649.         y2error("Cannot make a file system on the disk image");
  650.         return false;
  651.     }
  652.     return true;
  653.     }
  654.  
  655.     global define string GetTmpDir() {
  656.         if (yast_tmp_dir == nil || yast_tmp_dir == "") {
  657.                 // get temporary directory
  658.         map output = (map)SCR::Execute(.target.bash_output, "mktemp -d"); // Let bash create a tmp dir
  659.         yast_tmp_dir = deletechars(output["stdout"]:"", "\n\t ");
  660.                 if (yast_tmp_dir == "" || yast_tmp_dir == nil)
  661.                 {
  662.                     y2warning("Using /tmp directory for temporary files!");
  663.                     yast_tmp_dir = "/tmp";
  664.                 }
  665.         }
  666.         y2milestone("Using tmp directory: %1", yast_tmp_dir);
  667.         return yast_tmp_dir;
  668.     }
  669.  
  670.     global boolean RemoveTmpDir() {
  671.         boolean ret = false;
  672.         if (yast_tmp_dir != nil && yast_tmp_dir != "" && yast_tmp_dir != "/tmp") {
  673.                 y2milestone("Removing tmp dir: %1", yast_tmp_dir);
  674.                 integer bash_ret = (integer)SCR::Execute(.target.bash, sformat("rm -rf %1", yast_tmp_dir));
  675.                 if (bash_ret == 0) {
  676.             yast_tmp_dir = "";
  677.                         ret = true;
  678.                 }
  679.         }
  680.         return ret;
  681.     }
  682.  
  683.     global define boolean CreateImageWithProfile(string image, string profile)
  684.     {
  685.     // create 16MB image
  686.     if (!CreateExt2Image(image, 16))
  687.     {
  688.         return false;
  689.     }
  690.  
  691.     // make directory for temporary device mounting
  692.     string dir = GetTmpDir() + "/mnt";
  693.     SCR::Execute(.target.mkdir, dir);
  694.  
  695.     // mount the image
  696.     string command = sformat("/bin/mount -o loop -- '%1' '%2'", image, dir);
  697.     integer result = (integer)SCR::Execute (.target.bash, command);
  698.     if (result != 0)
  699.     {
  700.         y2error("Cannot mount image %1 to %2", image, dir);
  701.         SCR::Execute (.target.bash, "/bin/rm -- '" + image + "'");
  702.         return false;
  703.     }
  704.  
  705.         boolean ret = true;
  706.     // copy the profile
  707.     command = sformat("/bin/cp -- '%1' '%2'", profile, dir);
  708.     result = (integer) SCR::Execute (.target.bash, command);
  709.     if (result != 0)
  710.     {
  711.         y2error("Cannot copy profile %1 to %2", profile, dir);
  712.         ret = false;
  713.     }
  714.  
  715.     SCR::Execute(.target.umount, dir);
  716.  
  717.         if (! ret)
  718.         SCR::Execute (.target.bash, "/bin/rm -- '" + image + "'");
  719.  
  720.     return ret;
  721.     }
  722.  
  723.  
  724.     // uses source_id variable
  725.     global define string GetPackage(string package) {
  726.     PackageCallbacksInit::SetMediaCallbacks();
  727.     // ensure that appropriate sources are enabled and the remaining ones disabled
  728.     list<map<string,any> > source_data = Pkg::SourceEditGet();
  729.     source_data = maplist (map<string,any> src, source_data, {
  730.         if (src["SrcId"]:-1 == source_id)
  731.         src["enabled"] = true;
  732.         return src;
  733.     });
  734.     Pkg::SourceEditSet (source_data);
  735.     // get info about the package (media number and path to the package)
  736.     map<string,any> pkginfo = $[];
  737.     list<map<string,any> > pkginfoA = Pkg::PkgPropertiesAll(package);
  738.     y2milestone("pkginfoAll: %1", pkginfoA);
  739.  
  740.     foreach(map<string,any> pk, pkginfoA,
  741.     {
  742.         if (pk["status"]:`unknown == `available && pk["srcid"]:-1 == source_id)
  743.         {
  744.         // x86_64 arch: use x86_64 packages, not i386
  745.         if (Arch::x86_64() && pk["arch"]:"unknown" != "x86_64")
  746.         {
  747.             continue;
  748.         }
  749.  
  750.         pkginfo = pk;
  751.         }
  752.     }
  753.     );
  754.  
  755.     string pkg_path = pkginfo["path"]:"";
  756.     string ret = "";
  757.  
  758.     // check whether the package was found
  759.     if (pkg_path != "" && pkg_path != nil)
  760.     {
  761.         // get local location
  762.         ret = Pkg::SourceProvideFile(source_id, pkginfo["medianr"]:0, pkg_path);
  763.         string tmpdir = VM_Common::GetTmpDir();
  764.         string target = sformat ("%1/%2.rpm", tmpdir, package);
  765.         SCR::Execute (.target.bash, sformat ("/bin/cp %1 %2", ret, target));
  766.         ret = target;
  767.     }
  768.  
  769.     return ret;
  770.     }
  771.  
  772.     global define boolean InstallPackages(list<string> packages) {
  773.     return Package::InstallAll(packages);
  774.     }
  775.  
  776.     global define boolean CopyFile(string source, string target) {
  777.     y2milestone("copying file %1 to %2", source, target);
  778.     // -a (archive) = preserve mode and timestamps
  779.     // -b (backup) = make a backup of the target file
  780.     return (SCR::Execute(.target.bash, sformat("/bin/cp -a -b -- '%1' '%2'", source, target))) == 0;
  781.     }
  782.  
  783.     global define string PackageArch() {
  784.     string arch = "";
  785.  
  786.     if (Arch::i386())
  787.     {
  788.         arch = "i586";
  789.     }
  790.     else if (Arch::x86_64())
  791.     {
  792.         arch = "x86_64";
  793.     }
  794.     else
  795.     {
  796.         arch = Arch::arch_short();
  797.         y2warning("Unknown architecture, using arch=%1", arch);
  798.     }
  799.  
  800.     return arch;
  801.     }
  802.  
  803.  
  804.     global define string GetFileNameFromPath(string fname) {
  805.     string ret = "";
  806.  
  807.     if (fname != nil)
  808.     {
  809.         list<string> parts = splitstring(fname, "/");
  810.         ret = parts[size(parts) - 1]:"";
  811.     }
  812.  
  813.     return ret;
  814.     }
  815.  
  816.     // kernel_filename = "./boot/vmlinuz-*-xen"
  817.     // kernel_regexp = "vmlinuz-*-xen"
  818.     // Extract kernel from RPM file
  819.     global define string ExtractKernelImage(string package, string target, string kernel_filename, string kernel_regexp) {
  820.     string tmpdir = VM_Common::GetTmpDir();
  821.     SCR::Execute(.target.mkdir, tmpdir);
  822.     string cmd = sformat("cd '%1' && /usr/bin/rpm2cpio '%2' | /usr/bin/cpio -idvum -- '%3'", tmpdir, package, kernel_filename);
  823.  
  824.     map out = (map)SCR::Execute(.target.bash_output, cmd);
  825.     y2milestone("out: %1", out);
  826.  
  827.     cmd = sformat("/usr/bin/find '%1' -type f -name '%2'", tmpdir + "/boot", kernel_regexp);
  828.     out = (map)SCR::Execute(.target.bash_output, cmd);
  829.     y2milestone("out: %1", out);
  830.  
  831.     list<string> stdout = splitstring(out["stdout"]:"", "\n");
  832.     string file = stdout[0]:"";
  833.  
  834.     y2milestone("found kernel: %1", file);
  835.  
  836.     if (file != nil && file != "") {
  837.         CopyFile(file, target);
  838.         return GetFileNameFromPath(file);
  839.     }
  840.  
  841.     return "";
  842.     }
  843.  
  844.     global define map<integer,boolean> InstSourceStatus() {
  845.     map<integer,boolean> ret = $[];
  846.  
  847.     list<integer> sources = Pkg::SourceGetCurrent(false);
  848.  
  849.     foreach(integer src, sources, {
  850.         map general_data = Pkg::SourceGeneralData(src);
  851.         y2milestone("general_data: %1", general_data);
  852.         ret[src] = general_data["enabled"]:false;
  853.         }
  854.     );
  855.  
  856.     return ret;
  857.     }
  858.  
  859.     global define map<string,string> DisableAllSources() {
  860.     map<string,string> ret = $[];
  861.  
  862.     list<integer> sources = Pkg::SourceGetCurrent (false);
  863.  
  864.     foreach(integer src, sources, {
  865.         Pkg::SourceSetEnabled(src, false);
  866.         }
  867.     );
  868.  
  869.     return ret;
  870.     }
  871.  
  872.     global define void SetSourceState(map<integer,boolean> state) {
  873.     list<integer> sources = Pkg::SourceGetCurrent (false);
  874.     foreach(integer src, boolean enabled, state, {
  875.         Pkg::SourceSetEnabled(src, enabled);
  876.         }
  877.     );
  878.     }
  879.  
  880.     global define integer IsInstSourceDefined(string url) {
  881.     list<integer> sources = Pkg::SourceGetCurrent (false);
  882.     integer ret = -1;
  883.  
  884.     foreach(integer src, sources, {
  885.         map general_data = Pkg::SourceGeneralData(src);
  886.         if (url == general_data["url"]:"")
  887.         {
  888.             ret = src;
  889.         }
  890.         }
  891.     );
  892.  
  893.     return ret;
  894.     }
  895.  
  896.  
  897.     global define string ParseFstab(string fstab) {
  898.         map out = (map) SCR::Execute(.target.bash_output, sformat("/bin/grep -E \"[[:space:]]/[[:space:]]\" '%1' | /usr/bin/awk '{print $1}'",  fstab));
  899.     string rdev = "";
  900.  
  901.     if (out["exit"]:-1 == 0 )
  902.     {
  903.         rdev = (string) (out["stdout"]:"");
  904.         list<string> root_dev_list = splitstring(rdev, "\n");
  905.         rdev = root_dev_list[0]:"";
  906.         y2milestone("Found root device: %1", rdev);
  907.     }
  908.     else
  909.     {
  910.         y2error("Cannot read fstab root device entry: %1", out);
  911.     }
  912.  
  913.     return rdev;
  914.     }
  915.  
  916.     global define list<string> SearchFile(string dir, string name) {
  917.     list<string> ret = [];
  918.     string cmd = sformat("cd -- '%1' && ls -1 -- '%2'", dir, name);
  919.     map outputmap = (map)SCR::Execute(.target.bash_output, cmd);
  920.  
  921.     string outputstring = outputmap["stdout"]:"";
  922.  
  923.     if (outputstring != nil && outputstring != "")
  924.     {
  925.         ret = splitstring(outputstring, "\n");
  926.         // remove empty lines
  927.         ret = filter(string f, ret, {return f != nil && f != "";});
  928.     }
  929.  
  930.     return ret;
  931.     }
  932.  
  933.     global define boolean TryMount(string image, integer offset, string mntpoint) {
  934.     y2milestone("TryMount: image=%1, offset=%2, mntpoint=%3", image, offset, mntpoint);
  935.     boolean result = (boolean) SCR::Execute(.target.mount, [image, mntpoint], sformat("-o loop,offset=%1", offset));
  936.     y2milestone("result: %1", result);
  937.     return result;
  938.     }
  939.  
  940.     global string vm_control_file = "/usr/share/YaST2/control/vm_install.xml";
  941.  
  942.     global void InitProductControl() {
  943.     ProductControl::custom_control_file = vm_control_file;
  944.  
  945.     if (!ProductControl::Init())
  946.     {
  947.         // popup error message
  948.         // %1 = absolute pathname to a product control file (i.e. '/usr/share/YaST2/control/vm_install.xml')
  949.         Report::Error(sformat(_("Control file %1 was not found."), ProductControl::custom_control_file));
  950.     }
  951.     }
  952.  
  953.     global define string getMACproposal() {
  954.     string mac = "";
  955.  
  956.     if (random_MAC == true) {
  957.         // part of proposal - MAC address is not specified, assign random
  958.         mac = _("Random MAC address");
  959.  
  960.         if (MAC_address != nil && MAC_address != "")
  961.         {
  962.         // add proposed value
  963.         mac = sformat("%1 (Proposed value '%2')", mac, MAC_address);
  964.         }
  965.     }
  966.     else {
  967.         mac = MAC_address;
  968.     }
  969.  
  970.     return mac;
  971.     }
  972.  
  973.     global define boolean CreateInstallationImage(string kernelpkg, string target) {
  974.     string arch = VM_Common::PackageArch();
  975.     // get installation package
  976.     string inst = VM_Common::GetPackage("install-initrd");
  977.     y2milestone("image rpm: %1", inst);
  978.  
  979.     if (inst == nil || inst == "")
  980.     {
  981.         y2error("Cannot obtain install-initrd package.");
  982.         return false;
  983.     }
  984.  
  985.     string tmpdir = VM_Common::GetTmpDir();
  986.     SCR::Execute(.target.mkdir, tmpdir);
  987.     string cmd = sformat("cd -- '%1' && /usr/bin/rpm2cpio '%2' | /usr/bin/cpio -idvum", tmpdir, inst);
  988.  
  989.     map out = (map)SCR::Execute(.target.bash_output, cmd);
  990.     y2debug("out: %1", out);
  991.  
  992.     cmd = sformat("/bin/ls -1 %1/*.gz", tmpdir + "/usr/lib/install-initrd");
  993.     out = (map)SCR::Execute(.target.bash_output, cmd);
  994.     y2debug("out: %1", out);
  995.  
  996.     list<string> stdout = splitstring(out["stdout"]:"", "\n");
  997.     y2debug("found base initrd files: %1", stdout);
  998.  
  999.     string file = stdout[0]:"";
  1000.     y2milestone("found initrd: %1", file);
  1001.  
  1002.     // create the image
  1003.     cmd = sformat("%1/usr/sbin/mkinstallinitrd --kernel-rpm '%2' --libdir '%3' '%4'", tmpdir, kernelpkg, tmpdir + "/usr/lib/install-initrd", target);
  1004.     out = (map)SCR::Execute(.target.bash_output, cmd);
  1005.     y2milestone("mkinstallinitrd output: %1", out);
  1006.  
  1007.     return out["exit"]:1 == 0;
  1008.     }
  1009.  
  1010.     string GetTwoHexDigits()
  1011.     {
  1012.         string hex = "0123456789abcdef";
  1013.         return substring(hex, random(16), 1) + substring(hex, random(16), 1);
  1014.     }
  1015.  
  1016.     global string Propose_MAC_address(string option)
  1017.     {
  1018.         srandom(time());
  1019.         string ret = "00:16:3e:" + GetTwoHexDigits() + ":" + GetTwoHexDigits() + ":" + GetTwoHexDigits();
  1020.  
  1021.     // TODO detect if the address is already in use on the network
  1022.  
  1023.     y2milestone("Proposed MAC: %1", ret);
  1024.     return ret;
  1025.     }
  1026.  
  1027.     global boolean isGraphicalDisplay() {
  1028.     // check whether X window system is accessible by testing
  1029.     // for the existance of the DISPLAY enviroment value (#194389)
  1030.     boolean ret = true;
  1031.     string cmd = "echo $DISPLAY";
  1032.     map result = (map) SCR::Execute(.target.bash_output, cmd);
  1033.     string display_val = deletechars(result["stdout"]:"", String::CSpace());
  1034.     y2milestone("DISPLAY=%1", display_val);
  1035.         if (display_val == nil || display_val == "") {
  1036.                 ret = false;
  1037.         }
  1038.  
  1039.         y2milestone("X check (isGraphicalDisplay): %1", ret);
  1040.     return ret;
  1041.     }
  1042.  
  1043.  
  1044. /* EOF */
  1045. }
  1046.