windows-nt/Source/XPSP1/NT/sdktools/logerr/logerr.cpp
2020-09-26 16:20:57 +08:00

624 lines
16 KiB
C++

//+-----------------------------------------------------------------------------
//
// File logerr.cpp
//
// Contents Error and output logging to avoid broken nmake
// This program reassigns stderr and stdout to two files
// named TMPERR and tmpout, executes a given command and
// appends the error and output messages to logerr.err
// and logerr.log respectively.
//
// Returns 1 (which stops the execution of nmake) only if
// logerr.err is not accesible. All other i/o errors are
// logged to logerr.err.
//
// Author & Date adinas 02/18/98 create file
// adinas 04/15/98 update to the new bingen's error values
// bensont 04/05/00
//
//-------------------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <winerror.h>
#include <windows.h>
#include <string.h>
#include "iodll.h"
#include <ntverp.h>
#define LOGFILE "LOGFILE" // The exactly string of the system environment variable name
#define ERRFILE "ERRFILE" // The exactly string of the system environment variable name
#define TEMPEXT ".temp"
#define DEFAULT_LOGFILE "logerr.log" // Default log filename
#define DEFAULT_ERRFILE "logerr.err" // Default err filename
#define MAX_FNAME_LEN MAX_PATH // Maximum length of the log/err filename string
#define MAX_CMD_LEN 2048 // Maximum length of the command-line string
#define LAST_KNOWN_WRN 11 // Maximum warning number known by logerr
#define LAST_KNOWN_ERR 130 // Maximum error number known by logerr
#define IODLL_UNKNOWN 1 // Used for unknown IODLL errors or warning
#define SYSTEM 1 // Used for bingen errors with code > LAST_ERROR
CHAR * pszCmdLine = NULL;
CHAR szCommand[MAX_CMD_LEN];
CHAR szLine[MAX_CMD_LEN];
CHAR szLogfile[MAX_FNAME_LEN]; // Log filename, ex "logerr.log"
CHAR szTempLogfile[MAX_FNAME_LEN]; // Temp Log filename, ex "logerr.err.temp"
CHAR szErrfile[MAX_FNAME_LEN]; // Error filename, ex "logerr.err"
CHAR szTempErrfile[MAX_FNAME_LEN]; // Temp Error filename, ex "logerr.err.temp"
FILE *bak_std_out = stdout; // Backup stdout
FILE *bak_std_err = stderr; // Backup stdin
FILE *out_stream = NULL; // Stream for the new stdout
FILE *out_stream_temp = NULL; // Stream for the new stdout
FILE *err_stream = NULL; // Stream for the err file
FILE *err_stream_temp = NULL; // Stream for the new stderr
int returnval = 0; // Return value
DWORD errorlevel = 0;
BOOL Status;
BOOL bReportError = FALSE;
BOOL bBuildCommand = FALSE;
// Define macros for printing
// fatal error messages (FATAL) at stderr
// fatal error messages (SFATAL) in logerr.log and logerr.err
// error messages (ERRMSG) in logerr.log and logerr.err
// error number (ERRNO) in logerr.log and logerr.err
// warning messages (WRNMSG) in logerr.log
// no messages (NOMSG) in logerr.log
#define FATAL(err,msg) \
fprintf(bak_std_err,"fatal error: %s %s",err,msg); \
returnval=1;
#define SFATAL(err,msg) \
fprintf(bak_std_out,"fatal error: %s %s",err,msg); \
fprintf(bak_std_err,"fatal error: %s %s",err,msg); \
returnval=1;
#define ERRMSG(err,msg) \
fprintf(stderr,"ERROR %s: %s\n",#err,msg); \
fprintf(stdout,"ERROR %s: %s\n",#err,msg);
#define ERRNO(err,msg) \
fprintf(stderr,"ERROR %d: %s\n",err,msg); \
fprintf(stdout,"ERROR %d: %s\n",err,msg);
#define WRNMSG(wrn,msg) \
fprintf(stdout,"WARNING %s: %s\n",#wrn,msg);
#define WRNNO(wrn,msg) \
fprintf(stdout,"WARNING %d: %s\n",wrn,msg);
#define NOMSG(msg) \
fprintf(stdout,"%s\n",msg);
// Print the command preceeded by ERROR or WARNING
// if errorlevel is non zero.
// Use ReportCmdExit for all commands but bingen.
// For bingen, use ReportBingenExit.
int __cdecl ReportCmdExit( INT errorlevel, CHAR* szCmdline );
int __cdecl ReportBingenExit ( INT errorlevel, CHAR* szCmdline );
int __cdecl ReportBuildExit ( INT errorlevel, CHAR* szCmdline );
int __cdecl ReportRsrcExit ( INT errorlevel, CHAR* szCmdline );
void __cdecl strlower(char *s);
char * __cdecl strnchr(char *s, char c);
int __cdecl GetEnvVar(char *envvarname, char *valuebuffer, char *defaultvalue, int bufsize);
void __cdecl AppendDump(FILE *Master, CHAR *Transfile, BOOL bLogError);
//+--------------------------------------------------------------
//
// Function: main
//
//---------------------------------------------------------------
int
__cdecl main(
int argc,
char* argv[] )
{
SSIZE_T len = 0; // The string length of the first item (command) of the command line
// PROCESS_INFORMATION piProcInfo;
// STARTUPINFO siStartInfo;
// If no argument, print the help.
if ( argc !=2 ) goto Help;
pszCmdLine = strnchr(argv[1], ' ');
Help:;
// Provide help for using the tool, if required
if ( argc <= 1 ||
0 == strcmp( argv[1], "/?" ) ||
0 == strcmp( argv[1], "-?" ) ||
NULL == pszCmdLine ) {
fprintf( stderr, "Usage:\tlogerr \"<command line>\"\n");
fprintf( stderr, "Ex:\tlogerr \"xcopy /vf c:\\tmp\\myfile.txt .\"\n");
returnval = 1;
goto Error;
}
// Get Environment, LOGFILE, ERRFILE and ComSpec
if ( (GetEnvVar(LOGFILE, szLogfile, DEFAULT_LOGFILE, MAX_FNAME_LEN) == 0) ||
(GetEnvVar(ERRFILE, szErrfile, DEFAULT_ERRFILE, MAX_FNAME_LEN) == 0))
goto Error;
// Evaluate templog filename
strcpy(szTempLogfile, szLogfile);
strcpy(&szTempLogfile[strlen(szTempLogfile)], TEMPEXT);
// Evaluate temperr filename
strcpy(szTempErrfile, szErrfile);
strcpy(&szTempErrfile[strlen(szTempErrfile)], TEMPEXT);
// Prepare the output / error output file handle
if ( (out_stream = fopen( szLogfile, "at")) == NULL) {
FATAL(szLogfile, "Failed to open log file.");
goto Error;
}
if ( (out_stream_temp = freopen(szTempLogfile, "w+t", stdout)) == NULL) {
FATAL(szTempLogfile, "Failed to open temp error file.");
goto Error;
}
if ( (err_stream = fopen(szErrfile, "a+t")) == NULL) {
FATAL(szErrfile, "Failed to open error file.");
goto Error;
}
if ( (err_stream_temp = freopen(szTempErrfile, "w+t", stderr)) == NULL) {
FATAL(szTempErrfile, "Failed to open temp error file.");
goto Error;
}
fseek(out_stream, 0, SEEK_END);
fseek(err_stream, 0, SEEK_END);
// Get the argument as command line (pszCmdLine)
if (strlen(pszCmdLine) >= MAX_CMD_LEN ) { //- default_cmd_len - strlen(buf)
FATAL(pszCmdLine, "The Full Command is too long !!!");
goto Error;
}
// Get the first word as command (szCommand)
len = strchr(pszCmdLine, ' ') - pszCmdLine;
if (len < 0) len = strlen(pszCmdLine);
if (len >= MAX_CMD_LEN) {
FATAL(pszCmdLine,"The First Command is too long !!!");
goto Error;
}
// system to execute the program
strncpy(szCommand, pszCmdLine, len);
strlower(szCommand);
errorlevel=system( pszCmdLine );
if ( strcmp( szCommand, "bingen" ) == 0)
bReportError = ReportBingenExit( errorlevel, pszCmdLine );
else if ( _stricmp( szCommand, "rsrc" ) == 0)
bReportError = ReportRsrcExit( errorlevel, pszCmdLine );
else if ( _stricmp( szCommand, "build" ) == 0) {
bReportError = ReportBuildExit( errorlevel, pszCmdLine );
bBuildCommand = TRUE;
} else
bReportError = ReportCmdExit( errorlevel, pszCmdLine );
// Temp Error file complete, set to err_stream
SetStdHandle(STD_ERROR_HANDLE, err_stream);
if (NULL != err_stream_temp)
fclose(err_stream_temp);
else {
FATAL(szTempErrfile, "Failed to close error file.");
goto Error;
}
// Temp Error file complete, set to err_stream
SetStdHandle(STD_OUTPUT_HANDLE, out_stream);
if (NULL != out_stream_temp)
fclose(out_stream_temp);
else {
FATAL(szTempLogfile, "Failed to close log file.");
goto Error;
}
if (bReportError) {
fprintf(err_stream, "ERROR %d: %s\n", errorlevel, pszCmdLine);
fprintf(out_stream, "ERROR %d: %s\n", errorlevel, pszCmdLine);
} else {
fprintf(out_stream, "%s\n", pszCmdLine);
}
AppendDump(out_stream, szTempLogfile, 0);
if (bBuildCommand)
AppendDump(out_stream, "Build.log", 0);
AppendDump(out_stream, szTempErrfile, 1);
if (bBuildCommand)
AppendDump(err_stream, "Build.err", 1);
Error:
SetStdHandle(STD_ERROR_HANDLE, bak_std_out);
SetStdHandle(STD_OUTPUT_HANDLE, bak_std_err);
if (NULL != err_stream)
fclose(err_stream);
if (NULL != out_stream)
fclose(out_stream);
// Delete the temporary files
_unlink (szTempErrfile);
_unlink (szTempLogfile);
return returnval;
} // main
int
__cdecl ReportBingenExit(
INT errorlevel,
CHAR* szCmdline
) {
int result=FALSE;
switch (errorlevel) {
case ERROR_NO_ERROR:
// NOMSG(szCmdline);
break;
case ERROR_RW_NO_RESOURCES:
WRNMSG(ERROR_RW_NO_RESOURCES,szCmdline);
break;
case ERROR_RW_VXD_MSGPAGE:
WRNMSG(ERROR_RW_VXD_MSGPAGE,szCmdline);
break;
case ERROR_IO_CHECKSUM_MISMATCH:
WRNMSG(ERROR_IO_CHECKSUM_MISMATCH,szCmdline);
break;
case ERROR_FILE_CUSTOMRES:
WRNMSG(ERROR_FILE_CUSTOMRES,szCmdline);
break;
case ERROR_FILE_VERSTAMPONLY:
WRNMSG(ERROR_FILE_VERSTAMPONLY,szCmdline);
break;
case ERROR_RET_RESIZED:
WRNMSG(ERROR_RET_RESIZED,szCmdline);
break;
case ERROR_RET_ID_NOTFOUND:
WRNMSG(ERROR_RET_ID_NOTFOUND,szCmdline);
break;
case ERROR_RET_CNTX_CHANGED:
WRNMSG(ERROR_RET_CNTX_CHANGED,szCmdline);
break;
case ERROR_RET_INVALID_TOKEN:
WRNMSG(ERROR_RET_INVALID_TOKEN,szCmdline);
break;
case ERROR_RET_TOKEN_REMOVED:
WRNMSG(ERROR_RET_TOKEN_REMOVED,szCmdline);
break;
case ERROR_RET_TOKEN_MISMATCH:
WRNMSG(ERROR_RET_TOKEN_MISMATCH,szCmdline);
break;
case ERROR_HANDLE_INVALID:
ERRMSG(ERROR_HANDLE_INVALID,szCmdline);
result = TRUE;
break;
case ERROR_READING_INI:
ERRMSG(ERROR_READING_INI,szCmdline);
result = TRUE;
break;
case ERROR_NEW_FAILED:
ERRMSG(ERROR_NEW_FAILED,szCmdline);
result = TRUE;
break;
case ERROR_OUT_OF_DISKSPACE:
ERRMSG(ERROR_OUT_OF_DISKSPACE,szCmdline);
result = TRUE;
break;
case ERROR_FILE_OPEN:
ERRMSG(ERROR_FILE_OPEN,szCmdline);
result = TRUE;
break;
case ERROR_FILE_CREATE:
ERRMSG(ERROR_FILE_CREATE,szCmdline);
result = TRUE;
break;
case ERROR_FILE_INVALID_OFFSET:
ERRMSG(ERROR_FILE_INVALID_OFFSET,szCmdline);
result = TRUE;
break;
case ERROR_FILE_READ:
ERRMSG(ERROR_FILE_READ,szCmdline);
result = TRUE;
break;
case ERROR_FILE_WRITE:
ERRMSG(ERROR_FILE_WRITE,szCmdline);
result = TRUE;
break;
case ERROR_DLL_LOAD:
ERRMSG(ERROR_DLL_LOAD,szCmdline);
result = TRUE;
break;
case ERROR_DLL_PROC_ADDRESS:
ERRMSG(ERROR_DLL_PROC_ADDRESS,szCmdline);
result = TRUE;
break;
case ERROR_RW_LOADIMAGE:
ERRMSG(ERROR_RW_LOADIMAGE,szCmdline);
result = TRUE;
break;
case ERROR_RW_PARSEIMAGE:
ERRMSG(ERROR_RW_PARSEIMAGE,szCmdline);
result = TRUE;
break;
case ERROR_RW_GETIMAGE:
ERRMSG(ERROR_RW_GETIMAGE,szCmdline);
result = TRUE;
break;
case ERROR_RW_NOTREADY:
ERRMSG(ERROR_RW_NOTREADY,szCmdline);
result = TRUE;
break;
case ERROR_RW_BUFFER_TOO_SMALL:
ERRMSG(ERROR_RW_BUFFER_TOO_SMALL,szCmdline);
result = TRUE;
break;
case ERROR_RW_INVALID_FILE:
ERRMSG(ERROR_RW_INVALID_FILE,szCmdline);
result = TRUE;
break;
case ERROR_RW_IMAGE_TOO_BIG:
ERRMSG(ERROR_RW_IMAGE_TOO_BIG,szCmdline);
result = TRUE;
break;
case ERROR_RW_TOO_MANY_LEVELS:
ERRMSG(ERROR_RW_TOO_MANY_LEVELS,szCmdline);
result = TRUE;
break;
case ERROR_IO_INVALIDITEM:
ERRMSG(ERROR_IO_INVALIDITEM,szCmdline);
result = TRUE;
break;
case ERROR_IO_INVALIDID:
ERRMSG(ERROR_IO_INVALIDID,szCmdline);
result = TRUE;
break;
case ERROR_IO_INVALID_DLL:
ERRMSG(ERROR_IO_INVALID_DLL,szCmdline);
result = TRUE;
break;
case ERROR_IO_TYPE_NOT_SUPPORTED:
ERRMSG(ERROR_IO_TYPE_NOT_SUPPORTED,szCmdline);
result = TRUE;
break;
case ERROR_IO_INVALIDMODULE:
ERRMSG(ERROR_IO_INVALIDMODULE,szCmdline);
result = TRUE;
break;
case ERROR_IO_RESINFO_NULL:
ERRMSG(ERROR_IO_RESINFO_NULL,szCmdline);
result = TRUE;
break;
case ERROR_IO_UPDATEIMAGE:
ERRMSG(ERROR_IO_UPDATEIMAGE,szCmdline);
result = TRUE;
break;
case ERROR_IO_FILE_NOT_SUPPORTED:
ERRMSG(ERROR_IO_FILE_NOT_SUPPORTED,szCmdline);
result = TRUE;
break;
case ERROR_FILE_SYMPATH_NOT_FOUND:
ERRMSG(ERROR_FILE_SYMPATH_NOT_FOUND,szCmdline);
result = TRUE;
break;
case ERROR_FILE_MULTILANG:
ERRMSG(ERROR_FILE_MULTILANG,szCmdline);
result = TRUE;
break;
case ERROR_IO_SYMBOLFILE_NOT_FOUND:
ERRMSG(ERROR_IO_SYMBOLFILE_NOT_FOUND,szCmdline);
result = TRUE;
break;
default:
break;
};
if (errorlevel > LAST_KNOWN_WRN && errorlevel <= LAST_WRN) {
WRNMSG(IODLL_UNKNOWN,szCmdline);
}
if (errorlevel > LAST_KNOWN_ERR && errorlevel <= LAST_ERROR) {
result = TRUE;
ERRMSG(IODLL_UNKNOWN,szCmdline);
}
if (errorlevel > LAST_ERROR) {
result = TRUE;
ERRMSG(SYSTEM,szCmdline);
}
return result;
} // ReportBingenExit
int
__cdecl ReportCmdExit (
INT errorlevel,
CHAR* szCmdline) {
int result=FALSE;
switch (errorlevel) {
case 0:
// NOMSG(szCmdline);
break;
default:
// ERRNO(errorlevel,szCmdline);
result = TRUE;
}
return result;
} // ReportCmdExit
int
__cdecl ReportRsrcExit(
INT errorlevel,
CHAR* szCmdline
) {
int result=FALSE;
switch (errorlevel) {
case 0:
// NOMSG(szCmdline);
break;
case 1:
WRNNO(1,szCmdline );
break;
default:
ERRNO(errorlevel,szCmdline );
result = TRUE;
break;
} // switch
return result;
}
int
__cdecl ReportBuildExit(
INT errorlevel,
CHAR* szCmdline
) {
int result=FALSE;
switch (errorlevel) {
case 0:
// NOMSG(szCmdline);
break;
default:
// ERRNO(errorlevel,szCmdline );
result = TRUE;
break;
} // switch
return result;
}
char * __cdecl strnchr(char *s, char c) {
while(*s==c);
return (*s==NULL)?NULL:s;
}
int __cdecl GetEnvVar(char *envvarname, char *valuebuffer, char *defaultvalue, int bufsize) {
int ret = 0;
// ret == 0 => undefine ERRFILE, set to default
// ret > MAX_FNAME_LEN => out of buffersize, set to fatal error
if ((ret=GetEnvironmentVariable(envvarname, valuebuffer, bufsize)) == 0)
strcpy(valuebuffer, defaultvalue);
else if (ret > bufsize) {
FATAL(envvarname,"The Environment Variable's value is too long!!!");
return 0;
}
return 1;
}
void __cdecl strlower(char *s) {
while(*s) {
if(isalpha(*s)) *s|=0x20;
s++;
}
}
void __cdecl AppendDump(FILE *Master, CHAR *Transfile, BOOL bLogError) {
SSIZE_T len = 0;
FILE *Transaction;
if ((Transaction=fopen(Transfile, "rt")) == NULL) {
return;
}
while (fgets(szLine, sizeof(szLine) - sizeof(szLine[0]), Transaction)) {
// Remove double \n
for (len = strlen(szLine); --len >=0 && szLine[len] < ' '; szLine[len]=0);
// Next Line if is empty line
if (len < 1) continue;
if (0 != ferror(Transaction)) {
SFATAL(Transfile,"Unable to open for reading");
return;
} // if
// Write to log file
fprintf(Master, "\t%s\n", szLine);
// Write to error file if need
if (bLogError && bReportError) fprintf(err_stream, "\t%s\n", szLine);
}
if( ferror( Transaction ) ) {
FATAL(pszCmdLine,"Temp error file broken !!!");
}
if (NULL != Transaction)
fclose(Transaction);
}