1 /*---------------------------------------------------------------------------* 2 3 Copyright 2010-2012 Nintendo. All rights reserved. 4 5 These coded instructions, statements, and computer programs contain 6 proprietary information of Nintendo of America Inc. and/or Nintendo 7 Company Ltd., and are protected by Federal copyright law. They may 8 not be disclosed to third parties or copied or duplicated in any form, 9 in whole or in part, without the prior written consent of Nintendo. 10 11 *---------------------------------------------------------------------------*/ 12 using System.Collections.Generic; 13 using System; 14 using System.IO; 15 using System.Runtime.InteropServices; 16 using System.Text; 17 using System.Globalization; 18 19 namespace CafeX 20 { 21 public enum CAFEX_ERROR 22 { 23 OK = 0, 24 UPDATE_BRINGUP_BOOT1_UPDATE = 0, 25 RUN_SOFT_LAUNCH_WITH_DISCRUN = 1, 26 ON_RECURSIVE_CALL = 1, 27 SETBOOTMODE_BAD_MODE = 1, 28 MASTERING_AOC_INVALID_PARAMETERS = 1, 29 RUN_RPX_DOESNT_EXIST = 2, 30 HOSTCHECKVERSION_NO_HOSTBRIDGE = 2, 31 HOSTCHECKVERSION_FSEMUL_FAILED = 2, 32 HOSTCHECKVERSION_OLD_VERSIONS = 2, 33 BOOTMODEDETECT_FSEMUL_FAILED = 2, 34 MASTERING_DOWNLOAD_MASTERPART_NOT_FOUND = 2, 35 MASTERING_DOWNLOAD_WUMA_NOT_FOUND = 2, 36 MASTERING_DISC_MASTER_ARCHIVE_NOT_PROVIDED = 3, 37 MASTERING_AOC_CONTENT_SECTION_NOT_FOUND = 3, 38 MASTERING_DOWNLOAD_INVALID_WUMA = 4, 39 MASTERING_AOC_TOO_MANY_CONTENT_DIRS = 4, 40 MASTERING_DISC_INVALID_MASTER_ARCHIVE = 3, 41 MASTERING_DOWNLOAD_INVALID_OUTPUT_BASE_DIR = 5, 42 RUN_HOSTSTOP_RVAL_NON_ZERO = 5, 43 RUN_NO_RPX_SPECIFIED = 6, 44 RUN_TITLE_ID_NOT_FOUND_IN_MLC = 7, 45 RUN_FASTLAUNCH_FAILED = 7, 46 MASTERING_DOWNLOAD_INVALID_TEMP_DIR = 7, 47 MASTERING_DISC_INVALID_TEMP_DIR = 7, 48 RUN_CANT_FIND_OS_DIRECTORY = 8, 49 RUN_OS_NOT_PRESENT = 8, 50 RUN_DASH_R_WITH_NO_PREVIOUS_LAUNCH_INFO = 9, 51 RUN_DASH_R_CANT_FIND_APPLICATION = 9, 52 RUN_DISCRUN_NAND_UNABLE_TO_FIND_APPLICATION = 9, 53 RUN_UPDATE_ARGLIST_FAILED = 11, 54 RUN_CHECKTITLEID_FAILED = 12, 55 RUN_UPDATE_APP_XML_FAILED = 12, 56 RUN_UPDATE_COS_XML_FAILED = 12, 57 RUN_UPDATE_META_XML_FAILED = 12, 58 RUN_UPDATE_SYSTEM_XML_FAILED = 12, 59 MASTERING_ERROR = 14, 60 RUN_BAD_DEBUGGER = 20, 61 RUN_BAD_DEBUGGER_PORT = 21, 62 RUN_TEST_MODE_WITH_NAND_BOOT = 25, 63 RUN_PCFSSERVER_SYNC_FAILED = 30, 64 BOOTRUN_MAKEBSF_FAILED = 30, 65 BOOTRUN_MAKEDLF_FAILED = 31, 66 CAFEDEVRUN_CAFEMAKEDLF_FAILED = 31, 67 CAFEDEVRUN_NO_IMAGE_FILE = 50, 68 CAFEDEVRUN_CANT_FIND_APP_XML = 53, 69 RUN_KILL_RESTART_FAILED = 54, 70 CHECKNAME_FAILED = 55, 71 72 73 // CafeX only 74 UNEXPECTED = -1, 75 NO_SDK_HOSTBRIDGE_ENV_VARS = -2, 76 BAD_COMMAND = -3, 77 BAD_ARGUMENT = -4, 78 NO_DEVKIT_VARS = -5, 79 NO_SESSIONMANAGER_DLL = -6, 80 RUN_SPACES_IN_CAFE_ROOT = -7, 81 RUN_COULDNT_PARSE_SDK_VERSION_HEADER = -8, 82 RUN_NO_SDK_VERSION_HEADER = -9, 83 RUN_BAD_H_ARGUMENT = -10, 84 RUN_INVALID_OPTION = -11, 85 RUN_NO_TEMP_VAR = -12, 86 BOOTRUN_NO_TEMP_VAR = -13, 87 RUN_NON_MULTI_DEBUGGER = -14, 88 UPDATE_INVALID_OPTION = -15, 89 SETBOOTMODE_FAILED = -16, 90 RUN_TITLE_ID_REQUIRED = -17, 91 SYNCTOOL_FAILED = -18, 92 RECOVERY_FAILED = -19, 93 CLEARDATA_FAILED = -20, 94 MIONURL_FAILED = -21, 95 IMAGEUPLOADER_FAILED = -22, 96 SYSLOG_LEVEL_SET_FAILED = -23, 97 UPDATE_FAILED = -24, 98 UPLOADED_IMAGE_OS_MISMATCH = -25, 99 RUN_LAUNCH_FAILED = -26, 100 MIONPS_ERROR = -27, //mionps will always return an error code of 17 on failure, so we must check the string associated with the error. 101 BOOT_SYNC_FAILED = -28, 102 TITLE_SYNC_FAILED = -29, 103 104 // Unmapped errors - should return 2 until BASH scripts map them to other values. 105 RUN_MEMMAP_NOT_SUPPORTED = 2, 106 RUN_BAD_TITLE_ID = 2, 107 RUN_NO_CAFE_DATA_DIR = 2, 108 RUN_D_OPTION_USED = 2, 109 ON_DATA_DIR_MISSING = 2, 110 } 111 112 internal class CafeXReturn 113 { 114 public CAFEX_ERROR error; 115 public int appExitCode; 116 117 /// <summary> 118 /// Constructor for CAFEX_ERROR class. Sets the Error to the user-specified error. 119 /// Exit code = 0. 120 /// </summary> 121 /// <param name="err"></param> CafeXReturn(CAFEX_ERROR err)122 public CafeXReturn(CAFEX_ERROR err) 123 { 124 error = err; 125 appExitCode = 0; 126 } 127 /// <summary> 128 /// Constructor for CAFEX_ERROR class. Sets the application error code 129 /// according to the app's actual exit code. Error = OK. 130 /// </summary> 131 /// <param name="exitcode"></param> CafeXReturn(int exitcode)132 public CafeXReturn(int exitcode) 133 { 134 error = CAFEX_ERROR.OK; 135 appExitCode = exitcode; 136 } 137 138 /// <summary> 139 /// Constructor for CAFEX_ERROR class. 140 /// </summary> 141 /// <param name="err">The Error CafeX should return</param> 142 /// <param name="exitcode">The exit code of the application</param> CafeXReturn(CAFEX_ERROR err, int exitcode)143 public CafeXReturn(CAFEX_ERROR err, int exitcode) 144 { 145 error = err; 146 appExitCode = exitcode; 147 } 148 CafeXReturn()149 public CafeXReturn() 150 { 151 error = CAFEX_ERROR.UNEXPECTED; 152 appExitCode = -1; 153 } 154 } 155 156 partial class Program 157 { 158 159 #if TIMER 160 public static PerfTimer CafeXSetupTime = new PerfTimer("CafeXSetupTime"); 161 #endif 162 163 private enum TargetEncoding 164 { 165 ConsoleIn, 166 ConsoleOut, 167 CafeOut 168 } 169 170 // This variable is set if cafex is called with '-q'. 171 internal static bool quiet_mode = false; 172 // this variable is set if cafex is called with -noinput 173 internal static bool no_console = false; 174 // The cafex command to execute. 175 internal static string command = string.Empty; 176 177 // Global software and firmware versions 178 internal static int sw_ver_flat = 0; 179 internal static int fw_ver_flat = 0; 180 181 internal static readonly uint RETRY_ATTEMPS = 3; 182 183 internal const int DEVKIT_HELP_REQUEST_TIMEOUT = 5000; 184 internal const int DEVKIT_HELP_RESPONSE_TIMEOUT = 5000; 185 186 internal const int COSDEBUG_FASTLAUNCH_RETRIES = 3; 187 internal const int COSDEBUG_FASTLAUNCH_TIMEOUT = 10000; // 10 seconds 188 internal const int COSDEBUG_FASTLAUNCH_DELAY = 2000; // 2 seconds 189 190 internal const int COSDEBUG_KILLRESTART_RETRIES = 1; 191 internal const int COSDEBUG_KILLRESTART_TIMEOUT = 1000; // 1 second 192 internal const int COSDEBUG_KILLRESTART_DELAY = 1000; // 1 second 193 194 internal const int KILLRESTART_SOFTLAUNCH_TIMEOUT = 10000; // 10 seconds 195 196 internal static readonly TimeSpan RETRY_TIMESPAN = new TimeSpan(0, 0, 1); 197 198 internal static readonly TimeSpan COS_REBOOT_DELAY = new TimeSpan(0, 0, 5); 199 200 internal static readonly TimeSpan COS_READY_DELAY = new TimeSpan(0, 0, 12); 201 202 static private string PERMISSION_ERROR_TEXT = "Check your permission to write to the file's directory, and that the file name provided does not conflict with an existing directory name."; 203 204 static public Encoding cafeOutEncoding; 205 206 // static private bool CALLED_FROM_CYGWIN = false; 207 /// <summary> 208 /// Cleans up input argument array by removing any empty ones, and 209 /// breaking up those that are not spaced out properly (eg. -t0x00...) 210 /// which makes the argument parsing logic more reliable. 211 /// </summary> 212 /// <param name="args">Input argument array of strings.</param> 213 /// <returns>New array of arguments.</returns> CleanupArguments(string[] args)214 static private string[] CleanupArguments(string[] args) 215 { 216 #if DEBUG 217 Log.WriteLine("CleanEmptArguments started."); 218 #endif 219 220 List<string> newList = new List<string>(); 221 int rpxIndex = int.MaxValue; 222 bool rpxFound = false; 223 224 for (int counter = 0; counter < args.Length; ++counter) 225 { 226 string argument = args[counter]; 227 228 if (argument != null) 229 { 230 bool breakUpParameter = false; 231 bool notAfterDashA = false; 232 233 if (argument.Length > 2) 234 { 235 if (!rpxFound) 236 { 237 if (argument.ToLowerInvariant().EndsWith(".rpx") || 238 argument.ToLowerInvariant().EndsWith(".elf")) 239 { 240 rpxFound = true; 241 rpxIndex = counter; 242 } 243 } 244 245 if (counter < rpxIndex) 246 { 247 // Special Cases 248 switch (argument.Substring(0, 2)) 249 { 250 case "-t": 251 notAfterDashA = (counter == 0) || (!(args[counter - 1].StartsWith("-a"))); 252 if (notAfterDashA) 253 { 254 breakUpParameter = true; 255 } 256 break; 257 case "-w": 258 notAfterDashA = (counter == 0) || (!(args[counter - 1].StartsWith("-a"))); 259 if (notAfterDashA) 260 { 261 breakUpParameter = true; 262 } 263 break; 264 default: 265 // Nothing to do : breakUpParameter = false 266 break; 267 } 268 } 269 } 270 271 if (breakUpParameter) 272 { 273 // This is a case where the cafe argument and setting are not spaced out properly 274 newList.Add(argument.Substring(0, 2)); 275 newList.Add(argument.Substring(2)); 276 } 277 else 278 { 279 // Just add the argument - it is good! 280 newList.Add(argument); 281 } 282 } 283 } 284 285 return newList.ToArray(); 286 } 287 288 /// <summary> 289 /// Sets either the Console.In or Console.Out encoding using the encoder name or codepage provided. 290 /// </summary> 291 /// <param name="target">Console In or Console Out.</param> 292 /// <param name="encoderValue">String representing the codepage or encoding name.</param> 293 /// <returns>True if encoding was changed, false if not.</returns> SetEncoding(TargetEncoding target, string encoderValue)294 static private bool SetEncoding(TargetEncoding target, string encoderValue) 295 { 296 if (string.IsNullOrEmpty(encoderValue)) 297 { 298 // It will use the default encoders. 299 return false; 300 } 301 302 int codePage = 0; 303 bool returnVal = false; 304 string defaultEncodingCodePage = Encoding.Default.WindowsCodePage.ToString(); 305 306 // could be a string as the name of the encoding 307 if (encoderValue.ToLowerInvariant().Equals("default")) 308 { 309 encoderValue = defaultEncodingCodePage; 310 } 311 312 //handle situation where user provides the number for the codepage 313 if (int.TryParse(encoderValue, out codePage)) 314 { 315 if (codePage > 0) 316 { 317 //It was given a valid codepage 318 try 319 { 320 switch (target) 321 { 322 case TargetEncoding.ConsoleIn: 323 Console.InputEncoding = Encoding.GetEncoding(codePage); 324 returnVal = true; 325 break; 326 case TargetEncoding.ConsoleOut: 327 Console.OutputEncoding = Encoding.GetEncoding(codePage); 328 returnVal = true; 329 break; 330 case TargetEncoding.CafeOut: 331 Program.cafeOutEncoding = Encoding.GetEncoding(codePage); 332 returnVal = true; 333 break; 334 } 335 } 336 catch (ArgumentOutOfRangeException) 337 { } 338 catch (ArgumentException) 339 { } 340 catch (NotSupportedException) 341 { } 342 catch (IOException) 343 { } 344 catch (System.Security.SecurityException) 345 { } 346 } 347 } 348 else //did they pass in the string representation of the encoding? 349 { 350 try 351 { 352 switch (target) 353 { 354 case TargetEncoding.ConsoleIn: 355 Console.InputEncoding = Encoding.GetEncoding(encoderValue); 356 returnVal = true; 357 break; 358 case TargetEncoding.ConsoleOut: 359 Console.OutputEncoding = Encoding.GetEncoding(encoderValue); 360 returnVal = true; 361 break; 362 case TargetEncoding.CafeOut: 363 Program.cafeOutEncoding = Encoding.GetEncoding(encoderValue); 364 returnVal = true; 365 break; 366 } 367 } 368 catch (ArgumentException) 369 { } 370 catch (NotSupportedException) 371 { } 372 catch (IOException) 373 { } 374 catch (System.Security.SecurityException) 375 { } 376 } 377 378 if (!returnVal && !encoderValue.Equals(defaultEncodingCodePage)) 379 { 380 // Failed with the user request, trying to default 381 Console.WriteLine("cafex : unable to set {0} encoding to {1}. Reverting to default {2}.", target.ToString(), encoderValue, defaultEncodingCodePage); 382 return SetEncoding(target, defaultEncodingCodePage); 383 } 384 385 return returnVal; 386 } 387 388 private static HandlerRoutine cchr = null; 389 ConsoleCtrlCheck(CtrlTypes ctrlType)390 private static bool ConsoleCtrlCheck(CtrlTypes ctrlType) 391 { 392 Console.WriteLine("\ncafex: terminated"); 393 Environment.Exit(0); 394 return true; 395 } 396 Main(string[] args)397 static int Main(string[] args) 398 { 399 #if TIMER 400 string logFilePath = "%CAFE_TEMP%\\%SESSION_PATH_PREFIX%caferun\\CafeXPerf.log"; 401 Log.OpenLogFile(logFilePath); 402 CafeXSetupTime.Start(); 403 #endif 404 cchr = new HandlerRoutine(ConsoleCtrlCheck); 405 SetConsoleCtrlHandler(cchr, true); 406 GC.KeepAlive(cchr); 407 408 #if DEBUG 409 // System.Diagnostics.Debugger.Break(); 410 string logFilePath = "%CAFE_TEMP%\\%SESSION_PATH_PREFIX%caferun\\CafeX.log"; 411 Log.OpenLogFile(logFilePath); 412 Log.WriteLine("-------------------------- CAFEX NEW INSTANCE ----------------------------------"); 413 Log.WriteLine("Main started. Command line = " + Environment.CommandLine); 414 #endif 415 416 if(CAFE_PROFILE.value != null && CAFE_PROFILE.value == "1") 417 { 418 Console.WriteLine("CafeX: Profiling is enabled!"); 419 CafeXEventtLog.Instance.WriteToEventLog(500, DateTime.Now, EventStatus.BEGIN, EventProcess.CAFEX, "CAFEX NEW INSTANCE"); 420 } 421 StreamWriter output_writer = null; 422 TextWriter old_out = null; 423 TextWriter old_err = null; 424 425 FileUtil.GatherEnvironment(); 426 427 // Setting default encoding variables 428 if (string.IsNullOrEmpty(CAFEX_STDIN_ENCODING.value)) 429 { 430 CAFEX_STDIN_ENCODING.value = "default"; 431 } 432 433 if (string.IsNullOrEmpty(CAFEX_STDOUT_ENCODING.value)) 434 { 435 // Standard out should be different depending on the country. 436 int defaultEncodingCodePage = Encoding.Default.WindowsCodePage; 437 switch(defaultEncodingCodePage) 438 { 439 case 932: //Japan - Shift_JIS 440 CAFEX_STDOUT_ENCODING.value = "default"; 441 break; 442 default: 443 CAFEX_STDOUT_ENCODING.value = "utf-8"; 444 break; 445 } 446 } 447 448 try 449 { 450 int arg_pos = 0; 451 args = CleanupArguments(args); 452 453 // Handle the arguments to cafex in any order. 454 // Valid options are -q and -o. 455 while (true) 456 { 457 if (args.Length > arg_pos && args[arg_pos] == "-q") 458 { 459 quiet_mode = true; 460 ++arg_pos; 461 } 462 // Format for -o is -o [filename], so need to make sure there are 2 more arguments. 463 else if (args.Length > arg_pos + 1 && args[arg_pos] == "-o") 464 { 465 if (!ArgumentChecks.IsArgumentValidSetting(args, arg_pos + 1)) 466 { 467 PrintCafeXHelp(); 468 return (int)CAFEX_ERROR.BAD_ARGUMENT; 469 } 470 471 string output_file = PathConverter.Windowsify(args[arg_pos + 1]); 472 if (!FileUtil.IsValidFile(output_file, false)) 473 { 474 Console.WriteLine("Invalid file name!\n"); 475 PrintCafeXHelp(); 476 return (int) CAFEX_ERROR.BAD_ARGUMENT; 477 } 478 479 arg_pos += 2; 480 481 FileStream fs = null; 482 try 483 { 484 fs = new FileStream(output_file, FileMode.Create); 485 } 486 catch (System.UnauthorizedAccessException) 487 { 488 Console.WriteLine(PERMISSION_ERROR_TEXT); 489 PrintCafeXHelp(); 490 return (int)CAFEX_ERROR.BAD_ARGUMENT; 491 } 492 catch (System.Security.SecurityException) 493 { 494 Console.WriteLine(PERMISSION_ERROR_TEXT); 495 PrintCafeXHelp(); 496 return (int)CAFEX_ERROR.BAD_ARGUMENT; 497 } 498 499 old_out = Console.Out; 500 old_err = Console.Error; 501 output_writer = new StreamWriter(fs); 502 Console.SetOut(output_writer); 503 Console.SetError(output_writer); 504 } 505 else if (args.Length > arg_pos + 1 && args[arg_pos] == "-I") 506 { 507 // Get the STDIN encoding 508 if (!ArgumentChecks.IsArgumentValidSetting(args, arg_pos + 1)) 509 { 510 PrintCafeXHelp(); 511 return (int)CAFEX_ERROR.BAD_ARGUMENT; 512 } 513 514 CAFEX_STDIN_ENCODING.value = args[arg_pos + 1]; 515 arg_pos += 2; 516 } 517 else if (args.Length > arg_pos + 1 && args[arg_pos] == "-O") 518 { 519 if (!ArgumentChecks.IsArgumentValidSetting(args, arg_pos + 1)) 520 { 521 PrintCafeXHelp(); 522 return (int)CAFEX_ERROR.BAD_ARGUMENT; 523 } 524 525 CAFEX_STDOUT_ENCODING.value = args[arg_pos + 1]; 526 arg_pos += 2; 527 } 528 else if (args[arg_pos] == "-noinput") 529 { 530 no_console = true; 531 arg_pos++; 532 } 533 else 534 { 535 // If it's anything else then it's the command. 536 break; 537 } 538 } 539 540 541 // Get the command. 542 if (args.Length > arg_pos) 543 { 544 command = args[arg_pos].ToLowerInvariant(); 545 ++arg_pos; 546 } 547 548 CAFEX_ERROR ret = InitialEnvVarSetup(); 549 if (ret != CAFEX_ERROR.OK) 550 { 551 return (int)ret; 552 } 553 554 ret = CheckCafeRootAndHostBridgeVars(); 555 if (ret != CAFEX_ERROR.OK) 556 { 557 return (int)ret; 558 } 559 560 if (!string.IsNullOrEmpty(NO_CONSOLE.value) && NO_CONSOLE.value == "1") 561 { 562 // Disable console input if it was specified in the enviromnment 563 no_console = true; 564 } 565 566 // Sets the quiet mode if CAFE_CONSOLE is toucan and 567 // "-q" parameter was not provided by caller. 568 if (!quiet_mode && (CAFE_CONSOLE.value != "cattoucan")) 569 { 570 quiet_mode = true; 571 } 572 else if (CAFE_CONSOLE.value == "cattoucan") 573 { 574 // If explicitly setting console to cattoucan, it 575 // should override even if the "-q" parameter was 576 // set. This solves validation.sh tests running 577 // in softlaunch mode. 578 quiet_mode = false; 579 } 580 581 // Print the encoding 582 if (!command.Equals("stop")) 583 { 584 // Set encodings 585 if (CafeX.Program.IsInputRedirected) 586 { 587 Console.WriteLine("cafex : input is redirected. Using legacy keyboard input and not changing encodings."); 588 } 589 else 590 { 591 SetEncoding(TargetEncoding.ConsoleIn, CAFEX_STDIN_ENCODING.value); 592 SetEncoding(TargetEncoding.ConsoleOut, CAFEX_STDOUT_ENCODING.value); 593 594 Console.WriteLine("cafex input/keyboard encoding code page: {0}", Console.InputEncoding.CodePage); 595 Console.WriteLine("cafex output/screen encoding code page: {0}", Console.OutputEncoding.CodePage); 596 } 597 598 //always want to set this. 599 SetEncoding(TargetEncoding.CafeOut, CAFE_OUTPUT_ENCODING.value); 600 if (Program.cafeOutEncoding != null) 601 { 602 Console.WriteLine("cafe output/stream encoding code page: {0}", Program.cafeOutEncoding.CodePage); 603 } 604 } 605 606 int args_to_copy = args.Length - arg_pos; 607 string[] args_for_command = new string[args_to_copy]; 608 Array.Copy(args, arg_pos, args_for_command, 0, args_to_copy); 609 610 CafeXReturn exitCode = DoCommand(args_for_command, quiet_mode); 611 if (exitCode.error == CAFEX_ERROR.BAD_ARGUMENT) 612 { 613 Console.WriteLine("cafex : Bad command."); 614 PrintCafeXHelp(); 615 } 616 617 if (exitCode.error != CAFEX_ERROR.OK) 618 return (int)exitCode.error; 619 else 620 return exitCode.appExitCode; 621 } 622 catch (Exception e) 623 { 624 Console.OutputEncoding.GetEncoder().Reset(); 625 string errorFile = "cafexErrorLog_" + System.Diagnostics.Process.GetCurrentProcess().Id.ToString() + "_" + 626 DateTime.Now.ToString("yyyyMMddHHmm") + ".log"; 627 string errorLog = "CafeX error log\nDate:" + DateTime.Now + "\nError message:" + 628 e.Message + "\nStack trace:" + e.StackTrace + "\n"; 629 if (string.IsNullOrEmpty(CAFE_TEMP.value)) 630 { 631 errorFile = Path.Combine(Directory.GetCurrentDirectory(), SESSION_PATH_PREFIX.value + errorFile); 632 } 633 else 634 { 635 errorFile = Path.Combine(CAFE_TEMP.value, SESSION_PATH_PREFIX.value + errorFile); 636 } 637 638 try 639 { 640 System.IO.File.WriteAllText(errorFile, errorLog); 641 Console.WriteLine("CafeX error log was saved as '{0}'", errorFile); 642 } 643 catch (IOException) 644 { 645 Console.WriteLine("Unable to write the file '{0}'", errorFile); 646 Console.WriteLine("Writing log to console window:"); 647 Console.WriteLine(errorLog); 648 } 649 650 Console.WriteLine("CafeX encountered an error executing the command."); 651 Console.WriteLine("Please confirm this is a supported command and has the correct arguments."); 652 Console.WriteLine("Error message: " + e.Message); 653 654 return (int)CAFEX_ERROR.UNEXPECTED; 655 } 656 finally 657 { 658 // Re-set the original stdout and stderr. 659 if (output_writer != null) 660 { 661 Console.SetOut(old_out); 662 Console.SetError(old_err); 663 output_writer.Close(); 664 } 665 #if DEBUG || TIMER 666 Log.WriteLine("-------------------------- END OF CAFEX INSTANCE ----------------------------------"); 667 Log.CloseLogFile(); 668 #endif 669 if (CAFE_PROFILE.value != null && CAFE_PROFILE.value == "1") 670 { 671 CafeXEventtLog.Instance.WriteToEventLog(501, DateTime.Now, EventStatus.END, EventProcess.CAFEX, "END OF CAFEX INSTANCE"); 672 } 673 674 } 675 676 } 677 678 CheckCafeRootAndHostBridgeVars()679 internal static CAFEX_ERROR CheckCafeRootAndHostBridgeVars() 680 { 681 #if DEBUG 682 Log.WriteLine("CheckCafeRootAndHostBridgeVars started."); 683 #endif 684 685 CAFEX_ERROR ret = CAFEX_ERROR.OK; 686 687 if (CAFE_ROOT.value == null) 688 { 689 Console.WriteLine("CafeX Error: CAFE_ROOT environment variable is not set."); 690 ret = CAFEX_ERROR.NO_SDK_HOSTBRIDGE_ENV_VARS; 691 } 692 if (MION_BRIDGE_TOOLS.value == null) 693 { 694 Console.WriteLine("CafeX Error: MION_BRIDGE_TOOLS environment variable is not set."); 695 ret = CAFEX_ERROR.NO_SDK_HOSTBRIDGE_ENV_VARS; 696 } 697 698 return ret; 699 } 700 CheckDevkitVars()701 internal static CAFEX_ERROR CheckDevkitVars() 702 { 703 #if DEBUG 704 Log.WriteLine("CheckDevkitVars started. Retuns CAFEX_ERRO.OK if BRIDGE_CURRENT_NAME and BRIDGE_CURRENT_IP_ADDRESS are provided."); 705 #endif 706 707 CAFEX_ERROR ret = CAFEX_ERROR.OK; 708 709 if (string.IsNullOrEmpty(BRIDGE_CURRENT_NAME.value)) 710 { 711 Console.WriteLine("CafeX Error: BRIDGE_CURRENT_NAME environment variable is not set."); 712 ret = CAFEX_ERROR.NO_DEVKIT_VARS; 713 } 714 if (string.IsNullOrEmpty(BRIDGE_CURRENT_IP_ADDRESS.value)) 715 { 716 Console.WriteLine("CafeX Error: BRIDGE_CURRENT_IP_ADDRESS environment variable is not set."); 717 ret = CAFEX_ERROR.NO_DEVKIT_VARS; 718 } 719 720 return ret; 721 } 722 DoCommand(string[] args, bool quiet_mode)723 internal static CafeXReturn DoCommand(string[] args, bool quiet_mode) 724 { 725 #if DEBUG 726 Log.WriteLine("DoCommand started. quiet_mode=" + quiet_mode.ToString()); 727 string argString = null; 728 if (args != null) 729 { 730 foreach (string arg in args) 731 { 732 argString += arg + " "; 733 } 734 } 735 Log.WriteLine("Arguments=" + argString); 736 #endif 737 738 CafeXReturn ret = new CafeXReturn(CAFEX_ERROR.OK); 739 740 switch (command.ToLowerInvariant()) 741 { 742 case "help": 743 { 744 PrintCafeXHelp(); 745 break; 746 } 747 748 case "stop": 749 { 750 ret.error = CheckDevkitVars(); 751 if (ret.error != CAFEX_ERROR.OK) 752 break; 753 754 stop(args); 755 756 break; 757 } 758 759 case "run": 760 { 761 ret.error = CheckDevkitVars(); 762 if (ret.error != CAFEX_ERROR.OK) 763 break; 764 765 ret = run(args, true, true); 766 767 break; 768 } 769 770 case "discrun": 771 { 772 ret.error = CheckDevkitVars(); 773 if (ret.error != CAFEX_ERROR.OK) 774 break; 775 776 ret = discrun(args, true, true); 777 778 break; 779 } 780 781 case "headlessrun": 782 { 783 ret.error = CheckDevkitVars(); 784 if (ret.error != CAFEX_ERROR.OK) 785 break; 786 787 ret = headlessrun(args); 788 break; 789 } 790 791 case "on": 792 { 793 ret.error = CheckDevkitVars(); 794 if (ret.error != CAFEX_ERROR.OK) 795 break; 796 797 ret = on(args, true, true); 798 799 break; 800 } 801 802 case "update": 803 { 804 ret.error = CheckDevkitVars(); 805 if (ret.error != CAFEX_ERROR.OK) 806 break; 807 808 ret.error = update(args); 809 810 break; 811 } 812 813 case "revert": 814 { 815 ret.error = CheckDevkitVars(); 816 if (ret.error != CAFEX_ERROR.OK) 817 break; 818 819 ret.error = revert(args); 820 821 break; 822 } 823 824 case "recover": 825 { 826 ret.error = CheckDevkitVars(); 827 if (ret.error != CAFEX_ERROR.OK) 828 break; 829 830 ret.error = recover(args); 831 832 break; 833 } 834 835 case "cleardata": 836 { 837 ret.error = CheckDevkitVars(); 838 if (ret.error != CAFEX_ERROR.OK) 839 break; 840 841 ret.error = cleardata(args); 842 843 break; 844 } 845 846 case "setbootmode": 847 { 848 ret.error = CheckDevkitVars(); 849 if (ret.error != CAFEX_ERROR.OK) 850 break; 851 852 ret.error = setbootmode(args); 853 854 break; 855 } 856 857 case "syncsession": 858 { 859 ret.error = CheckDevkitVars(); 860 if (ret.error != CAFEX_ERROR.OK) 861 break; 862 863 ret.error = syncsession(args); 864 865 break; 866 } 867 case "makeaoc": 868 case "makemaster": 869 case "makedisc": 870 case "makedownload": 871 { 872 Console.WriteLine("CafeX Error: This function is no longer supported. Please use makecfmaster.exe to use commands for mastering."); 873 ret.error = CAFEX_ERROR.BAD_COMMAND; 874 break; 875 } 876 case "findbridges": 877 { 878 break; 879 } 880 881 case "version": 882 { 883 System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly(); 884 885 // With an AssemblyVersion of <major>.<minor>.*, the build is the number of days since 1/1/2000 886 // and the revision is the number of seconds since midnight 887 Version asmVer = asm.GetName().Version; 888 889 DateTime buildDate = new DateTime(2000, 1, 1); // Start at 1/1/2000 890 buildDate = buildDate.AddDays(asmVer.Build); // Add the days since 1/1/2000 891 buildDate = buildDate.AddSeconds(asmVer.Revision * 2); // Add the number of seconds since midnight 892 893 System.Diagnostics.FileVersionInfo fileVer = System.Diagnostics.FileVersionInfo.GetVersionInfo(asm.Location); 894 895 //NEVER EVER CHANGE THE NEXT TWO LINES. YOUR LIFE MAY BE FORFEIT IF YOU DO. 896 Console.WriteLine("cafex {0}", fileVer.FileVersion); 897 Console.WriteLine("{0}",buildDate.ToString("MM/dd/yyyy hh:mm tt",DateTimeFormatInfo.InvariantInfo)); 898 899 ret.error = CAFEX_ERROR.OK; 900 break; 901 } 902 case "launch": 903 { 904 ret.error = launchTitle(args); 905 break; 906 } 907 default: 908 { 909 if (string.IsNullOrEmpty(command) || command.StartsWith("-")) 910 { 911 Console.WriteLine("CafeX Error: Missing command. Please try \"cafex help\" for usage information."); 912 } 913 else 914 { 915 Console.WriteLine("CafeX Error: Invalid command '{0}'. Please try \"cafex help\" for usage information.", command); 916 } 917 ret.error = CAFEX_ERROR.BAD_COMMAND; 918 break; 919 } 920 } 921 922 return ret; 923 } 924 925 private enum FileType { Unknown, Disk, Char, Pipe }; 926 private enum StdHandle { Stdin = -10, Stdout = -11, Stderr = -12 }; 927 [DllImport("kernel32.dll")] GetFileType(IntPtr hdl)928 private static extern FileType GetFileType(IntPtr hdl); 929 [DllImport("kernel32.dll")] GetStdHandle(StdHandle std)930 private static extern IntPtr GetStdHandle(StdHandle std); 931 [DllImport("Kernel32")] SetConsoleCtrlHandler(HandlerRoutine Handler, Boolean Add)932 public static extern Boolean SetConsoleCtrlHandler(HandlerRoutine Handler, 933 Boolean Add); 934 935 // sent to the handler routine. 936 public enum CtrlTypes 937 { 938 939 CTRL_C_EVENT = 0, 940 CTRL_BREAK_EVENT, 941 CTRL_CLOSE_EVENT, 942 CTRL_LOGOFF_EVENT = 5, 943 CTRL_SHUTDOWN_EVENT 944 } 945 946 947 // A delegate type to be used as the handler routine 948 // for SetConsoleCtrlHandler. HandlerRoutine(CtrlTypes CtrlType)949 public delegate bool HandlerRoutine(CtrlTypes CtrlType); 950 951 internal static bool IsOutputRedirected 952 { 953 get 954 { 955 return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdout)); 956 } 957 } 958 959 internal static bool IsInputRedirected 960 { 961 get 962 { 963 return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdin)); 964 } 965 } 966 967 PrintCafeXHelp()968 internal static void PrintCafeXHelp() 969 { 970 Console.WriteLine("Usage: cafex [options] [command] [arguments]"); 971 Console.WriteLine(); 972 Console.WriteLine("options:"); 973 Console.WriteLine(" -q The command will be executed, and CafeX returns immediately. No output is collected."); 974 Console.WriteLine(" -o <filename> All output is redirected to the specified file."); 975 Console.WriteLine(" -I <encoding> The encoding for the console standard in. Valid encoding arguments are: codepage"); 976 Console.WriteLine(" (eg. 65001, 932, etc), or the encoding name (eg. UTF-8, shift_jis, etc)."); 977 Console.WriteLine(" This setting overrides the CAFEX_STDIN_ENCODING environment variable."); 978 Console.WriteLine(" Note: If the environment variable and this switch is not provided, the default windows encoding is used."); 979 Console.WriteLine(" -O <encoding> The encoding for the console standard out. Valid encoding arguments are: codepage"); 980 Console.WriteLine(" (eg. 65001, 932, etc), or the encoding name (eg. UTF-8, shift_jis, etc)."); 981 Console.WriteLine(" This setting overrides the CAFEX_STDOUT_ENCODING environment variable."); 982 Console.WriteLine(" Note: If the environment variable and this switch is not provided, UTF-8 is default."); 983 Console.WriteLine(" -noinput Disables reading of the PC keyboard or STDIN if redirected."); 984 Console.WriteLine(" Note: Setting the environment variable NO_CONSOLE=1 has the same effect."); 985 Console.WriteLine(); 986 Console.WriteLine("commands:"); 987 Console.WriteLine(" stop Stop the devkit."); 988 Console.WriteLine(" run Run an application."); 989 Console.WriteLine(" discrun Run an application using block level interface."); 990 Console.WriteLine(" headlessrun Run an application disconnected from the network."); 991 Console.WriteLine(" on Start System Config Tool."); 992 Console.WriteLine(" update Update devkit firmware."); 993 Console.WriteLine(" revert Downgrade devkit OS to an older SDK."); 994 Console.WriteLine(" recover Attempt to recover a devkit from corrupted OS."); 995 Console.WriteLine(" cleardata Clear the user data in NAND."); 996 Console.WriteLine(" setbootmode Change the boot mode of the devkit."); 997 Console.WriteLine(" syncsession Sync the session data directory with the default one."); 998 Console.WriteLine(" launch Launches a title through system config tool"); 999 Console.WriteLine(); 1000 Console.WriteLine(" version Prints version and build information then exits."); 1001 Console.WriteLine(); 1002 Console.WriteLine("arguments:"); 1003 Console.WriteLine("Execute cafex [command] -h for information on valid arguments for each command."); 1004 } 1005 } 1006 } 1007