fix: stop using "magic" numbers in string operations for the copyannofile2log feature
fix: When using the copylogfromannofile workaround, extract the build ID and build duration and add to the log as these are useful for analysis. The log should now be identical to the stdout file.
fix: Remove extra blank lines from output in copylogfromannofile mode.
/*
* Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of the License "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description:
* @internalComponent * @released
* Rofsbuild mainfile to generate both rofs and data drive image.
*
*/
#include <string.h>
#include <stdlib.h>
#include <f32file.h>
#include "e32image.h"
#include "h_utl.h"
#include "h_ver.h"
#include "r_obey.h"
#include "r_driveimage.h"
#include "r_driveutl.h"
#include "r_coreimage.h"
#include "parameterfileprocessor.h"
#include "r_smrimage.h"
static const TInt RofsbuildMajorVersion=2;
static const TInt RofsbuildMinorVersion=6;
static const TInt RofsbuildPatchVersion=5;
static TBool SizeSummary=EFalse;
static TPrintType SizeWhere=EAlways;
static TInt gHeaderType=1; // EPOC header
static TInt MAXIMUM_THREADS = 128;
static TInt DEFAULT_THREADS = 8;
ECompression gCompress=ECompressionUnknown;
TUint gCompressionMethod=0;
TBool gFastCompress = EFalse;
TInt gThreadNum = 0;
TInt gCPUNum = 0;
char* g_pCharCPUNum = NULL;
TInt gCodePagingOverride = -1;
TInt gDataPagingOverride = -1;
TInt gLogLevel = 0; // Information is logged based on logging level.
// The default is 0. So all the existing logs are generated as if gLogLevel = 0.
// If any extra information required, the log level must be appropriately supplied.
// Currrently, file details in ROM (like, file name in ROM & host, file size, whether
// the file is hidden etc) are logged when gLogLevel >= LOG_LEVEL_FILE_DETAILS.
TBool gUseCoreImage=EFalse; // command line option for using core image file
char* gImageFilename=NULL; // instead of obey file
TBool gEnableStdPathWarning=EFalse;// for in-correct destination path warning(executables).
TBool gLowMem=EFalse;
extern TBool gDriveImage; // to Support data drive image.
TText* gDriveFilename=NULL; // input drive oby filename.
string filename; // to store oby filename passed to Rofsbuild.
TBool reallyHelp=EFalse;
TBool gSmrImage = EFalse;
TText* gSmrFileName = NULL;
void PrintVersion()
{
Print(EAlways,"\nROFSBUILD - Rofs/Datadrive image builder");
Print(EAlways, " V%d.%d.%d\n", RofsbuildMajorVersion, RofsbuildMinorVersion, RofsbuildPatchVersion);
Print(EAlways,Copyright);
}
char HelpText[] =
"Syntax: ROFSBUILD [options] obeyfilename(Rofs)\n"
"Option: -v verbose, -?, -s[log|screen|both] size summary\n"
" -d<bitmask> set trace mask (DEB build only)\n"
" -compress compress executable files where possible\n"
" -fastcompress compress files with faster bytepair and tradeoff of compress ratio\n"
" -j<digit> do the main job with <digit> threads\n"
" -compressionmethod none|inflate|bytepair to set the compression\n"
" none uncompress the image.\n"
" inflate compress the image.\n"
" bytepair compress the image.\n"
" -coreimage <core image file>\n"
" -datadrive=<drive obyfile1>,<drive obyfile2>,... for driveimage creation\n"
" user can also input rofs oby file if required to generate both.\n"
" -smr=<SMR obyfile1>,<SMR obyfile2>,... for SMR partition creation\n"
" -loglevel<level> level of information to log (valid levels are 0,1,2).\n"//Tools like Visual ROM builder need the host/ROM filenames, size & if the file is hidden.
" -wstdpath warn if destination path provided for a file is not the standard path\n"
" -argfile=<FileName> specify argument-file name containing list of command-line arguments\n"
" -lowmem use memory-mapped file for image build to reduce physical memory consumption\n";
char ReallyHelpText[] =
"Log Level:\n"
" 0 produce the default logs\n"
" 1 produce file detail logs in addition to the default logs\n"
" 2 logs e32 header attributes in addition to the level 1 details\n";
void processParamfile(string aFileName);
/**
Process the command line arguments and prints the helpful message if none are supplied.
@param argc - No. of argument.
@param *argv[] - Arguments value.
*/
void processCommandLine(int argc, char *argv[], TBool paramFileFlag=EFalse)
{
// If "-argfile" option is passed to rofsbuild, then process the parameters
// specified in parameter-file first and then the options passed from the
// command-line.
string ParamFileArg("-ARGFILE=");
if(paramFileFlag == EFalse)
{
for (int count=1; count<argc; count++)
{
string paramFile;
strupr(argv[count]);
if(strncmp(argv[count],ParamFileArg.c_str(),ParamFileArg.length())==0)
{
paramFile.assign(&argv[count][ParamFileArg.length()]);
processParamfile(paramFile);
}
}
}
int i=1;
while (i<argc)
{
strupr(argv[i]);
if ((argv[i][0] == '-') || (argv[i][0] == '/'))
{ // switch
if (argv[i][1] == 'V')
H.iVerbose = ETrue;
else if(strncmp (argv[i], "-SMR=", 5) == 0)
{
if(argv[i][5])
{
gSmrImage = ETrue;
gSmrFileName = (TText*)strdup(&argv[i][5]);
}
else
{
Print (EError, "SMR obey file is missing\n");
}
}
else if (argv[i][1] == 'S')
{
SizeSummary=ETrue;
if (argv[i][2] == 'L')
SizeWhere=ELog;
if (argv[i][2] == 'S')
SizeWhere=EScreen;
}
else if (strncmp(argv[i],ParamFileArg.c_str(),ParamFileArg.length())==0)
{
if (paramFileFlag)
{
String paramFile;
paramFile.assign(&argv[i][ParamFileArg.length()]);
processParamfile(paramFile);
}
else
{
i++;
continue;
}
}
else if (strcmp(argv[i], "-COMPRESS")==0)
{
gCompress=ECompressionCompress;
gCompressionMethod = KUidCompressionDeflate;
}
else if (strcmp(argv[i], "-FASTCOMPRESS")==0)
{
gFastCompress=ETrue;
}
else if (strncmp(argv[i], "-J",2)==0)
{
if(argv[i][2])
gThreadNum = atoi(&argv[i][2]);
else
{
printf("WARNING: The option should be like '-j4'.\n");
gThreadNum = 0;
}
if(gThreadNum <= 0 || gThreadNum > MAXIMUM_THREADS)
{
if(gCPUNum > 0 && gCPUNum <= MAXIMUM_THREADS)
{
printf("WARNING: The number of concurrent jobs set by -j should be between 1 and 128. And the number of processors %d will be used as the number of concurrent jobs.\n", gCPUNum);
gThreadNum = gCPUNum;
}
else if(g_pCharCPUNum)
{
printf("WARNING: The number of concurrent jobs set by -j should be between 1 and 128. And the NUMBER_OF_PROCESSORS is invalid, so the default value %d will be used.\n", DEFAULT_THREADS);
gThreadNum = DEFAULT_THREADS;
}
else
{
printf("WARNING: The number of concurrent jobs set by -j should be between 1 and 128. And the NUMBER_OF_PROCESSORS is not available, so the default value %d will be used.\n", DEFAULT_THREADS);
gThreadNum = DEFAULT_THREADS;
}
}
}
else if (strcmp(argv[i], "-UNCOMPRESS")==0)
{
gCompress=ECompressionUncompress;
}
else if( strcmp(argv[i], "-COMPRESSIONMETHOD") == 0 )
{
// next argument should a be method
if( (i+1) >= argc || argv[i+1][0] == '-')
{
Print (EError, "Missing compression method! Set it to default (no compression)!");
gCompressionMethod = 0;
}
else
{
i++;
strupr(argv[i]);
if( strcmp(argv[i], "NONE") == 0)
{
gCompress=ECompressionUncompress;
gCompressionMethod = 0;
}
else if( strcmp(argv[i], "INFLATE") == 0)
{
gCompress=ECompressionCompress;
gCompressionMethod = KUidCompressionDeflate;
}
else if( strcmp(argv[i], "BYTEPAIR") == 0)
{
gCompress=ECompressionCompress;
gCompressionMethod = KUidCompressionBytePair;
}
else
{
Print (EError, "Unknown compression method! Set it to default (no compression)!");
gCompress=ECompressionUnknown;
gCompressionMethod = 0;
}
}
}
else if (strcmp(argv[i], "-COREIMAGE") ==0)
{
gUseCoreImage = ETrue;
// next argument should be image filename
if ((i+1 >= argc) || argv[i+1][0] == '-')
Print (EError, "Missing image file name");
else
{
i++;
gImageFilename = strdup(argv[i]);
}
}
else if (strncmp(argv[i], "-DATADRIVE=",11) ==0)
{
if(argv[i][11])
{
gDriveImage = ETrue;
gDriveFilename = (TText*)strdup(&argv[i][11]);
}
else
{
Print (EError, "Drive obey file is missing\n");
}
}
else if (argv[i][1] == '?')
{
reallyHelp=ETrue;
}
else if (strcmp(argv[i], "-WSTDPATH") ==0) // Warn if destination path provided for a executables are incorrect as per platsec.
{
gEnableStdPathWarning=ETrue;
}
else if( strcmp(argv[i], "-LOGLEVEL") == 0)
{
// next argument should a be loglevel
if( (i+1) >= argc || argv[i+1][0] == '-')
{
Print (EError, "Missing loglevel!");
gLogLevel = DEFAULT_LOG_LEVEL;
}
else
{
i++;
if (strcmp(argv[i], "2") == 0)
gLogLevel = (LOG_LEVEL_FILE_DETAILS | LOG_LEVEL_FILE_ATTRIBUTES);
if (strcmp(argv[i], "1") == 0)
gLogLevel = LOG_LEVEL_FILE_DETAILS;
else if (strcmp(argv[i], "0") == 0)
gLogLevel = DEFAULT_LOG_LEVEL;
else
Print(EError, "Only loglevel 0, 1 or 2 is allowed!");
}
}
else if( strcmp(argv[i], "-LOGLEVEL2") == 0)
gLogLevel = (LOG_LEVEL_FILE_DETAILS | LOG_LEVEL_FILE_ATTRIBUTES);
else if( strcmp(argv[i], "-LOGLEVEL1") == 0)
gLogLevel = LOG_LEVEL_FILE_DETAILS;
else if( strcmp(argv[i], "-LOGLEVEL0") == 0)
gLogLevel = DEFAULT_LOG_LEVEL;
else if (strcmp(argv[i], "-LOWMEM") == 0)
gLowMem = ETrue;
else
cout << "Unrecognised option " << argv[i] << "\n";
}
else // Must be the obey filename
filename=argv[i];
i++;
}
if (paramFileFlag)
return;
if((gDriveImage == EFalse) && (gSmrImage == EFalse) && (filename.empty() || (gUseCoreImage && gImageFilename == NULL)))
{
PrintVersion();
cout << HelpText;
if (reallyHelp)
{
ObeyFileReader::KeywordHelp();
cout << ReallyHelpText;
}
else if (filename.empty())
{
Print(EError, "Obey filename is missing\n");
}
}
}
/**
Function to process parameter-file.
@param aFileName parameter-file name.
*/
void processParamfile(string aFileName)
{
CParameterFileProcessor parameterFile(aFileName);
// Invoke fuction "ParameterFileProcessor" to process parameter-file.
if(parameterFile.ParameterFileProcessor())
{
TUint noOfParameters = parameterFile.GetNoOfArguments();
char** parameters = parameterFile.GetParameters();
TBool paramFileFlag=ETrue;
// Invoke function "processCommandLine" to process parameters read from parameter-file.
processCommandLine(noOfParameters,parameters,paramFileFlag);
}
}
/**
Main logic for data drive image creation. Called many types depending on no. of drive obey files.
@param aobeyFileName - Drive obey file.
@param alogfile - log file name required for file system module.
@return - returns the status, after processing the drive obey file.
*/
TInt ProcessDataDriveMain(TText* aobeyFileName,TText* alogfile)
{
ObeyFileReader *reader=new ObeyFileReader(aobeyFileName);
if(!reader)
return KErrNoMemory;
if(!reader->Open())
{
if (reader)
{
delete reader;
}
return KErrGeneral;
}
TInt retstatus =0;
CObeyFile* mainObeyFile=new CObeyFile(*reader);
CDriveImage* userImage = 0;
if(!mainObeyFile)
{
if (reader)
{
delete reader;
}
return KErrNoMemory;
}
// Process data drive image.
// let's clear the TRomNode::sDefaultInitialAttr first, 'cause data drive is different from rom image
TRomNode::sDefaultInitialAttr = 0;
retstatus = mainObeyFile->ProcessDataDrive();
if (retstatus == KErrNone)
{
// Build a Data drive image using the description compiled into the CObeyFile object
userImage = new CDriveImage(mainObeyFile);
if(userImage)
{
// Drive image creation.
retstatus = userImage->CreateImage(alogfile);
if(retstatus == KErrNone)
{
cout << "\nSuccessfully generated the Drive image : " << mainObeyFile->iDriveFileName << "\n";
}
else
{
cout << "\nFailed to generate the Image : " << mainObeyFile->iDriveFileName << "\n";
}
delete userImage;
userImage = 0;
}
else
{
retstatus = KErrNoMemory;
}
}
// restore
TRomNode::sDefaultInitialAttr = (TUint8)KEntryAttReadOnly;
cout << "\n-----------------------------------------------------------\n";
delete mainObeyFile;
delete reader;
return retstatus;
}
TInt ProcessSmrImageMain(TText* aObeyFileName, TText* /* alogfile */)
{
ObeyFileReader *reader = new ObeyFileReader(aObeyFileName);
if(!reader)
return KErrNoMemory;
if(!reader->Open())
{
if (reader)
{
delete reader;
}
return KErrGeneral;
}
TInt retstatus = 0;
CObeyFile* mainObeyFile = new CObeyFile(*reader);
CSmrImage* smrImage = 0;
if(!mainObeyFile)
{
if (reader)
{
delete reader;
}
return KErrNoMemory;
}
if(mainObeyFile->Process())
{
smrImage = new CSmrImage(mainObeyFile);
if(smrImage)
{
if((retstatus=smrImage->Initialise()) == KErrNone)
{
retstatus = smrImage->CreateImage();
}
if(retstatus == KErrNone)
{
cout << "\nSuccessfully generated the SMR image : " << smrImage->GetImageName().c_str() << "\n";
}
else
{
cout << "\nFailed to generate the Image : " << smrImage->GetImageName().c_str() << "\n";
}
delete smrImage;
}
else
{
retstatus = KErrNoMemory;
}
}
delete mainObeyFile;
delete reader;
return retstatus;
}
/**
Rofsbuild Main function, which creates both Rofs and Data drive image.
@param argc - No. of argument.
@param *argv[] - Arguments value.
@return - returns the status to caller.
*/
TInt main(int argc, char *argv[])
{
TInt r =0;
g_pCharCPUNum = getenv("NUMBER_OF_PROCESSORS");
if(g_pCharCPUNum != NULL)
gCPUNum = atoi(g_pCharCPUNum);
processCommandLine(argc, argv);
TText *obeyFileName = NULL;
if(!filename.empty())
obeyFileName=(TText*)filename.c_str();
if ((obeyFileName==NULL) && (gDriveFilename==NULL) && (gSmrFileName == NULL))
return KErrGeneral;
if(gThreadNum == 0)
{
if(gCPUNum > 0 && gCPUNum <= MAXIMUM_THREADS)
{
printf("The number of processors (%d) is used as the number of concurrent jobs.\n", gCPUNum);
gThreadNum = gCPUNum;
}
else if(g_pCharCPUNum)
{
printf("WARNING: The NUMBER_OF_PROCESSORS is invalid, and the default value %d will be used.\n", DEFAULT_THREADS);
gThreadNum = DEFAULT_THREADS;
}
else
{
printf("WARNING: The NUMBER_OF_PROCESSORS is not available, and the default value %d will be used.\n", DEFAULT_THREADS);
gThreadNum = DEFAULT_THREADS;
}
}
// Process drive obey files.
if(gDriveImage)
{
TText temp = 0;
TText *driveobeyFileName = gDriveFilename;
do
{
while(((temp = *gDriveFilename++) != ',') && (temp != 0));
*(--gDriveFilename)++ = 0;
if(*driveobeyFileName)
{
TText* logfile = 0;
if(Getlogfile(driveobeyFileName,logfile)== KErrNone)
{
H.SetLogFile(logfile);
PrintVersion();
GetLocalTime();
r = ProcessDataDriveMain(driveobeyFileName,logfile);
H.CloseLogFile();
delete[] logfile;
if(r == KErrNoMemory)
return KErrNoMemory;
}
else
{
cout << "Error : Invalid obey file name : " << driveobeyFileName << "\n" ;
}
}
driveobeyFileName = gDriveFilename;
}
while(temp != 0);
gDriveImage=EFalse;
}
if(gSmrImage)
{
TText temp = 0;
TText *smrImageObeyFileName = gSmrFileName;
do
{
while(((temp = *gSmrFileName++) != ',') && (temp != 0));
*(--gSmrFileName)++ = 0;
if(*smrImageObeyFileName)
{
TText * logfile = 0;
if(Getlogfile(smrImageObeyFileName,logfile) == KErrNone)
{
H.SetLogFile(logfile);
PrintVersion();
GetLocalTime();
r = ProcessSmrImageMain(smrImageObeyFileName, logfile);
H.CloseLogFile();
delete[] logfile;
if(r == KErrNoMemory)
return KErrNoMemory;
}
else
{
cout << "Error: Invalid obey file name: " << smrImageObeyFileName << "\n";
}
}
smrImageObeyFileName = gSmrFileName;
}
while(temp != 0);
gSmrImage = EFalse;
}
// Process Rofs Obey files.
if(obeyFileName)
{
H.SetLogFile((unsigned char *)"ROFSBUILD.LOG");
PrintVersion();
ObeyFileReader *reader=new ObeyFileReader(obeyFileName);
if (!reader->Open())
return KErrGeneral;
E32Rofs* RofsImage = 0; // for image from obey file
CCoreImage *core= 0; // for image from core image file
MRofsImage* imageInfo=0;
CObeyFile *mainObeyFile=new CObeyFile(*reader);
// need check if obey file has coreimage keyword
TText *file = mainObeyFile->ProcessCoreImage();
if (file)
{
// hase coreimage keyword but only use if command line option
// for coreimage not already selected
if (!gUseCoreImage)
{
gUseCoreImage = ETrue;
gImageFilename = (char *)file;
}
}
if (!gUseCoreImage)
{
r=mainObeyFile->ProcessRofs();
if (r==KErrNone)
{
// Build a ROFS image using the description compiled into the
// CObeyFile object
RofsImage = new E32Rofs( mainObeyFile );
if( !RofsImage )
{
return KErrNoMemory;
}
r = RofsImage->Create();
if( KErrNone == r )
{
if(SizeSummary)
RofsImage->DisplaySizes(SizeWhere);
RofsImage->WriteImage( gHeaderType );
}
imageInfo = RofsImage;
mainObeyFile->Release();
}
else if (r!=KErrNotFound)
return r;
}
else
{
// need to use core image
RCoreImageReader *reader = new RCoreImageReader(gImageFilename);
if (!reader)
{
return KErrNoMemory;
}
core= new CCoreImage(reader);
if (!core)
{
return KErrNoMemory;
}
r = core->ProcessImage();
if (r != KErrNone)
return r;
imageInfo = core;
mainObeyFile->SkipToExtension();
}
do
{
CObeyFile* extensionObeyFile = 0;
E32Rofs* extensionRofs = 0;
extensionObeyFile = new CObeyFile(*reader);
r = extensionObeyFile->ProcessExtensionRofs(imageInfo);
if (r==KErrEof)
{
if(RofsImage)
delete RofsImage;
if(core)
delete core;
delete extensionObeyFile;
return KErrNone;
}
if (r!=KErrNone)
break;
extensionRofs = new E32Rofs(extensionObeyFile);
r=extensionRofs->CreateExtension(imageInfo);
if (r!=KErrNone)
{
delete extensionRofs;
delete extensionObeyFile;
break;
}
if(SizeSummary)
RofsImage->DisplaySizes(SizeWhere);
r=extensionRofs->WriteImage(0);
delete extensionRofs;
delete extensionObeyFile;
extensionRofs = 0;
extensionObeyFile = 0;
}
while (r==KErrNone);
if(RofsImage)
delete RofsImage;
if(core)
delete core;
delete mainObeyFile;
}
return r;
}//end of main.