refactor: Improve Daemon uninstall exception flow

This commit is contained in:
Nick Bolton 2025-02-24 13:17:22 +00:00
parent 5a7f6bd1c0
commit a6956b9516
2 changed files with 67 additions and 68 deletions

View file

@ -1,6 +1,6 @@
/* /*
* Deskflow -- mouse and keyboard sharing utility * Deskflow -- mouse and keyboard sharing utility
* SPDX-FileCopyrightText: (C) 2012 - 2016 Symless Ltd. * SPDX-FileCopyrightText: (C) 2012 - 2016, 2025 Symless Ltd.
* SPDX-FileCopyrightText: (C) 2012 Nick Bolton * SPDX-FileCopyrightText: (C) 2012 Nick Bolton
* SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception * SPDX-License-Identifier: GPL-2.0-only WITH LicenseRef-OpenSSL-Exception
*/ */
@ -29,6 +29,8 @@
using namespace deskflow::core; using namespace deskflow::core;
void handleError(const char *message);
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
#if SYSAPI_WIN32 #if SYSAPI_WIN32
@ -45,7 +47,16 @@ int main(int argc, char **argv)
LOG((CLOG_PRINT "%s daemon (v%s)", kAppName, kVersion)); LOG((CLOG_PRINT "%s daemon (v%s)", kAppName, kVersion));
auto &daemon = DaemonApp::instance(); auto &daemon = DaemonApp::instance();
const auto initResult = daemon.init(&events, argc, argv); DaemonApp::InitResult initResult;
try {
initResult = daemon.init(&events, argc, argv);
} catch (std::exception &e) {
handleError(e.what());
return kExitFailed;
} catch (...) {
handleError("Unrecognized error.");
return kExitFailed;
}
switch (initResult) { switch (initResult) {
using enum DaemonApp::InitResult; using enum DaemonApp::InitResult;
@ -112,3 +123,14 @@ int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int)
} }
#endif #endif
void handleError(const char *message)
{
// Always print error to stdout in case run as CLI program.
LOG_ERR("%s", message);
#if SYSAPI_WIN32
// Show a message box for when run from MSI in Win32 subsystem.
MessageBoxA(nullptr, message, "Deskflow daemon error", MB_OK | MB_ICONERROR);
#endif
}

View file

@ -171,70 +171,58 @@ DaemonApp::InitResult DaemonApp::init(IEventQueue *events, int argc, char **argv
m_events = events; m_events = events;
bool isUninstalling = false; // default log level to system setting.
try { if (string logLevel = ARCH->setting("LogLevel"); logLevel != "")
// default log level to system setting. CLOG->setFilter(logLevel.c_str());
if (string logLevel = ARCH->setting("LogLevel"); logLevel != "")
CLOG->setFilter(logLevel.c_str());
for (int i = 1; i < argc; ++i) { for (int i = 1; i < argc; ++i) {
string arg(argv[i]); string arg(argv[i]);
if (arg == "-h" || arg == "--help") { if (arg == "-h" || arg == "--help") {
showHelp(argc, argv); showHelp(argc, argv);
return ShowHelp; return ShowHelp;
} else if (arg == "-f" || arg == "--foreground") { } else if (arg == "-f" || arg == "--foreground") {
m_foreground = true; m_foreground = true;
} }
#if SYSAPI_WIN32 #if SYSAPI_WIN32
else if (arg == "--install" || arg == "/install") { else if (arg == "--install" || arg == "/install") {
LOG((CLOG_NOTE "installing windows daemon")); LOG((CLOG_NOTE "installing windows daemon"));
ARCH->installDaemon(); ARCH->installDaemon();
return Installed; return Installed;
} else if (arg == "--uninstall" || arg == "/uninstall") { } else if (arg == "--uninstall" || arg == "/uninstall") {
LOG((CLOG_NOTE "uninstalling windows daemon")); LOG((CLOG_NOTE "uninstalling windows daemon"));
isUninstalling = true; try {
ARCH->uninstallDaemon(); ARCH->uninstallDaemon();
return Uninstalled; } catch (XArch &e) {
std::string message = e.what();
if (message.find("The service has not been started") != std::string::npos) {
// HACK: this message happens intermittently, not sure where from but
// it's quite misleading for the user. they thing something has gone
// horribly wrong, but it's just the service manager reporting a false
// positive (the service has actually shut down in most cases).
LOG_DEBUG("ignoring service start error on uninstall: %s", message.c_str());
} else {
throw e;
}
} }
return Uninstalled;
}
#endif #endif
else { else {
stringstream ss; LOG_ERR("unknown argument: %s", arg.c_str());
ss << "Unrecognized argument: " << arg; return ArgsError;
handleError(ss.str().c_str());
showHelp(argc, argv);
return ArgsError;
}
} }
if (!m_foreground) {
#if SYSAPI_WIN32
// Only use MS debug outputter when the process is daemonized, since stdout won't be accessible
// in that case, but is accessible when running in the foreground.
CLOG->insert(new MSWindowsDebugOutputter()); // NOSONAR - Adopted by `Log`
#endif
}
return StartDaemon;
} catch (XArch &e) {
std::string message = e.what();
if (isUninstalling && (message.find("The service has not been started") != std::string::npos)) {
// TODO: if we're keeping this use error code instead (what is it?!).
// HACK: this message happens intermittently, not sure where from but
// it's quite misleading for the user. they thing something has gone
// horribly wrong, but it's just the service manager reporting a false
// positive (the service has actually shut down in most cases).
} else {
handleError(message.c_str());
}
} catch (std::exception &e) {
handleError(e.what());
} catch (...) {
handleError("Unrecognized error.");
} }
return FatalError; if (!m_foreground) {
#if SYSAPI_WIN32
// Only use MS debug outputter when the process is daemonized, since stdout won't be accessible
// in that case, but is accessible when running in the foreground.
CLOG->insert(new MSWindowsDebugOutputter());
#endif
}
return StartDaemon;
} }
void DaemonApp::mainLoop(bool foreground) void DaemonApp::mainLoop(bool foreground)
@ -280,17 +268,6 @@ void DaemonApp::mainLoop(bool foreground)
} }
} }
void DaemonApp::handleError(const char *message)
{
// Always print error to stdout in case run as CLI program.
LOG_ERR("%s", message);
#if SYSAPI_WIN32
// Show a message box for when run from MSI in Win32 subsystem.
MessageBoxA(nullptr, message, "Deskflow daemon error", MB_OK | MB_ICONERROR);
#endif
}
std::string DaemonApp::logFilename() std::string DaemonApp::logFilename()
{ {
string logFilename; string logFilename;