]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/win32/filed/winservice.cpp
Fixed symbol file generation on Microsoft Visual Studio builds.
[bacula/bacula] / bacula / src / win32 / filed / winservice.cpp
1 //  Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
2 //
3 //  This file was part of the VNC system.
4 //
5 //  The VNC system is free software; you can redistribute it and/or modify
6 //  it under the terms of the GNU General Public License as published by
7 //  the Free Software Foundation; either version 2 of the License, or
8 //  (at your option) any later version.
9 //
10 //  This program is distributed in the hope that it will be useful,
11 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 //  GNU General Public License for more details.
14 //
15 //  You should have received a copy of the GNU General Public License
16 //  along with this program; if not, write to the Free Software
17 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307,
18 //  USA.
19 //
20 // If the source code for the VNC system is not available from the place 
21 // whence you received this file, check http://www.uk.research.att.com/vnc or contact
22 // the authors on vnc@uk.research.att.com for information on obtaining it.
23 //
24 // This file has been adapted to the Win32 version of Bacula
25 // by Kern E. Sibbald.  Many thanks to ATT and James Weatherall,
26 // the original author, for providing an excellent template.
27 //
28 // Copyright (C) 2000-2006 Kern E. Sibbald
29 //
30
31
32 // winService
33
34 // Implementation of service-oriented functionality of Bacula
35 // I.e. command line options that contact a running version of
36 // Bacula and ask it to do something (show about, show status,
37 // show events, ...)
38
39
40 #include "bacula.h"
41 #include "winbacula.h"
42 #include "winservice.h"
43 #include "wintray.h"
44
45 void set_service_description(SC_HANDLE hSCManager, SC_HANDLE hService,
46                              LPSTR lpDesc);
47
48 // OS-SPECIFIC ROUTINES
49
50 // Create an instance of the bacService class to cause the static fields to be
51 // initialised properly
52
53 bacService init;
54
55 extern bool    silent;
56
57 bacService::bacService()
58 {
59    OSVERSIONINFO osversioninfo;
60    osversioninfo.dwOSVersionInfoSize = sizeof(osversioninfo);
61
62    // Get the current OS version
63    if (!GetVersionEx(&osversioninfo)) {
64       g_platform_id = 0;
65    } else {
66       g_platform_id = osversioninfo.dwPlatformId;
67    }
68 }
69
70
71 // IsWin95 - returns a BOOL indicating whether the current OS is Win95
72 BOOL
73 bacService::IsWin95()
74 {
75    return (g_platform_id == VER_PLATFORM_WIN32_WINDOWS);
76 }
77
78 // IsWinNT - returns a bool indicating whether the current OS is WinNT
79 BOOL
80 bacService::IsWinNT()
81 {
82    return (g_platform_id == VER_PLATFORM_WIN32_NT);
83 }
84
85 // Internal routine to find the  Bacula menu class window and
86 // post a message to it!
87
88 BOOL
89 PostToBacula(UINT message, WPARAM wParam, LPARAM lParam)
90 {
91   // Locate the hidden Bacula menu window
92   HWND hservwnd = FindWindow(MENU_CLASS_NAME, NULL);
93   if (hservwnd == NULL) {
94      return FALSE;
95   }
96
97   // Post the message to Bacula
98   PostMessage(hservwnd, message, wParam, lParam);
99   return TRUE;
100 }
101
102
103 // Static routine to show the About dialog for a currently-running
104 // copy of Bacula, (usually a servicified version.)
105
106 BOOL
107 bacService::ShowAboutBox()
108 {
109   // Post to the Bacula menu window
110   if (!PostToBacula(MENU_ABOUTBOX_SHOW, 0, 0)) {
111      MessageBox(NULL, _("No existing instance of Bacula File service could be contacted"), szAppName, MB_ICONEXCLAMATION | MB_OK);
112      return FALSE;
113   }
114   return TRUE;
115 }
116
117 // Static routine to show the Status dialog for a currently-running
118 // copy of Bacula, (usually a servicified version.)
119
120 BOOL
121 bacService::ShowStatus()
122 {
123   // Post to the Bacula menu window
124   if (!PostToBacula(MENU_STATUS_SHOW, 0, 0)) {
125      MessageBox(NULL, _("No existing instance of Bacula File service could be contacted"), szAppName, MB_ICONEXCLAMATION | MB_OK);
126      return FALSE;
127   }
128   return TRUE;
129 }
130
131 // SERVICE-MODE ROUTINES
132
133 // Service-mode defines:
134
135 // Internal service name
136 #define BAC_SERVICENAME        "Bacula-fd"
137
138 // Displayed service name
139 #define BAC_SERVICEDISPLAYNAME "Bacula File Server"
140
141 // List other required serves 
142 #define BAC_DEPENDENCIES __TEXT("tcpip\0afd\0") 
143
144
145 // Internal service state
146 SERVICE_STATUS          g_srvstatus;       // current status of the service
147 SERVICE_STATUS_HANDLE   g_hstatus;
148 DWORD                   g_error = 0;
149 DWORD                   g_servicethread = 0;
150 char*                   g_errortext[256];
151
152
153 // Forward defines of internal service functions
154 void WINAPI ServiceMain(DWORD argc, char **argv);
155 DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam);
156 void ServiceStop();
157 void WINAPI ServiceCtrl(DWORD ctrlcode);
158 bool WINAPI CtrlHandler (DWORD ctrltype);
159 BOOL ReportStatus(DWORD state, DWORD exitcode, DWORD waithint);
160
161 // ROUTINE TO QUERY WHETHER THIS PROCESS IS RUNNING AS A SERVICE OR NOT
162
163 BOOL    g_servicemode = FALSE;
164
165 BOOL
166 bacService::RunningAsService()
167 {
168    return g_servicemode;
169 }
170
171 BOOL
172 bacService::KillRunningCopy()
173 {
174   while (PostToBacula(WM_CLOSE, 0, 0)) {
175      Sleep(500);
176   }
177   return TRUE;
178 }
179
180 // SERVICE MAIN ROUTINE
181 int
182 bacService::BaculaServiceMain()
183 {
184    // Mark that we are a service
185    g_servicemode = TRUE;
186
187    // How to run as a service depends upon the OS being used
188    switch (g_platform_id) {
189
190    // Windows 95/98/Me
191    case VER_PLATFORM_WIN32_WINDOWS:
192       {
193       // Obtain a handle to the kernel library
194       HINSTANCE kerneldll = LoadLibrary("KERNEL32.DLL");
195       if (kerneldll == NULL) {
196          MessageBox(NULL, _("KERNEL32.DLL not found: Bacula service not started"), 
197              "Bacula Service", MB_OK);
198          break;
199       }
200
201       // And find the RegisterServiceProcess function
202       DWORD (WINAPI *RegisterService)(DWORD, DWORD);
203       RegisterService = (DWORD (WINAPI *)(DWORD, DWORD))
204               GetProcAddress(kerneldll, "RegisterServiceProcess");
205       if (RegisterService == NULL) {
206          MessageBox(NULL, _("Registry service not found: Bacula service not started"),
207             "Bacula Service", MB_OK);
208          log_error_message(_("Registry service not found")); 
209          break;
210       }
211       
212       // Register this process with the OS as a service!
213       RegisterService(0, 1);
214
215       // Run the main program as a service
216       BaculaAppMain();
217
218       // Then remove the service from the system service table
219       RegisterService(0, 0);
220
221       // Free the kernel library
222       FreeLibrary(kerneldll);
223       break;
224       }
225
226
227    // Windows NT, Win2K, WinXP 
228    case VER_PLATFORM_WIN32_NT:
229       {
230       // Create a service entry table
231       SERVICE_TABLE_ENTRY dispatchTable[] = {
232          {BAC_SERVICENAME, (LPSERVICE_MAIN_FUNCTION)ServiceMain},
233          {NULL, NULL}
234       };
235
236       // Call the service control dispatcher with our entry table
237       if (!StartServiceCtrlDispatcher(dispatchTable)) {
238          log_error_message(_("StartServiceCtrlDispatcher failed."));
239       }
240       break;
241       } /* end case */
242    } /* end switch */
243    return 0;
244 }
245
246 // SERVICE MAIN ROUTINE - NT ONLY !!!
247 // NT/Win2K/WinXP ONLY !!!
248 void WINAPI ServiceMain(DWORD argc, char **argv)
249 {
250     DWORD dwThreadID;
251
252     // Register the service control handler
253     g_hstatus = RegisterServiceCtrlHandler(BAC_SERVICENAME, ServiceCtrl);
254
255     if (g_hstatus == 0) {
256        log_error_message(_("RegisterServiceCtlHandler failed")); 
257        MessageBox(NULL, _("Contact Register Service Handler failure"),
258           "Bacula service", MB_OK);
259        return;
260     }
261
262      // Set up some standard service state values
263     g_srvstatus.dwServiceType = SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS;
264     g_srvstatus.dwServiceSpecificExitCode = 0;
265
266         // Give this status to the SCM
267     if (!ReportStatus(
268             SERVICE_START_PENDING,          // Service state
269             NO_ERROR,                       // Exit code type
270             45000)) {                       // Hint as to how long Bacula should have hung before you assume error
271
272         ReportStatus(SERVICE_STOPPED, g_error,  0);
273         log_error_message(_("ReportStatus STOPPED failed 1")); 
274         return;
275     }
276
277         // Now start the service for real
278     (void)CreateThread(NULL, 0, ServiceWorkThread, NULL, 0, &dwThreadID);
279     return;
280 }
281
282 // SERVICE START ROUTINE - thread that calls BaculaAppMain
283 //   NT ONLY !!!!
284 DWORD WINAPI ServiceWorkThread(LPVOID lpwThreadParam)
285 {
286
287     // Save the current thread identifier
288     g_servicethread = GetCurrentThreadId();
289
290     // report the status to the service control manager.
291     //
292     if (!ReportStatus(
293           SERVICE_RUNNING,       // service state
294           NO_ERROR,              // exit code
295           0)) {                  // wait hint
296        MessageBox(NULL, _("Report Service failure"), "Bacula Service", MB_OK);
297        log_error_message("ReportStatus RUNNING failed"); 
298        return 0;
299     }
300
301     /* Call Bacula main code */
302     BaculaAppMain();
303
304     /* Mark that we're no longer running */
305     g_servicethread = 0;
306
307     /* Tell the service manager that we've stopped */
308     ReportStatus(SERVICE_STOPPED, g_error, 0);
309     return 0;
310 }
311
312
313 // SERVICE STOP ROUTINE - post a quit message to the relevant thread
314 void ServiceStop()
315 {
316    // Post a quit message to the main service thread
317    if (g_servicethread != 0) {
318       PostThreadMessage(g_servicethread, WM_QUIT, 0, 0);
319    }
320 }
321
322 // SERVICE INSTALL ROUTINE
323 int
324 bacService::InstallService(const char *pszCmdLine)
325 {
326    const int pathlength = 2048;
327    char path[pathlength];
328    char servicecmd[pathlength];
329    int len;
330
331    // Get the filename of this executable
332    if (GetModuleFileName(NULL, path, pathlength-(strlen(BaculaRunService)+2)) == 0) {
333       MessageBox(NULL, _("Unable to install Bacula File service"), szAppName, MB_ICONEXCLAMATION | MB_OK);
334       return 0;
335    }
336
337    // Append the service-start flag to the end of the path:
338    if ((int)strlen(path) + 5 + (int)strlen(BaculaRunService) + (int)strlen(pszCmdLine) < pathlength) {
339       sprintf(servicecmd, "\"%s\" %s %s", path, BaculaRunService, pszCmdLine);
340    } else {
341       log_error_message(_("Service command length too long")); 
342       MessageBox(NULL, _("Service command length too long. Service not registered."),
343           szAppName, MB_ICONEXCLAMATION | MB_OK);
344       return 0;
345    }
346
347    // How to add the Bacula service depends upon the OS
348    switch (g_platform_id) {
349
350    // Windows 95/98/Me
351    case VER_PLATFORM_WIN32_WINDOWS:
352       // Locate the RunService registry entry
353       HKEY runservices;
354       if (RegCreateKey(HKEY_LOCAL_MACHINE, 
355               "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
356               &runservices) != ERROR_SUCCESS) {
357          log_error_message(_("Cannot write System Registry")); 
358          MessageBox(NULL, _("The System Registry could not be updated - the Bacula service was not installed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
359          break;
360       }
361
362       // Attempt to add a Bacula key
363       if (RegSetValueEx(runservices, szAppName, 0, REG_SZ, (unsigned char *)servicecmd, strlen(servicecmd)+1) != ERROR_SUCCESS) {
364          RegCloseKey(runservices);
365          log_error_message(_("Cannot add Bacula key to System Registry")); 
366          MessageBox(NULL, _("The Bacula service could not be installed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
367          break;
368       }
369
370       RegCloseKey(runservices);
371
372       // We have successfully installed the service!
373       if (!silent) {
374          MessageBox(NULL,
375               _("The Bacula File service was successfully installed.\n"
376               "The service may be started by double clicking on the\n"
377               "Bacula \"Start\" icon and will be automatically\n"
378               "be run the next time this machine is rebooted. "),
379               szAppName,
380               MB_ICONINFORMATION | MB_OK);
381       }
382       break;
383
384    // Windows NT, Win2K, WinXP
385    case VER_PLATFORM_WIN32_NT:
386       SC_HANDLE   hservice;
387       SC_HANDLE   hsrvmanager;
388
389       // Open the default, local Service Control Manager database
390       hsrvmanager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
391       if (hsrvmanager == NULL) {
392          log_error_message("OpenSCManager failed"); 
393          MessageBox(NULL,
394             _("The Service Control Manager could not be contacted - the Bacula service was not installed"),
395             szAppName, MB_ICONEXCLAMATION | MB_OK);
396          break;
397       }
398
399       // Create an entry for the Bacula service
400       hservice = CreateService(
401               hsrvmanager,                    // SCManager database
402               BAC_SERVICENAME,                // name of service
403               BAC_SERVICEDISPLAYNAME,         // name to display
404               SERVICE_ALL_ACCESS,             // desired access
405               SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS,
406                                                                       // service type
407               SERVICE_AUTO_START,             // start type
408               SERVICE_ERROR_NORMAL,           // error control type
409               servicecmd,                     // service's binary
410               NULL,                           // no load ordering group
411               NULL,                           // no tag identifier
412               BAC_DEPENDENCIES,               // dependencies
413               NULL,                           // LocalSystem account
414               NULL);                          // no password
415       if (hservice == NULL) {
416          CloseServiceHandle(hsrvmanager);
417          log_error_message("CreateService failed"); 
418          MessageBox(NULL,
419              _("The Bacula service could not be installed"),
420               szAppName, MB_ICONEXCLAMATION | MB_OK);
421          break;
422       }
423
424       set_service_description(hsrvmanager,hservice, 
425 _("Provides file backup and restore services. Bacula -- the network backup solution."));
426
427       CloseServiceHandle(hsrvmanager);
428       CloseServiceHandle(hservice);
429
430       // Everything went fine
431       if (!silent) {
432          MessageBox(NULL,
433               _("The Bacula File service was successfully installed.\n"
434               "The service may be started from the Control Panel and will\n"
435               "automatically be run the next time this machine is rebooted."),
436               szAppName,
437               MB_ICONINFORMATION | MB_OK);
438       }
439       break;
440    default:
441       log_error_message("Unknown Windows System version"); 
442       MessageBox(NULL, 
443                  _("Unknown Windows operating system.\n"     
444                  "Cannot install Bacula service.\n"),
445                  szAppName, MB_ICONEXCLAMATION | MB_OK);
446        break;     
447    };
448
449    return 0;
450 }
451
452
453 // SERVICE REMOVE ROUTINE
454 int
455 bacService::RemoveService()
456 {
457    // How to remove the Bacula service depends upon the OS
458    switch (g_platform_id) {
459
460    // Windows 95/98/Me
461    case VER_PLATFORM_WIN32_WINDOWS:
462       // Locate the RunService registry entry
463       HKEY runservices;
464       if (RegOpenKey(HKEY_LOCAL_MACHINE, 
465               "Software\\Microsoft\\Windows\\CurrentVersion\\RunServices",
466               &runservices) != ERROR_SUCCESS) {
467          MessageBox(NULL, 
468             _("Could not find registry entry.\nService probably not registerd - the Bacula service was not removed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
469       } else {
470          // Attempt to delete the Bacula key
471          if (RegDeleteValue(runservices, szAppName) != ERROR_SUCCESS) {
472             RegCloseKey(runservices);
473             MessageBox(NULL, _("Could not delete Registry key.\nThe Bacula service could not be removed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
474          }
475
476          RegCloseKey(runservices);
477          break;
478       }
479
480       // Try to kill any running copy of Bacula
481       if (!KillRunningCopy()) {
482          MessageBox(NULL,
483              _("Bacula could not be contacted, probably not running"),
484              szAppName, MB_ICONEXCLAMATION | MB_OK);
485          break;
486       }
487
488       // We have successfully removed the service!
489       if (!silent) {
490          MessageBox(NULL, _("The Bacula service has been removed"), szAppName, MB_ICONINFORMATION | MB_OK);
491       }
492       break;
493
494    // Windows NT, Win2K, WinXP
495    case VER_PLATFORM_WIN32_NT:
496       SC_HANDLE   hservice;
497       SC_HANDLE   hsrvmanager;
498
499       // Open the SCM
500       hsrvmanager = OpenSCManager(
501          NULL,                   // machine (NULL == local)
502          NULL,                   // database (NULL == default)
503          SC_MANAGER_ALL_ACCESS   // access required
504          );
505       if (hsrvmanager) {
506          hservice = OpenService(hsrvmanager, BAC_SERVICENAME, SERVICE_ALL_ACCESS);
507          if (hservice != NULL) {
508             SERVICE_STATUS status;
509
510             // Try to stop the Bacula service
511             if (ControlService(hservice, SERVICE_CONTROL_STOP, &status)) {
512                while(QueryServiceStatus(hservice, &status)) {
513                   if (status.dwCurrentState == SERVICE_STOP_PENDING) {
514                      Sleep(1000);
515                   } else {
516                      break;
517                   }
518                }
519
520                if (status.dwCurrentState != SERVICE_STOPPED) {
521                   MessageBox(NULL, _("The Bacula file service could not be stopped"), szAppName, MB_ICONEXCLAMATION | MB_OK);
522                }
523             }
524
525             // Now remove the service from the SCM
526             if (DeleteService(hservice)) {
527                if (!silent) {
528                   MessageBox(NULL, _("The Bacula file service has been removed"), szAppName, MB_ICONINFORMATION | MB_OK);
529                }
530             } else {
531                MessageBox(NULL, _("The Bacula file service could not be removed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
532             }
533
534             CloseServiceHandle(hservice);
535          } else {
536             MessageBox(NULL, _("The Bacula file service could not be found"), szAppName, MB_ICONEXCLAMATION | MB_OK);
537          }
538
539          CloseServiceHandle(hsrvmanager);
540       } else {
541          MessageBox(NULL, _("The SCM could not be contacted - the Bacula file service was not removed"), szAppName, MB_ICONEXCLAMATION | MB_OK);
542       }
543       break;
544    }
545    return 0;
546 }
547
548 // USEFUL SERVICE SUPPORT ROUTINES
549
550 // Service control routine
551 void WINAPI ServiceCtrl(DWORD ctrlcode)
552 {
553     // What control code have we been sent?
554     switch(ctrlcode) {
555     case SERVICE_CONTROL_STOP:
556         // STOP : The service must stop
557         g_srvstatus.dwCurrentState = SERVICE_STOP_PENDING;
558         ServiceStop();
559         break;
560
561     case SERVICE_CONTROL_INTERROGATE:
562         // QUERY : Service control manager just wants to know our state
563         break;
564
565      default:
566         // Control code not recognised
567         break;
568     }
569
570     // Tell the control manager what we're up to.
571     ReportStatus(g_srvstatus.dwCurrentState, NO_ERROR, 0);
572 }
573
574 // Service manager status reporting
575 BOOL ReportStatus(DWORD state,
576                   DWORD exitcode,
577                   DWORD waithint)
578 {
579     static DWORD checkpoint = 1;
580     BOOL result = TRUE;
581
582     // If we're in the start state then we don't want the control manager
583     // sending us control messages because they'll confuse us.
584     if (state == SERVICE_START_PENDING) {
585        g_srvstatus.dwControlsAccepted = 0;
586     } else {
587        g_srvstatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;
588     }
589
590     // Save the new status we've been given
591     g_srvstatus.dwCurrentState = state;
592     g_srvstatus.dwWin32ExitCode = exitcode;
593     g_srvstatus.dwWaitHint = waithint;
594
595     // Update the checkpoint variable to let the SCM know that we
596     // haven't died if requests take a long time
597     if ((state == SERVICE_RUNNING) || (state == SERVICE_STOPPED)) {
598        g_srvstatus.dwCheckPoint = 0;
599     } else {
600        g_srvstatus.dwCheckPoint = checkpoint++;
601     }
602
603     // Tell the SCM our new status
604     if (!(result = SetServiceStatus(g_hstatus, &g_srvstatus))) {
605        log_error_message(_("SetServiceStatus failed"));
606     }
607
608     return result;
609 }
610
611 // Error reporting
612 void LogErrorMsg(char *message, char *fname, int lineno)
613 {
614    char        msgbuff[256];
615    HANDLE      heventsrc;
616    char *      strings[32];
617    LPTSTR      msg;
618
619    // Get the error code
620    g_error = GetLastError();
621    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER|
622                  FORMAT_MESSAGE_FROM_SYSTEM,
623                  NULL,
624                  g_error,
625                  0,
626                  (LPTSTR)&msg,
627                  0,
628                  NULL);
629
630    // Use event logging to log the error
631    heventsrc = RegisterEventSource(NULL, BAC_SERVICENAME);
632
633    sprintf(msgbuff, _("\n\n%s error: %ld at %s:%d"), 
634       BAC_SERVICENAME, g_error, fname, lineno);
635    strings[0] = msgbuff;
636    strings[1] = message;
637    strings[2] = msg;
638
639    if (heventsrc != NULL) {
640       MessageBeep(MB_OK);
641
642       ReportEvent(
643               heventsrc,              // handle of event source
644               EVENTLOG_ERROR_TYPE,    // event type
645               0,                      // event category
646               0,                      // event ID
647               NULL,                   // current user's SID
648               3,                      // strings in 'strings'
649               0,                      // no bytes of raw data
650               (const char **)strings, // array of error strings
651               NULL);                  // no raw data
652
653       DeregisterEventSource(heventsrc);
654    }
655    LocalFree(msg);
656 }
657 typedef BOOL  (WINAPI * WinAPI)(SC_HANDLE, DWORD, LPVOID);
658
659 void set_service_description(SC_HANDLE hSCManager, SC_HANDLE hService,
660                              LPSTR lpDesc) 
661
662     SC_LOCK sclLock; 
663     LPQUERY_SERVICE_LOCK_STATUS lpqslsBuf; 
664     SERVICE_DESCRIPTION sdBuf;
665     DWORD dwBytesNeeded;
666     WinAPI ChangeServiceDescription;
667  
668     HINSTANCE hLib = LoadLibrary("ADVAPI32.DLL");
669     if (!hLib) {
670        return;
671     }
672     ChangeServiceDescription = (WinAPI)GetProcAddress(hLib,
673        "ChangeServiceConfig2A");
674     FreeLibrary(hLib);
675     if (!ChangeServiceDescription) {
676        return;
677     }
678     
679     // Need to acquire database lock before reconfiguring. 
680     sclLock = LockServiceDatabase(hSCManager); 
681  
682     // If the database cannot be locked, report the details. 
683     if (sclLock == NULL) {
684        // Exit if the database is not locked by another process. 
685        if (GetLastError() != ERROR_SERVICE_DATABASE_LOCKED) {
686           log_error_message("LockServiceDatabase"); 
687           return;
688        }
689  
690        // Allocate a buffer to get details about the lock. 
691        lpqslsBuf = (LPQUERY_SERVICE_LOCK_STATUS)LocalAlloc( 
692             LPTR, sizeof(QUERY_SERVICE_LOCK_STATUS)+256); 
693        if (lpqslsBuf == NULL) {
694           log_error_message("LocalAlloc"); 
695           return;
696        }
697  
698        // Get and print the lock status information. 
699        if (!QueryServiceLockStatus( 
700               hSCManager, 
701               lpqslsBuf, 
702               sizeof(QUERY_SERVICE_LOCK_STATUS)+256, 
703               &dwBytesNeeded)) {
704           log_error_message("QueryServiceLockStatus"); 
705        }
706  
707        if (lpqslsBuf->fIsLocked) {
708           printf(_("Locked by: %s, duration: %ld seconds\n"), 
709                 lpqslsBuf->lpLockOwner, 
710                 lpqslsBuf->dwLockDuration); 
711        } else {
712           printf(_("No longer locked\n")); 
713        }
714  
715        LocalFree(lpqslsBuf); 
716        log_error_message(_("Could not lock database")); 
717        return;
718     } 
719  
720     // The database is locked, so it is safe to make changes. 
721  
722     sdBuf.lpDescription = lpDesc;
723
724     if (!ChangeServiceDescription(
725          hService,                   // handle to service
726          SERVICE_CONFIG_DESCRIPTION, // change: description
727          &sdBuf) ) {                 // value: new description
728        log_error_message("ChangeServiceConfig2");
729     }
730
731     // Release the database lock. 
732     UnlockServiceDatabase(sclLock); 
733 }