2 Bacula® - The Network Backup Solution
4 Copyright (C) 2007-2010 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from
7 many others, a complete list can be found in the file AUTHORS.
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
23 Bacula® is a registered trademark of Kern Sibbald.
24 The licensor of Bacula is the Free Software Foundation Europe
25 (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26 Switzerland, email:ftf@fsfeurope.org.
30 * Kern Sibbald, August 2007
32 * This is a generic service routine, which is used by all three
33 * of the daemons. Each one compiles it with slightly different
41 /* Forward reference */
42 static void set_service_description(SC_HANDLE hSCManager,
43 SC_HANDLE hService, LPSTR lpDesc);
45 /* Other Window component dependencies */
46 #define BAC_DEPENDENCIES __TEXT("tcpip\0afd\0")
49 SERVICE_STATUS_HANDLE service_handle;
50 SERVICE_STATUS service_status;
51 DWORD service_error = 0;
52 static bool is_service = false;
54 /* Forward references */
55 void WINAPI serviceControlCallback(DWORD ctrlcode);
56 BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
57 DWORD WINAPI baculaWorkerThread(LPVOID lpwThreadParam);
61 * Post a message to a running instance of the app
63 bool postToBacula(UINT message, WPARAM wParam, LPARAM lParam)
65 /* Locate the Bacula menu window */
66 HWND hservwnd = FindWindow(APP_NAME, NULL);
67 if (hservwnd == NULL) {
71 /* Post the message to Bacula */
72 PostMessage(hservwnd, message, wParam, lParam);
78 * Running as a service?
86 * terminate any running Bacula
88 int stopRunningBacula()
90 postToBacula(WM_CLOSE, 0, 0);
96 * New style service start callback handler for the OS.
97 * the OS returns control here immediately after starting
100 void WINAPI serviceStartCallback(DWORD argc, char **argv)
104 /* Register our service */
105 service_handle = RegisterServiceCtrlHandler(APP_NAME, serviceControlCallback);
106 if (!service_handle) {
107 log_error_message(_("RegisterServiceCtlHandler failed"));
108 MessageBox(NULL, _("Failure contacting the Service Handler"),
113 service_status.dwServiceType = SERVICE_WIN32;
114 service_status.dwServiceSpecificExitCode = 0;
117 if (!ReportStatus(SERVICE_START_PENDING, NO_ERROR, 45000)) {
118 ReportStatus(SERVICE_STOPPED, service_error, 0);
119 log_error_message(_("Service start report failed"));
123 /* Now create the Bacula worker thread */
124 (void)CreateThread(NULL, 0, baculaWorkerThread, NULL, 0, &dwThreadID);
131 static void serviceStop()
133 /* Post a quit message our service thread */
134 if (service_thread_id != 0) {
135 PostThreadMessage(service_thread_id, WM_QUIT, 0, 0);
140 * Service Control callback handler. The OS can call us here
141 * at any time, most often to stop the service.
143 void WINAPI serviceControlCallback(DWORD ctrlcode)
146 case SERVICE_CONTROL_STOP:
147 service_status.dwCurrentState = SERVICE_STOP_PENDING;
148 serviceStop(); /* our stop service routine */
152 /* Report our status */
153 ReportStatus(service_status.dwCurrentState, NO_ERROR, 0);
158 * Run Bacula as a service
160 int baculaServiceMain()
162 is_service = true; /* indicate we are running as a service */
164 if (have_service_api) { /* New style service API */
165 /* Tell OS where to dispatch service calls to us */
166 SERVICE_TABLE_ENTRY dispatchTable[] = {
167 {APP_NAME, (LPSERVICE_MAIN_FUNCTION)serviceStartCallback},
170 /* Start the service control dispatcher */
171 if (!StartServiceCtrlDispatcher(dispatchTable)) {
172 log_error_message(_("StartServiceCtrlDispatcher failed."));
174 /* Note, this thread continues in the ServiceCallback routine */
176 } else { /* old style Win95/98/Me */
177 HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
178 if (kerneldll == NULL) {
179 MessageBox(NULL, _("KERNEL32.DLL not found: Bacula service not started"),
184 /* Get entry point for RegisterServiceProcess function */
185 DWORD (WINAPI *RegisterService)(DWORD, DWORD);
186 RegisterService = (DWORD (WINAPI *)(DWORD, DWORD))
187 GetProcAddress(kerneldll, "RegisterServiceProcess");
188 if (RegisterService == NULL) {
189 MessageBox(NULL, _("Registry service not found: Bacula service not started"),
191 log_error_message(_("Registry service entry point not found"));
195 RegisterService(0, 1); /* register us as a service */
196 BaculaAppMain(); /* call the main Bacula code */
197 RegisterService(0, 0); /* terminate the service */
198 FreeLibrary(kerneldll); /* free up kernel dll */
205 * New style service bacula worker thread
207 DWORD WINAPI baculaWorkerThread(LPVOID lpwThreadParam)
209 service_thread_id = GetCurrentThreadId();
211 if (!ReportStatus(SERVICE_RUNNING, NO_ERROR, 0)) {
212 MessageBox(NULL, _("Report Service failure"), APP_DESC, MB_OK);
213 log_error_message("ReportStatus RUNNING failed");
217 /* Call Bacula main code */
220 /* Mark that we're no longer running */
221 service_thread_id = 0;
223 /* Tell the service manager that we've stopped */
224 ReportStatus(SERVICE_STOPPED, service_error, 0);
231 * Install the Bacula service on the OS -- very complicated
233 int installService(const char *cmdOpts)
235 const int maxlen = 2048;
239 bsnprintf(svcmd, sizeof(svcmd), "service: install: %s", cmdOpts, APP_DESC, MB_OK);
241 /* Get our filename */
242 if (GetModuleFileName(NULL, path, maxlen-11) == 0) {
243 MessageBox(NULL, _("Unable to install the service"), APP_DESC, MB_ICONEXCLAMATION | MB_OK);
247 /* Create a valid command for starting the service */
248 if ((int)strlen(path) + (int)strlen(cmdOpts) + 30 < maxlen) {
249 bsnprintf(svcmd, sizeof(svcmd), "\"%s\" /service %s", path, cmdOpts);
251 log_error_message(_("Service command length too long"));
252 MessageBox(NULL, _("Service command length too long. Service not registered."),
253 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
257 if (have_service_api) {
258 SC_HANDLE baculaService, serviceManager;
260 /* Open the service control manager */
261 serviceManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
262 if (!serviceManager) {
263 log_error_message("Open Service Manager failed");
265 _("The Service Control Manager could not be contacted - the service was not installed"),
266 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
270 /* Now actually create the Bacula service entry */
271 baculaService = CreateService(
273 APP_NAME, /* Our service name */
274 APP_DESC, /* Display name */
276 SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
278 SERVICE_ERROR_NORMAL,
279 svcmd, /* Command string to start the service */
282 BAC_DEPENDENCIES, /* Services to start before us */
283 NULL, /* Use default SYSTEM account */
285 if (!baculaService) {
286 CloseServiceHandle(serviceManager);
287 log_error_message("CreateService failed for " APP_DESC);
288 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be installed"),
289 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
293 /* Set a text description in the service manager's control panel */
294 set_service_description(serviceManager, baculaService,
295 (char *)_("Provides file backup and restore services. Bacula -- the network backup solution."));
297 CloseServiceHandle(serviceManager);
298 CloseServiceHandle(baculaService);
301 /* Old style service -- create appropriate registry key path */
303 if (RegCreateKey(HKEY_LOCAL_MACHINE,
304 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
305 &runservices) != ERROR_SUCCESS) {
306 log_error_message(_("Cannot write System Registry for " APP_DESC));
307 MessageBox(NULL, _("The System Registry could not be updated - the Bacula service was not installed"),
308 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
312 /* Add the Bacula values */
313 if (RegSetValueEx(runservices, APP_NAME, 0, REG_SZ,
314 (unsigned char *)svcmd, strlen(svcmd)+1) != ERROR_SUCCESS) {
315 RegCloseKey(runservices);
316 log_error_message(_("Cannot add Bacula key to System Registry"));
317 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be installed"),
318 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
321 RegCloseKey(runservices);
324 /* At this point the service is installed */
327 _("The " APP_DESC "was successfully installed.\n"
328 "The service may be started by double clicking on the\n"
329 "Bacula \"Start\" icon and will be automatically\n"
330 "be run the next time this machine is rebooted. "),
331 APP_DESC, MB_ICONINFORMATION | MB_OK);
338 * Remove a service from the OS (normally done when we are installing
343 if (have_service_api) { /* Newer Windows platform (NT, Win2K, ...) */
344 SC_HANDLE serviceManager, baculaService;
347 serviceManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
348 if (serviceManager) {
349 /* Now get the Bacula service entry */
350 baculaService = OpenService(serviceManager, APP_NAME, SERVICE_ALL_ACCESS);
352 SERVICE_STATUS status;
354 /* If the service is running, stop it */
355 if (ControlService(baculaService, SERVICE_CONTROL_STOP, &status)) {
356 while(QueryServiceStatus(baculaService, &status)) {
357 if (status.dwCurrentState == SERVICE_STOP_PENDING) {
363 if (status.dwCurrentState != SERVICE_STOPPED) {
365 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be stopped"),
366 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
371 if (DeleteService(baculaService)) {
373 MessageBox(NULL, _("The Bacula service: " APP_NAME " has been removed"),
374 APP_DESC, MB_ICONINFORMATION | MB_OK);
377 MessageBox(NULL, _("The Bacula service: " APP_NAME " could not be removed"),
378 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
379 stat = 1; /* error */
381 CloseServiceHandle(baculaService);
385 MessageBox(NULL, _("An existing Bacula service: " APP_NAME " could not be found for "
386 "removal. This is not normally an error."),
387 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
390 CloseServiceHandle(serviceManager);
394 MessageBox(NULL, _("The service Manager could not be contacted - the Bacula service was not removed"),
395 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
396 return 1; /* error */
399 } else { /* Old Win95/98/Me OS */
400 /* Open the registry path key */
402 if (RegOpenKey(HKEY_LOCAL_MACHINE,
403 "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
404 &runservices) != ERROR_SUCCESS) {
407 _("Could not find registry entry.\nService probably not registerd - the Bacula service was not removed"),
408 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
411 /* Now delete the Bacula entry */
412 if (RegDeleteValue(runservices, APP_NAME) != ERROR_SUCCESS) {
413 RegCloseKey(runservices);
414 MessageBox(NULL, _("Could not delete Registry key for " APP_NAME ".\n"
415 "The Bacula service could not be removed"), APP_DESC, MB_ICONEXCLAMATION | MB_OK);
417 RegCloseKey(runservices);
421 /* Stop any running Bacula */
422 if (!stopRunningBacula()) {
425 _("Bacula could not be contacted, probably not running"),
426 APP_DESC, MB_ICONEXCLAMATION | MB_OK);
428 return 0; /* not really an error */
431 /* At this point, the service has been removed */
433 MessageBox(NULL, _("The Bacula service has been removed"), APP_DESC, MB_ICONINFORMATION | MB_OK);
441 * This subroutine is called to report our current status to the
442 * new style service manager
444 BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint)
446 static DWORD checkpoint = 1;
449 /* No callbacks until we are started */
450 if (state == SERVICE_START_PENDING) {
451 service_status.dwControlsAccepted = 0;
453 service_status.dwControlsAccepted = SERVICE_ACCEPT_STOP;
456 /* Save global service_status state */
457 service_status.dwCurrentState = state;
458 service_status.dwWin32ExitCode = exitcode;
459 service_status.dwWaitHint = waithint;
462 * Update the checkpoint variable so the service manager knows
465 if (state == SERVICE_RUNNING || state == SERVICE_STOPPED) {
466 service_status.dwCheckPoint = 0;
468 service_status.dwCheckPoint = checkpoint++;
471 /* Send our new status */
472 result = SetServiceStatus(service_handle, &service_status);
474 log_error_message(_("SetServiceStatus failed"));
479 /* Log an error message for the last Windows error */
480 void LogLastErrorMsg(const char *message, const char *fname, int lineno)
484 const char *strings[3];
487 service_error = GetLastError();
488 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
489 FORMAT_MESSAGE_FROM_SYSTEM,
497 /* Use the OS event logging to log the error */
498 eventHandler = RegisterEventSource(NULL, APP_NAME);
500 bsnprintf(msgbuf, sizeof(msgbuf), _("\n\n%s error: %ld at %s:%d"),
501 APP_NAME, service_error, fname, lineno);
504 strings[1] = message;
508 ReportEvent(eventHandler, EVENTLOG_ERROR_TYPE,
512 3, /* Number of strings */
513 0, /* raw data size */
514 (const char **)strings, /* error strings */
515 NULL); /* raw data */
516 DeregisterEventSource(eventHandler);
521 typedef BOOL (WINAPI * WinAPI)(SC_HANDLE, DWORD, LPVOID);
524 * This is amazingly complicated just to get a bit of English explanation
525 * in the service manager's dialog box.
527 static void set_service_description(SC_HANDLE hSCManager, SC_HANDLE hService,
531 LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf;
532 SERVICE_DESCRIPTION sdBuf;
534 WinAPI ChangeServiceDescription;
536 HINSTANCE hLib = LoadLibrary("ADVAPI32.DLL");
540 ChangeServiceDescription = (WinAPI)GetProcAddress(hLib,
541 "ChangeServiceConfig2A");
543 if (!ChangeServiceDescription) {
547 // Need to acquire database lock before reconfiguring.
548 sclLock = LockServiceDatabase(hSCManager);
550 // If the database cannot be locked, report the details.
551 if (sclLock == NULL) {
552 // Exit if the database is not locked by another process.
553 if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED) {
554 log_error_message("LockServiceDatabase");
558 // Allocate a buffer to get details about the lock.
559 lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS)LocalAlloc(
560 LPTR, sizeof(QUERY_SERVICE_LOCK_STATUS)+256);
561 if (lpqslsBuf == NULL) {
562 log_error_message("LocalAlloc");
566 // Get and print the lock status information.
567 if (!QueryServiceLockStatus(
570 sizeof(QUERY_SERVICE_LOCK_STATUS)+256,
572 log_error_message("QueryServiceLockStatus");
575 if (lpqslsBuf->fIsLocked) {
576 printf(_("Locked by: %s, duration: %ld seconds\n"),
577 lpqslsBuf->lpLockOwner,
578 lpqslsBuf->dwLockDuration);
580 printf(_("No longer locked\n"));
583 LocalFree(lpqslsBuf);
584 log_error_message(_("Could not lock database"));
588 // The database is locked, so it is safe to make changes.
590 sdBuf.lpDescription = lpDesc;
592 if (!ChangeServiceDescription(
593 hService, // handle to service
594 SERVICE_CONFIG_DESCRIPTION, // change: description
595 &sdBuf) ) { // value: new description
596 log_error_message("ChangeServiceConfig2");
599 // Release the database lock.
600 UnlockServiceDatabase(sclLock);