Пример #1
0
int FlashAction::Execute(int argc, char **argv)
{
	// Setup argument types

	map<string, ArgumentType> argumentTypes;
	map<string, string> shortArgumentAliases;

	argumentTypes["repartition"] = kArgumentTypeFlag;

	argumentTypes["no-reboot"] = kArgumentTypeFlag;
	argumentTypes["resume"] = kArgumentTypeFlag;
	argumentTypes["verbose"] = kArgumentTypeFlag;
	argumentTypes["stdout-errors"] = kArgumentTypeFlag;
	argumentTypes["usb-log-level"] = kArgumentTypeString;

	argumentTypes["pit"] = kArgumentTypeString;
	shortArgumentAliases["pit"] = "pit";

	// Add wild-cards "%d" and "%s", for partition identifiers and partition names respectively.
	argumentTypes["%d"] = kArgumentTypeString;
	shortArgumentAliases["%d"] = "%d";

	argumentTypes["%s"] = kArgumentTypeString;
	shortArgumentAliases["%s"] = "%s";

	map<string, string> argumentAliases;
	argumentAliases["PIT"] = "pit"; // Map upper-case PIT argument (i.e. partition name) to known lower-case pit argument.

	// Handle arguments

	Arguments arguments(argumentTypes, shortArgumentAliases, argumentAliases);

	if (!arguments.ParseArguments(argc, argv, 2))
	{
		Interface::Print(FlashAction::usage);
		return (0);
	}

	bool reboot = arguments.GetArgument("no-reboot") == nullptr;
	bool resume = arguments.GetArgument("resume") != nullptr;
	bool verbose = arguments.GetArgument("verbose") != nullptr;
	
	if (arguments.GetArgument("stdout-errors") != nullptr)
		Interface::SetStdoutErrors(true);

	const StringArgument *usbLogLevelArgument = static_cast<const StringArgument *>(arguments.GetArgument("usb-log-level"));

	BridgeManager::UsbLogLevel usbLogLevel = BridgeManager::UsbLogLevel::Default;

	if (usbLogLevelArgument)
	{
		const string& usbLogLevelString = usbLogLevelArgument->GetValue();

		if (usbLogLevelString.compare("none") == 0 || usbLogLevelString.compare("NONE") == 0)
		{
			usbLogLevel = BridgeManager::UsbLogLevel::None;
		}
		else if (usbLogLevelString.compare("error") == 0 || usbLogLevelString.compare("ERROR") == 0)
		{
			usbLogLevel = BridgeManager::UsbLogLevel::Error;
		}
		else if (usbLogLevelString.compare("warning") == 0 || usbLogLevelString.compare("WARNING") == 0)
		{
			usbLogLevel = BridgeManager::UsbLogLevel::Warning;
		}
		else if (usbLogLevelString.compare("info") == 0 || usbLogLevelString.compare("INFO") == 0)
		{
			usbLogLevel = BridgeManager::UsbLogLevel::Info;
		}
		else if (usbLogLevelString.compare("debug") == 0 || usbLogLevelString.compare("DEBUG") == 0)
		{
			usbLogLevel = BridgeManager::UsbLogLevel::Debug;
		}
		else
		{
			Interface::Print("Unknown USB log level: %s\n\n", usbLogLevelString.c_str());
			Interface::Print(FlashAction::usage);
			return (0);
		}
	}

	const StringArgument *pitArgument = static_cast<const StringArgument *>(arguments.GetArgument("pit"));

	bool repartition = arguments.GetArgument("repartition") != nullptr;

	if (repartition && !pitArgument)
	{
		Interface::Print("If you wish to repartition then a PIT file must be specified.\n\n");
		Interface::Print(FlashAction::usage);
		return (0);
	}

	// Open files
	
	FILE *pitFile = nullptr;
	vector<PartitionFile> partitionFiles;

	if (!openFiles(arguments, partitionFiles, pitFile))
	{
		closeFiles(partitionFiles, pitFile);
		return (1);
	}

	if (partitionFiles.size() == 0)
	{
		Interface::Print(FlashAction::usage);
		return (0);
	}

	// Info

	Interface::PrintReleaseInfo();
	Sleep(1000);

	// Perform flash

	BridgeManager *bridgeManager = new BridgeManager(verbose);
	bridgeManager->SetUsbLogLevel(usbLogLevel);

	if (bridgeManager->Initialise(resume) != BridgeManager::kInitialiseSucceeded || !bridgeManager->BeginSession())
	{
		closeFiles(partitionFiles, pitFile);
		delete bridgeManager;

		return (1);
	}

	bool success = sendTotalTransferSize(bridgeManager, partitionFiles, pitFile, repartition);

	if (success)
	{
		PitData *pitData = getPitData(bridgeManager, pitFile, repartition);
	
		if (pitData)
			success = flashPartitions(bridgeManager, partitionFiles, pitData, repartition);
		else
			success = false;

		delete pitData;
	}

	if (!bridgeManager->EndSession(reboot))
		success = false;

	delete bridgeManager;
	
	closeFiles(partitionFiles, pitFile);

	return (success ? 0 : 1);
}
Пример #2
0
int main(int argc, char **argv)
{
	map<string, string> argumentMap;
	int actionIndex;

	if (!InterfaceManager::GetArguments(argc, argv, argumentMap, &actionIndex))
	{
		Sleep(250);
		return (0);
	}

	initialiseKnownPartitionNames();

	if (actionIndex == InterfaceManager::kActionHelp)
	{
		InterfaceManager::Print(InterfaceManager::usage);
		return (0);
	}
	else if (actionIndex == InterfaceManager::kActionFlash)
	{
		if (argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgRepartition]) != argumentMap.end()
			&& argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgPit]) == argumentMap.end())
		{
			InterfaceManager::Print("If you wish to repartition then a PIT file must be specified.\n");
			return (0);
		}

		if (argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgPit]) != argumentMap.end()
			&& argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgRepartition]) == argumentMap.end())
		{
			InterfaceManager::Print("A PIT file should only be used when repartitioning.\n");
			return (0);
		}
	}
	else if (actionIndex == InterfaceManager::kActionDump)
	{
		if (argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgOutput]) == argumentMap.end())
		{
			InterfaceManager::Print("Output file not specified.\n\n");
			InterfaceManager::Print(InterfaceManager::usage);
			return (0);
		}

		if (argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipType]) == argumentMap.end())
		{
			InterfaceManager::Print("You must specify a chip type.\n\n");
			InterfaceManager::Print(InterfaceManager::usage);
			return (0);
		}

		string chipType = argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipType])->second;
		if (!(chipType == "RAM" || chipType == "ram" || chipType == "NAND" || chipType == "nand"))
		{
			InterfaceManager::Print("Unknown chip type: %s.\n\n", chipType.c_str());
			InterfaceManager::Print(InterfaceManager::usage);
			return (0);
		}

		if (argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipId]) == argumentMap.end())
		{
			InterfaceManager::Print("You must specify a Chip ID.\n\n");
			InterfaceManager::Print(InterfaceManager::usage);
			return (0);
		}

		int chipId = atoi(argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipId])->second.c_str());
		if (chipId < 0)
		{
			InterfaceManager::Print("Chip ID must be a non-negative integer.\n");
			return (0);
		}
	}

	InterfaceManager::Print("\nHeimdall v1.2.0, Copyright (c) 2010-2011, Benjamin Dobell, Glass Echidna\n");
	InterfaceManager::Print("http://www.glassechidna.com.au\n\n");
	InterfaceManager::Print("This software is provided free of charge. Copying and redistribution is\nencouraged.\n\n");
	InterfaceManager::Print("If you appreciate this software and you would like to support future\ndevelopment please consider donating:\n");
	InterfaceManager::Print("http://www.glassechidna.com.au/donate/\n\n");
	
	Sleep(1000);

	bool verbose = argumentMap.find(InterfaceManager::commonArgumentNames[InterfaceManager::kCommonArgVerbose]) != argumentMap.end();
	bool noReboot = argumentMap.find(InterfaceManager::commonArgumentNames[InterfaceManager::kCommonArgNoReboot]) != argumentMap.end();

	int communicationDelay = BridgeManager::kCommunicationDelayDefault;
	if (argumentMap.find(InterfaceManager::commonArgumentNames[InterfaceManager::kCommonArgDelay]) != argumentMap.end())
		communicationDelay = atoi(argumentMap.find(InterfaceManager::commonArgumentNames[InterfaceManager::kCommonArgDelay])->second.c_str());

	BridgeManager *bridgeManager = new BridgeManager(verbose, communicationDelay);

	if (!bridgeManager->Initialise())
	{
		delete bridgeManager;
		return (-2);
	}

	bool success;

	switch (actionIndex)
	{
		case InterfaceManager::kActionFlash:
		{
			map<string, FILE *> argumentFileMap;

			// We open the files before doing anything else to ensure they exist.
			if (!openFiles(argumentMap, argumentFileMap))
			{
				closeFiles(argumentFileMap);
				delete bridgeManager;

				return (0);
			}

			if (!bridgeManager->BeginSession())
			{
				closeFiles(argumentFileMap);
				delete bridgeManager;

				return (-1);
			}

			bool repartition = argumentMap.find(InterfaceManager::flashArgumentNames[InterfaceManager::kFlashArgRepartition]) != argumentMap.end();
			success = attemptFlash(bridgeManager, argumentFileMap, repartition);

			if (noReboot)
				success = bridgeManager->EndSession() && success;
			else
				success = bridgeManager->EndSession() && bridgeManager->RebootDevice() && success;

			closeFiles(argumentFileMap);

			break;
		}

		case InterfaceManager::kActionClosePcScreen:
		{
			if (!bridgeManager->BeginSession())
			{
				delete bridgeManager;
				return (-1);
			}

			InterfaceManager::Print("Attempting to close connect to pc screen...\n");

			if (noReboot)
				success = bridgeManager->EndSession();
			else
				success = bridgeManager->EndSession() && bridgeManager->RebootDevice();

			if (success)
				InterfaceManager::Print("Attempt complete\n");

			break;
		}

		case InterfaceManager::kActionDump:
		{
			const char *outputFilename = argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgOutput])->second.c_str();
			FILE *dumpFile = fopen(outputFilename, "wb");
			if (!dumpFile)
			{
				InterfaceManager::PrintError("Failed to open file \"%s\"\n", outputFilename);

				delete bridgeManager;
				return (-1);
			}

			int chipType = 0;
			string chipTypeName = argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipType])->second;
			if (chipTypeName == "NAND" || chipTypeName == "nand")
				chipType = 1;

			int chipId = atoi(argumentMap.find(InterfaceManager::dumpArgumentNames[InterfaceManager::kDumpArgChipId])->second.c_str());

			if (!bridgeManager->BeginSession())
			{
				fclose(dumpFile);

				delete bridgeManager;
				return (-1);
			}

			success = bridgeManager->ReceiveDump(chipType, chipId, dumpFile);

			fclose(dumpFile);

			if (noReboot)
				success = bridgeManager->EndSession() && success;
			else
				success = bridgeManager->EndSession() && bridgeManager->RebootDevice() && success;

			break;
		}

		case InterfaceManager::kActionPrintPit:
		{
			if (!bridgeManager->BeginSession())
			{
				delete bridgeManager;
				return (-1);
			}

			unsigned char *devicePit;

			if (downloadPitFile(bridgeManager, &devicePit) < -1)
			{
				if (!bridgeManager->EndSession())
					return (-1);

				if (!noReboot)
					bridgeManager->RebootDevice();

				delete bridgeManager;
				return (-1);
			}

			PitData *pitData = new PitData();

			if (pitData->Unpack(devicePit))
			{
				pitData->Print();
				success = true;
			}
			else
			{
				InterfaceManager::PrintError("Failed to unpack device's PIT file!\n");
				success = false;
			}

			delete pitData;

			if (noReboot)
				success = bridgeManager->EndSession() && success;
			else
				success = bridgeManager->EndSession() && bridgeManager->RebootDevice() && success;

			break;
		}
	}

	delete bridgeManager;

	return ((success) ? 0 : -1);
}