mirror of
https://git.proxmox.com/git/fwupd
synced 2025-08-03 00:02:45 +00:00
Use StartServiceCtrlDispatcherA for the daemon on Windows
This commit is contained in:
parent
0f89c48556
commit
065b2a33f4
138
src/fu-main-windows.c
Normal file
138
src/fu-main-windows.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Copyright (C) 2022 Richard Hughes <richard@hughsie.com>
|
||||
*
|
||||
* SPDX-License-Identifier: LGPL-2.1+
|
||||
*
|
||||
* - sc create fwupd start="auto" binPath="C:\Program Files (x86)\fwupd\bin\fwupd.exe"
|
||||
* - sc delete fwupd
|
||||
*/
|
||||
|
||||
#define G_LOG_DOMAIN "FuMain"
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "fu-daemon.h"
|
||||
#include "fu-debug.h"
|
||||
|
||||
static SERVICE_STATUS gSvcStatus = {.dwServiceType = SERVICE_WIN32_OWN_PROCESS,
|
||||
.dwServiceSpecificExitCode = 0};
|
||||
static SERVICE_STATUS_HANDLE gSvcStatusHandle = 0;
|
||||
static FuDaemon *gDaemon = NULL;
|
||||
|
||||
static void
|
||||
fu_main_svc_report_status(DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
|
||||
{
|
||||
static DWORD dwCheckPoint = 1;
|
||||
|
||||
gSvcStatus.dwCurrentState = dwCurrentState;
|
||||
gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
|
||||
gSvcStatus.dwWaitHint = dwWaitHint;
|
||||
|
||||
if (dwCurrentState == SERVICE_START_PENDING)
|
||||
gSvcStatus.dwControlsAccepted = 0;
|
||||
else
|
||||
gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
|
||||
|
||||
if (dwCurrentState == SERVICE_RUNNING || dwCurrentState == SERVICE_STOPPED)
|
||||
gSvcStatus.dwCheckPoint = 0;
|
||||
else
|
||||
gSvcStatus.dwCheckPoint = dwCheckPoint++;
|
||||
|
||||
SetServiceStatus(gSvcStatusHandle, &gSvcStatus);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
fu_main_svc_control_stop_cb(gpointer user_data)
|
||||
{
|
||||
FuDaemon *daemon = FU_DAEMON(user_data);
|
||||
fu_daemon_stop(daemon);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
fu_main_svc_control_cb(DWORD dwCtrl)
|
||||
{
|
||||
switch (dwCtrl) {
|
||||
case SERVICE_CONTROL_STOP:
|
||||
fu_main_svc_report_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
|
||||
/* there is no user_data, because global state with threads is completely fine */
|
||||
g_idle_add(fu_main_svc_control_stop_cb, gDaemon);
|
||||
fu_main_svc_report_status(gSvcStatus.dwCurrentState, NO_ERROR, 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
fu_main_svc_main_cb(DWORD dwArgc, LPSTR *lpszArgv)
|
||||
{
|
||||
g_autoptr(FuDaemon) daemon = gDaemon = fu_daemon_new();
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GOptionContext) context = g_option_context_new(NULL);
|
||||
|
||||
/* parse debugging args */
|
||||
g_option_context_add_group(context, fu_debug_get_option_group());
|
||||
if (!g_option_context_parse(context, (gint *)&dwArgc, &lpszArgv, &error)) {
|
||||
g_printerr("Failed to parse command line: %s\n", error->message);
|
||||
return;
|
||||
}
|
||||
|
||||
gSvcStatusHandle = RegisterServiceCtrlHandlerA((LPSTR) "fwupd", fu_main_svc_control_cb);
|
||||
if (gSvcStatusHandle == NULL) {
|
||||
g_warning("RegisterServiceCtrlHandlerA failed [%u]", (guint)GetLastError());
|
||||
return;
|
||||
}
|
||||
|
||||
/* set up the daemon, which includes coldplugging devices -- then run it */
|
||||
fu_main_svc_report_status(SERVICE_START_PENDING, NO_ERROR, 1000);
|
||||
if (!fu_daemon_setup(daemon, &error)) {
|
||||
g_warning("Failed to load daemon: %s", error->message);
|
||||
return;
|
||||
}
|
||||
fu_main_svc_report_status(SERVICE_RUNNING, NO_ERROR, 0);
|
||||
fu_daemon_start(daemon);
|
||||
fu_main_svc_report_status(SERVICE_STOPPED, NO_ERROR, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
fu_main_console(int argc, char *argv[])
|
||||
{
|
||||
g_autoptr(FuDaemon) daemon = gDaemon = fu_daemon_new();
|
||||
g_autoptr(GError) error = NULL;
|
||||
g_autoptr(GOptionContext) context = g_option_context_new(NULL);
|
||||
|
||||
/* parse debugging args */
|
||||
g_option_context_add_group(context, fu_debug_get_option_group());
|
||||
if (!g_option_context_parse(context, &argc, &argv, &error)) {
|
||||
g_printerr("Failed to parse command line: %s\n", error->message);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
/* set up the daemon, which includes coldplugging devices -- then run it */
|
||||
if (!fu_daemon_setup(daemon, &error)) {
|
||||
g_printerr("Failed to load daemon: %s\n", error->message);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
fu_daemon_start(daemon);
|
||||
|
||||
/* success */
|
||||
g_message("Daemon ready for requests");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
SERVICE_TABLE_ENTRYA svc_table[] = {{(LPSTR) "fwupd", fu_main_svc_main_cb}, {NULL, NULL}};
|
||||
if (!StartServiceCtrlDispatcherA(svc_table)) {
|
||||
/* program is being run as a console application rather than as a service */
|
||||
if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT)
|
||||
return fu_main_console(argc, argv);
|
||||
g_printerr("StartServiceCtrlDispatcherA failed [%u]\n", (guint)GetLastError());
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
@ -212,12 +212,20 @@ if get_option('man')
|
||||
endif
|
||||
|
||||
if build_daemon
|
||||
|
||||
# the StartServiceCtrlDispatcherA design is so different use a different source file
|
||||
if host_machine.system() == 'windows'
|
||||
daemon_loader_src = 'fu-main-windows.c'
|
||||
else
|
||||
daemon_loader_src = 'fu-main.c'
|
||||
endif
|
||||
|
||||
executable(
|
||||
'fwupd',
|
||||
resources_src,
|
||||
fu_hash,
|
||||
sources : [
|
||||
'fu-main.c',
|
||||
daemon_loader_src,
|
||||
'fu-daemon.c',
|
||||
daemon_src,
|
||||
],
|
||||
|
Loading…
Reference in New Issue
Block a user