From: Tom Yu Date: Mon, 12 Dec 2011 20:46:24 +0000 (+0000) Subject: kfw leash: add -console option to create console for debug output X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=5fa98cdabb89a772e138c9e68b475f33458c8ef0;p=krb5.git kfw leash: add -console option to create console for debug output Signed-off-by: Kevin Wasserman ticket: 7050 git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25570 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/windows/leash/Leash.cpp b/src/windows/leash/Leash.cpp index 88ee7356a..1f12e913e 100644 --- a/src/windows/leash/Leash.cpp +++ b/src/windows/leash/Leash.cpp @@ -26,6 +26,7 @@ #include "mitwhich.h" #include #include "lglobals.h" +#include "out2con.h" #include #include @@ -305,6 +306,11 @@ BOOL CLeashApp::InitInstance() { autoInit = TRUE; } + else if (0 == stricmp(optionParam+1, "console") || + 0 == stricmp(optionParam+1, "c")) + { + CreateConsoleEcho(); + } else { MessageBox(hMsg, @@ -312,6 +318,7 @@ BOOL CLeashApp::InitInstance() "'-renew' or '-r' to perform ticket renewal (and exit)\n" "'-destroy' or '-d' to perform ticket destruction (and exit)\n" "'-autoinit' or '-a' to perform automatic ticket initialization\n" + "'-console' or '-c' to attach a console for debugging\n" "'-ms2mit' or '-import' or '-m' to perform ticket importation (and exit)", "Leash Error", MB_OK); return FALSE; diff --git a/src/windows/leash/Makefile.in b/src/windows/leash/Makefile.in index 1edf6b45e..997f2259b 100644 --- a/src/windows/leash/Makefile.in +++ b/src/windows/leash/Makefile.in @@ -45,6 +45,7 @@ OBJS= \ $(OUTPRE)LeashView.obj \ $(OUTPRE)lglobals.obj \ $(OUTPRE)MainFrm.obj \ + $(OUTPRE)out2con.obj \ $(OUTPRE)StdAfx.obj \ $(OUTPRE)AfsProperties.obj \ $(OUTPRE)VSroutines.obj \ diff --git a/src/windows/leash/out2con.cpp b/src/windows/leash/out2con.cpp new file mode 100644 index 000000000..f7a1d35a9 --- /dev/null +++ b/src/windows/leash/out2con.cpp @@ -0,0 +1,126 @@ +#include "out2con.h" + +#include +#include +#include + +class ConsoleEcho +{ +public: + ConsoleEcho(); + ~ConsoleEcho(); + +private: + DWORD ThreadLoop(); + + static DWORD WINAPI ThreadFunc(void* param); + + FILE m_originalStdout; + int m_stdoutfd; + int m_pipefd; + HANDLE m_hReadPipe, m_hWritePipe; + HANDLE m_hThread; + + static const int BUFSIZE=512; +}; + + +ConsoleEcho * +CreateConsoleEcho() +{ + return new ConsoleEcho; +} + +void +DestroyConsoleEcho(ConsoleEcho *echo) +{ + delete echo; +} + + +DWORD WINAPI ConsoleEcho::ThreadFunc(void* param) +{ + return ((ConsoleEcho*)(param))->ThreadLoop(); +} + + +DWORD ConsoleEcho::ThreadLoop() +{ + DWORD dwRead, dwWritten; + CHAR chBuf[BUFSIZE]; + BOOL bSuccess = FALSE; + // Note that the following does not work when running in the msvc2010 + // debugger with redirected output; you still get the redirected file + // handle, not the console: + //HANDLE hConsoleStdOut = GetStdHandle(STD_OUTPUT_HANDLE); + // This seems to be more reliable: + HANDLE hConsoleStdOut = CreateFile("CONOUT$", + GENERIC_WRITE, + FILE_SHARE_WRITE, + NULL, OPEN_EXISTING, 0, 0); + for (;;) { + // read from redirected stdout + bSuccess = ReadFile(m_hReadPipe, chBuf, BUFSIZE, &dwRead, NULL); + if (!bSuccess || (dwRead == 0)) + break; + + // write to console + WriteFile(hConsoleStdOut, chBuf, dwRead, &dwWritten, NULL); + // also write to original stdout + if (m_stdoutfd>=0) { + _write(m_stdoutfd, chBuf, dwRead); + // _commit() causes assert if m_stdoutfd is a device (e.g., console or NUL). + if (!_isatty(m_stdoutfd)) + _commit(m_stdoutfd); + } + } + CloseHandle(hConsoleStdOut); + return 0; +} + +ConsoleEcho::ConsoleEcho() +{ + // setup console + AllocConsole(); + // create pipe + CreatePipe(&m_hReadPipe, &m_hWritePipe, NULL, 0); + // save original stdout to preserve commandline-specified redirection + m_stdoutfd = _fileno(stdout); + // and copy the whole damn FILE structure so we can restore it + // when we're done. I don't know any other way to restore the + // crazy windows gui default '-2' filedesc stdout. + m_originalStdout = *stdout; + // hook up the write end of our pipe to stdout + m_pipefd = _open_osfhandle((intptr_t)m_hWritePipe, 0); + // take our os file handle and allocate a crt FILE for it + FILE* fp = _fdopen(m_pipefd, "w"); + // copy to stdout + *stdout = *fp; + // now slam the allocated FILE's _flag to zero to mark it as free without + // actually closing the os file handle and pipe + fp->_flag = 0; + + // disable buffering + setvbuf(stdout, NULL, _IONBF, 0); + + // Create a thread to process our pipe, forwarding output + // to both the console and the original stdout + m_hThread = CreateThread(NULL, 0, &ThreadFunc, this, 0, NULL); +} + +ConsoleEcho::~ConsoleEcho() +{ + // fclose() unfortunately immediately invalidates the read pipe before the + // pipe thread has a chance to flush it, so don't do that. + //fclose(stdout); + + // instead, just slam the original stdout + *stdout = m_originalStdout; + //printf("Safe to printf now and no longer echoed to console.\n"); + // Close write pipe + _close(m_pipefd); + // and wait here for pipe thread to exit + WaitForSingleObject(m_hThread, 1000); + // now close read pipe as well + CloseHandle(m_hReadPipe); +} diff --git a/src/windows/leash/out2con.h b/src/windows/leash/out2con.h new file mode 100644 index 000000000..ebd3859d3 --- /dev/null +++ b/src/windows/leash/out2con.h @@ -0,0 +1,38 @@ +#ifndef OUT2CON_H +#define OUT2CON_H + +/* Call CreateConsoleEcho() to create a console and begin echoing stdout to it. + * The original stream (if any) will still receive output from stdout. + * Call DestroyConsoleEcho() to stop echoing stdout to the console. + * The original stream continues to receive stdout. + * + * WARNING: it is not safe to use stdout from another thread during + * CreateConsoleEcho() or DestroyConsoleEcho() + */ + +class ConsoleEcho; + +ConsoleEcho * +CreateConsoleEcho(); + +void +DestroyConsoleEcho(ConsoleEcho *consoleEcho); + +// Convenience class to automatically echo to console within a scope +class AutoConsoleEcho +{ +public: + AutoConsoleEcho() : m_echo(CreateConsoleEcho()) + { + } + + ~AutoConsoleEcho() + { + DestroyConsoleEcho(m_echo); + } +private: + ConsoleEcho* m_echo; +}; + + +#endif