aboutsummaryrefslogtreecommitdiffstats
path: root/tools/control
diff options
context:
space:
mode:
authorrac61@labyrinth.cl.cam.ac.uk <rac61@labyrinth.cl.cam.ac.uk>2003-07-03 13:18:21 +0000
committerrac61@labyrinth.cl.cam.ac.uk <rac61@labyrinth.cl.cam.ac.uk>2003-07-03 13:18:21 +0000
commitbafd4c37acf0e8e5ac503dc05b6d24525ce2797a (patch)
treee8756b60ed45a806aa141a7dc8944bc29c0c33a5 /tools/control
parentfe93dfc027a2a216965f1473bfaf657669d46cb8 (diff)
downloadxen-bafd4c37acf0e8e5ac503dc05b6d24525ce2797a.tar.gz
xen-bafd4c37acf0e8e5ac503dc05b6d24525ce2797a.tar.bz2
xen-bafd4c37acf0e8e5ac503dc05b6d24525ce2797a.zip
bitkeeper revision 1.260 (3f042d1dYDmgfLY_ZLTlHlDZ45a_hA)
Refactor domctl into new tool, xenctl-cmdline, ready for combining with vd manager (and future porting of xenctl web interface to new backend)
Diffstat (limited to 'tools/control')
-rw-r--r--tools/control/Makefile19
-rw-r--r--tools/control/build-cmdline.xml50
-rw-r--r--tools/control/src/org/xenoserver/cmdline/CommandParser.java70
-rw-r--r--tools/control/src/org/xenoserver/cmdline/Main.java49
-rw-r--r--tools/control/src/org/xenoserver/cmdline/ParseDestroy.java37
-rw-r--r--tools/control/src/org/xenoserver/cmdline/ParseFailedException.java22
-rw-r--r--tools/control/src/org/xenoserver/cmdline/ParseHelp.java53
-rw-r--r--tools/control/src/org/xenoserver/cmdline/ParseList.java46
-rw-r--r--tools/control/src/org/xenoserver/cmdline/ParseNew.java81
-rw-r--r--tools/control/src/org/xenoserver/cmdline/ParseStart.java37
-rw-r--r--tools/control/src/org/xenoserver/cmdline/ParseStop.java37
-rw-r--r--tools/control/src/org/xenoserver/control/Command.java27
-rw-r--r--tools/control/src/org/xenoserver/control/CommandDestroy.java58
-rw-r--r--tools/control/src/org/xenoserver/control/CommandFailedException.java32
-rw-r--r--tools/control/src/org/xenoserver/control/CommandList.java108
-rw-r--r--tools/control/src/org/xenoserver/control/CommandNew.java301
-rw-r--r--tools/control/src/org/xenoserver/control/CommandStart.java49
-rw-r--r--tools/control/src/org/xenoserver/control/CommandStop.java50
-rw-r--r--tools/control/src/org/xenoserver/control/Defaults.java205
-rw-r--r--tools/control/src/org/xenoserver/control/Domain.java31
-rw-r--r--tools/control/src/org/xenoserver/control/InetAddressPattern.java60
-rw-r--r--tools/control/src/org/xenoserver/control/Settings.java41
-rw-r--r--tools/control/src/org/xenoserver/control/StringPattern.java59
-rwxr-xr-xtools/control/xenctl33
24 files changed, 1552 insertions, 3 deletions
diff --git a/tools/control/Makefile b/tools/control/Makefile
index f78d796d65..fcf244a445 100644
--- a/tools/control/Makefile
+++ b/tools/control/Makefile
@@ -1,8 +1,21 @@
-default: domctl xenctl
+default: cmdline
-install: install-domctl install-xenctl
+install: install-cmdline
-clean: clean-domctl clean-xenctl
+clean: clean-cmdline
+
+
+
+cmdline: FORCE
+ ant -buildfile build-cmdline.xml dist
+
+install-cmdline: domctl
+ cp xenctl-cmdline.jar xenctl ../../../install/bin
+ chmod 755 ../../../install/bin/xenctl
+
+clean-cmdline:
+ ant -buildfile build-cmdline.xml clean
+ rm -f xenctl-cmdline.jar
diff --git a/tools/control/build-cmdline.xml b/tools/control/build-cmdline.xml
new file mode 100644
index 0000000000..4cf6fbfc39
--- /dev/null
+++ b/tools/control/build-cmdline.xml
@@ -0,0 +1,50 @@
+<project name="xenctl cmdline project" default="compile">
+ <property name="src" location="src"/>
+ <property name="build" location="build-cmdline"/>
+
+ <target name="init">
+ <tstamp/>
+ <mkdir dir="${build}"/>
+ </target>
+
+ <target name="compile" depends="init">
+ <javac srcdir="${src}" destdir="${build}" debug="on">
+ <include name="org/xenoserver/cmdline/**"/>
+ <include name="org/xenoserver/control/**"/>
+ </javac>
+ </target>
+
+ <target name="dist" depends="compile">
+ <jar jarfile="xenctl-cmdline.jar"
+ excludes="*~"
+ basedir="${build}">
+ <fileset dir="${src}">
+ <include name="org/xenoserver/cmdline/**"/>
+ <include name="org/xenoserver/control/**"/>
+ </fileset>
+ <fileset dir=".">
+ <include name="build-cmdline.xml"/>
+ <include name="xenctl"/>
+ <include name="domctl.xml"/>
+ <include name="Makefile"/>
+ </fileset>
+ <manifest>
+ <attribute name="Built-By" value="${user.name}"/>
+ <attribute name="Main-Class" value="org.xenoserver.cmdline.Main"/>
+ <attribute name="Sealed" value="true"/>
+ </manifest>
+ </jar>
+ </target>
+
+ <target name="test" depends="compile">
+ <java fork="true" classname="org.xenoserver.cmdline.Main">
+ <classpath>
+ <pathelement path="${build}"/>
+ </classpath>
+ </java>
+ </target>
+
+ <target name="clean">
+ <delete dir="${build}"/>
+ </target>
+</project> \ No newline at end of file
diff --git a/tools/control/src/org/xenoserver/cmdline/CommandParser.java b/tools/control/src/org/xenoserver/cmdline/CommandParser.java
new file mode 100644
index 0000000000..3f4fc85032
--- /dev/null
+++ b/tools/control/src/org/xenoserver/cmdline/CommandParser.java
@@ -0,0 +1,70 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.Defaults;
+
+/**
+ * Subclasses of Parser know how to parse arguments for a given command
+ * and execute it, displaying any output.
+ */
+public abstract class CommandParser {
+ /**
+ * Subclasses should implement this method such that it outputs any successful
+ * output to the screen, or throws an exception if required arguments
+ * are missing or malformed. It also may propagate exceptions from the
+ * command execution.
+ *
+ * @param d The defaults object to use.
+ * @param args The arguments to parse.
+ * @throws ParseFailedException if the arguments are not suitable.
+ * @throws CommandFailedException if the command did not execute successfully.
+ */
+ public abstract void parse(Defaults d, String args[]) throws ParseFailedException, CommandFailedException;
+
+ /** Return the command name which will be matched on the command line. */
+ public abstract String getName();
+ /** Return a usage string for this command. */
+ public abstract String getUsage();
+ /** Return the help text for this command. */
+ public abstract String getHelpText();
+
+ public String getStringParameter(String args[], char key, String def)
+ {
+ String r = getParameter (args, key);
+ return (r == null) ? def : r;
+ }
+
+ public int getIntParameter(String args[], char key, int def)
+ {
+ String r = getParameter (args, key);
+ return (r == null) ? def : (Integer.parseInt (r));
+ }
+
+ public boolean getFlagParameter(String args[], char key)
+ {
+ String r = getParameter (args, key);
+ return (r == null) ? false : true;
+ }
+
+ protected String getParameter (String args[], char key)
+ {
+ int i;
+ String result = null;
+ for (i = 0; i < args.length; i ++)
+ {
+ if (args[i].startsWith("-" + key))
+ {
+ if (args[i].length() > 2)
+ {
+ result = args[i].substring(2, args[i].length());
+ }
+ else
+ {
+ result = "";
+ }
+ }
+ }
+ return result;
+ }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/Main.java b/tools/control/src/org/xenoserver/cmdline/Main.java
new file mode 100644
index 0000000000..a85c1923a7
--- /dev/null
+++ b/tools/control/src/org/xenoserver/cmdline/Main.java
@@ -0,0 +1,49 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.Defaults;
+
+public class Main {
+ private static ParseHelp help = new ParseHelp();
+ static CommandParser commands[] =
+ { help,
+ new ParseNew(),
+ new ParseStart(),
+ new ParseStop(),
+ new ParseDestroy(),
+ new ParseList() };
+
+ public static void main(String[] args) {
+ Defaults d = new Defaults();
+ int ec = -1;
+
+ if (args.length == 0) {
+ help.parse(d, args);
+ } else {
+ String c = args[0];
+ int i;
+ for (i = 0; i < commands.length; i++) {
+ if (commands[i].getName().equals(c)) {
+ if (commands[i].getFlagParameter(args, '?')) {
+ help.doHelpFor(commands[i]);
+ } else {
+ try {
+ commands[i].parse(d, args);
+ ec = 0;
+ } catch (ParseFailedException e) {
+ System.err.println( e.getMessage() );
+ } catch (CommandFailedException e) {
+ System.err.println( e.getMessage() );
+ }
+ }
+ break;
+ }
+ }
+ if (i == commands.length) {
+ System.out.println("Unknown command " + c);
+ }
+ }
+
+ System.exit(ec);
+ }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseDestroy.java b/tools/control/src/org/xenoserver/cmdline/ParseDestroy.java
new file mode 100644
index 0000000000..4368c9d3da
--- /dev/null
+++ b/tools/control/src/org/xenoserver/cmdline/ParseDestroy.java
@@ -0,0 +1,37 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandDestroy;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.Defaults;
+
+public class ParseDestroy extends CommandParser {
+ public void parse(Defaults d, String[] args) throws ParseFailedException, CommandFailedException {
+ int domain_id = getIntParameter(args, 'n', 0);
+ boolean force = getFlagParameter(args, 'f');
+
+ if (domain_id == 0) {
+ throw new ParseFailedException("Expected -n<domain_id>");
+ }
+
+ String output = new CommandDestroy(d, domain_id, force).execute();
+ if ( output != null )
+ System.out.println( output );
+ }
+
+ public String getName()
+ {
+ return "destroy";
+ }
+
+ public String getUsage()
+ {
+ return "[-f] [-n<domain_id>]";
+ }
+
+ public String getHelpText()
+ {
+ return
+ "Destory the specified domain. -f forcibly destroys it.";
+ }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseFailedException.java b/tools/control/src/org/xenoserver/cmdline/ParseFailedException.java
new file mode 100644
index 0000000000..6e51be32a1
--- /dev/null
+++ b/tools/control/src/org/xenoserver/cmdline/ParseFailedException.java
@@ -0,0 +1,22 @@
+package org.xenoserver.cmdline;
+
+/**
+ * Thrown when a command line could not be parsed.
+ */
+public class ParseFailedException extends Exception {
+ public ParseFailedException() {
+ super();
+ }
+
+ public ParseFailedException(String message) {
+ super(message);
+ }
+
+ public ParseFailedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public ParseFailedException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseHelp.java b/tools/control/src/org/xenoserver/cmdline/ParseHelp.java
new file mode 100644
index 0000000000..0a8362e53d
--- /dev/null
+++ b/tools/control/src/org/xenoserver/cmdline/ParseHelp.java
@@ -0,0 +1,53 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.Defaults;
+
+public class ParseHelp extends CommandParser {
+
+ public void parse(Defaults d, String[] args) {
+ if (args.length <= 1) {
+ System.out.println("Usage:");
+ for (int i = 0; i < Main.commands.length; i++) {
+ String name = Main.commands[i].getName();
+ String usage = Main.commands[i].getUsage();
+ while (name.length() < 12)
+ name = name + " ";
+ System.out.println(" " + name + usage);
+ }
+ } else {
+ for (int i = 0; i < Main.commands.length; i++) {
+ String name = Main.commands[i].getName();
+ String usage = Main.commands[i].getUsage();
+ if (name.equals(args[1])) {
+ doHelpFor(Main.commands[i]);
+ break;
+ }
+ }
+ }
+
+ System.out.println("");
+ }
+
+ public void doHelpFor(CommandParser c)
+ {
+ System.out.println ("xenctl " + c.getName() + " " + c.getUsage());
+ System.out.println ();
+ System.out.println (c.getHelpText ());
+ }
+
+ public String getName()
+ {
+ return "help";
+ }
+
+ public String getUsage()
+ {
+ return "";
+ }
+
+ public String getHelpText()
+ {
+ return "This message";
+ }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseList.java b/tools/control/src/org/xenoserver/cmdline/ParseList.java
new file mode 100644
index 0000000000..72d81c5af4
--- /dev/null
+++ b/tools/control/src/org/xenoserver/cmdline/ParseList.java
@@ -0,0 +1,46 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.CommandList;
+import org.xenoserver.control.Defaults;
+import org.xenoserver.control.Domain;
+
+public class ParseList extends CommandParser {
+
+ public void parse(Defaults d, String[] args) throws ParseFailedException, CommandFailedException {
+ CommandList list = new CommandList(d);
+ String output = list.execute();
+ if ( output != null )
+ System.out.println( output );
+ Domain[] domains = list.domains();
+
+ for (int loop = 0; loop < domains.length; loop++)
+ {
+ System.out.println ("id: " + domains[loop].id +
+ " (" + domains[loop].name+ ")");
+ System.out.println (" processor: " + domains[loop].processor);
+ System.out.println (" has cpu: " + domains[loop].cpu);
+ System.out.println (" state: " + domains[loop].nstate + " " +
+ domains[loop].state);
+ System.out.println (" mcu advance: " + domains[loop].mcu);
+ System.out.println (" total pages: " + domains[loop].pages);
+ }
+ }
+
+ public String getName()
+ {
+ return "list";
+ }
+
+ public String getUsage()
+ {
+ return "";
+ }
+
+ public String getHelpText()
+ {
+ return
+ "List domain information";
+ }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseNew.java b/tools/control/src/org/xenoserver/cmdline/ParseNew.java
new file mode 100644
index 0000000000..5ddfd7a3cf
--- /dev/null
+++ b/tools/control/src/org/xenoserver/cmdline/ParseNew.java
@@ -0,0 +1,81 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.CommandNew;
+import org.xenoserver.control.Defaults;
+
+public class ParseNew extends CommandParser {
+
+ public void parse(Defaults d, String[] args) throws ParseFailedException, CommandFailedException {
+ String name = getStringParameter(args, 'n', d.domainName);
+ int size = getIntParameter(args, 'k', d.domainSizeKB);
+ String image = getStringParameter(args, 'i', d.domainImage);
+ String initrd = getStringParameter (args, 'r', d.domainInitRD);
+ int vifs = getIntParameter(args, 'v', d.domainVIFs);
+ String bargs = getStringParameter (args, 'a', d.args) + " ";
+ String root_dev = getStringParameter (args, 'd', d.rootDevice);
+ String nfs_root_path = getStringParameter (args, 'f', d.NWNFSRoot);
+ String nw_ip = getStringParameter (args, '4', d.NWIP);
+ String nw_gw = getStringParameter (args, 'g', d.NWGW);
+ String nw_mask = getStringParameter (args, 'm', d.NWMask);
+ String nw_nfs_server = getStringParameter (args, 's', d.NWNFSServer);
+ String nw_host = getStringParameter (args, 'h', d.NWHost);
+
+ d.describe();
+
+ CommandNew c = new CommandNew(d, name, size, image, initrd, vifs,
+ bargs, root_dev, nfs_root_path,
+ nw_ip, nw_gw, nw_mask, nw_nfs_server, nw_host);
+ c.execute();
+ String[] output = c.output();
+ for ( int i = 0; i < output.length; i++ )
+ System.out.println( output[i] );
+ }
+
+ public String getName()
+ {
+ return "new";
+ }
+
+ public String getUsage()
+ {
+ return "[-n<domain_name>] [-k<size>] [-i<image>] [-v<num_vifs>] [-r<initrd>] [-d<root_device>] [-f<nfs_root>] [-s<nfs_boot_server>] [-4<ipv4_boot_address>] [-g<ipv4_boot_gateway>] [-m<ipv4_boot_netmask>] [-h<hostname>] [-a<args>]";
+ }
+
+ public String getHelpText()
+ {
+ return
+ "Create a new domain. Note that most of the parameters will assume\n" +
+ "default values: it should not be necessary to specify them all. See\n" +
+ "domctl.xml for the current default settings.\n" +
+ "\n" +
+ "General command line options:\n" +
+ " -n Domain name domain_name\n" +
+ " -k Domain size (kb) domain_size_kb\n" +
+ " -i Domain image name domain_image\n" +
+ " -v Number of VIFs domain_vifs\n" +
+ " -r InitRD (if required) domain_init_rd\n" +
+ " -d Root device (e.g /dev/nfs, /dev/hda3) root_device\n" +
+ " -a Additional boot parameters\n" +
+ "\n" +
+ "Networking options:\n" +
+ " -f NFS root (if /dev/nfs specified) nw_nfs_root\n" +
+ " -s NFS server nw_nfs_server\n" +
+ " -4 Domain IPv4 address nw_ip\n" +
+ " -g Domain gateway nw_gw\n" +
+ " -m Domain net mask nw_mask\n" +
+ " -h Domain hostname nw_host\n" +
+ "\n" +
+ "Parameters to -d, -f, -4, -g, -h can be specified as patterns into\n" +
+ "which the allocated domain ID will be incorporated. e.g. for\n" +
+ "domain 1 patterns would expand as follows:\n" +
+ "\n" +
+ " /dev/hda+ /dev/hda1\n" +
+ " /dev/hda7+ /dev/hda8\n" +
+ " 128.232.8.50+ 128.232.8.51\n" +
+ "\n" +
+ "Additionally, patterns for -4 -g -m can include an = which is\n" +
+ "expanded to the corresponding setting from the calling domain.\n";
+ }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseStart.java b/tools/control/src/org/xenoserver/cmdline/ParseStart.java
new file mode 100644
index 0000000000..435e36a1f2
--- /dev/null
+++ b/tools/control/src/org/xenoserver/cmdline/ParseStart.java
@@ -0,0 +1,37 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.CommandStart;
+import org.xenoserver.control.Defaults;
+
+public class ParseStart extends CommandParser {
+
+ public void parse(Defaults d, String[] args) throws ParseFailedException, CommandFailedException {
+ int domain_id = getIntParameter(args, 'n', 0);
+
+ if (domain_id == 0) {
+ throw new ParseFailedException("Expected -n<domain_id>");
+ }
+
+ String output = new CommandStart(d, domain_id).execute();
+ if ( output != null )
+ System.out.println( output );
+ }
+
+ public String getName()
+ {
+ return "start";
+ }
+
+ public String getUsage()
+ {
+ return "[-n<domain_id>]";
+ }
+
+ public String getHelpText()
+ {
+ return
+ "Start the specified domain.";
+ }
+}
diff --git a/tools/control/src/org/xenoserver/cmdline/ParseStop.java b/tools/control/src/org/xenoserver/cmdline/ParseStop.java
new file mode 100644
index 0000000000..30aeadbdec
--- /dev/null
+++ b/tools/control/src/org/xenoserver/cmdline/ParseStop.java
@@ -0,0 +1,37 @@
+package org.xenoserver.cmdline;
+
+import org.xenoserver.control.Command;
+import org.xenoserver.control.CommandFailedException;
+import org.xenoserver.control.CommandStop;
+import org.xenoserver.control.Defaults;
+
+public class ParseStop extends CommandParser {
+
+ public void parse(Defaults d, String[] args) throws ParseFailedException, CommandFailedException {
+ int domain_id = getIntParameter(args, 'n', 0);
+
+ if (domain_id == 0) {
+ throw new ParseFailedException("Expected -n<domain_id>");
+ }
+
+ String output = new CommandStop(d, domain_id).execute();
+ if ( output != null )
+ System.out.println( output );
+ }
+
+ public String getName()
+ {
+ return "stop";
+ }
+
+ public String getUsage()
+ {
+ return "[-n<domain_id>]";
+ }
+
+ public String getHelpText()
+ {
+ return
+ "Stop the specified domain.";
+ }
+}
diff --git a/tools/control/src/org/xenoserver/control/Command.java b/tools/control/src/org/xenoserver/control/Command.java
new file mode 100644
index 0000000000..a327f29973
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/Command.java
@@ -0,0 +1,27 @@
+package org.xenoserver.control;
+
+/**
+ * Subclasses of Command are responsible for applying changes to domain
+ * and virtual disk settings.
+ */
+public abstract class Command {
+ /**
+ * Subclasses should define an execute method which will apply the
+ * relevant change, if possible.
+ *
+ * @return The results of executing the command, if successful, or null if
+ * the command does not need to return results.
+ * @throws CommandFailedException if the command could not be completed.
+ */
+ public abstract String execute() throws CommandFailedException;
+
+ protected String reportCommand (String cmd_array[])
+ {
+ StringBuffer sb = new StringBuffer();
+ int i;
+ for (i = 0; i < cmd_array.length; i ++) {
+ sb.append (cmd_array[i] + " ");
+ }
+ return sb.toString();
+ }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandDestroy.java b/tools/control/src/org/xenoserver/control/CommandDestroy.java
new file mode 100644
index 0000000000..bc1f65e193
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/CommandDestroy.java
@@ -0,0 +1,58 @@
+package org.xenoserver.control;
+
+/**
+ * Destroys a domain.
+ */
+public class CommandDestroy extends Command {
+ private Defaults d;
+ private int domain_id;
+ private boolean force;
+
+ /**
+ * Constructor for CommandDestroy.
+ *
+ * @param d Defaults object to use.
+ * @param domain_id Domain ID number to destroy.
+ * @param force Force destruction.
+ */
+ public CommandDestroy(Defaults d, int domain_id, boolean force) {
+ this.d = d;
+ this.domain_id = domain_id;
+ this.force = force;
+ }
+
+ public String execute() throws CommandFailedException {
+ Runtime r = Runtime.getRuntime();
+ String output = null;
+
+ try {
+ Process destroy_p;
+ String destroy_cmdarray[] = force ? new String[3] : new String[2];
+ int destroy_rc;
+ int idx = 0;
+ destroy_cmdarray[idx++] = d.XIToolsDir + "xi_destroy";
+ if (force) {
+ destroy_cmdarray[idx++] = "-f";
+ }
+ destroy_cmdarray[idx++] = "" + domain_id;
+
+ if (Settings.TEST) {
+ output = reportCommand(destroy_cmdarray);
+ } else {
+ destroy_p = r.exec(destroy_cmdarray);
+ destroy_rc = destroy_p.waitFor();
+
+ if (destroy_rc != 0) {
+ throw CommandFailedException.XICommandFailed("Could not destroy domain", destroy_cmdarray);
+ }
+ output = "Destroyed domain " + domain_id;
+ }
+ } catch (CommandFailedException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CommandFailedException("Could not destroy domain (" + e + ")", e);
+ }
+
+ return output;
+ }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandFailedException.java b/tools/control/src/org/xenoserver/control/CommandFailedException.java
new file mode 100644
index 0000000000..f8571c33e2
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/CommandFailedException.java
@@ -0,0 +1,32 @@
+package org.xenoserver.control;
+
+/**
+ * Thrown to indicate that a command failed to execute.
+ */
+public class CommandFailedException extends Exception {
+ public CommandFailedException() {
+ super();
+ }
+
+ public CommandFailedException(String message) {
+ super(message);
+ }
+
+ public CommandFailedException(String message, Throwable cause) {
+ super(message, cause);
+ }
+
+ public CommandFailedException(Throwable cause) {
+ super(cause);
+ }
+
+ public static CommandFailedException XICommandFailed(String message, String cmd_array[]) {
+ StringBuffer sb = new StringBuffer();
+ int i;
+ sb.append (message + " using: ");
+ for (i = 0; i < cmd_array.length; i ++) {
+ sb.append (cmd_array[i] + " ");
+ }
+ return new CommandFailedException( sb.toString() );
+ }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandList.java b/tools/control/src/org/xenoserver/control/CommandList.java
new file mode 100644
index 0000000000..af2622553f
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/CommandList.java
@@ -0,0 +1,108 @@
+package org.xenoserver.control;
+
+import java.io.BufferedReader;
+import java.io.InputStreamReader;
+import java.util.StringTokenizer;
+import java.util.Vector;
+
+/**
+ * Lists details of all domains. After execute() has been called, call
+ * domains() to get the array of domains.
+ */
+public class CommandList extends Command {
+ private Defaults d;
+ private Domain[] array;
+
+ /**
+ * Constructor for CommandList.
+ * @param d Defaults object to use.
+ */
+ public CommandList(Defaults d) {
+ this.d = d;
+ }
+
+ /**
+ * Retrieves the list of domains.
+ * @return null, call domains() to get the list.
+ */
+ public String execute() throws CommandFailedException {
+ Runtime r = Runtime.getRuntime();
+ int rc = 0;
+ Vector v = new Vector();
+ String outline;
+ BufferedReader in;
+ String output = null;
+
+ try {
+ Process start_p;
+ String start_cmdarray[] = new String[1];
+ int start_rc;
+ start_cmdarray[0] = d.XIToolsDir + "xi_list";
+
+ if (Settings.TEST) {
+ output = reportCommand(start_cmdarray);
+ } else {
+ start_p = r.exec(start_cmdarray);
+ start_rc = start_p.waitFor();
+ if (start_rc != 0) {
+ throw CommandFailedException.XICommandFailed("Could not get domain list", start_cmdarray);
+ }
+
+ in =
+ new BufferedReader(new InputStreamReader(start_p.getInputStream()));
+
+ outline = in.readLine();
+ while (outline != null) {
+ Domain domain = new Domain();
+
+ StringTokenizer st = new StringTokenizer(outline);
+ if (st.hasMoreTokens()) {
+ domain.id = Integer.parseInt(st.nextToken());
+ }
+ if (st.hasMoreTokens()) {
+ domain.processor = Integer.parseInt(st.nextToken());
+ }
+ if (st.hasMoreTokens()) {
+ if (st.nextToken().equals("1")) {
+ domain.cpu = true;
+ } else {
+ domain.cpu = false;
+ }
+ }
+ if (st.hasMoreTokens()) {
+ domain.nstate = Integer.parseInt(st.nextToken());
+ }
+ if (st.hasMoreTokens()) {
+ domain.state = st.nextToken().toLowerCase();
+ }
+ if (st.hasMoreTokens()) {
+ domain.mcu = Integer.parseInt(st.nextToken());
+ }
+ if (st.hasMoreTokens()) {
+ domain.pages = Integer.parseInt(st.nextToken());
+ }
+ if (st.hasMoreTokens()) {
+ domain.name = st.nextToken();
+ }
+
+ v.add(domain);
+
+ outline = in.readLine();
+ }
+
+ }
+ } catch (CommandFailedException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CommandFailedException("Could not get domain list(" + e + ")", e);
+ }
+
+ array = new Domain[v.size()];
+ v.toArray(array);
+ return output;
+ }
+
+ public Domain[] domains() {
+ return array;
+ }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandNew.java b/tools/control/src/org/xenoserver/control/CommandNew.java
new file mode 100644
index 0000000000..4f32e97b64
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/CommandNew.java
@@ -0,0 +1,301 @@
+package org.xenoserver.control;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.util.zip.GZIPInputStream;
+
+/**
+ * Creates a new domain. As this command returns a multi-line result,
+ * call output() to get an array of strings.
+ */
+public class CommandNew extends Command {
+ private Defaults d;
+ private String name;
+ private int size;
+ private String image;
+ private String initrd;
+ private int vifs;
+ private String bargs;
+ private String root_dev;
+ private String nfs_root_path;
+ private String nw_ip;
+ private String nw_gw;
+ private String nw_mask;
+ private String nw_nfs_server;
+ private String nw_host;
+ private String[] output;
+
+ public String[] output() {
+ return output;
+ }
+
+ /**
+ * Constructor for CommandNew.
+ * @param d Defaults object to use.
+ * @param name Name for the domain.
+ * @param size Memory size for the domain.
+ * @param image Image to boot domain from.
+ * @param initrd Initrd to boot domain with.
+ * @param vifs Number of virtual interfaces for the domain.
+ * @param bargs Boot arguments for the domain.
+ * @param root_dev Root device for the domain.
+ * @param nfs_root_path NFS root to be used by the domain.
+ * @param nw_ip IP address pattern to use for the domain's interfaces.
+ * @param nw_gw Gateway to configure the domain for.
+ * @param nw_mask Network mask to configure the domain for.
+ * @param nw_nfs_server NFS server to be used by the domain.
+ * @param nw_host Hostname to be used by the domain.
+ */
+ public CommandNew(
+ Defaults d,
+ String name,
+ int size,
+ String image,
+ String initrd,
+ int vifs,
+ String bargs,
+ String root_dev,
+ String nfs_root_path,
+ String nw_ip,
+ String nw_gw,
+ String nw_mask,
+ String nw_nfs_server,
+ String nw_host) {
+ this.d = d;
+ this.name = name;
+ this.size = size;
+ this.image = image;
+ this.initrd = initrd;
+ this.vifs = vifs;
+ this.bargs = bargs;
+ this.root_dev = root_dev;
+ this.nfs_root_path = nfs_root_path;
+ this.nw_ip = nw_ip;
+ this.nw_gw = nw_gw;
+ this.nw_mask = nw_mask;
+ this.nw_nfs_server = nw_nfs_server;
+ this.nw_host = nw_host;
+ }
+
+ public String execute() throws CommandFailedException {
+ Runtime r = Runtime.getRuntime();
+ int domain_id = -1;
+ BufferedReader br;
+ int idx;
+ int i;
+ File image_tmp = null;
+ File initrd_tmp = null;
+ String domain_ip = "";
+
+ String create_cmdarray[] = new String[3];
+ String build_cmdarray[] = new String[6];
+ String vifinit_cmdarray[] = new String[4];
+
+ try {
+ try {
+ /* Some initial sanity checks */
+ if (root_dev.equals("/dev/nfs") && (vifs == 0)) {
+ throw new CommandFailedException("Cannot use NFS root without VIFs configured");
+ }
+
+ /* Uncompress the image and initrd */
+ if (image.endsWith(".gz")) {
+ image_tmp = getUncompressed("xen-image-", image);
+ image = image_tmp.getPath();
+ }
+
+ if (initrd != null && initrd.endsWith(".gz")) {
+ initrd_tmp = getUncompressed("xen-initrd-", initrd);
+ initrd = initrd_tmp.getPath();
+ }
+
+ /* Create a new empty domain */
+ Process create_p;
+ int create_rc;
+ create_cmdarray[0] = d.XIToolsDir + "xi_create";
+ create_cmdarray[1] = "" + size;
+ create_cmdarray[2] = name;
+ if (Settings.TEST) {
+ reportCommand(create_cmdarray);
+ domain_id = 1;
+ create_rc = 0;
+ } else {
+ create_p = r.exec(create_cmdarray);
+ br =
+ new BufferedReader(
+ new InputStreamReader(create_p.getInputStream()));
+ domain_id = Integer.parseInt(br.readLine());
+ create_rc = create_p.waitFor();
+ }
+
+ if (create_rc != 0) {
+ throw CommandFailedException.XICommandFailed("Failed to create domain", create_cmdarray);
+ } else if (domain_id > d.MaxDomainNumber) {
+ throw new CommandFailedException(
+ "Cannot configure more than " + d.MaxDomainNumber + " domains");
+ }
+
+ /* Set up boot parameters to pass to xi_build. */
+ if (root_dev.equals("/dev/nfs")) {
+ if (vifs == 0) {
+ throw new CommandFailedException("Cannot use NFS root without VIFs configured");
+ }
+ if (nfs_root_path == null) {
+ throw new CommandFailedException("No NFS root specified");
+ }
+ if (nw_nfs_server == null) {
+ throw new CommandFailedException("No NFS server specified");
+ }
+ bargs =
+ (bargs
+ + " root=/dev/nfs "
+ + "nfsroot="
+ + StringPattern.parse(nfs_root_path).resolve(domain_id)
+ + " ");
+ } else {
+ bargs =
+ (bargs
+ + " root="
+ + StringPattern.parse(root_dev).resolve(domain_id)
+ + " ");
+
+ }
+
+ if (vifs > 0) {
+ domain_ip = InetAddressPattern.parse(nw_ip).resolve(domain_id);
+ if (nw_host == null) {
+ try {
+ nw_host = InetAddress.getByName(domain_ip).getHostName();
+ } catch (UnknownHostException uhe) {
+ nw_host = "" + nw_ip;
+ }
+
+ }
+ bargs =
+ ("ip="
+ + domain_ip
+ + ":"
+ + ((nw_nfs_server == null)
+ ? ""
+ : (InetAddressPattern.parse(nw_nfs_server).resolve(domain_id)))
+ + ":"
+ + ((nw_gw == null)
+ ? ""
+ : (InetAddressPattern.parse(nw_gw).resolve(domain_id)))
+ + ":"
+ + ((nw_mask == null)
+ ? ""
+ : InetAddressPattern.parse(nw_mask).resolve(domain_id))
+ + ":"
+ + ((nw_host == null) ? "" : nw_host)
+ + ":eth0:off "
+ + bargs);
+ }
+
+ /* Build the domain */
+ Process build_p;
+ int build_rc;
+ idx = 0;
+ for (i = 0; i < build_cmdarray.length; i++)
+ build_cmdarray[i] = "";
+ build_cmdarray[idx++] = d.XIToolsDir + "xi_build";
+ build_cmdarray[idx++] = "" + domain_id;
+ build_cmdarray[idx++] = "" + image;
+ build_cmdarray[idx++] = "" + vifs;
+ if (initrd != null)
+ build_cmdarray[idx++] = "initrd=" + initrd;
+ build_cmdarray[idx++] = "" + bargs;
+ if (Settings.TEST) {
+ reportCommand(build_cmdarray);
+ build_rc = 0;
+ } else {
+ build_p = r.exec(build_cmdarray);
+ build_rc = build_p.waitFor();
+ }
+
+ if (build_rc != 0) {
+ throw CommandFailedException.XICommandFailed("Failed to build domain", build_cmdarray);
+ }
+
+ /* Set up the first VIF if necessary */
+ if (vifs > 0) {
+ Process vifinit_p;
+ int vifinit_rc;
+ vifinit_cmdarray[0] = d.XIToolsDir + "xi_vifinit";
+ vifinit_cmdarray[1] = "" + domain_id;
+ vifinit_cmdarray[2] = "0";
+ vifinit_cmdarray[3] = domain_ip;
+ if (Settings.TEST) {
+ reportCommand(vifinit_cmdarray);
+ vifinit_rc = 0;
+ } else {
+ vifinit_p = r.exec(vifinit_cmdarray);
+ vifinit_rc = vifinit_p.waitFor();
+ }
+
+ if (vifinit_rc != 0) {
+ throw CommandFailedException.XICommandFailed(
+ "Failed to initialise VIF 0",
+ vifinit_cmdarray);
+ }
+ }
+ } finally {
+ if (image_tmp != null)
+ image_tmp.delete();
+ if (initrd_tmp != null)
+ initrd_tmp.delete();
+ }
+ } catch (CommandFailedException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CommandFailedException("Could not create new domain (" + e + ")", e);
+ }
+
+ output = new String[ vifs > 0 ? 6 : 4 ];
+ output[0] = "Domain created with arguments:";
+ output[1] = "";
+ for (i = 0; i < create_cmdarray.length; i++)
+ output[1] += create_cmdarray[i] + " ";
+ output[2] = "Domain built with arguments:";
+ output[3] = "";
+ for (i = 0; i < build_cmdarray.length; i++)
+ output[3] += build_cmdarray[i] + " ";
+ if ( vifs > 0 ) {
+ output[4] = "VIF 0 initialized with arguments:";
+ output[5] = "";
+ for (i = 0; i < vifinit_cmdarray.length; i++)
+ output[5] += vifinit_cmdarray[i] + " ";
+ }
+
+ return null;
+ }
+
+ private File getUncompressed (String prefix, String original) throws IOException {
+ FileOutputStream fos;
+ GZIPInputStream gis;
+ File result;
+ byte buffer[] = new byte[1024];
+ int l;
+
+ result = File.createTempFile (prefix, null);
+
+ try {
+ fos = new FileOutputStream (result);
+ gis = new GZIPInputStream (new FileInputStream (original));
+ while ((l = gis.read(buffer, 0, buffer.length)) != -1) {
+ fos.write (buffer, 0, l);
+ }
+ } catch (IOException ioe) {
+ result.delete ();
+ throw ioe;
+ }
+
+ return result;
+ }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandStart.java b/tools/control/src/org/xenoserver/control/CommandStart.java
new file mode 100644
index 0000000000..7722ccd5af
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/CommandStart.java
@@ -0,0 +1,49 @@
+package org.xenoserver.control;
+
+/**
+ * Starts a domain.
+ */
+public class CommandStart extends Command {
+ private Defaults d;
+ private int domain_id;
+
+ /**
+ * Constructor for CommandStart.
+ * @param d Defaults object to use.
+ * @param domain_id Domain to start.
+ */
+ public CommandStart(Defaults d, int domain_id) {
+ this.d = d;
+ this.domain_id = domain_id;
+ }
+
+ public String execute() throws CommandFailedException {
+ Runtime r = Runtime.getRuntime();
+ String output = null;
+
+ try {
+ Process start_p;
+ String start_cmdarray[] = new String[2];
+ int start_rc;
+ start_cmdarray[0] = d.XIToolsDir + "xi_start";
+ start_cmdarray[1] = "" + domain_id;
+
+ if (Settings.TEST) {
+ output = reportCommand(start_cmdarray);
+ } else {
+ start_p = r.exec(start_cmdarray);
+ start_rc = start_p.waitFor();
+ if (start_rc != 0) {
+ throw CommandFailedException.XICommandFailed("Could not start domain", start_cmdarray);
+ }
+ output = "Started domain " + domain_id;
+ }
+ } catch (CommandFailedException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CommandFailedException("Could not start new domain (" + e + ")", e);
+ }
+
+ return output;
+ }
+}
diff --git a/tools/control/src/org/xenoserver/control/CommandStop.java b/tools/control/src/org/xenoserver/control/CommandStop.java
new file mode 100644
index 0000000000..d280875dfb
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/CommandStop.java
@@ -0,0 +1,50 @@
+package org.xenoserver.control;
+
+/**
+ * Stops a domain.
+ */
+public class CommandStop extends Command {
+ private Defaults d;
+ private int domain_id;
+
+ /**
+ * Constructor for CommandStop.
+ * @param d The defaults object to use.
+ * @param domain_id The domain to stop.
+ */
+ public CommandStop(Defaults d, int domain_id) {
+ this.d = d;
+ this.domain_id = domain_id;
+ }
+
+ public String execute() throws CommandFailedException {
+ Runtime r = Runtime.getRuntime();
+ String output = null;
+
+ try {
+ Process stop_p;
+ String stop_cmdarray[] = new String[2];
+ int stop_rc;
+ stop_cmdarray[0] = d.XIToolsDir + "xi_stop";
+ stop_cmdarray[1] = "" + domain_id;
+
+ if (Settings.TEST) {
+ output = reportCommand(stop_cmdarray);
+ } else {
+ stop_p = r.exec(stop_cmdarray);
+ stop_rc = stop_p.waitFor();
+
+ if (stop_rc != 0) {
+ throw CommandFailedException.XICommandFailed("Could not stop domain", stop_cmdarray);
+ }
+ output = "Stopped domain " + domain_id;
+ }
+ } catch (CommandFailedException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CommandFailedException("Could not stop new domain (" + e + ")", e);
+ }
+
+ return output;
+ }
+}
diff --git a/tools/control/src/org/xenoserver/control/Defaults.java b/tools/control/src/org/xenoserver/control/Defaults.java
new file mode 100644
index 0000000000..61fd47f1ef
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/Defaults.java
@@ -0,0 +1,205 @@
+package org.xenoserver.control;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.InputSource;
+import org.xml.sax.XMLReader;
+import org.xml.sax.helpers.DefaultHandler;
+
+/**
+ * The Defaults class stores the default settings to be used by the
+ * management utilities. On construction it parses the defaults file
+ * located through the Settings class.
+ */
+public class Defaults
+{
+ public String domainName;
+
+ public int domainSizeKB;
+ public String domainImage;
+ public String domainInitRD;
+ public int domainVIFs;
+
+ public String rootDevice;
+
+ public String NWIP;
+ public String NWGW;
+ public String NWMask;
+ public String NWHost;
+
+ public String NWNFSServer;
+ public String NWNFSRoot;
+
+ public int MaxDomainNumber = Integer.MAX_VALUE;
+ public String args = "";
+
+ public String XIToolsDir = "";
+
+ /***********************************************************************/
+
+ public Defaults ()
+ {
+ File f = Settings.getDefaultsFile ();
+
+ if (f == null)
+ {
+ return;
+ }
+
+ try
+ {
+ XMLReader xr = new org.apache.crimson.parser.XMLReaderImpl();
+ Handler handler = new Handler ();
+ xr.setContentHandler (handler);
+ xr.setErrorHandler (handler);
+ xr.parse (new InputSource(new FileReader (f)));
+ }
+ catch (Exception e)
+ {
+ System.err.println ("Could not read defaults file " + f +
+ "\nException: " + e);
+ e.printStackTrace();
+ return;
+ }
+ }
+
+ public void describe () {
+ System.out.println ("Domain defaults:");
+ System.out.println (" name " + domainName);
+ System.out.println (" size " + domainSizeKB);
+ System.out.println (" vifs " + domainVIFs);
+ System.out.println (" domainImage " + domainImage);
+ System.out.println (" domainInitRD " + domainInitRD);
+ System.out.println (" rootDevice " + rootDevice);
+ System.out.println (" NWIP " + NWIP);
+ System.out.println (" NWGW " + NWGW);
+ System.out.println (" NWMask " + NWMask);
+ System.out.println (" MaxDomainNumber " + MaxDomainNumber);
+ System.out.println (" NWNFSServer " + NWNFSServer);
+ System.out.println (" NWNFSRoot " + NWNFSRoot);
+ System.out.println (" XIToolsDir " + XIToolsDir);
+ System.out.println (" args " + args);
+ }
+
+ /***********************************************************************/
+
+ class Handler extends DefaultHandler
+ {
+ boolean inDomctlDefaults;
+ String lastName;
+
+ public void startDocument ()
+ {
+ }
+
+ public void endDocument ()
+ {
+ }
+
+ public void startElement (String uri, String name,
+ String qname, Attributes atts)
+ {
+ if (qname.equals ("domctl_defaults")) {
+ inDomctlDefaults = true;
+ } else {
+ lastName = qname;
+ }
+ }
+
+ public void endElement (String uri, String name, String qname)
+ {
+ lastName = "";
+ if (qname.equals ("domctl_defaults")) {
+ inDomctlDefaults = false;
+ }
+ }
+
+ public void characters (char ch[], int start, int length)
+ {
+ String s = new String (ch, start, length);
+ if (lastName != null)
+ {
+ if (lastName.equals ("domain_size_kb")) {
+ domainSizeKB = Integer.parseInt (s);
+ } else if (lastName.equals ("domain_image")) {
+ domainImage = s;
+ } else if (lastName.equals ("domain_name")) {
+ domainName = s;
+ } else if (lastName.equals ("domain_init_rd")) {
+ domainInitRD = s;
+ } else if (lastName.equals ("domain_vifs")) {
+ domainVIFs = Integer.parseInt (s);
+ } else if (lastName.equals ("root_device")) {
+ rootDevice = s;
+ } else if (lastName.equals ("nw_ip")) {
+ NWIP = expandDefault (s, runCommand(XIToolsDir+Settings.XI_HELPER+" ip").trim());
+ } else if (lastName.equals ("nw_gw")) {
+ NWGW = expandDefault (s, runCommand(XIToolsDir+Settings.XI_HELPER+" route").trim());
+ } else if (lastName.equals ("nw_mask")) {
+ NWMask = expandDefault (s, runCommand(XIToolsDir+Settings.XI_HELPER+" mask").trim());
+ } else if (lastName.equals ("nw_host")) {
+ NWHost = s;
+ } else if (lastName.equals ("nw_nfs_server")) {
+ NWNFSServer = s;
+ } else if (lastName.equals ("nw_nfs_root")) {
+ NWNFSRoot = s;
+ } else if (lastName.equals ("args")) {
+ args = s;
+ } else if (lastName.equals ("max_domain_number")) {
+ MaxDomainNumber = Integer.parseInt(s);
+ } else if (lastName.equals ("xi_tools_dir")) {
+ XIToolsDir = s;
+ }
+ }
+ }
+ }
+
+ public String expandDefault (String supplied, String self)
+ {
+ if (supplied.startsWith ("=")) {
+ if (supplied.length() > 1) {
+ return self + supplied.substring (1, supplied.length());
+ } else {
+ return self;
+ }
+ } else {
+ return supplied;
+ }
+ }
+
+
+ public String
+ runCommand (String command)
+ {
+ Runtime runtime = Runtime.getRuntime();
+ String outline;
+ StringBuffer output = new StringBuffer();
+
+ try
+ {
+ Process process = runtime.exec(command);
+ BufferedReader in = new BufferedReader(
+ new InputStreamReader(process.getInputStream()));
+
+ outline = in.readLine();
+ while (outline != null)
+ {
+ output.append("\n" + outline);
+ outline = in.readLine();
+ }
+ }
+ catch (IOException e)
+ {
+ return e.toString();
+ }
+
+ return output.toString();
+ }
+
+
+}
diff --git a/tools/control/src/org/xenoserver/control/Domain.java b/tools/control/src/org/xenoserver/control/Domain.java
new file mode 100644
index 0000000000..27f9ec9e39
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/Domain.java
@@ -0,0 +1,31 @@
+package org.xenoserver.control;
+
+/**
+ * A Domain object holds the details of one domain suitable for returning
+ * from methods enquiring about domain status.
+ */
+public class
+Domain
+{
+ public int id; /* domain id */
+ public int processor; /* processor */
+ public boolean cpu; /* has cpu */
+ public int nstate; /* state */
+ public String state; /* running, interruptable, uninterruptable,
+ wait, suspended, dying */
+ public int mcu; /* mcu advances */
+ public int pages; /* total pages */
+ public String name; /* name */
+
+ Domain()
+ {
+ id = 0;
+ processor = 0;
+ cpu = false;
+ nstate = 0;
+ state = "";
+ mcu = 0;
+ pages = 0;
+ name = "none";
+ }
+}
diff --git a/tools/control/src/org/xenoserver/control/InetAddressPattern.java b/tools/control/src/org/xenoserver/control/InetAddressPattern.java
new file mode 100644
index 0000000000..7b45b093f8
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/InetAddressPattern.java
@@ -0,0 +1,60 @@
+package org.xenoserver.control;
+
+import java.net.*;
+
+public class InetAddressPattern
+{
+ InetAddress base;
+ boolean addDom;
+
+ static InetAddressPattern parse (String t)
+ {
+ InetAddressPattern result = new InetAddressPattern ();
+ char[] ca = t.toCharArray ();
+ int idx = 0;
+ int len = ca.length;
+
+ try {
+ if (len == 0) {
+ result.base = null;
+ result.addDom = false;
+ } else if (ca[len - 1] == '+') {
+ result.base = InetAddress.getByName(t.substring(0, len - 1));
+ result.addDom = true;
+ } else {
+ result.base = InetAddress.getByName(t);
+ result.addDom = false;
+ }
+ } catch (UnknownHostException uhe) {
+ result.base = null;
+ result.addDom = false;
+ }
+
+ return result;
+ }
+
+ public String resolve (int domain_id) {
+ byte b[] = base.getAddress ();
+ if (addDom) {
+ if (((int)b[3]) + domain_id > 255) {
+ if (((int)b[2]) + domain_id > 255) {
+ if (((int)b[1]) + domain_id > 255) {
+ b[0] ++;
+ }
+ b[1] ++;
+ }
+ b[2] ++;
+ }
+ b[3] += domain_id;
+ }
+ return "" +
+ (b[0] + (b[0] < 0 ? 256 : 0)) + "." +
+ (b[1] + (b[1] < 0 ? 256 : 0)) + "." +
+ (b[2] + (b[2] < 0 ? 256 : 0)) + "." +
+ (b[3] + (b[3] < 0 ? 256 : 0));
+ }
+
+ public String toString () {
+ return "[" + base + (addDom ? "+dom_id" : "") + "]";
+ }
+}
diff --git a/tools/control/src/org/xenoserver/control/Settings.java b/tools/control/src/org/xenoserver/control/Settings.java
new file mode 100644
index 0000000000..74203e618f
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/Settings.java
@@ -0,0 +1,41 @@
+package org.xenoserver.control;
+
+import java.io.File;
+import java.util.StringTokenizer;
+
+/**
+ * The Settings class is a repository for global settings such as the IP of
+ * the machine and the location of the defaults file.
+ */
+public final class Settings
+{
+ public static final String DEFAULTS_FILE = System.getProperty ("DEFAULTS_FILE", "domctl.xml");
+ public static final String DEFAULTS_PATH = System.getProperty ("DEFAULTS_PATH", ".:/etc:/var/lib/xen");
+ public static final String LOCAL_IP = System.getProperty ("LOCAL_IP");
+ public static final String LOCAL_MASK = System.getProperty ("LOCAL_MASK");
+ public static final String LOCAL_GW = System.getProperty ("LOCAL_ROUTE");
+ public static final boolean TEST = (System.getProperty ("TEST") != null);
+ public static final String XI_HELPER = System.getProperty ("XI_HELPER", "xi_helper");
+
+
+ public static File getDefaultsFile() {
+ StringTokenizer tok = new StringTokenizer (DEFAULTS_PATH, ":");
+ File result = null;
+ File probe;
+
+ while (tok.hasMoreTokens ()) {
+ String probe_dir = tok.nextToken ();
+ probe = new File (probe_dir, DEFAULTS_FILE);
+ if (probe.exists ()) {
+ result = probe;
+ break;
+ }
+ }
+
+ if (result == null) {
+ System.err.println ("Could not find " + DEFAULTS_FILE + " in path " + DEFAULTS_PATH);
+ }
+
+ return result;
+ }
+}
diff --git a/tools/control/src/org/xenoserver/control/StringPattern.java b/tools/control/src/org/xenoserver/control/StringPattern.java
new file mode 100644
index 0000000000..5df2470a91
--- /dev/null
+++ b/tools/control/src/org/xenoserver/control/StringPattern.java
@@ -0,0 +1,59 @@
+package org.xenoserver.control;
+
+public class StringPattern
+{
+ String base;
+ int bn;
+ boolean addDom;
+ boolean appendDom;
+
+ static StringPattern parse (String t)
+ {
+ StringPattern result = new StringPattern ();
+ char[] ca = t.toCharArray ();
+ int idx = 0;
+ int len = ca.length;
+
+ if (len == 0) {
+ result.base = "";
+ result.bn = 0;
+ result.addDom = false;
+ } else if (ca[len - 1] == '+') {
+ idx = len - 2;
+ if ((idx >= 0) && (ca[idx] >= '0') && (ca[idx] <= '9')) {
+ while ((idx >= 0) && (ca[idx] >= '0') && (ca[idx] <= '9')) {
+ idx --;
+ }
+ result.base = t.substring(0, idx + 1);
+ result.bn = Integer.parseInt (t.substring (idx + 1, len - 1));
+ result.addDom = true;
+ } else {
+ result.base = t.substring(0, len - 1);
+ result.appendDom = true;
+ }
+ } else {
+ result.base = t;
+ }
+
+ return result;
+ }
+
+ public String resolve (int domain_id) {
+ if (addDom) {
+ return base + (bn + domain_id);
+ } else if (appendDom) {
+ return base + domain_id;
+ } else {
+ return base;
+ }
+ }
+
+ public String toString () {
+ return ("[" +
+ base +
+ (addDom ? "+" + bn : "") +
+ ((addDom || appendDom) ? "+ID" : "") +
+ "]");
+ }
+
+}
diff --git a/tools/control/xenctl b/tools/control/xenctl
new file mode 100755
index 0000000000..17ec375aaf
--- /dev/null
+++ b/tools/control/xenctl
@@ -0,0 +1,33 @@
+#!/bin/bash
+
+if [ -z "$DEFAULTS_FILE" ] ; then DEFAULTS_FILE=domctl.xml ; fi
+if [ -z "$DEFAULTS_PATH" ] ; then DEFAULTS_PATH=.:/etc:/var/lib/xen ; fi
+if [ -z "$QUERY_DEV" ] ; then QUERY_DEV=eth0 ; fi
+if [ -z "$IFCONFIG" ] ; then IFCONFIG=/sbin/ifconfig ; fi
+if [ -z "$ROUTE" ] ; then ROUTE=/sbin/route ; fi
+if [ -z "$JAVA" ] ; then JAVA=java ; fi
+
+if [ "$1" = "new" ] ; then
+ if [ ! -x "$IFCONFIG" ]; then
+ echo Could not find executable $IFCONFIG
+ exit 1
+ fi
+
+ if [ ! -x "$ROUTE" ]; then
+ echo Could not find executable $ROUTE
+ exit 1
+ fi
+
+ # Try to determine dom0 network settings to avoid hard-coding
+ # particular machines in the defaults file
+ LOCAL_IP=$(/sbin/ifconfig $QUERY_DEV | grep 'inet addr' | tr ':' '\t' | awk '{print $3}')
+ LOCAL_MASK=$(/sbin/ifconfig $QUERY_DEV | grep 'Mask' | tr ':' '\t' | awk '{print $7}')
+ LOCAL_ROUTE=$(/sbin/route -n | grep $QUERY_DEV | grep 'G' | awk '{print $2}')
+fi
+
+
+#ARGS="-DTEST -DDEFAULTS_FILE=$DEFAULTS_FILE -DDEFAULTS_PATH=$DEFAULTS_PATH -DLOCAL_IP=$LOCAL_IP -DLOCAL_MASK=$LOCAL_MASK -DLOCAL_ROUTE=$LOCAL_ROUTE"
+ARGS="-DDEFAULTS_FILE=$DEFAULTS_FILE -DDEFAULTS_PATH=$DEFAULTS_PATH -DLOCAL_IP=$LOCAL_IP -DLOCAL_MASK=$LOCAL_MASK -DLOCAL_ROUTE=$LOCAL_ROUTE"
+
+
+$JAVA $ARGS -jar $(dirname $0)/xenctl-cmdline.jar $*