diff options
Diffstat (limited to 'src/gui.cpp')
| -rw-r--r-- | src/gui.cpp | 91 |
1 files changed, 61 insertions, 30 deletions
diff --git a/src/gui.cpp b/src/gui.cpp index 672f0ff..296d20c 100644 --- a/src/gui.cpp +++ b/src/gui.cpp | |||
| @@ -1410,63 +1410,94 @@ static bool g_wizardConverted = false; | |||
| 1410 | static int g_restartArgc = 0; | 1410 | static int g_restartArgc = 0; |
| 1411 | static char** g_restartArgv = NULL; | 1411 | static char** g_restartArgv = NULL; |
| 1412 | 1412 | ||
| 1413 | #ifdef _WIN32 | ||
| 1414 | // Quote one argument so CommandLineToArgvW parses it back to exactly this | ||
| 1415 | // string: only backslashes that immediately precede a double quote (including | ||
| 1416 | // the closing one) are doubled, so ordinary Windows paths are not mangled. | ||
| 1417 | static std::string QuoteArgWin(const std::string& a) | ||
| 1418 | { | ||
| 1419 | if (!a.empty() && a.find_first_of(" \t\"") == std::string::npos) | ||
| 1420 | return a; | ||
| 1421 | std::string r = "\""; | ||
| 1422 | size_t bs = 0; | ||
| 1423 | for (size_t i = 0; i < a.size(); i++) | ||
| 1424 | { | ||
| 1425 | if (a[i] == '\\') { bs++; continue; } | ||
| 1426 | if (a[i] == '"') { r.append(bs * 2 + 1, '\\'); r += '"'; bs = 0; continue; } | ||
| 1427 | r.append(bs, '\\'); bs = 0; r += a[i]; | ||
| 1428 | } | ||
| 1429 | r.append(bs * 2, '\\'); | ||
| 1430 | r += "\""; | ||
| 1431 | return r; | ||
| 1432 | } | ||
| 1433 | #endif | ||
| 1434 | |||
| 1413 | // Relaunch Bitflash with the same arguments and datadir, then ask this instance | 1435 | // Relaunch Bitflash with the same arguments and datadir, then ask this instance |
| 1414 | // to exit. A short delay lets the old process release the network port and the | 1436 | // to exit -- but only once the relaunch has actually started, so a failure never |
| 1415 | // block-index files before the new one opens them, so mining resumes cleanly on | 1437 | // leaves the user with no node running. The new instance waits (-restartwait) |
| 1416 | // the SQLite wallet instead of both instances fighting over the same files. | 1438 | // before it opens the network port and the block index, so this one is gone |
| 1439 | // first and they never fight over the same files. | ||
| 1417 | static void RestartApplication() | 1440 | static void RestartApplication() |
| 1418 | { | 1441 | { |
| 1442 | bool fLaunched = false; | ||
| 1419 | #ifdef _WIN32 | 1443 | #ifdef _WIN32 |
| 1420 | char exePath[MAX_PATH]; | 1444 | char exePath[MAX_PATH]; |
| 1421 | if (GetModuleFileNameA(NULL, exePath, MAX_PATH) == 0) | 1445 | if (GetModuleFileNameA(NULL, exePath, MAX_PATH) == 0) |
| 1422 | return; | 1446 | return; |
| 1423 | std::string strArgs; | 1447 | std::string strCmd = QuoteArgWin(exePath); |
| 1424 | bool fHasDataDir = false; | 1448 | bool fHasDataDir = false; |
| 1425 | for (int i = 1; i < g_restartArgc; i++) | 1449 | for (int i = 1; i < g_restartArgc; i++) |
| 1426 | { | 1450 | { |
| 1427 | std::string a = g_restartArgv[i] ? g_restartArgv[i] : ""; | 1451 | std::string a = g_restartArgv[i] ? g_restartArgv[i] : ""; |
| 1428 | if (a.find("-datadir=") == 0 || a.find("/datadir=") == 0) | 1452 | if (a.find("-datadir=") == 0 || a.find("/datadir=") == 0) |
| 1429 | fHasDataDir = true; | 1453 | fHasDataDir = true; |
| 1430 | strArgs += " \"" + a + "\""; | 1454 | strCmd += " " + QuoteArgWin(a); |
| 1431 | } | 1455 | } |
| 1432 | if (!fHasDataDir) | 1456 | if (!fHasDataDir) |
| 1433 | strArgs += " \"-datadir=" + GetAppDir() + "\""; | 1457 | strCmd += " " + QuoteArgWin("-datadir=" + GetAppDir()); |
| 1434 | 1458 | strCmd += " -restartwait"; | |
| 1435 | std::string strBat = GetAppDir() + "\\bitflash-restart.bat"; | 1459 | |
| 1436 | FILE* pf = fopen(strBat.c_str(), "wb"); | 1460 | std::vector<char> cmdBuf(strCmd.begin(), strCmd.end()); |
| 1437 | if (pf) | 1461 | cmdBuf.push_back('\0'); |
| 1462 | STARTUPINFOA si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); | ||
| 1463 | PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(pi)); | ||
| 1464 | if (CreateProcessA(NULL, &cmdBuf[0], NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) | ||
| 1438 | { | 1465 | { |
| 1439 | // ping is the reliable no-console delay on Windows; timeout needs a tty. | 1466 | CloseHandle(pi.hProcess); |
| 1440 | fprintf(pf, | 1467 | CloseHandle(pi.hThread); |
| 1441 | "@echo off\r\n" | 1468 | fLaunched = true; |
| 1442 | "ping 127.0.0.1 -n 3 >nul\r\n" | ||
| 1443 | "start \"\" \"%s\"%s\r\n" | ||
| 1444 | "del \"%%~f0\"\r\n", | ||
| 1445 | exePath, strArgs.c_str()); | ||
| 1446 | fclose(pf); | ||
| 1447 | std::string strCmd = "cmd /c \"" + strBat + "\""; | ||
| 1448 | STARTUPINFOA si; memset(&si, 0, sizeof(si)); si.cb = sizeof(si); | ||
| 1449 | PROCESS_INFORMATION pi; memset(&pi, 0, sizeof(pi)); | ||
| 1450 | if (CreateProcessA(NULL, (char*)strCmd.c_str(), NULL, NULL, FALSE, | ||
| 1451 | CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) | ||
| 1452 | { | ||
| 1453 | CloseHandle(pi.hProcess); | ||
| 1454 | CloseHandle(pi.hThread); | ||
| 1455 | } | ||
| 1456 | } | 1469 | } |
| 1457 | #else | 1470 | #else |
| 1458 | pid_t pid = fork(); | 1471 | pid_t pid = fork(); |
| 1459 | if (pid == 0) | 1472 | if (pid == 0) |
| 1460 | { | 1473 | { |
| 1474 | // Child: wait for the parent to release the port and files, then re-exec. | ||
| 1475 | // /proc/self/exe is the reliable absolute path; argv[0] may be relative | ||
| 1476 | // or a bare name that execv() cannot resolve. | ||
| 1461 | sleep(2); | 1477 | sleep(2); |
| 1478 | char exePath[4096]; | ||
| 1479 | ssize_t len = readlink("/proc/self/exe", exePath, sizeof(exePath) - 1); | ||
| 1480 | if (len > 0) | ||
| 1481 | { | ||
| 1482 | exePath[len] = '\0'; | ||
| 1483 | execv(exePath, g_restartArgv); | ||
| 1484 | } | ||
| 1462 | if (g_restartArgv) | 1485 | if (g_restartArgv) |
| 1463 | execv(g_restartArgv[0], g_restartArgv); | 1486 | execv(g_restartArgv[0], g_restartArgv); |
| 1464 | _exit(127); | 1487 | _exit(127); |
| 1465 | } | 1488 | } |
| 1489 | fLaunched = (pid > 0); | ||
| 1466 | #endif | 1490 | #endif |
| 1467 | fShutdown = true; | 1491 | |
| 1468 | if (glfwGetCurrentContext()) | 1492 | if (fLaunched) |
| 1469 | glfwSetWindowShouldClose(glfwGetCurrentContext(), true); | 1493 | { |
| 1494 | fShutdown = true; | ||
| 1495 | if (glfwGetCurrentContext()) | ||
| 1496 | glfwSetWindowShouldClose(glfwGetCurrentContext(), true); | ||
| 1497 | } | ||
| 1498 | else | ||
| 1499 | g_wizardStatus = "Could not relaunch automatically -- please restart " | ||
| 1500 | "Bitflash yourself to switch to the SQLite wallet."; | ||
| 1470 | } | 1501 | } |
| 1471 | 1502 | ||
| 1472 | static void DrawBackendWizardDialog() | 1503 | static void DrawBackendWizardDialog() |