diff --git a/xmlrpc/GNUmakefile.in b/xmlrpc/GNUmakefile.in
index cb214f900144e35a0cdc06940975fa1843b52c0e..05c29ec7f90a9d9542616f21405ecb29a5a4ac24 100644
--- a/xmlrpc/GNUmakefile.in
+++ b/xmlrpc/GNUmakefile.in
@@ -1,6 +1,6 @@
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2004 University of Utah and the Flux Group.
+# Copyright (c) 2004, 2005 University of Utah and the Flux Group.
 # All rights reserved.
 #
 
@@ -31,7 +31,7 @@ USERLIBS	= sshxmlrpc.py emulabclient.py
 SYMLINKS        = node_admin node_reboot os_load create_image node_list \
 		  delay_config link_config savelogs portstats eventsys_control \
 		  readycount nscheck startexp batchexp startexp swapexp endexp \
-		  modexp expinfo node_avail tbuisp
+		  modexp expinfo node_avail tbuisp expwait
 
 #
 # Force dependencies on the scripts so that they will be rerun through
diff --git a/xmlrpc/script_wrapper.py.in b/xmlrpc/script_wrapper.py.in
index 249f63c52cd5afe73aab637990145e0cc9db0a8c..aee2d5b9926cb7f8dcb1567541f2250bd62cdb88 100755
--- a/xmlrpc/script_wrapper.py.in
+++ b/xmlrpc/script_wrapper.py.in
@@ -1,7 +1,7 @@
 #! /usr/bin/env python
 #
 # EMULAB-COPYRIGHT
-# Copyright (c) 2004 University of Utah and the Flux Group.
+# Copyright (c) 2004, 2005 University of Utah and the Flux Group.
 # All rights reserved.
 # 
 # Permission to use, copy, modify and distribute this software is hereby
@@ -113,6 +113,8 @@ API = {
                             "help" : "Get information about an experiment" },
     "tbuisp"            : { "func" : "tbuisp",
                             "help" : "Upload code to a mote" },
+    "expwait"           : { "func" : "expwait",
+                            "help" : "Wait for experiment to reach a state" },
 };
 
 #
@@ -1653,6 +1655,72 @@ class tbuisp:
         
     pass
 
+#
+# expwait
+#
+class expwait:
+    def __init__(self, argv=None):
+        self.argv = argv;
+        return
+
+    def apply(self):
+        try:
+            opts, req_args = getopt.getopt(self.argv, "ht:e:", [ "help" ]);
+            pass
+        except getopt.error, e:
+            print e.args[0]
+            self.usage();
+            return -1;
+
+        show   = [];
+        params = {};
+        for opt, val in opts:
+            if opt in ("-h", "--help"):
+                self.usage()
+                return 0
+            elif opt == "-t":
+                params["timeout"] = val;
+                pass
+            elif opt == "-e":
+                pid,eid = string.split(val, ",")
+                params["proj"] = pid;
+                params["exp"]  = eid;
+                pass
+            pass
+
+        #
+        # The point is to allow backwards compatable pid eid arguments, but
+        # move to the better -e pid,eid format eventually. 
+        #
+        if not params.has_key("proj"):
+            if len(req_args) != 3:
+                self.usage();
+                return -1;
+            
+            params["proj"]  = req_args[0];
+            params["exp"]   = req_args[1];
+            params["state"] = req_args[2];
+            pass
+        elif len(req_args) != 1:
+            self.usage();
+            return -1;
+        else:
+            params["state"] = req_args[0];
+            pass
+
+        rval,response = do_method("experiment", "statewait", params);
+        return rval;
+
+    def usage(self):
+	print "expwait [-t timeout] -e pid,eid state";
+	print "expwait [-t timeout] pid eid state";
+	print "where:";
+ 	print "     -e   - Project and Experiment ID";
+        print "     -t   - Maximum time to wait (in seconds).";
+        wrapperoptions();
+        return
+    pass
+
 #
 # Process program arguments. There are two ways we could be invoked.
 # 1) as the wrapper, with the first required argument the name of the script.