/* * $Id$ * * Copyright (C) 2003-2015 JNode.org * * This library is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public * License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this library; If not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ package org.jnode.build; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.util.Properties; import java.util.TreeSet; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.Task; /** * This task builds a VMWare '.vmx' file to allow JNode to be run using VMWare player. * * @author crawley@jnode.org * @author epr@jnode.org */ public class VMwareBuilderTask extends Task { private String logFile; // log file use for kernel debugger messages private String isoFile; private int memSize; private String overrideFile; private String vmdkImageFile; private String saveDir; private String name; /** * @return Returns the Virtual machine name */ public final String getName() { return name; } /** * @Set the Virtual machine name */ public final void setName(String name) { this.name = name; } /** * @return Returns the memory size. */ public final int getMemSize() { return memSize; } /** * @param memSize The memory size to set. */ public final void setMemSize(int memSize) { this.memSize = memSize; } /** * @return Returns the log file. */ public final String getLogFile() { return logFile; } /** * @param logFile The log file to set. */ public final void setLogFile(String logFile) { this.logFile = logFile; } /** * The VmdkImage file is a VMX virtual disk image file. * * @return Returns the VmdkImage file or <code>null</code> */ public String getVmdkImageFile() { return vmdkImageFile; } /** * @param vmdkImageFile The VmdkImage file to set. */ public void setVmdkImageFile(String vmdkImageFile) { this.vmdkImageFile = vmdkImageFile; } /** * The override file is a Java Properties file containing VMX settings * to override the default ones hard-wired into this class. * * @return Returns the override file or <code>null</code> */ public String getOverrideFile() { return overrideFile; } /** * @param overrideFile The override file to set. */ public void setOverrideFile(String overrideFile) { this.overrideFile = overrideFile; } /** * The save directory is used to preserve certain VMWare state * files across 'clean' builds. * * @return the save directory */ public String getSaveDir() { return saveDir; } /** * @param saveDir the save directory to set */ public void setSaveDir(String saveDir) { this.saveDir = saveDir; } /** * @see org.apache.tools.ant.Task#execute() */ @Override public void execute() throws BuildException { // Build the default properties, based on the supplied memSize and logFile. Properties props = new Properties(); buildDefaultProperties(props); if (overrideFile != null && overrideFile.length() > 0) { // If VMX overrides are provided, read them and add them to the properties; BufferedReader br = null; try { // Unfortunately, we cannot use java.util.Property#load(...) because // VMX properties can have ':' in the property name. br = new BufferedReader(new FileReader(overrideFile)); String line; final Pattern propertyPattern = Pattern.compile("^([a-zA-Z0-9\\.:]+)\\s*=\\s*\"([^\"]*)\""); final Pattern commentPattern = Pattern.compile("^#"); while ((line = br.readLine()) != null) { line = line.trim(); if (line.isEmpty() || commentPattern.matcher(line).find()) { continue; } Matcher matcher = propertyPattern.matcher(line); if (!matcher.find()) { throw new BuildException("Cannot parse this VMX override: '" + line + "'"); } props.put(matcher.group(1), matcher.group(2)); } } catch (FileNotFoundException ex) { throw new BuildException("Cannot open the VMX override file: " + overrideFile, ex); } catch (IOException ex) { throw new BuildException("Problem reading the VMX override file: " + overrideFile, ex); } finally { if (br != null) { try { br.close(); } catch (IOException ex) { /* ignore it */ } } } } if (vmdkImageFile != null && vmdkImageFile.length() > 0) { File file = new File(vmdkImageFile); if (!file.exists()) { System.err.println(vmdkImageFile + " does not exists"); } else if (file.length() == 0) { System.err.println(vmdkImageFile + " is empty"); } else { // Add VMX properties to configure a virtual disk props.setProperty("ide1:0.present", "TRUE"); props.setProperty("ide1:0.fileName", vmdkImageFile); props.setProperty("ide1:0.mode", "persistent"); props.setProperty("ide1:0.startConnected", "TRUE"); props.setProperty("ide1:0.writeThrough", "TRUE"); props.setProperty("ide1:0.redo", ""); } } // Now output the VMX file from the properties, sorted in key order for neatness. File vmxFile = new File(isoFile + ".vmx"); try { FileWriter out = new FileWriter(vmxFile); try { PrintWriter w = new PrintWriter(out); TreeSet<Object> keys = new TreeSet<Object>(); keys.addAll(props.keySet()); for (Object key : keys) { Object value = props.get(key); w.println(key + " = \"" + value + "\""); } } finally { out.close(); } } catch (IOException ex) { throw new BuildException("Cannot write the VMX file: " + vmxFile); } // Finally reinstate the saved JNode.nvram file if we have one. if (saveDir != null) { File savedNVRam = new File(saveDir, "JNode.nvram"); File nvram = new File(new File(isoFile).getParentFile(), "JNode.nvram"); if (savedNVRam.exists() && !nvram.exists()) { InputStream is = null; OutputStream os = null; try { is = new FileInputStream(savedNVRam); os = new FileOutputStream(nvram); byte[] buffer = new byte[(int) savedNVRam.length()]; is.read(buffer); os.write(buffer); os.flush(); } catch (IOException ex) { throw new BuildException("Cannot copy the saved 'JNode.nvram' file: " + ex.getMessage()); } finally { if (is != null) { try { is.close(); } catch (IOException ex) { // ignore } } if (os != null) { try { os.close(); } catch (IOException ex) { // ignore } } } } } } private void buildDefaultProperties(Properties props) { props.put("config.version", "8"); props.put("virtualHW.version", "4"); props.put("memsize", String.valueOf(memSize)); props.put("MemAllowAutoScaleDown", "FALSE"); props.put("ide0:0.present", "TRUE"); props.put("ide0:0.startConnected", "TRUE"); props.put("ide0:0.fileName", new File(isoFile).getName()); props.put("ide0:0.deviceType", "cdrom-image"); props.put("ide0:0.redo", ""); props.put("ide1:0.present", "FALSE"); props.put("ide1:0.startConnected", "TRUE"); props.put("floppy0.present", "FALSE"); props.put("usb.present", "TRUE"); props.put("sound.present", "FALSE"); props.put("sound.virtualDev", "es1371"); props.put("displayName", (name != null) ? name : "JNode"); props.put("guestOS", "dos"); props.put("nvram", "JNode.nvram"); props.put("MemTrimRate", "-1"); final String osName = System.getProperty("os.name").toLowerCase(); if (osName.contains("linux") || osName.contains("unix") || osName.contains("bsd")) { props.put("ethernet0.connectionType", "bridged"); props.put("ethernet0.vnet", "/dev/vmnet1"); } props.put("ethernet0.addressType", "generated"); props.put("ethernet0.generatedAddress", "00:0c:29:2a:96:30"); props.put("ethernet0.generatedAddressOffset", "0"); props.put("ethernet0.present", "TRUE"); props.put("ethernet0.startConnected", "TRUE"); props.put("uuid.location", "56 4d 94 59 c9 96 80 88-6c 3a 37 80 04 68 c9 b2"); props.put("uuid.bios", "56 4d 94 59 c9 96 80 88-6c 3a 37 80 04 68 c9 b2"); if (logFile != null && logFile.trim().length() != 0) { props.put("serial0.present", "TRUE"); props.put("serial0.fileType", "file"); props.put("serial0.fileName", logFile); } props.put("tools.syncTime", "TRUE"); props.put("uuid.action", "create"); props.put("checkpoint.vmState", ""); } /** * @return Returns the isoFile. */ public final String getIsoFile() { return isoFile; } /** * @param isoFile The isoFile to set. */ public final void setIsoFile(String isoFile) { this.isoFile = isoFile; } }