package org.openslx.util.vm; import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.Map; import java.util.TreeMap; import org.apache.log4j.Logger; import static org.openslx.util.vm.QemuConfig.Header.*; import org.openslx.util.vm.VmMetaData.DriveBusType; public final class QemuConfig { private static final Logger LOGGER = Logger.getLogger(QemuConfig.class); private Map, TreeMap> entries = new LinkedHashMap<>(); private String osName = new String(); private final String quote = "\""; private ArrayList hddsArray = new ArrayList<>(); // BOOT("netdev", "net0") -> toString -> "[netdev "net0"]" public static enum Header { BOOT("boot-opts", null), DEVICE("device", ""), DRIVE("drive", ""), MACHINE("machine", null), MEMORY("memory", null), NAME("name", null), NETDEV("netdev", ""), SMP("smp-opts", null); private final String header; private String id; private Header(String header, String id) { this.header = header; this.id = id; } public String getHeader() { return this.header; } public String getID() { return id; } public void setID(String id) { this.id = id; } @Override public String toString() { return "[" + header + " \"" + id + "\"]"; } } public QemuConfig(byte[] vmContent, int length) { //transform byte[] to arralist sorted ArrayList result; BufferedReader stream = null; try { stream = new BufferedReader( new InputStreamReader( new ByteArrayInputStream(vmContent, 0, length), StandardCharsets.ISO_8859_1)); result = new ArrayList<>(); String line; while ((line = stream.readLine()) != null) { if (line.startsWith("#") == false) { if (line.isEmpty() == false) { if (line.contains(DEVICE.getHeader())) { result.add(DEVICE.getHeader()); } else { result.add(line.trim()); } } } } stream.close(); stream = null; } catch (IOException e) { result = null; } finally { if (stream != null) { try { stream.close(); stream = null; } catch (IOException ioe2) { } } } init(result); } public QemuConfig(File configFile) { //Transform file into byte[]/arraylist ArrayList result; BufferedReader stream = null; try { stream = new BufferedReader( new InputStreamReader( new FileInputStream(configFile), StandardCharsets.ISO_8859_1)); result = new ArrayList<>(); String line; while ((line = stream.readLine()) != null) { if (line.startsWith("#") == false) { if (line.isEmpty() == false) { result.add(line.trim()); } } } stream.close(); stream = null; } catch (IOException e) { result = null; } finally { if (stream != null) { try { stream.close(); stream = null; } catch (IOException ioe2) { } } } init(result); } public void init(ArrayList lines) { int index = -1; int nbDev = 0; int nbDrive = 0; ArrayList listID = new ArrayList<>(); LinkedHashMap headers = null; TreeMap options = null; boolean exist = false; if (lines != null) { //Adding all the lines to a Map for (String option : lines) { if (option.startsWith("[") && option.endsWith("]")) { option = option.replaceAll("\\[|\\]", ""); headers = new LinkedHashMap<>(); if (option.contains(DRIVE.getHeader()) && option.contains(quote)) { //Check drive with id String[] drive = option.split(quote); for (String id : listID) { if (drive[1].equals(id)) { DRIVE.setID("id-disk-" + nbDrive); listID.add(DRIVE.getID()); exist = true; } } if (!exist) { DRIVE.setID(drive[1]); listID.add(DRIVE.getID()); } headers.put(DRIVE.getHeader(), DRIVE.getID()); nbDrive++; } else if (option.equals(DRIVE.getHeader())) {//Check drive without id DRIVE.setID("id-disk-" + nbDrive); listID.add(DRIVE.getID()); headers.put(option, DRIVE.getID()); nbDrive++; // } else if (option.equals(NETDEV.toString())){//Check drive without id TODO } else if (option.equals(DEVICE.getHeader())) {//This will alwas come as [device] DRIVE.setID("dev" + nbDev); headers.put(option, DRIVE.getID()); nbDev++; } else { headers.put(option, null); } options = new TreeMap<>(); index++; } else if (index == -1) { //In case file doesn't begin with a header LOGGER.error("This config file is invalid. Chech syntax. Must begin with [..]"); } else { String[] parameter = option.split("="); options.put(parameter[0].trim(), parameter[1].trim().replace("\"", "")); entries.put(headers, options); } } } } public TreeMap get(String key, String id) { TreeMap value = null; LinkedHashMap keys = new LinkedHashMap(); keys.put(key, id); if (entries.containsKey(keys)) { value = entries.get(keys); } return value; //value of key } public void set(LinkedHashMap key, TreeMap value) { entries.put(key, value); } public TreeMap, TreeMap> get() { return (TreeMap, TreeMap>) entries; } public String getDisplayName() { String result = ""; LinkedHashMap key = new LinkedHashMap(); key.put(NAME.getHeader(), null); if (entries.containsKey(key)) { result = entries.get(key).get("guest"); } return result; } public boolean isMachineSnapshot() { boolean isSnapshot = false; LinkedHashMap key = new LinkedHashMap(); key.put(DRIVE.getHeader(), DRIVE.getID()); String active = entries.get(key).get("snapshot"); if (active != null && active.equals("on")) { isSnapshot = true; } return isSnapshot; } public void setOsName() { //It is not defined in config file. Using dummy name. Will be set in combo box later osName = "QemuOS"; } public String getOsName() { return osName; } public void setHdds() { int dev = 0; String filename = null; DriveBusType bus = null; String controllerDevice = null; TreeMap options = new TreeMap<>(); for (Map.Entry, TreeMap> entry : entries.entrySet()) { if (entry.getKey().containsKey(DRIVE.getHeader())) { if (entry.getValue().containsKey("index")) { if (entry.getValue().get("index").equals("0")) { DRIVE.setID(entry.getKey().get(DRIVE.getHeader())); //Get Path filename = entry.getValue().get("file"); if (filename == null) { LOGGER.error("Please make sure your harddrive has a path"); } //Get Bus Type String busType = entry.getValue().get("if"); if (busType == null) { bus = DriveBusType.IDE; } else { switch (busType) { case "ide": bus = DriveBusType.IDE; break; case "scsi": bus = DriveBusType.SCSI; break; case "sata": //not available for Qemu. Others : sd, mtd, floppy, pflash, virtio break; default: break; } } } } } //TODO set default device if no device found if (entry.getKey().containsKey(DEVICE.getHeader())) { String drive = entry.getValue().get("drive"); if (drive != null && drive.equals(DRIVE.getID())) { controllerDevice = entry.getValue().get("driver"); } } for (String key : entry.getKey().keySet()) { if (key.contains(DEVICE.getHeader())) { dev++; } } //No device if (dev == 0) { if (bus.equals(DriveBusType.IDE)) { controllerDevice = "ide-hd"; }else if (bus.equals(DriveBusType.SCSI)) { controllerDevice = "scsi-hd"; } } if ((bus != null) && (filename != null) && (controllerDevice != null)) { hddsArray.add(new VmMetaData.HardDisk(controllerDevice, bus, filename)); break; } } } public ArrayList getHdds() { return hddsArray; } public String toString(boolean filtered) { StringBuilder sb = new StringBuilder(300); LinkedHashMap, TreeMap> sortedArray = null; if (filtered) { sortedArray = new LinkedHashMap<>(); for (Map.Entry, TreeMap> entry : entries.entrySet()) { if ((entry.getKey().keySet().equals(NAME.getHeader())) || (entry.getKey().keySet().equals(DRIVE.getHeader()) || entry.getKey().keySet().equals(DEVICE.getHeader()))) { sortedArray.put(entry.getKey(), entry.getValue()); } } } for (Map.Entry, TreeMap> entry : sortedArray == null ? entries.entrySet() : sortedArray.entrySet()) { String header = entry.getKey().keySet().toString();; if (entry.getKey().containsKey(DRIVE.getHeader())) { if ((entry.getValue().get("index") != null)) { if ((entry.getValue().get("index").equals("0"))) { header = DRIVE.toString(); } else { continue; } } else { continue; } } if (entry.getKey().containsKey(DEVICE.getHeader())) { header = "[" + DEVICE.getHeader() + "]"; } sb.append(header + "\n"); TreeMap values = entry.getValue(); for (String key : values.keySet()) { String value = values.get(key); sb.append(" " + key + " = " + value + "\n"); } } LOGGER.debug(sb); return sb.toString(); } }