kvm.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [KVM-AUTOTEST PATCH 1/4] KVM test: allow setting shell line separator string in the config file
@ 2009-09-20 15:16 Michael Goldish
  2009-09-20 15:16 ` [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN Michael Goldish
  2009-10-05 19:25 ` [Autotest] [KVM-AUTOTEST PATCH 1/4] KVM test: allow setting shell line separator string in the config file Lucas Meneghel Rodrigues
  0 siblings, 2 replies; 8+ messages in thread
From: Michael Goldish @ 2009-09-20 15:16 UTC (permalink / raw)
  To: autotest, kvm; +Cc: Michael Goldish

The shell line separator string is appended to strings sent by sendline().

The string is controlled by the parameter shell_linesep.  It defaults to "\n".

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 client/tests/kvm/kvm_tests.cfg.sample |    1 +
 client/tests/kvm/kvm_utils.py         |   12 ++++++------
 client/tests/kvm/kvm_vm.py            |    7 ++++---
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/client/tests/kvm/kvm_tests.cfg.sample b/client/tests/kvm/kvm_tests.cfg.sample
index 38f5a5a..540d0a2 100644
--- a/client/tests/kvm/kvm_tests.cfg.sample
+++ b/client/tests/kvm/kvm_tests.cfg.sample
@@ -364,6 +364,7 @@ variants:
         shell_prompt = "^\w:\\.*>\s*$"
         username = Administrator
         password = 123456
+        shell_linesep = "\r\n"
         shell_client = nc
         shell_port = 22
         # File transfers are currently unsupported
diff --git a/client/tests/kvm/kvm_utils.py b/client/tests/kvm/kvm_utils.py
index 88299be..53b664a 100644
--- a/client/tests/kvm/kvm_utils.py
+++ b/client/tests/kvm/kvm_utils.py
@@ -576,7 +576,7 @@ def scp_from_remote(host, port, username, password, remote_path, local_path,
     return remote_scp(command, password, timeout)
 
 
-def ssh(host, port, username, password, prompt, timeout=10):
+def ssh(host, port, username, password, prompt, linesep="\n", timeout=10):
     """
     Log into a remote host (guest) using SSH.
 
@@ -591,10 +591,10 @@ def ssh(host, port, username, password, prompt, timeout=10):
     """
     command = ("ssh -o UserKnownHostsFile=/dev/null -p %s %s@%s" %
                (port, username, host))
-    return remote_login(command, password, prompt, "\n", timeout)
+    return remote_login(command, password, prompt, linesep, timeout)
 
 
-def telnet(host, port, username, password, prompt, timeout=10):
+def telnet(host, port, username, password, prompt, linesep="\n", timeout=10):
     """
     Log into a remote host (guest) using Telnet.
 
@@ -608,10 +608,10 @@ def telnet(host, port, username, password, prompt, timeout=10):
     @return: kvm_spawn object on success and None on failure.
     """
     command = "telnet -l %s %s %s" % (username, host, port)
-    return remote_login(command, password, prompt, "\r\n", timeout)
+    return remote_login(command, password, prompt, linesep, timeout)
 
 
-def netcat(host, port, username, password, prompt, timeout=10):
+def netcat(host, port, username, password, prompt, linesep="\n", timeout=10):
     """
     Log into a remote host (guest) using Netcat.
 
@@ -625,7 +625,7 @@ def netcat(host, port, username, password, prompt, timeout=10):
     @return: kvm_spawn object on success and None on failure.
     """
     command = "nc %s %s" % (host, port)
-    return remote_login(command, password, prompt, "\n", timeout)
+    return remote_login(command, password, prompt, linesep, timeout)
 
 
 # The following are utility functions related to ports.
diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
index 55220f9..07ceb6d 100755
--- a/client/tests/kvm/kvm_vm.py
+++ b/client/tests/kvm/kvm_vm.py
@@ -669,6 +669,7 @@ class VM:
         username = self.params.get("username", "")
         password = self.params.get("password", "")
         prompt = self.params.get("shell_prompt", "[\#\$]")
+        linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
         client = self.params.get("shell_client")
         address = self.get_address(nic_index)
         port = self.get_port(int(self.params.get("shell_port")))
@@ -679,13 +680,13 @@ class VM:
 
         if client == "ssh":
             session = kvm_utils.ssh(address, port, username, password,
-                                    prompt, timeout)
+                                    prompt, linesep, timeout)
         elif client == "telnet":
             session = kvm_utils.telnet(address, port, username, password,
-                                       prompt, timeout)
+                                       prompt, linesep, timeout)
         elif client == "nc":
             session = kvm_utils.netcat(address, port, username, password,
-                                       prompt, timeout)
+                                       prompt, linesep, timeout)
 
         if session:
             session.set_status_test_command(self.params.get("status_test_"
-- 
1.5.4.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN
  2009-09-20 15:16 [KVM-AUTOTEST PATCH 1/4] KVM test: allow setting shell line separator string in the config file Michael Goldish
@ 2009-09-20 15:16 ` Michael Goldish
  2009-09-20 15:16   ` [KVM-AUTOTEST PATCH 3/4] KVM test: WinXP-64-rss.steps: modify first barrier Michael Goldish
  2009-09-21  9:51   ` [Autotest] [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN Yolkfull Chow
  2009-10-05 19:25 ` [Autotest] [KVM-AUTOTEST PATCH 1/4] KVM test: allow setting shell line separator string in the config file Lucas Meneghel Rodrigues
  1 sibling, 2 replies; 8+ messages in thread
From: Michael Goldish @ 2009-09-20 15:16 UTC (permalink / raw)
  To: autotest, kvm; +Cc: Michael Goldish

Some Windows programs behave badly when their STDIN is redirected to a pipe
(most notably wmic).  Therefore, keep STDIN unredirected, and send input to the
console window as a series of WM_CHAR messages.

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 client/tests/kvm/deps/rss.cpp |   54 +++++++++++++++++-----------------------
 1 files changed, 23 insertions(+), 31 deletions(-)

diff --git a/client/tests/kvm/deps/rss.cpp b/client/tests/kvm/deps/rss.cpp
index 73a849a..66d9a5b 100644
--- a/client/tests/kvm/deps/rss.cpp
+++ b/client/tests/kvm/deps/rss.cpp
@@ -22,9 +22,9 @@ struct client_info {
     SOCKET socket;
     sockaddr_in addr;
     int pid;
+    HWND hwnd;
     HANDLE hJob;
     HANDLE hChildOutputRead;
-    HANDLE hChildInputWrite;
     HANDLE hThreadChildToSocket;
 };
 
@@ -161,15 +161,10 @@ DWORD WINAPI SocketToChild(LPVOID client_info_ptr)
         sprintf(message, "Client (%s) entered text: \"%s\"\r\n",
                 client_info_str, formatted_buffer);
         AppendMessage(message);
-        // Write the data to the child's STDIN
-        WriteFile(ci.hChildInputWrite, buffer, bytes_received,
-                  &bytes_written, NULL);
-        // Make sure all the data was written
-        if (bytes_written != bytes_received) {
-            sprintf(message,
-                    "SocketToChild: bytes received (%d) != bytes written (%d)",
-                    bytes_received, bytes_written);
-            ExitOnError(message, 1);
+        // Send the data as a series of WM_CHAR messages to the console window
+        for (int i=0; i<bytes_received; i++) {
+            SendMessage(ci.hwnd, WM_CHAR, (WPARAM)buffer[i], 0);
+            SendMessage(ci.hwnd, WM_SETFOCUS, 0, 0);
         }
     }
 
@@ -194,7 +189,6 @@ DWORD WINAPI SocketToChild(LPVOID client_info_ptr)
     CloseHandle(ci.hJob);
     CloseHandle(ci.hThreadChildToSocket);
     CloseHandle(ci.hChildOutputRead);
-    CloseHandle(ci.hChildInputWrite);
 
     AppendMessage("SocketToChild thread exited\r\n");
 
@@ -203,18 +197,25 @@ DWORD WINAPI SocketToChild(LPVOID client_info_ptr)
 
 void PrepAndLaunchRedirectedChild(client_info *ci,
                                   HANDLE hChildStdOut,
-                                  HANDLE hChildStdIn,
                                   HANDLE hChildStdErr)
 {
     PROCESS_INFORMATION pi;
     STARTUPINFO si;
 
+    // Allocate a new console for the child
+    HWND hwnd = GetForegroundWindow();
+    FreeConsole();
+    AllocConsole();
+    ShowWindow(GetConsoleWindow(), SW_HIDE);
+    if (hwnd)
+        SetForegroundWindow(hwnd);
+
     // Set up the start up info struct.
     ZeroMemory(&si, sizeof(STARTUPINFO));
     si.cb = sizeof(STARTUPINFO);
     si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
     si.hStdOutput = hChildStdOut;
-    si.hStdInput  = hChildStdIn;
+    si.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
     si.hStdError  = hChildStdErr;
     // Use this if you want to hide the child:
     si.wShowWindow = SW_HIDE;
@@ -223,7 +224,7 @@ void PrepAndLaunchRedirectedChild(client_info *ci,
 
     // Launch the process that you want to redirect.
     if (!CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE,
-                       CREATE_NEW_CONSOLE, NULL, "C:\\", &si, &pi))
+                       0, NULL, "C:\\", &si, &pi))
         ExitOnError("CreateProcess failed");
 
     // Close any unnecessary handles.
@@ -235,12 +236,16 @@ void PrepAndLaunchRedirectedChild(client_info *ci,
     // Assign the process to a newly created JobObject
     ci->hJob = CreateJobObject(NULL, NULL);
     AssignProcessToJobObject(ci->hJob, pi.hProcess);
+    // Keep the console window's handle
+    ci->hwnd = GetConsoleWindow();
+
+    // Detach from the child's console
+    FreeConsole();
 }
 
 void SpawnSession(client_info *ci)
 {
     HANDLE hOutputReadTmp, hOutputRead, hOutputWrite;
-    HANDLE hInputWriteTmp, hInputRead, hInputWrite;
     HANDLE hErrorWrite;
     SECURITY_ATTRIBUTES sa;
 
@@ -261,10 +266,6 @@ void SpawnSession(client_info *ci)
                          TRUE, DUPLICATE_SAME_ACCESS))
         ExitOnError("DuplicateHandle failed");
 
-    // Create the child input pipe.
-    if (!CreatePipe(&hInputRead, &hInputWriteTmp, &sa, 0))
-        ExitOnError("CreatePipe failed");
-
     // Create new output read handle and the input write handles. Set
     // the Properties to FALSE. Otherwise, the child inherits the
     // properties and, as a result, non-closeable handles to the pipes
@@ -276,29 +277,20 @@ void SpawnSession(client_info *ci)
                          DUPLICATE_SAME_ACCESS))
         ExitOnError("DuplicateHandle failed");
 
-    if (!DuplicateHandle(GetCurrentProcess(), hInputWriteTmp,
-                         GetCurrentProcess(),
-                         &hInputWrite, // Address of new handle.
-                         0, FALSE, // Make it uninheritable.
-                         DUPLICATE_SAME_ACCESS))
-        ExitOnError("DuplicateHandle failed");
-
     // Close inheritable copies of the handles you do not want to be
     // inherited.
-    if (!CloseHandle(hOutputReadTmp)) ExitOnError("CloseHandle failed");
-    if (!CloseHandle(hInputWriteTmp)) ExitOnError("CloseHandle failed");
+    if (!CloseHandle(hOutputReadTmp))
+        ExitOnError("CloseHandle failed");
 
-    PrepAndLaunchRedirectedChild(ci, hOutputWrite, hInputRead, hErrorWrite);
+    PrepAndLaunchRedirectedChild(ci, hOutputWrite, hErrorWrite);
 
     ci->hChildOutputRead = hOutputRead;
-    ci->hChildInputWrite = hInputWrite;
 
     // Close pipe handles (do not continue to modify the parent).
     // You need to make sure that no handles to the write end of the
     // output pipe are maintained in this process or else the pipe will
     // not close when the child process exits and the ReadFile will hang.
     if (!CloseHandle(hOutputWrite)) ExitOnError("CloseHandle failed");
-    if (!CloseHandle(hInputRead )) ExitOnError("CloseHandle failed");
     if (!CloseHandle(hErrorWrite)) ExitOnError("CloseHandle failed");
 }
 
-- 
1.5.4.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [KVM-AUTOTEST PATCH 3/4] KVM test: WinXP-64-rss.steps: modify first barrier
  2009-09-20 15:16 ` [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN Michael Goldish
@ 2009-09-20 15:16   ` Michael Goldish
  2009-09-20 15:16     ` [KVM-AUTOTEST PATCH 4/4] KVM test: kvm_subprocess: minimize the number of modules imported by the server Michael Goldish
  2009-09-21  9:51   ` [Autotest] [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN Yolkfull Chow
  1 sibling, 1 reply; 8+ messages in thread
From: Michael Goldish @ 2009-09-20 15:16 UTC (permalink / raw)
  To: autotest, kvm; +Cc: Michael Goldish

The start menu button seems to have two possible appearances.
Therefore change the barrier to test the center of the screen (including the
mouse cursor) instead.

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 client/tests/kvm/steps/WinXP-64-rss.steps |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/client/tests/kvm/steps/WinXP-64-rss.steps b/client/tests/kvm/steps/WinXP-64-rss.steps
index a47c19c..ebf32d6 100644
--- a/client/tests/kvm/steps/WinXP-64-rss.steps
+++ b/client/tests/kvm/steps/WinXP-64-rss.steps
@@ -5,7 +5,7 @@
 step 45.95
 screendump 20090808_220900_04a6bdc48c7e7b21c40da156b3c5e39a.ppm
 # desktop reached
-barrier_2 68 20 10 455 84c2097166d61662c0da0f522ba6a860 230
+barrier_2 80 67 286 217 857ee08ee09b52e69e70189853da5b95 230
 # Sending keys: 0xdc-r
 key 0xdc-r
 # --------------------------------
-- 
1.5.4.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [KVM-AUTOTEST PATCH 4/4] KVM test: kvm_subprocess: minimize the number of modules imported by the server
  2009-09-20 15:16   ` [KVM-AUTOTEST PATCH 3/4] KVM test: WinXP-64-rss.steps: modify first barrier Michael Goldish
@ 2009-09-20 15:16     ` Michael Goldish
  0 siblings, 0 replies; 8+ messages in thread
From: Michael Goldish @ 2009-09-20 15:16 UTC (permalink / raw)
  To: autotest, kvm; +Cc: Michael Goldish

Rearrange the code (put the server on top) so that the server imports only the
modules it requires.  This reduces the startup time of child processes.

Signed-off-by: Michael Goldish <mgoldish@redhat.com>
---
 client/tests/kvm/kvm_subprocess.py |  359 ++++++++++++++++++------------------
 1 files changed, 181 insertions(+), 178 deletions(-)

diff --git a/client/tests/kvm/kvm_subprocess.py b/client/tests/kvm/kvm_subprocess.py
index f748586..424c801 100755
--- a/client/tests/kvm/kvm_subprocess.py
+++ b/client/tests/kvm/kvm_subprocess.py
@@ -5,8 +5,187 @@ A class and functions used for running and controlling child processes.
 @copyright: 2008-2009 Red Hat Inc.
 """
 
-import sys, subprocess, pty, select, os, time, signal, re, termios, fcntl
-import threading, logging, commands
+import os, sys, pty, select, termios, fcntl
+
+
+# The following helper functions are shared by the server and the client.
+
+def _lock(filename):
+    if not os.path.exists(filename):
+        open(filename, "w").close()
+    fd = os.open(filename, os.O_RDWR)
+    fcntl.lockf(fd, fcntl.LOCK_EX)
+    return fd
+
+
+def _unlock(fd):
+    fcntl.lockf(fd, fcntl.LOCK_UN)
+    os.close(fd)
+
+
+def _locked(filename):
+    try:
+        fd = os.open(filename, os.O_RDWR)
+    except:
+        return False
+    try:
+        fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
+    except:
+        os.close(fd)
+        return True
+    fcntl.lockf(fd, fcntl.LOCK_UN)
+    os.close(fd)
+    return False
+
+
+def _wait(filename):
+    fd = _lock(filename)
+    _unlock(fd)
+
+
+def _get_filenames(base_dir, id):
+    return [os.path.join(base_dir, s + id) for s in
+            "shell-pid-", "status-", "output-", "inpipe-",
+            "lock-server-running-", "lock-client-starting-"]
+
+
+def _get_reader_filename(base_dir, id, reader):
+    return os.path.join(base_dir, "outpipe-%s-%s" % (reader, id))
+
+
+# The following is the server part of the module.
+
+if __name__ == "__main__":
+    id = sys.stdin.readline().strip()
+    echo = sys.stdin.readline().strip() == "True"
+    readers = sys.stdin.readline().strip().split(",")
+    command = sys.stdin.readline().strip() + " && echo %s > /dev/null" % id
+
+    # Define filenames to be used for communication
+    base_dir = "/tmp/kvm_spawn"
+    (shell_pid_filename,
+     status_filename,
+     output_filename,
+     inpipe_filename,
+     lock_server_running_filename,
+     lock_client_starting_filename) = _get_filenames(base_dir, id)
+
+    # Populate the reader filenames list
+    reader_filenames = [_get_reader_filename(base_dir, id, reader)
+                        for reader in readers]
+
+    # Set $TERM = dumb
+    os.putenv("TERM", "dumb")
+
+    (shell_pid, shell_fd) = pty.fork()
+    if shell_pid == 0:
+        # Child process: run the command in a subshell
+        os.execv("/bin/sh", ["/bin/sh", "-c", command])
+    else:
+        # Parent process
+        lock_server_running = _lock(lock_server_running_filename)
+
+        # Set terminal echo on/off and disable pre- and post-processing
+        attr = termios.tcgetattr(shell_fd)
+        attr[0] &= ~termios.INLCR
+        attr[0] &= ~termios.ICRNL
+        attr[0] &= ~termios.IGNCR
+        attr[1] &= ~termios.OPOST
+        if echo:
+            attr[3] |= termios.ECHO
+        else:
+            attr[3] &= ~termios.ECHO
+        termios.tcsetattr(shell_fd, termios.TCSANOW, attr)
+
+        # Open output file
+        output_file = open(output_filename, "w")
+        # Open input pipe
+        os.mkfifo(inpipe_filename)
+        inpipe_fd = os.open(inpipe_filename, os.O_RDWR)
+        # Open output pipes (readers)
+        reader_fds = []
+        for filename in reader_filenames:
+            os.mkfifo(filename)
+            reader_fds.append(os.open(filename, os.O_RDWR))
+
+        # Write shell PID to file
+        file = open(shell_pid_filename, "w")
+        file.write(str(shell_pid))
+        file.close()
+
+        # Print something to stdout so the client can start working
+        print "Server %s ready" % id
+        sys.stdout.flush()
+
+        # Initialize buffers
+        buffers = ["" for reader in readers]
+
+        # Read from child and write to files/pipes
+        while True:
+            check_termination = False
+            # Make a list of reader pipes whose buffers are not empty
+            fds = [fd for (i, fd) in enumerate(reader_fds) if buffers[i]]
+            # Wait until there's something to do
+            r, w, x = select.select([shell_fd, inpipe_fd], fds, [], 0.5)
+            # If a reader pipe is ready for writing --
+            for (i, fd) in enumerate(reader_fds):
+                if fd in w:
+                    bytes_written = os.write(fd, buffers[i])
+                    buffers[i] = buffers[i][bytes_written:]
+            # If there's data to read from the child process --
+            if shell_fd in r:
+                try:
+                    data = os.read(shell_fd, 16384)
+                except OSError:
+                    data = ""
+                if not data:
+                    check_termination = True
+                # Remove carriage returns from the data -- they often cause
+                # trouble and are normally not needed
+                data = data.replace("\r", "")
+                output_file.write(data)
+                output_file.flush()
+                for i in range(len(readers)):
+                    buffers[i] += data
+            # If os.read() raised an exception or there was nothing to read --
+            if check_termination or shell_fd not in r:
+                pid, status = os.waitpid(shell_pid, os.WNOHANG)
+                if pid:
+                    status = os.WEXITSTATUS(status)
+                    break
+            # If there's data to read from the client --
+            if inpipe_fd in r:
+                data = os.read(inpipe_fd, 1024)
+                os.write(shell_fd, data)
+
+        # Write the exit status to a file
+        file = open(status_filename, "w")
+        file.write(str(status))
+        file.close()
+
+        # Wait for the client to finish initializing
+        _wait(lock_client_starting_filename)
+
+        # Delete FIFOs
+        for filename in reader_filenames + [inpipe_filename]:
+            try:
+                os.unlink(filename)
+            except OSError:
+                pass
+
+        # Close all files and pipes
+        output_file.close()
+        os.close(inpipe_fd)
+        for fd in reader_fds:
+            os.close(fd)
+
+        _unlock(lock_server_running)
+        exit(0)
+
+
+# The following is the client part of the module.
+
+import subprocess, time, signal, re, threading, logging
 import common, kvm_utils
 
 
@@ -77,49 +256,6 @@ def run_fg(command, output_func=None, output_prefix="", timeout=1.0):
     return (status, output)
 
 
-def _lock(filename):
-    if not os.path.exists(filename):
-        open(filename, "w").close()
-    fd = os.open(filename, os.O_RDWR)
-    fcntl.lockf(fd, fcntl.LOCK_EX)
-    return fd
-
-
-def _unlock(fd):
-    fcntl.lockf(fd, fcntl.LOCK_UN)
-    os.close(fd)
-
-
-def _locked(filename):
-    try:
-        fd = os.open(filename, os.O_RDWR)
-    except:
-        return False
-    try:
-        fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
-    except:
-        os.close(fd)
-        return True
-    fcntl.lockf(fd, fcntl.LOCK_UN)
-    os.close(fd)
-    return False
-
-
-def _wait(filename):
-    fd = _lock(filename)
-    _unlock(fd)
-
-
-def _get_filenames(base_dir, id):
-    return [os.path.join(base_dir, s + id) for s in
-            "shell-pid-", "status-", "output-", "inpipe-",
-            "lock-server-running-", "lock-client-starting-"]
-
-
-def _get_reader_filename(base_dir, id, reader):
-    return os.path.join(base_dir, "outpipe-%s-%s" % (reader, id))
-
-
 class kvm_spawn:
     """
     This class is used for spawning and controlling a child process.
@@ -1031,136 +1167,3 @@ class kvm_shell_session(kvm_expect):
                                                           internal_timeout,
                                                           print_func)
         return output
-
-
-# The following is the server part of the module.
-
-def _server_main():
-    id = sys.stdin.readline().strip()
-    echo = sys.stdin.readline().strip() == "True"
-    readers = sys.stdin.readline().strip().split(",")
-    command = sys.stdin.readline().strip() + " && echo %s > /dev/null" % id
-
-    # Define filenames to be used for communication
-    base_dir = "/tmp/kvm_spawn"
-    (shell_pid_filename,
-     status_filename,
-     output_filename,
-     inpipe_filename,
-     lock_server_running_filename,
-     lock_client_starting_filename) = _get_filenames(base_dir, id)
-
-    # Populate the reader filenames list
-    reader_filenames = [_get_reader_filename(base_dir, id, reader)
-                        for reader in readers]
-
-    # Set $TERM = dumb
-    os.putenv("TERM", "dumb")
-
-    (shell_pid, shell_fd) = pty.fork()
-    if shell_pid == 0:
-        # Child process: run the command in a subshell
-        os.execv("/bin/sh", ["/bin/sh", "-c", command])
-    else:
-        # Parent process
-        lock_server_running = _lock(lock_server_running_filename)
-
-        # Set terminal echo on/off and disable pre- and post-processing
-        attr = termios.tcgetattr(shell_fd)
-        attr[0] &= ~termios.INLCR
-        attr[0] &= ~termios.ICRNL
-        attr[0] &= ~termios.IGNCR
-        attr[1] &= ~termios.OPOST
-        if echo:
-            attr[3] |= termios.ECHO
-        else:
-            attr[3] &= ~termios.ECHO
-        termios.tcsetattr(shell_fd, termios.TCSANOW, attr)
-
-        # Open output file
-        output_file = open(output_filename, "w")
-        # Open input pipe
-        os.mkfifo(inpipe_filename)
-        inpipe_fd = os.open(inpipe_filename, os.O_RDWR)
-        # Open output pipes (readers)
-        reader_fds = []
-        for filename in reader_filenames:
-            os.mkfifo(filename)
-            reader_fds.append(os.open(filename, os.O_RDWR))
-
-        # Write shell PID to file
-        file = open(shell_pid_filename, "w")
-        file.write(str(shell_pid))
-        file.close()
-
-        # Print something to stdout so the client can start working
-        print "Server %s ready" % id
-        sys.stdout.flush()
-
-        # Initialize buffers
-        buffers = ["" for reader in readers]
-
-        # Read from child and write to files/pipes
-        while True:
-            check_termination = False
-            # Make a list of reader pipes whose buffers are not empty
-            fds = [fd for (i, fd) in enumerate(reader_fds) if buffers[i]]
-            # Wait until there's something to do
-            r, w, x = select.select([shell_fd, inpipe_fd], fds, [], 0.5)
-            # If a reader pipe is ready for writing --
-            for (i, fd) in enumerate(reader_fds):
-                if fd in w:
-                    bytes_written = os.write(fd, buffers[i])
-                    buffers[i] = buffers[i][bytes_written:]
-            # If there's data to read from the child process --
-            if shell_fd in r:
-                try:
-                    data = os.read(shell_fd, 16384)
-                except OSError:
-                    data = ""
-                if not data:
-                    check_termination = True
-                # Remove carriage returns from the data -- they often cause
-                # trouble and are normally not needed
-                data = data.replace("\r", "")
-                output_file.write(data)
-                output_file.flush()
-                for i in range(len(readers)):
-                    buffers[i] += data
-            # If os.read() raised an exception or there was nothing to read --
-            if check_termination or shell_fd not in r:
-                pid, status = os.waitpid(shell_pid, os.WNOHANG)
-                if pid:
-                    status = os.WEXITSTATUS(status)
-                    break
-            # If there's data to read from the client --
-            if inpipe_fd in r:
-                data = os.read(inpipe_fd, 1024)
-                os.write(shell_fd, data)
-
-        # Write the exit status to a file
-        file = open(status_filename, "w")
-        file.write(str(status))
-        file.close()
-
-        # Wait for the client to finish initializing
-        _wait(lock_client_starting_filename)
-
-        # Delete FIFOs
-        for filename in reader_filenames + [inpipe_filename]:
-            try:
-                os.unlink(filename)
-            except OSError:
-                pass
-
-        # Close all files and pipes
-        output_file.close()
-        os.close(inpipe_fd)
-        for fd in reader_fds:
-            os.close(fd)
-
-        _unlock(lock_server_running)
-
-
-if __name__ == "__main__":
-    _server_main()
-- 
1.5.4.1


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [Autotest] [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN
  2009-09-20 15:16 ` [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN Michael Goldish
  2009-09-20 15:16   ` [KVM-AUTOTEST PATCH 3/4] KVM test: WinXP-64-rss.steps: modify first barrier Michael Goldish
@ 2009-09-21  9:51   ` Yolkfull Chow
  1 sibling, 0 replies; 8+ messages in thread
From: Yolkfull Chow @ 2009-09-21  9:51 UTC (permalink / raw)
  To: Michael Goldish; +Cc: autotest, kvm

On Sun, Sep 20, 2009 at 06:16:28PM +0300, Michael Goldish wrote:
> Some Windows programs behave badly when their STDIN is redirected to a pipe
> (most notably wmic).  Therefore, keep STDIN unredirected, and send input to the
> console window as a series of WM_CHAR messages.

Hi Michael, I just tried this patch. After re-compiling and
installing RSS, seems never a command could be executed successfully or
returned with results. I tested this on Win2008-32. Any clue for 
fixing up it?

> 
> Signed-off-by: Michael Goldish <mgoldish@redhat.com>
> ---
>  client/tests/kvm/deps/rss.cpp |   54 +++++++++++++++++-----------------------
>  1 files changed, 23 insertions(+), 31 deletions(-)
> 
> diff --git a/client/tests/kvm/deps/rss.cpp b/client/tests/kvm/deps/rss.cpp
> index 73a849a..66d9a5b 100644
> --- a/client/tests/kvm/deps/rss.cpp
> +++ b/client/tests/kvm/deps/rss.cpp
> @@ -22,9 +22,9 @@ struct client_info {
>      SOCKET socket;
>      sockaddr_in addr;
>      int pid;
> +    HWND hwnd;
>      HANDLE hJob;
>      HANDLE hChildOutputRead;
> -    HANDLE hChildInputWrite;
>      HANDLE hThreadChildToSocket;
>  };
>  
> @@ -161,15 +161,10 @@ DWORD WINAPI SocketToChild(LPVOID client_info_ptr)
>          sprintf(message, "Client (%s) entered text: \"%s\"\r\n",
>                  client_info_str, formatted_buffer);
>          AppendMessage(message);
> -        // Write the data to the child's STDIN
> -        WriteFile(ci.hChildInputWrite, buffer, bytes_received,
> -                  &bytes_written, NULL);
> -        // Make sure all the data was written
> -        if (bytes_written != bytes_received) {
> -            sprintf(message,
> -                    "SocketToChild: bytes received (%d) != bytes written (%d)",
> -                    bytes_received, bytes_written);
> -            ExitOnError(message, 1);
> +        // Send the data as a series of WM_CHAR messages to the console window
> +        for (int i=0; i<bytes_received; i++) {
> +            SendMessage(ci.hwnd, WM_CHAR, (WPARAM)buffer[i], 0);
> +            SendMessage(ci.hwnd, WM_SETFOCUS, 0, 0);
>          }
>      }
>  
> @@ -194,7 +189,6 @@ DWORD WINAPI SocketToChild(LPVOID client_info_ptr)
>      CloseHandle(ci.hJob);
>      CloseHandle(ci.hThreadChildToSocket);
>      CloseHandle(ci.hChildOutputRead);
> -    CloseHandle(ci.hChildInputWrite);
>  
>      AppendMessage("SocketToChild thread exited\r\n");
>  
> @@ -203,18 +197,25 @@ DWORD WINAPI SocketToChild(LPVOID client_info_ptr)
>  
>  void PrepAndLaunchRedirectedChild(client_info *ci,
>                                    HANDLE hChildStdOut,
> -                                  HANDLE hChildStdIn,
>                                    HANDLE hChildStdErr)
>  {
>      PROCESS_INFORMATION pi;
>      STARTUPINFO si;
>  
> +    // Allocate a new console for the child
> +    HWND hwnd = GetForegroundWindow();
> +    FreeConsole();
> +    AllocConsole();
> +    ShowWindow(GetConsoleWindow(), SW_HIDE);
> +    if (hwnd)
> +        SetForegroundWindow(hwnd);
> +
>      // Set up the start up info struct.
>      ZeroMemory(&si, sizeof(STARTUPINFO));
>      si.cb = sizeof(STARTUPINFO);
>      si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
>      si.hStdOutput = hChildStdOut;
> -    si.hStdInput  = hChildStdIn;
> +    si.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
>      si.hStdError  = hChildStdErr;
>      // Use this if you want to hide the child:
>      si.wShowWindow = SW_HIDE;
> @@ -223,7 +224,7 @@ void PrepAndLaunchRedirectedChild(client_info *ci,
>  
>      // Launch the process that you want to redirect.
>      if (!CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE,
> -                       CREATE_NEW_CONSOLE, NULL, "C:\\", &si, &pi))
> +                       0, NULL, "C:\\", &si, &pi))
>          ExitOnError("CreateProcess failed");
>  
>      // Close any unnecessary handles.
> @@ -235,12 +236,16 @@ void PrepAndLaunchRedirectedChild(client_info *ci,
>      // Assign the process to a newly created JobObject
>      ci->hJob = CreateJobObject(NULL, NULL);
>      AssignProcessToJobObject(ci->hJob, pi.hProcess);
> +    // Keep the console window's handle
> +    ci->hwnd = GetConsoleWindow();
> +
> +    // Detach from the child's console
> +    FreeConsole();
>  }
>  
>  void SpawnSession(client_info *ci)
>  {
>      HANDLE hOutputReadTmp, hOutputRead, hOutputWrite;
> -    HANDLE hInputWriteTmp, hInputRead, hInputWrite;
>      HANDLE hErrorWrite;
>      SECURITY_ATTRIBUTES sa;
>  
> @@ -261,10 +266,6 @@ void SpawnSession(client_info *ci)
>                           TRUE, DUPLICATE_SAME_ACCESS))
>          ExitOnError("DuplicateHandle failed");
>  
> -    // Create the child input pipe.
> -    if (!CreatePipe(&hInputRead, &hInputWriteTmp, &sa, 0))
> -        ExitOnError("CreatePipe failed");
> -
>      // Create new output read handle and the input write handles. Set
>      // the Properties to FALSE. Otherwise, the child inherits the
>      // properties and, as a result, non-closeable handles to the pipes
> @@ -276,29 +277,20 @@ void SpawnSession(client_info *ci)
>                           DUPLICATE_SAME_ACCESS))
>          ExitOnError("DuplicateHandle failed");
>  
> -    if (!DuplicateHandle(GetCurrentProcess(), hInputWriteTmp,
> -                         GetCurrentProcess(),
> -                         &hInputWrite, // Address of new handle.
> -                         0, FALSE, // Make it uninheritable.
> -                         DUPLICATE_SAME_ACCESS))
> -        ExitOnError("DuplicateHandle failed");
> -
>      // Close inheritable copies of the handles you do not want to be
>      // inherited.
> -    if (!CloseHandle(hOutputReadTmp)) ExitOnError("CloseHandle failed");
> -    if (!CloseHandle(hInputWriteTmp)) ExitOnError("CloseHandle failed");
> +    if (!CloseHandle(hOutputReadTmp))
> +        ExitOnError("CloseHandle failed");
>  
> -    PrepAndLaunchRedirectedChild(ci, hOutputWrite, hInputRead, hErrorWrite);
> +    PrepAndLaunchRedirectedChild(ci, hOutputWrite, hErrorWrite);
>  
>      ci->hChildOutputRead = hOutputRead;
> -    ci->hChildInputWrite = hInputWrite;
>  
>      // Close pipe handles (do not continue to modify the parent).
>      // You need to make sure that no handles to the write end of the
>      // output pipe are maintained in this process or else the pipe will
>      // not close when the child process exits and the ReadFile will hang.
>      if (!CloseHandle(hOutputWrite)) ExitOnError("CloseHandle failed");
> -    if (!CloseHandle(hInputRead )) ExitOnError("CloseHandle failed");
>      if (!CloseHandle(hErrorWrite)) ExitOnError("CloseHandle failed");
>  }
>  
> -- 
> 1.5.4.1
> 
> _______________________________________________
> Autotest mailing list
> Autotest@test.kernel.org
> http://test.kernel.org/cgi-bin/mailman/listinfo/autotest

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Autotest] [KVM-AUTOTEST PATCH 1/4] KVM test: allow setting shell line separator string in the config file
  2009-09-20 15:16 [KVM-AUTOTEST PATCH 1/4] KVM test: allow setting shell line separator string in the config file Michael Goldish
  2009-09-20 15:16 ` [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN Michael Goldish
@ 2009-10-05 19:25 ` Lucas Meneghel Rodrigues
  1 sibling, 0 replies; 8+ messages in thread
From: Lucas Meneghel Rodrigues @ 2009-10-05 19:25 UTC (permalink / raw)
  To: Michael Goldish; +Cc: autotest, kvm

Patchset applied!

On Sun, Sep 20, 2009 at 12:16 PM, Michael Goldish <mgoldish@redhat.com> wrote:
> The shell line separator string is appended to strings sent by sendline().
>
> The string is controlled by the parameter shell_linesep.  It defaults to "\n".
>
> Signed-off-by: Michael Goldish <mgoldish@redhat.com>
> ---
>  client/tests/kvm/kvm_tests.cfg.sample |    1 +
>  client/tests/kvm/kvm_utils.py         |   12 ++++++------
>  client/tests/kvm/kvm_vm.py            |    7 ++++---
>  3 files changed, 11 insertions(+), 9 deletions(-)
>
> diff --git a/client/tests/kvm/kvm_tests.cfg.sample b/client/tests/kvm/kvm_tests.cfg.sample
> index 38f5a5a..540d0a2 100644
> --- a/client/tests/kvm/kvm_tests.cfg.sample
> +++ b/client/tests/kvm/kvm_tests.cfg.sample
> @@ -364,6 +364,7 @@ variants:
>         shell_prompt = "^\w:\\.*>\s*$"
>         username = Administrator
>         password = 123456
> +        shell_linesep = "\r\n"
>         shell_client = nc
>         shell_port = 22
>         # File transfers are currently unsupported
> diff --git a/client/tests/kvm/kvm_utils.py b/client/tests/kvm/kvm_utils.py
> index 88299be..53b664a 100644
> --- a/client/tests/kvm/kvm_utils.py
> +++ b/client/tests/kvm/kvm_utils.py
> @@ -576,7 +576,7 @@ def scp_from_remote(host, port, username, password, remote_path, local_path,
>     return remote_scp(command, password, timeout)
>
>
> -def ssh(host, port, username, password, prompt, timeout=10):
> +def ssh(host, port, username, password, prompt, linesep="\n", timeout=10):
>     """
>     Log into a remote host (guest) using SSH.
>
> @@ -591,10 +591,10 @@ def ssh(host, port, username, password, prompt, timeout=10):
>     """
>     command = ("ssh -o UserKnownHostsFile=/dev/null -p %s %s@%s" %
>                (port, username, host))
> -    return remote_login(command, password, prompt, "\n", timeout)
> +    return remote_login(command, password, prompt, linesep, timeout)
>
>
> -def telnet(host, port, username, password, prompt, timeout=10):
> +def telnet(host, port, username, password, prompt, linesep="\n", timeout=10):
>     """
>     Log into a remote host (guest) using Telnet.
>
> @@ -608,10 +608,10 @@ def telnet(host, port, username, password, prompt, timeout=10):
>     @return: kvm_spawn object on success and None on failure.
>     """
>     command = "telnet -l %s %s %s" % (username, host, port)
> -    return remote_login(command, password, prompt, "\r\n", timeout)
> +    return remote_login(command, password, prompt, linesep, timeout)
>
>
> -def netcat(host, port, username, password, prompt, timeout=10):
> +def netcat(host, port, username, password, prompt, linesep="\n", timeout=10):
>     """
>     Log into a remote host (guest) using Netcat.
>
> @@ -625,7 +625,7 @@ def netcat(host, port, username, password, prompt, timeout=10):
>     @return: kvm_spawn object on success and None on failure.
>     """
>     command = "nc %s %s" % (host, port)
> -    return remote_login(command, password, prompt, "\n", timeout)
> +    return remote_login(command, password, prompt, linesep, timeout)
>
>
>  # The following are utility functions related to ports.
> diff --git a/client/tests/kvm/kvm_vm.py b/client/tests/kvm/kvm_vm.py
> index 55220f9..07ceb6d 100755
> --- a/client/tests/kvm/kvm_vm.py
> +++ b/client/tests/kvm/kvm_vm.py
> @@ -669,6 +669,7 @@ class VM:
>         username = self.params.get("username", "")
>         password = self.params.get("password", "")
>         prompt = self.params.get("shell_prompt", "[\#\$]")
> +        linesep = eval("'%s'" % self.params.get("shell_linesep", r"\n"))
>         client = self.params.get("shell_client")
>         address = self.get_address(nic_index)
>         port = self.get_port(int(self.params.get("shell_port")))
> @@ -679,13 +680,13 @@ class VM:
>
>         if client == "ssh":
>             session = kvm_utils.ssh(address, port, username, password,
> -                                    prompt, timeout)
> +                                    prompt, linesep, timeout)
>         elif client == "telnet":
>             session = kvm_utils.telnet(address, port, username, password,
> -                                       prompt, timeout)
> +                                       prompt, linesep, timeout)
>         elif client == "nc":
>             session = kvm_utils.netcat(address, port, username, password,
> -                                       prompt, timeout)
> +                                       prompt, linesep, timeout)
>
>         if session:
>             session.set_status_test_command(self.params.get("status_test_"
> --
> 1.5.4.1
>
> _______________________________________________
> Autotest mailing list
> Autotest@test.kernel.org
> http://test.kernel.org/cgi-bin/mailman/listinfo/autotest
>



-- 
Lucas

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Autotest] [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN
  2009-09-21 12:30 ` [Autotest] [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN Michael Goldish
@ 2009-09-22  8:55   ` Yolkfull Chow
  0 siblings, 0 replies; 8+ messages in thread
From: Yolkfull Chow @ 2009-09-22  8:55 UTC (permalink / raw)
  To: Michael Goldish; +Cc: autotest, kvm

On Mon, Sep 21, 2009 at 08:30:26AM -0400, Michael Goldish wrote:
> 
> ----- "Yolkfull Chow" <yzhou@redhat.com> wrote:
> 
> > On Sun, Sep 20, 2009 at 06:16:28PM +0300, Michael Goldish wrote:
> > > Some Windows programs behave badly when their STDIN is redirected to
> > a pipe
> > > (most notably wmic).  Therefore, keep STDIN unredirected, and send
> > input to the
> > > console window as a series of WM_CHAR messages.
> > 
> > Hi Michael, I just tried this patch. After re-compiling and
> > installing RSS, seems never a command could be executed successfully
> > or
> > returned with results. I tested this on Win2008-32. Any clue for 
> > fixing up it?
> 
> Did you also apply the other patch --
> "allow setting shell line separator string in the config file"?

I did forget apply the second patch of that set. It now works and 'wmic'
works fine as well. Thank you very much for working this out.:-)

Cheers,

> 
> By default, when using nc, autotest ends commands with "\n".
> The modified rss.exe seems to require lines to end with "\r\n" (it's a
> common line separator in Windows).
> The patch I mentioned adds a "shell_linesep" parameter that controls
> the line separator and changes the line separator on Windows to "\r\n".
> 
> If you can't apply the patch (conflicts or whatever), go to kvm_utils.py,
> find the "netcat" function, and change this line:
> return remote_login(command, password, prompt, "\n", timeout)
> to this:
> return remote_login(command, password, prompt, "\r\n", timeout)
> 
> If it still doesn't work then we have a real problem and I'll have to
> start debugging stuff.
> 
> (Note: if you want to manually test rss.exe, use telnet instead of nc
> (e.g. telnet localhost 5000) because telnet ends lines with "\r\n".)
> 
> > > 
> > > Signed-off-by: Michael Goldish <mgoldish@redhat.com>
> > > ---
> > >  client/tests/kvm/deps/rss.cpp |   54
> > +++++++++++++++++-----------------------
> > >  1 files changed, 23 insertions(+), 31 deletions(-)
> > > 
> > > diff --git a/client/tests/kvm/deps/rss.cpp
> > b/client/tests/kvm/deps/rss.cpp
> > > index 73a849a..66d9a5b 100644
> > > --- a/client/tests/kvm/deps/rss.cpp
> > > +++ b/client/tests/kvm/deps/rss.cpp
> > > @@ -22,9 +22,9 @@ struct client_info {
> > >      SOCKET socket;
> > >      sockaddr_in addr;
> > >      int pid;
> > > +    HWND hwnd;
> > >      HANDLE hJob;
> > >      HANDLE hChildOutputRead;
> > > -    HANDLE hChildInputWrite;
> > >      HANDLE hThreadChildToSocket;
> > >  };
> > >  
> > > @@ -161,15 +161,10 @@ DWORD WINAPI SocketToChild(LPVOID
> > client_info_ptr)
> > >          sprintf(message, "Client (%s) entered text: \"%s\"\r\n",
> > >                  client_info_str, formatted_buffer);
> > >          AppendMessage(message);
> > > -        // Write the data to the child's STDIN
> > > -        WriteFile(ci.hChildInputWrite, buffer, bytes_received,
> > > -                  &bytes_written, NULL);
> > > -        // Make sure all the data was written
> > > -        if (bytes_written != bytes_received) {
> > > -            sprintf(message,
> > > -                    "SocketToChild: bytes received (%d) != bytes
> > written (%d)",
> > > -                    bytes_received, bytes_written);
> > > -            ExitOnError(message, 1);
> > > +        // Send the data as a series of WM_CHAR messages to the
> > console window
> > > +        for (int i=0; i<bytes_received; i++) {
> > > +            SendMessage(ci.hwnd, WM_CHAR, (WPARAM)buffer[i], 0);
> > > +            SendMessage(ci.hwnd, WM_SETFOCUS, 0, 0);
> > >          }
> > >      }
> > >  
> > > @@ -194,7 +189,6 @@ DWORD WINAPI SocketToChild(LPVOID
> > client_info_ptr)
> > >      CloseHandle(ci.hJob);
> > >      CloseHandle(ci.hThreadChildToSocket);
> > >      CloseHandle(ci.hChildOutputRead);
> > > -    CloseHandle(ci.hChildInputWrite);
> > >  
> > >      AppendMessage("SocketToChild thread exited\r\n");
> > >  
> > > @@ -203,18 +197,25 @@ DWORD WINAPI SocketToChild(LPVOID
> > client_info_ptr)
> > >  
> > >  void PrepAndLaunchRedirectedChild(client_info *ci,
> > >                                    HANDLE hChildStdOut,
> > > -                                  HANDLE hChildStdIn,
> > >                                    HANDLE hChildStdErr)
> > >  {
> > >      PROCESS_INFORMATION pi;
> > >      STARTUPINFO si;
> > >  
> > > +    // Allocate a new console for the child
> > > +    HWND hwnd = GetForegroundWindow();
> > > +    FreeConsole();
> > > +    AllocConsole();
> > > +    ShowWindow(GetConsoleWindow(), SW_HIDE);
> > > +    if (hwnd)
> > > +        SetForegroundWindow(hwnd);
> > > +
> > >      // Set up the start up info struct.
> > >      ZeroMemory(&si, sizeof(STARTUPINFO));
> > >      si.cb = sizeof(STARTUPINFO);
> > >      si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
> > >      si.hStdOutput = hChildStdOut;
> > > -    si.hStdInput  = hChildStdIn;
> > > +    si.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
> > >      si.hStdError  = hChildStdErr;
> > >      // Use this if you want to hide the child:
> > >      si.wShowWindow = SW_HIDE;
> > > @@ -223,7 +224,7 @@ void PrepAndLaunchRedirectedChild(client_info
> > *ci,
> > >  
> > >      // Launch the process that you want to redirect.
> > >      if (!CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE,
> > > -                       CREATE_NEW_CONSOLE, NULL, "C:\\", &si,
> > &pi))
> > > +                       0, NULL, "C:\\", &si, &pi))
> > >          ExitOnError("CreateProcess failed");
> > >  
> > >      // Close any unnecessary handles.
> > > @@ -235,12 +236,16 @@ void PrepAndLaunchRedirectedChild(client_info
> > *ci,
> > >      // Assign the process to a newly created JobObject
> > >      ci->hJob = CreateJobObject(NULL, NULL);
> > >      AssignProcessToJobObject(ci->hJob, pi.hProcess);
> > > +    // Keep the console window's handle
> > > +    ci->hwnd = GetConsoleWindow();
> > > +
> > > +    // Detach from the child's console
> > > +    FreeConsole();
> > >  }
> > >  
> > >  void SpawnSession(client_info *ci)
> > >  {
> > >      HANDLE hOutputReadTmp, hOutputRead, hOutputWrite;
> > > -    HANDLE hInputWriteTmp, hInputRead, hInputWrite;
> > >      HANDLE hErrorWrite;
> > >      SECURITY_ATTRIBUTES sa;
> > >  
> > > @@ -261,10 +266,6 @@ void SpawnSession(client_info *ci)
> > >                           TRUE, DUPLICATE_SAME_ACCESS))
> > >          ExitOnError("DuplicateHandle failed");
> > >  
> > > -    // Create the child input pipe.
> > > -    if (!CreatePipe(&hInputRead, &hInputWriteTmp, &sa, 0))
> > > -        ExitOnError("CreatePipe failed");
> > > -
> > >      // Create new output read handle and the input write handles.
> > Set
> > >      // the Properties to FALSE. Otherwise, the child inherits the
> > >      // properties and, as a result, non-closeable handles to the
> > pipes
> > > @@ -276,29 +277,20 @@ void SpawnSession(client_info *ci)
> > >                           DUPLICATE_SAME_ACCESS))
> > >          ExitOnError("DuplicateHandle failed");
> > >  
> > > -    if (!DuplicateHandle(GetCurrentProcess(), hInputWriteTmp,
> > > -                         GetCurrentProcess(),
> > > -                         &hInputWrite, // Address of new handle.
> > > -                         0, FALSE, // Make it uninheritable.
> > > -                         DUPLICATE_SAME_ACCESS))
> > > -        ExitOnError("DuplicateHandle failed");
> > > -
> > >      // Close inheritable copies of the handles you do not want to
> > be
> > >      // inherited.
> > > -    if (!CloseHandle(hOutputReadTmp)) ExitOnError("CloseHandle
> > failed");
> > > -    if (!CloseHandle(hInputWriteTmp)) ExitOnError("CloseHandle
> > failed");
> > > +    if (!CloseHandle(hOutputReadTmp))
> > > +        ExitOnError("CloseHandle failed");
> > >  
> > > -    PrepAndLaunchRedirectedChild(ci, hOutputWrite, hInputRead,
> > hErrorWrite);
> > > +    PrepAndLaunchRedirectedChild(ci, hOutputWrite, hErrorWrite);
> > >  
> > >      ci->hChildOutputRead = hOutputRead;
> > > -    ci->hChildInputWrite = hInputWrite;
> > >  
> > >      // Close pipe handles (do not continue to modify the parent).
> > >      // You need to make sure that no handles to the write end of
> > the
> > >      // output pipe are maintained in this process or else the pipe
> > will
> > >      // not close when the child process exits and the ReadFile will
> > hang.
> > >      if (!CloseHandle(hOutputWrite)) ExitOnError("CloseHandle
> > failed");
> > > -    if (!CloseHandle(hInputRead )) ExitOnError("CloseHandle
> > failed");
> > >      if (!CloseHandle(hErrorWrite)) ExitOnError("CloseHandle
> > failed");
> > >  }
> > >  
> > > -- 
> > > 1.5.4.1
> > > 
> > > _______________________________________________
> > > Autotest mailing list
> > > Autotest@test.kernel.org
> > > http://test.kernel.org/cgi-bin/mailman/listinfo/autotest
> --
> To unsubscribe from this list: send the line "unsubscribe kvm" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [Autotest] [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN
       [not found] <984972916.460261253536000782.JavaMail.root@zmail05.collab.prod.int.phx2.redhat.com>
@ 2009-09-21 12:30 ` Michael Goldish
  2009-09-22  8:55   ` Yolkfull Chow
  0 siblings, 1 reply; 8+ messages in thread
From: Michael Goldish @ 2009-09-21 12:30 UTC (permalink / raw)
  To: Yolkfull Chow; +Cc: autotest, kvm


----- "Yolkfull Chow" <yzhou@redhat.com> wrote:

> On Sun, Sep 20, 2009 at 06:16:28PM +0300, Michael Goldish wrote:
> > Some Windows programs behave badly when their STDIN is redirected to
> a pipe
> > (most notably wmic).  Therefore, keep STDIN unredirected, and send
> input to the
> > console window as a series of WM_CHAR messages.
> 
> Hi Michael, I just tried this patch. After re-compiling and
> installing RSS, seems never a command could be executed successfully
> or
> returned with results. I tested this on Win2008-32. Any clue for 
> fixing up it?

Did you also apply the other patch --
"allow setting shell line separator string in the config file"?

By default, when using nc, autotest ends commands with "\n".
The modified rss.exe seems to require lines to end with "\r\n" (it's a
common line separator in Windows).
The patch I mentioned adds a "shell_linesep" parameter that controls
the line separator and changes the line separator on Windows to "\r\n".

If you can't apply the patch (conflicts or whatever), go to kvm_utils.py,
find the "netcat" function, and change this line:
return remote_login(command, password, prompt, "\n", timeout)
to this:
return remote_login(command, password, prompt, "\r\n", timeout)

If it still doesn't work then we have a real problem and I'll have to
start debugging stuff.

(Note: if you want to manually test rss.exe, use telnet instead of nc
(e.g. telnet localhost 5000) because telnet ends lines with "\r\n".)

> > 
> > Signed-off-by: Michael Goldish <mgoldish@redhat.com>
> > ---
> >  client/tests/kvm/deps/rss.cpp |   54
> +++++++++++++++++-----------------------
> >  1 files changed, 23 insertions(+), 31 deletions(-)
> > 
> > diff --git a/client/tests/kvm/deps/rss.cpp
> b/client/tests/kvm/deps/rss.cpp
> > index 73a849a..66d9a5b 100644
> > --- a/client/tests/kvm/deps/rss.cpp
> > +++ b/client/tests/kvm/deps/rss.cpp
> > @@ -22,9 +22,9 @@ struct client_info {
> >      SOCKET socket;
> >      sockaddr_in addr;
> >      int pid;
> > +    HWND hwnd;
> >      HANDLE hJob;
> >      HANDLE hChildOutputRead;
> > -    HANDLE hChildInputWrite;
> >      HANDLE hThreadChildToSocket;
> >  };
> >  
> > @@ -161,15 +161,10 @@ DWORD WINAPI SocketToChild(LPVOID
> client_info_ptr)
> >          sprintf(message, "Client (%s) entered text: \"%s\"\r\n",
> >                  client_info_str, formatted_buffer);
> >          AppendMessage(message);
> > -        // Write the data to the child's STDIN
> > -        WriteFile(ci.hChildInputWrite, buffer, bytes_received,
> > -                  &bytes_written, NULL);
> > -        // Make sure all the data was written
> > -        if (bytes_written != bytes_received) {
> > -            sprintf(message,
> > -                    "SocketToChild: bytes received (%d) != bytes
> written (%d)",
> > -                    bytes_received, bytes_written);
> > -            ExitOnError(message, 1);
> > +        // Send the data as a series of WM_CHAR messages to the
> console window
> > +        for (int i=0; i<bytes_received; i++) {
> > +            SendMessage(ci.hwnd, WM_CHAR, (WPARAM)buffer[i], 0);
> > +            SendMessage(ci.hwnd, WM_SETFOCUS, 0, 0);
> >          }
> >      }
> >  
> > @@ -194,7 +189,6 @@ DWORD WINAPI SocketToChild(LPVOID
> client_info_ptr)
> >      CloseHandle(ci.hJob);
> >      CloseHandle(ci.hThreadChildToSocket);
> >      CloseHandle(ci.hChildOutputRead);
> > -    CloseHandle(ci.hChildInputWrite);
> >  
> >      AppendMessage("SocketToChild thread exited\r\n");
> >  
> > @@ -203,18 +197,25 @@ DWORD WINAPI SocketToChild(LPVOID
> client_info_ptr)
> >  
> >  void PrepAndLaunchRedirectedChild(client_info *ci,
> >                                    HANDLE hChildStdOut,
> > -                                  HANDLE hChildStdIn,
> >                                    HANDLE hChildStdErr)
> >  {
> >      PROCESS_INFORMATION pi;
> >      STARTUPINFO si;
> >  
> > +    // Allocate a new console for the child
> > +    HWND hwnd = GetForegroundWindow();
> > +    FreeConsole();
> > +    AllocConsole();
> > +    ShowWindow(GetConsoleWindow(), SW_HIDE);
> > +    if (hwnd)
> > +        SetForegroundWindow(hwnd);
> > +
> >      // Set up the start up info struct.
> >      ZeroMemory(&si, sizeof(STARTUPINFO));
> >      si.cb = sizeof(STARTUPINFO);
> >      si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
> >      si.hStdOutput = hChildStdOut;
> > -    si.hStdInput  = hChildStdIn;
> > +    si.hStdInput  = GetStdHandle(STD_INPUT_HANDLE);
> >      si.hStdError  = hChildStdErr;
> >      // Use this if you want to hide the child:
> >      si.wShowWindow = SW_HIDE;
> > @@ -223,7 +224,7 @@ void PrepAndLaunchRedirectedChild(client_info
> *ci,
> >  
> >      // Launch the process that you want to redirect.
> >      if (!CreateProcess(NULL, "cmd.exe", NULL, NULL, TRUE,
> > -                       CREATE_NEW_CONSOLE, NULL, "C:\\", &si,
> &pi))
> > +                       0, NULL, "C:\\", &si, &pi))
> >          ExitOnError("CreateProcess failed");
> >  
> >      // Close any unnecessary handles.
> > @@ -235,12 +236,16 @@ void PrepAndLaunchRedirectedChild(client_info
> *ci,
> >      // Assign the process to a newly created JobObject
> >      ci->hJob = CreateJobObject(NULL, NULL);
> >      AssignProcessToJobObject(ci->hJob, pi.hProcess);
> > +    // Keep the console window's handle
> > +    ci->hwnd = GetConsoleWindow();
> > +
> > +    // Detach from the child's console
> > +    FreeConsole();
> >  }
> >  
> >  void SpawnSession(client_info *ci)
> >  {
> >      HANDLE hOutputReadTmp, hOutputRead, hOutputWrite;
> > -    HANDLE hInputWriteTmp, hInputRead, hInputWrite;
> >      HANDLE hErrorWrite;
> >      SECURITY_ATTRIBUTES sa;
> >  
> > @@ -261,10 +266,6 @@ void SpawnSession(client_info *ci)
> >                           TRUE, DUPLICATE_SAME_ACCESS))
> >          ExitOnError("DuplicateHandle failed");
> >  
> > -    // Create the child input pipe.
> > -    if (!CreatePipe(&hInputRead, &hInputWriteTmp, &sa, 0))
> > -        ExitOnError("CreatePipe failed");
> > -
> >      // Create new output read handle and the input write handles.
> Set
> >      // the Properties to FALSE. Otherwise, the child inherits the
> >      // properties and, as a result, non-closeable handles to the
> pipes
> > @@ -276,29 +277,20 @@ void SpawnSession(client_info *ci)
> >                           DUPLICATE_SAME_ACCESS))
> >          ExitOnError("DuplicateHandle failed");
> >  
> > -    if (!DuplicateHandle(GetCurrentProcess(), hInputWriteTmp,
> > -                         GetCurrentProcess(),
> > -                         &hInputWrite, // Address of new handle.
> > -                         0, FALSE, // Make it uninheritable.
> > -                         DUPLICATE_SAME_ACCESS))
> > -        ExitOnError("DuplicateHandle failed");
> > -
> >      // Close inheritable copies of the handles you do not want to
> be
> >      // inherited.
> > -    if (!CloseHandle(hOutputReadTmp)) ExitOnError("CloseHandle
> failed");
> > -    if (!CloseHandle(hInputWriteTmp)) ExitOnError("CloseHandle
> failed");
> > +    if (!CloseHandle(hOutputReadTmp))
> > +        ExitOnError("CloseHandle failed");
> >  
> > -    PrepAndLaunchRedirectedChild(ci, hOutputWrite, hInputRead,
> hErrorWrite);
> > +    PrepAndLaunchRedirectedChild(ci, hOutputWrite, hErrorWrite);
> >  
> >      ci->hChildOutputRead = hOutputRead;
> > -    ci->hChildInputWrite = hInputWrite;
> >  
> >      // Close pipe handles (do not continue to modify the parent).
> >      // You need to make sure that no handles to the write end of
> the
> >      // output pipe are maintained in this process or else the pipe
> will
> >      // not close when the child process exits and the ReadFile will
> hang.
> >      if (!CloseHandle(hOutputWrite)) ExitOnError("CloseHandle
> failed");
> > -    if (!CloseHandle(hInputRead )) ExitOnError("CloseHandle
> failed");
> >      if (!CloseHandle(hErrorWrite)) ExitOnError("CloseHandle
> failed");
> >  }
> >  
> > -- 
> > 1.5.4.1
> > 
> > _______________________________________________
> > Autotest mailing list
> > Autotest@test.kernel.org
> > http://test.kernel.org/cgi-bin/mailman/listinfo/autotest

^ permalink raw reply	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2009-10-05 19:26 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-09-20 15:16 [KVM-AUTOTEST PATCH 1/4] KVM test: allow setting shell line separator string in the config file Michael Goldish
2009-09-20 15:16 ` [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN Michael Goldish
2009-09-20 15:16   ` [KVM-AUTOTEST PATCH 3/4] KVM test: WinXP-64-rss.steps: modify first barrier Michael Goldish
2009-09-20 15:16     ` [KVM-AUTOTEST PATCH 4/4] KVM test: kvm_subprocess: minimize the number of modules imported by the server Michael Goldish
2009-09-21  9:51   ` [Autotest] [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN Yolkfull Chow
2009-10-05 19:25 ` [Autotest] [KVM-AUTOTEST PATCH 1/4] KVM test: allow setting shell line separator string in the config file Lucas Meneghel Rodrigues
     [not found] <984972916.460261253536000782.JavaMail.root@zmail05.collab.prod.int.phx2.redhat.com>
2009-09-21 12:30 ` [Autotest] [KVM-AUTOTEST PATCH 2/4] KVM test: rss.cpp: send characters to the console window rather than directly to STDIN Michael Goldish
2009-09-22  8:55   ` Yolkfull Chow

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).