From 166fa7717608a7a72de4eb1855e9c667b34f0024 Mon Sep 17 00:00:00 2001 From: Daniel Reimer Date: Wed, 27 Jan 2010 19:03:52 +0000 Subject: [PATCH] Update log2lines to Version 1.11 (Jan Roeloffzen) Bug 4342 - Added -P Pipeline option for Powershell support, see below - Renaming some structs to avoid potential naming conflicts with windows.h - stdin/out -> stdIn/Out for redirecting - Fixed potential mem leak - A little more tracing and cleanup Updated piperead (Jan Roeloffzen) Bug 5146 - Added Pipe client function, based on msdn example - Improved option handling (try piperead -h) - logging, error handling - Integrated in build (pipetools.mak) svn path=/trunk/; revision=45287 --- reactos/tools/pipetools/piperead.cpp | 164 ++++++++++++++++++++++---- reactos/tools/pipetools/pipetools.mak | 47 ++++++++ reactos/tools/rsym/log2lines.c | 104 +++++++++++----- reactos/tools/tools.mak | 1 + 4 files changed, 267 insertions(+), 49 deletions(-) create mode 100644 reactos/tools/pipetools/pipetools.mak diff --git a/reactos/tools/pipetools/piperead.cpp b/reactos/tools/pipetools/piperead.cpp index bac9e0eb6fb..a7db908bcf9 100644 --- a/reactos/tools/pipetools/piperead.cpp +++ b/reactos/tools/pipetools/piperead.cpp @@ -2,13 +2,10 @@ // piperead.cpp // // Martin Fuchs, 30.11.2003 -// - -// -// Invoke as: "piperead [pipe_name]", -// for example: "piperead com_1" -// - +// +// Jan Roeloffzen, 26.1.2010 +// Pipe client, based on msdn example + #define WIN32_LEAN_AND_MEAN #include @@ -21,24 +18,15 @@ #endif +#define BUFSIZE 1024 + static void print_error(DWORD win32_error) { fprintf(stderr, "WIN32 error %lu\n", win32_error); } - -int main(int argc, char** argv) +static int pipeServer(char *path) { - char path[MAX_PATH]; - const char* pipe_name; - - if (argc > 1) - pipe_name = *++argv; - else - pipe_name = "com_1"; - - sprintf(path, "\\\\.\\pipe\\%s", pipe_name); - HANDLE hPipe = CreateNamedPipe(path, PIPE_ACCESS_DUPLEX|FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_WAIT|PIPE_TYPE_BYTE, 1, 4096, 4096, 30000, NULL); if (hPipe == INVALID_HANDLE_VALUE) { @@ -48,23 +36,26 @@ int main(int argc, char** argv) for(;;) { DWORD read; - BYTE buffer[1024]; + BYTE buffer[BUFSIZE]; if (!ReadFile(hPipe, buffer, sizeof(buffer), &read, NULL)) { DWORD error = GetLastError(); - if (error == ERROR_PIPE_LISTENING) + if (error == ERROR_PIPE_LISTENING) { + fprintf(stderr,"INVALID_HANDLE_VALUE\n"); Sleep(1000); - else if (error == ERROR_BROKEN_PIPE) { + } else if (error == ERROR_BROKEN_PIPE) { CloseHandle(hPipe); hPipe = CreateNamedPipe(path, PIPE_ACCESS_DUPLEX|FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_WAIT|PIPE_TYPE_BYTE, 1, 4096, 4096, 30000, NULL); if (hPipe == INVALID_HANDLE_VALUE) { + fprintf(stderr,"INVALID_HANDLE_VALUE\n"); print_error(GetLastError()); return 1; } } else { + fprintf(stderr,"error %lu\n",error); print_error(error); break; } @@ -79,3 +70,132 @@ int main(int argc, char** argv) return 0; } + +static int pipeClient(char *path) +{ + HANDLE hPipe=INVALID_HANDLE_VALUE; + TCHAR chBuf[BUFSIZE]; + BOOL fSuccess = FALSE; + DWORD cbRead; + DWORD Err; + int res = 0; + + setvbuf(stdout, NULL, _IONBF, 0); + while (1) { + hPipe = CreateFile( + path, // pipe name + GENERIC_READ, + 0, // no sharing + NULL, // default security attributes + OPEN_EXISTING, // opens existing pipe + 0, // default attributes + NULL); // no template file + + // Break if the pipe handle is valid. + if (hPipe != INVALID_HANDLE_VALUE) + break; + + // Exit if an error other than ERROR_PIPE_BUSY occurs. + if (GetLastError() != ERROR_PIPE_BUSY) { + fprintf(stderr,"Could not open pipe. Error=%lu\n", GetLastError() ); + res = -1; + break; + } + + // All pipe instances are busy, so wait for 20 seconds. + if ( ! WaitNamedPipe(path, 20000)) { + fprintf(stderr,"Could not open pipe: 20 second wait timed out."); + res = -2; + break; + } + } + + if (!res) do { + fSuccess = ReadFile( + hPipe, // pipe handle + chBuf, // buffer to receive reply + BUFSIZE, // size of buffer + &cbRead, // number of bytes read + NULL); // not overlapped + + if ( ! fSuccess ) { + Err = GetLastError(); + if ( Err == ERROR_MORE_DATA ) { + fSuccess = TRUE; + } else { + fprintf(stderr, "ReadFile: Error %lu \n", Err ); + res = -9; + break; + } + } + + fwrite(chBuf,1,cbRead,stdout); + } while ( fSuccess); + + if ( ! fSuccess) { + fprintf(stderr, "ReadFile from pipe failed. Error=%lu\n", GetLastError() ); + res = -5; + } + + if (hPipe != INVALID_HANDLE_VALUE) + CloseHandle(hPipe); + + return res; + +} + +void usage(void) +{ + fprintf(stderr, "Usage: piperead [-c] \n"); + fprintf(stderr, "-c means Client mode\n"); + fprintf(stderr, "Example: piperead -c \\\\.\\pipe\\kdbg | log2lines -c\n\n"); +} + +int main(int argc, char** argv) +{ + char path[MAX_PATH]; + const char* pipe_name; + const char* clientMode; + int res = 0; + + pipe_name = "com_1"; + clientMode = NULL; + switch (argc) { + case 3: + clientMode = *++argv; + if (strcmp(clientMode,"-c") != 0) { + clientMode = NULL; + fprintf(stderr,"Invalid option: %s\n", clientMode); + res = -6; + } + //fall through + case 2: + pipe_name = *++argv; + if (strcmp(pipe_name,"-h") == 0) { + res = -7; + } + break; + default: + res = -8; + break; + } + if (res) { + usage(); + return res; + } + + if ( pipe_name[0] == '\\' ) { + //assume caller specified full path + sprintf(path, "%s", pipe_name); + } else { + sprintf(path, "\\\\.\\pipe\\%s", pipe_name); + } + + if ( clientMode ) { + res = pipeClient(path); + } else { + res = pipeServer(path); + } + + return res; +} diff --git a/reactos/tools/pipetools/pipetools.mak b/reactos/tools/pipetools/pipetools.mak new file mode 100644 index 00000000000..22eca3d6cbf --- /dev/null +++ b/reactos/tools/pipetools/pipetools.mak @@ -0,0 +1,47 @@ +PIPETOOLS_BASE = $(TOOLS_BASE)$(SEP)pipetools +PIPETOOLS_BASE_ = $(PIPETOOLS_BASE)$(SEP) +PIPETOOLS_INT = $(INTERMEDIATE_)$(PIPETOOLS_BASE) +PIPETOOLS_INT_ = $(PIPETOOLS_INT)$(SEP) +PIPETOOLS_OUT = $(OUTPUT_)$(PIPETOOLS_BASE) +PIPETOOLS_OUT_ = $(PIPETOOLS_OUT)$(SEP) + +$(PIPETOOLS_INT): | $(TOOLS_INT) + $(ECHO_MKDIR) + ${mkdir} $@ + +ifneq ($(INTERMEDIATE),$(OUTPUT)) +$(PIPETOOLS_OUT): | $(TOOLS_OUT) + $(ECHO_MKDIR) + ${mkdir} $@ +endif + + +PIPETOOLS_TARGET = \ + $(PIPETOOLS_OUT_)piperead$(EXEPOSTFIX) + +PIPETOOLS_SOURCES = \ + $(PIPETOOLS_BASE_)piperead.cpp + +PIPETOOLS_OBJECTS = \ + $(addprefix $(INTERMEDIATE_), $(PIPETOOLS_SOURCES:.cpp=.o)) + +PIPETOOLS_HOST_CFLAGS = $(TOOLS_CFLAGS) + +PIPETOOLS_HOST_LFLAGS = $(TOOLS_LFLAGS) + +.PHONY: pipetools +pipetools: $(PIPETOOLS_TARGET) + +$(PIPETOOLS_TARGET): $(PIPETOOLS_OBJECTS) | $(PIPETOOLS_OUT) + $(ECHO_HOSTLD) + ${host_gcc} $(PIPETOOLS_OBJECTS) $(PIPETOOLS_HOST_LFLAGS) -o $@ + +$(PIPETOOLS_INT_)piperead.o: $(PIPETOOLS_BASE_)piperead.cpp | $(PIPETOOLS_INT) + $(ECHO_HOSTCC) + ${host_gcc} $(PIPETOOLS_HOST_CFLAGS) -c $< -o $@ + + +.PHONY: pipetools_clean +pipetools_clean: + -@$(rm) $(PIPETOOLS_TARGET) $(PIPETOOLS_OBJECTS) 2>$(NUL) +clean: pipetools_clean diff --git a/reactos/tools/rsym/log2lines.c b/reactos/tools/rsym/log2lines.c index cf1899bde9b..2d8988ee04b 100644 --- a/reactos/tools/rsym/log2lines.c +++ b/reactos/tools/rsym/log2lines.c @@ -11,7 +11,7 @@ #include "rsym.h" -#define LOG2LINES_VERSION "1.9" +#define LOG2LINES_VERSION "1.11" /* Assume if an offset > ABS_TRESHOLD, then it must be absolute */ #define ABS_TRESHOLD 0x00400000L @@ -27,6 +27,8 @@ #define CACHEFILE "log2lines.cache" #define TRKBUILDPREFIX "bootcd-" #define SVN_PREFIX "/trunk/reactos/" +#define KDBG_PROMPT "kdbg>" +#define PIPEREAD_CMD "piperead -c" #if defined (__DJGPP__) || defined (__WIN32__) @@ -96,13 +98,13 @@ struct entry_struct struct entry_struct *pnext; }; -typedef struct entry_struct LIST_ENTRY; +typedef struct entry_struct LIST_MEMBER; struct list_struct { off_t st_size; - LIST_ENTRY *phead; - LIST_ENTRY *ptail; + LIST_MEMBER *phead; + LIST_MEMBER *ptail; }; struct summ_struct @@ -149,7 +151,7 @@ static SUMM summ; static LINEINFO lastLine; static REVINFO revinfo; -static char *optchars = "bcd:fFhl:mMrR:sS:tTuUvz:"; +static char *optchars = "bcd:fFhl:mMP:rR:sS:tTuUvz:"; static int opt_buffered = 0; // -b static int opt_help = 0; // -h static int opt_force = 0; // -f @@ -158,6 +160,7 @@ static int opt_verbose = 0; // -v static int opt_console = 0; // -c static int opt_mark = 0; // -m static int opt_Mark = 0; // -M +static char *opt_Pipe = NULL; // -P static int opt_raw = 0; // -r static int opt_stats = 0; // -s static int opt_Source = 0; // -S [+][,] @@ -172,6 +175,8 @@ static char opt_logFile[MAX_PATH]; // -l static char opt_7z[MAX_PATH]; // -z static char opt_scanned[LINESIZE]; // all scanned options static FILE *logFile = NULL; +static FILE *stdIn = NULL; +static FILE *stdOut = NULL; static char *cache_name; static char *tmp_name; @@ -220,6 +225,7 @@ mkPath(char *path, int isDir) return res; } +#if 0 static FILE * rfopen(char *path, char *mode) { @@ -232,12 +238,13 @@ rfopen(char *path, char *mode) f = fopen(tmppath, mode); return f; } +#endif -static LIST_ENTRY * +static LIST_MEMBER * entry_lookup(LIST *list, char *name) { - LIST_ENTRY *pprev = NULL; - LIST_ENTRY *pnext; + LIST_MEMBER *pprev = NULL; + LIST_MEMBER *pnext; if (!name || !name[0]) return NULL; @@ -261,8 +268,8 @@ entry_lookup(LIST *list, char *name) return NULL; } -static LIST_ENTRY * -entry_delete(LIST_ENTRY *pentry) +static LIST_MEMBER * +entry_delete(LIST_MEMBER *pentry) { if (!pentry) return NULL; @@ -272,8 +279,8 @@ entry_delete(LIST_ENTRY *pentry) return NULL; } -static LIST_ENTRY * -entry_insert(LIST *list, LIST_ENTRY *pentry) +static LIST_MEMBER * +entry_insert(LIST *list, LIST_MEMBER *pentry) { if (!pentry) return NULL; @@ -286,10 +293,10 @@ entry_insert(LIST *list, LIST_ENTRY *pentry) } #if 0 -static LIST_ENTRY * -entry_remove(LIST *list, LIST_ENTRY *pentry) +static LIST_MEMBER * +entry_remove(LIST *list, LIST_MEMBER *pentry) { - LIST_ENTRY *pprev = NULL, *p = NULL; + LIST_MEMBER *pprev = NULL, *p = NULL; if (!pentry) return NULL; @@ -320,17 +327,17 @@ entry_remove(LIST *list, LIST_ENTRY *pentry) } #endif -static LIST_ENTRY * +static LIST_MEMBER * cache_entry_create(char *Line) { - LIST_ENTRY *pentry; + LIST_MEMBER *pentry; char *s = NULL; int l; if (!Line) return NULL; - pentry = malloc(sizeof(LIST_ENTRY)); + pentry = malloc(sizeof(LIST_MEMBER)); if (!pentry) return NULL; @@ -372,10 +379,10 @@ cache_entry_create(char *Line) } -static LIST_ENTRY * +static LIST_MEMBER * sources_entry_create(LIST *list, char *path, char *prefix) { - LIST_ENTRY *pentry; + LIST_MEMBER *pentry; char *s = NULL; int l; @@ -384,7 +391,7 @@ sources_entry_create(LIST *list, char *path, char *prefix) if (!prefix) prefix = ""; - pentry = malloc(sizeof(LIST_ENTRY)); + pentry = malloc(sizeof(LIST_MEMBER)); if (!pentry) return NULL; @@ -988,7 +995,7 @@ static int read_cache(void) { FILE *fr; - LIST_ENTRY *pentry; + LIST_MEMBER *pentry; char *Line = NULL; int result = 0; @@ -1117,7 +1124,7 @@ static int translate_file(const char *cpath, size_t offset, char *toString) { size_t base = 0; - LIST_ENTRY *pentry = NULL; + LIST_MEMBER *pentry = NULL; int res = 0; char *path, *dpath; @@ -1552,6 +1559,11 @@ static char *verboseUsage = " -m Prefix (mark) each translated line with '* '.\n\n" " -M Prefix (mark) each NOT translated line with '? '.\n" " ( Only for lines of the form: )\n\n" +" -P \n" +" Pipeline command line. Spawn and pipeline its output to\n" +" log2lines (as stdin). This is for shells lacking support of (one of):\n" +" - Input file redirection.\n" +" - Pipelining byte streams, needed for the -c option.\n\n" " -r Raw output without translation.\n\n" " -R \n" " Revision commands interfacing with SVN. is one of:\n" @@ -1632,6 +1644,8 @@ static char *verboseUsage = " log2lines -c < \\\\.\\pipe\\kdbg\n\n" " Use kdbg debugger via console, and append copy to logFile:\n" " log2lines -c -l dbg.log < \\\\.\\pipe\\kdbg\n\n" +" Same as above, but for PowerShell:\n" +" log2lines -c -l dbg.log -P \"piperead -c \\\\.\\pipe\\kdbg\"\n\n" " Use kdbg debugger to send output to logfile:\n" " log2lines < \\\\.\\pipe\\kdbg > dbg.log\n\n" " Re-translate a debug log:\n" @@ -1868,6 +1882,8 @@ main(int argc, const char **argv) int i; char *s; + stdIn = stdin; + stdOut = stdout; strcpy(opt_dir, ""); strcpy(sources_path, ""); if ((s = getenv(SOURCES_ENV))) @@ -1876,9 +1892,20 @@ main(int argc, const char **argv) strcpy(opt_scanned, ""); for (i = 1; i < argc; i++) { + if (strcmp(argv[i],"-P")==0) + { + //Because its argument can contain spaces we cant use getopt(), a known bug: + if (i+1 < argc) + { + free(opt_Pipe); + opt_Pipe = malloc(LINESIZE); + strcpy(opt_Pipe, argv[i+1]); + } + } strcat(opt_scanned, argv[i]); strcat(opt_scanned, " "); } + l2l_dbg(4,"opt_scanned=[%s]\n",opt_scanned); strcpy(opt_logFile, ""); strcpy(opt_7z, CMD_7Z); @@ -1927,8 +1954,13 @@ main(int argc, const char **argv) case 'r': opt_raw++; break; + case 'P': + optCount++; + //just count, see above + break; case 'R': optCount++; + free(opt_Revision); opt_Revision = malloc(LINESIZE); sscanf(optarg, "%s", opt_Revision); break; @@ -2001,8 +2033,7 @@ main(int argc, const char **argv) return 0; read_cache(); - - l2l_dbg(3, "Cache read complete\n"); + l2l_dbg(4, "Cache read complete\n"); if (*opt_logFile) { @@ -2024,6 +2055,22 @@ main(int argc, const char **argv) return 2; } } + l2l_dbg(4, "opt_logFile processed\n"); + + if (opt_Pipe) + { + l2l_dbg(3, "Command line: \"%s\"\n",opt_Pipe); + + if (!(stdIn = POPEN(opt_Pipe, "r"))) + { + stdIn = stdin; //restore + l2l_dbg(0, "Could not popen '%s' (%s)\n", opt_Pipe, strerror(errno)); + free(opt_Pipe); opt_Pipe = NULL; + } + + free(opt_Pipe); opt_Pipe = NULL; + } + l2l_dbg(4, "opt_Pipe processed\n"); if (argc > 1) { // translate { } @@ -2043,7 +2090,7 @@ main(int argc, const char **argv) l2l_dbg(2, "translating %s %s\n", exefile, offset); translate_file(exefile, my_atoi(offset), Line); printf("%s\n", Line); - report(stdout); + report(stdOut); } else { @@ -2061,11 +2108,14 @@ main(int argc, const char **argv) } else { // translate logging from stdin - translate_files(stdin, stdout); + translate_files(stdIn, stdOut); } if (logFile) fclose(logFile); + if (opt_Pipe) + PCLOSE(stdIn); + return res; } diff --git a/reactos/tools/tools.mak b/reactos/tools/tools.mak index bd3e5abec9a..c20875f21c6 100644 --- a/reactos/tools/tools.mak +++ b/reactos/tools/tools.mak @@ -44,6 +44,7 @@ include tools/bin2c.mak include tools/buildno/buildno.mak include tools/gendib/gendib.mak include tools/rsym/log2lines.mak +include tools/pipetools/pipetools.mak include tools/nci/nci.mak ifeq ($(ARCH),powerpc) include tools/ofw_interface/ofw_interface.mak