2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2018 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * Kern Sibbald, August 2007
23 * This is a generic service routine, which is used by all three
24 * of the daemons. Each one compiles it with slightly different
32 /* Forward reference */
33 static void set_service_description(SC_HANDLE hSCManager,
34 SC_HANDLE hService, LPSTR lpDesc);
36 /* Other Window component dependencies */
37 #define BAC_DEPENDENCIES __TEXT("tcpip\0afd\0")
40 SERVICE_STATUS_HANDLE service_handle;
41 SERVICE_STATUS service_status;
42 DWORD service_error = 0;
43 static bool is_service = false;
45 /* Forward references */
46 void WINAPI serviceControlCallback(DWORD ctrlcode);
47 BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
48 DWORD WINAPI baculaWorkerThread(LPVOID lpwThreadParam);
52 * Post a message to a running instance of the app
54 bool postToBacula(UINT message, WPARAM wParam, LPARAM lParam)
56 /* Locate the Bacula menu window */
57 HWND hservwnd = FindWindow(APP_NAME, NULL);
58 if (hservwnd == NULL) {
62 /* Post the message to Bacula */
63 PostMessage(hservwnd, message, wParam, lParam);
69 * Running as a service?
77 * terminate any running Bacula
79 int stopRunningBacula()
81 postToBacula(WM_CLOSE, 0, 0);
87 * New style service start callback handler for the OS.
88 * the OS returns control here immediately after starting
91 void WINAPI serviceStartCallback(DWORD argc, char **argv)
95 /* Register our service */
96 service_handle = RegisterServiceCtrlHandler(APP_NAME, serviceControlCallback);
97 if (!service_handle) {
98 log_error_message(_("RegisterServiceCtlHandler failed"));
99 MessageBox(NULL, _("Failure contacting the Service Handler"),
104 service_status.dwServiceType = SERVICE_WIN32;
105 service_status.dwServiceSpecificExitCode = 0;
108 if (!ReportStatus(SERVICE_START_PENDING, NO_ERROR, 45000)) {
109 ReportStatus(SERVICE_STOPPED, service_error, 0);
110 log_error_message(_("Service start report failed"));
114 /* Now create the Bacula worker thread */
115 (void)CreateThread(NULL, 0, baculaWorkerThread, NULL, 0, &dwThreadID);
122 static void serviceStop()
124 /* Post a quit message our service thread */
125 if (service_thread_id != 0) {
126 PostThreadMessage(service_thread_id, WM_QUIT, 0, 0);
131 * Service Control callback handler. The OS can call us here
132 * at any time, most often to stop the service.
134 void WINAPI serviceControlCallback(DWORD ctrlcode)
137 case SERVICE_CONTROL_STOP:
138 service_status.dwCurrentState = SERVICE_STOP_PENDING;
139 serviceStop(); /* our stop service routine */
143 /* Report our status */
144 ReportStatus(service_status.dwCurrentState, NO_ERROR, 0);
149 * Run Bacula as a service
151 int baculaServiceMain()
153 is_service = true; /* indicate we are running as a service */
155 if (have_service_api) { /* New style service API */
156 /* Tell OS where to dispatch service calls to us */
157 SERVICE_TABLE_ENTRY dispatchTable[] = {
158 {(char *)APP_NAME, (LPSERVICE_MAIN_FUNCTION)serviceStartCallback},
161 /* Start the service control dispatcher */
162 if (!StartServiceCtrlDispatcher(dispatchTable)) {
163 log_error_message(_("StartServiceCtrlDispatcher failed."));
165 /* Note, this thread continues in the ServiceCallback routine */
167 } else { /* old style Win95/98/Me */
168 HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
169 if (kerneldll == NULL) {
170 MessageBox(NULL, _("KERNEL32.DLL not found: Bacula service not started"),
175 /* Get entry point for RegisterServiceProcess function */
176 DWORD (WINAPI *RegisterService)(DWORD, DWORD);
177 RegisterService = (DWORD (WINAPI *)(DWORD, DWORD))
178 GetProcAddress(kerneldll, "RegisterServiceProcess");
179 if (RegisterService == NULL) {
180 MessageBox(NULL, _("Registry service not found: Bacula service not started"),
182 log_error_message(_("Registry service entry point not found"));
183 FreeLibrary(kerneldll); /* free up kernel dll */
187 RegisterService(0, 1); /* register us as a service */
188 BaculaAppMain(); /* call the main Bacula code */
189 RegisterService(0, 0); /* terminate the service */
190 FreeLibrary(kerneldll); /* free up kernel dll */
197 * New style service bacula worker thread
199 DWORD WINAPI baculaWorkerThread(LPVOID lpwThreadParam)
201 service_thread_id = GetCurrentThreadId();
203 if (!ReportStatus(SERVICE_RUNNING, NO_ERROR, 0)) {
204 MessageBox(NULL, _("Report Service failure"), APP_DESC, MB_OK);
205 log_error_message("ReportStatus RUNNING failed");
209 /* Call Bacula main code */
212 /* Mark that we're no longer running */
213 service_thread_id = 0;
215 /* Tell the service manager that we've stopped */
216 ReportStatus(SERVICE_STOPPED, service_error, 0);
223 * Install the Bacula service on the OS -- very complicated
225 int installService(const char *cmdOpts)
227 const int maxlen = 2048;
231 bsnprintf(svcmd, sizeof(svcmd), "service: install: %s", cmdOpts, APP_DESC, MB_OK);
233 /* Get our filename */
234 if (GetModuleFileName(NULL, path, maxlen-11) == 0) {
235 MessageBox(NULL, _("Unable to install the service"), APP_DESC, MB_ICONEXCLAMATION | MB_OK);
239 /* Create a valid command for starting the service */
240 if ((int)strlen(path) + (int)strlen(cmdOpts) + 30 < maxlen) {
241 bsnprintf(svcmd, sizeof(svcmd), "\"%s\" /service %s", path, cmdOpts);
243 log_error_message(_("Service command length too long"));
244 MessageBox(NULL, _("Service command length too long. Service not registered."),
245 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
249 if (have_service_api) {
250 SC_HANDLE baculaService, serviceManager;
252 /* Open the service control manager */
253 serviceManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
254 if (!serviceManager) {
255 log_error_message("Open Service Manager failed");
257 _("The Service Control Manager could not be contacted - the service was not installed"),
258 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
262 /* Now actually create the Bacula service entry */
263 baculaService = CreateService(
265 APP_NAME, /* Our service name */
266 APP_DESC, /* Display name */
268 SERVICE_WIN32_OWN_PROCESS, /* | SERVICE_INTERACTIVE_PROCESS, */
270 SERVICE_ERROR_NORMAL,
271 svcmd, /* Command string to start the service */
274 BAC_DEPENDENCIES, /* Services to start before us */
275 NULL, /* Use default SYSTEM account */
277 if (!baculaService) {
278 CloseServiceHandle(serviceManager);
279 log_error_message("CreateService failed for " APP_DESC);
280 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be installed"),
281 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
285 /* Set a text description in the service manager's control panel */
286 set_service_description(serviceManager, baculaService,
287 (char *)_("Provides file backup and restore services. Bacula -- the network backup solution."));
289 CloseServiceHandle(serviceManager);
290 CloseServiceHandle(baculaService);
293 /* Old style service -- create appropriate registry key path */
295 if (RegCreateKey(HKEY_LOCAL_MACHINE,
296 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
297 &runservices) != ERROR_SUCCESS) {
298 log_error_message(_("Cannot write System Registry for " APP_DESC));
299 MessageBox(NULL, _("The System Registry could not be updated - the Bacula service was not installed"),
300 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
304 /* Add the Bacula values */
305 if (RegSetValueEx(runservices, APP_NAME, 0, REG_SZ,
306 (unsigned char *)svcmd, strlen(svcmd)+1) != ERROR_SUCCESS) {
307 RegCloseKey(runservices);
308 log_error_message(_("Cannot add Bacula key to System Registry"));
309 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be installed"),
310 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
313 RegCloseKey(runservices);
316 /* At this point the service is installed */
319 _("The " APP_DESC "was successfully installed.\n"
320 "The service may be started by double clicking on the\n"
321 "Bacula \"Start\" icon and will be automatically\n"
322 "be run the next time this machine is rebooted. "),
323 APP_DESC, MB_ICONINFORMATION | MB_OK);
330 * Remove a service from the OS (normally done when we are installing
335 SC_HANDLE serviceManager, baculaService;
338 if (have_service_api) { /* Newer Windows platforms (NT, Win2K, ...) */
339 serviceManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
340 if (serviceManager) {
341 /* Now get the Bacula service entry */
342 baculaService = OpenService(serviceManager, APP_NAME, SERVICE_ALL_ACCESS);
344 SERVICE_STATUS status;
345 /* If the service is running, stop it */
346 if (ControlService(baculaService, SERVICE_CONTROL_STOP, &status)) {
347 while(QueryServiceStatus(baculaService, &status)) {
348 if (status.dwCurrentState != SERVICE_STOP_PENDING) {
353 if (status.dwCurrentState != SERVICE_STOPPED) {
355 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be stopped"),
356 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
360 if (DeleteService(baculaService)) {
362 MessageBox(NULL, _("The Bacula service: " APP_NAME " has been removed"),
363 APP_DESC, MB_ICONINFORMATION | MB_OK);
366 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be removed"),
367 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
368 stat = 1; /* error */
370 CloseServiceHandle(baculaService);
373 MessageBox(NULL, _("An existing Bacula service: " APP_NAME " could not be found for "
374 "removal. This is not normally an error."),
375 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
378 CloseServiceHandle(serviceManager);
381 MessageBox(NULL, _("The service Manager could not be contacted - the Bacula service was not removed"),
382 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
383 return 1; /* error */
386 } else { /* Old Win95/98/Me OS */
387 /* Open the registry path key */
389 if (RegOpenKey(HKEY_LOCAL_MACHINE,
390 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
391 &runservices) != ERROR_SUCCESS) {
394 _("Could not find registry entry.\nService probably not registerd - the Bacula service was not removed"),
395 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
398 /* Now delete the Bacula entry */
399 if (RegDeleteValue(runservices, APP_NAME) != ERROR_SUCCESS) {
400 RegCloseKey(runservices);
401 MessageBox(NULL, _("Could not delete Registry key for " APP_NAME ".\n"
402 "The Bacula service could not be removed"), APP_DESC, MB_ICONEXCLAMATION | MB_OK);
404 RegCloseKey(runservices);
407 /* Stop any running Bacula */
408 if (!stopRunningBacula()) {
411 _("Bacula could not be contacted, probably not running"),
412 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
414 return 0; /* not really an error */
416 /* At this point, the service has been removed */
418 MessageBox(NULL, _("The Bacula service has been removed"), APP_DESC, MB_ICONINFORMATION | MB_OK);
426 * This subroutine is called to report our current status to the
427 * new style service manager
429 BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint)
431 static DWORD checkpoint = 1;
434 /* No callbacks until we are started */
435 if (state == SERVICE_START_PENDING) {
436 service_status.dwControlsAccepted = 0;
438 service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
441 /* Save global service_status state */
442 service_status.dwCurrentState = state;
443 service_status.dwWin32ExitCode = exitcode;
444 service_status.dwWaitHint = waithint;
447 * Update the checkpoint variable so the service manager knows
450 if (state == SERVICE_RUNNING || state == SERVICE_STOPPED) {
451 service_status.dwCheckPoint = 0;
453 service_status.dwCheckPoint = checkpoint++;
456 /* Send our new status */
457 result = SetServiceStatus(service_handle, &service_status);
459 log_error_message(_("SetServiceStatus failed"));
464 /* Log an error message for the last Windows error */
465 void LogLastErrorMsg(const char *message, const char *fname, int lineno)
469 const char *strings[3];
472 service_error = GetLastError();
473 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
474 FORMAT_MESSAGE_FROM_SYSTEM,
482 /* Use the OS event logging to log the error */
483 eventHandler = RegisterEventSource(NULL, APP_NAME);
485 bsnprintf(msgbuf, sizeof(msgbuf), _("\n\n%s error: %ld at %s:%d"),
486 APP_NAME, service_error, fname, lineno);
489 strings[1] = message;
493 ReportEvent(eventHandler, EVENTLOG_ERROR_TYPE,
497 3, /* Number of strings */
498 0, /* raw data size */
499 (const char **)strings, /* error strings */
500 NULL); /* raw data */
501 DeregisterEventSource(eventHandler);
506 typedef BOOL (WINAPI * WinAPI)(SC_HANDLE, DWORD, LPVOID);
509 * This is amazingly complicated just to get a bit of English explanation
510 * in the service manager's dialog box.
512 static void set_service_description(SC_HANDLE hSCManager, SC_HANDLE hService,
516 LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf;
517 SERVICE_DESCRIPTION sdBuf;
519 WinAPI ChangeServiceDescription;
521 HINSTANCE hLib = LoadLibrary("ADVAPI32.DLL");
525 ChangeServiceDescription = (WinAPI)GetProcAddress(hLib,
526 "ChangeServiceConfig2A");
528 if (!ChangeServiceDescription) {
532 // Need to acquire database lock before reconfiguring.
533 sclLock = LockServiceDatabase(hSCManager);
535 // If the database cannot be locked, report the details.
536 if (sclLock == NULL) {
537 // Exit if the database is not locked by another process.
538 if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED) {
539 log_error_message("LockServiceDatabase");
543 // Allocate a buffer to get details about the lock.
544 lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS)LocalAlloc(
545 LPTR, sizeof(QUERY_SERVICE_LOCK_STATUS)+256);
546 if (lpqslsBuf == NULL) {
547 log_error_message("LocalAlloc");
551 // Get and print the lock status information.
552 if (!QueryServiceLockStatus(
555 sizeof(QUERY_SERVICE_LOCK_STATUS)+256,
557 log_error_message("QueryServiceLockStatus");
560 if (lpqslsBuf->fIsLocked) {
561 printf(_("Locked by: %s, duration: %ld seconds\n"),
562 lpqslsBuf->lpLockOwner,
563 lpqslsBuf->dwLockDuration);
565 printf(_("No longer locked\n"));
568 LocalFree(lpqslsBuf);
569 log_error_message(_("Could not lock database"));
573 // The database is locked, so it is safe to make changes.
575 sdBuf.lpDescription = lpDesc;
577 if (!ChangeServiceDescription(
578 hService, // handle to service
579 SERVICE_CONFIG_DESCRIPTION, // change: description
580 &sdBuf) ) { // value: new description
581 log_error_message("ChangeServiceConfig2");
584 // Release the database lock.
585 UnlockServiceDatabase(sclLock);